Added dbus method to get whether 5Ghz band is supported
[platform/upstream/connman.git] / src / technology.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2013  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <string.h>
28 #if defined TIZEN_EXT
29 #include <stdio.h>
30 #include <stdlib.h>
31 #endif
32
33 #include <gdbus.h>
34
35 #include "connman.h"
36
37 static DBusConnection *connection;
38
39 static GSList *technology_list = NULL;
40
41 /*
42  * List of devices with no technology associated with them either because of
43  * no compiled in support or the driver is not yet loaded.
44 */
45 static GSList *techless_device_list = NULL;
46 static GHashTable *rfkill_list;
47
48 static bool global_offlinemode;
49
50 #if defined TIZEN_EXT
51 typedef enum {
52         CONNMAN_SCAN_TYPE_FULL_CHANNEL = 0x00,
53         CONNMAN_SCAN_TYPE_SPECIFIC_AP,
54         CONNMAN_SCAN_TYPE_MULTI_AP,
55 } connman_scan_type_e;
56
57 static connman_scan_type_e g_scan_type = -1;
58 #endif
59
60 struct connman_rfkill {
61         unsigned int index;
62         enum connman_service_type type;
63         bool softblock;
64         bool hardblock;
65 };
66
67 struct connman_technology {
68         int refcount;
69         enum connman_service_type type;
70         char *path;
71         GSList *device_list;
72         bool enabled;
73         char *regdom;
74         bool connected;
75
76         bool tethering;
77         bool tethering_persistent; /* Tells the save status, needed
78                                               * as offline mode might set
79                                               * tethering OFF.
80                                               */
81         char *tethering_ident;
82         char *tethering_passphrase;
83         bool tethering_hidden;
84
85         bool enable_persistent; /* Save the tech state */
86
87         GSList *driver_list;
88
89         DBusMessage *pending_reply;
90         guint pending_timeout;
91
92         GSList *scan_pending;
93
94         bool rfkill_driven;
95         bool softblocked;
96         bool hardblocked;
97         bool dbus_registered;
98 #if defined TIZEN_EXT_WIFI_MESH
99         DBusMessage *mesh_dbus_msg;
100 #endif
101 #if defined TIZEN_EXT
102         bool is_5_0_ghz_supported;
103 #endif
104 };
105
106 static GSList *driver_list = NULL;
107
108 static int technology_enabled(struct connman_technology *technology);
109 static int technology_disabled(struct connman_technology *technology);
110
111 static gint compare_priority(gconstpointer a, gconstpointer b)
112 {
113         const struct connman_technology_driver *driver1 = a;
114         const struct connman_technology_driver *driver2 = b;
115
116         return driver2->priority - driver1->priority;
117 }
118
119 static void rfkill_check(gpointer key, gpointer value, gpointer user_data)
120 {
121         struct connman_rfkill *rfkill = value;
122         enum connman_service_type type = GPOINTER_TO_INT(user_data);
123
124         /* Calling _technology_rfkill_add will update the tech. */
125         if (rfkill->type == type)
126                 __connman_technology_add_rfkill(rfkill->index, type,
127                                 rfkill->softblock, rfkill->hardblock);
128 }
129
130 bool
131 connman_technology_is_tethering_allowed(enum connman_service_type type)
132 {
133         static char *allowed_default[] = { "wifi", "bluetooth", "gadget",
134                                            NULL };
135         const char *type_str = __connman_service_type2string(type);
136         char **allowed;
137         int i;
138
139         if (!type_str)
140                 return false;
141
142         allowed = connman_setting_get_string_list("TetheringTechnologies");
143         if (!allowed)
144                 allowed = allowed_default;
145
146         for (i = 0; allowed[i]; i++) {
147                 if (g_strcmp0(allowed[i], type_str) == 0)
148                         return true;
149         }
150
151         return false;
152 }
153
154 static const char *get_name(enum connman_service_type type)
155 {
156         switch (type) {
157         case CONNMAN_SERVICE_TYPE_UNKNOWN:
158         case CONNMAN_SERVICE_TYPE_SYSTEM:
159         case CONNMAN_SERVICE_TYPE_GPS:
160         case CONNMAN_SERVICE_TYPE_VPN:
161                 break;
162         case CONNMAN_SERVICE_TYPE_GADGET:
163                 return "Gadget";
164         case CONNMAN_SERVICE_TYPE_ETHERNET:
165                 return "Wired";
166         case CONNMAN_SERVICE_TYPE_WIFI:
167                 return "WiFi";
168         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
169                 return "Bluetooth";
170         case CONNMAN_SERVICE_TYPE_CELLULAR:
171                 return "Cellular";
172         case CONNMAN_SERVICE_TYPE_P2P:
173                 return "P2P";
174 #if defined TIZEN_EXT_WIFI_MESH
175         case CONNMAN_SERVICE_TYPE_MESH:
176                 return "Mesh";
177 #endif
178         }
179
180         return NULL;
181 }
182
183 static void technology_save(struct connman_technology *technology)
184 {
185         GKeyFile *keyfile;
186         gchar *identifier;
187         const char *name = get_name(technology->type);
188
189         DBG("technology %p type %d name %s", technology, technology->type,
190                                                                         name);
191         if (!name)
192                 return;
193
194         keyfile = __connman_storage_load_global();
195         if (!keyfile)
196                 keyfile = g_key_file_new();
197
198         identifier = g_strdup_printf("%s", name);
199         if (!identifier)
200                 goto done;
201
202         g_key_file_set_boolean(keyfile, identifier, "Enable",
203                                 technology->enable_persistent);
204
205         g_key_file_set_boolean(keyfile, identifier, "Tethering",
206                                 technology->tethering_persistent);
207
208         g_key_file_set_boolean(keyfile, identifier, "Hidden",
209                                 technology->tethering_hidden);
210
211         if (technology->tethering_ident)
212                 g_key_file_set_string(keyfile, identifier,
213                                         "Tethering.Identifier",
214                                         technology->tethering_ident);
215
216         if (technology->tethering_passphrase)
217                 g_key_file_set_string(keyfile, identifier,
218                                         "Tethering.Passphrase",
219                                         technology->tethering_passphrase);
220
221 done:
222         g_free(identifier);
223
224         __connman_storage_save_global(keyfile);
225
226         g_key_file_free(keyfile);
227
228         return;
229 }
230
231 static void tethering_changed(struct connman_technology *technology)
232 {
233         dbus_bool_t tethering = technology->tethering;
234
235         connman_dbus_property_changed_basic(technology->path,
236                                 CONNMAN_TECHNOLOGY_INTERFACE, "Tethering",
237                                                 DBUS_TYPE_BOOLEAN, &tethering);
238
239         technology_save(technology);
240 }
241
242 int connman_technology_tethering_notify(struct connman_technology *technology,
243                                                         bool enabled)
244 {
245         int err;
246
247         DBG("technology %p enabled %u", technology, enabled);
248
249         if (technology->tethering == enabled)
250                 return -EALREADY;
251
252         if (enabled) {
253                 err = __connman_tethering_set_enabled();
254                 if (err < 0)
255                         return err;
256         } else
257                 __connman_tethering_set_disabled();
258
259         technology->tethering = enabled;
260         tethering_changed(technology);
261
262         return 0;
263 }
264
265 static int set_tethering(struct connman_technology *technology,
266                                 bool enabled)
267 {
268         int result = -EOPNOTSUPP;
269         int err;
270         const char *ident, *passphrase, *bridge;
271         GSList *tech_drivers;
272
273         ident = technology->tethering_ident;
274         passphrase = technology->tethering_passphrase;
275
276         __sync_synchronize();
277         if (!technology->enabled)
278                 return -EACCES;
279
280         bridge = __connman_tethering_get_bridge();
281         if (!bridge)
282                 return -EOPNOTSUPP;
283
284         if (technology->type == CONNMAN_SERVICE_TYPE_WIFI && (!ident))
285                 return -EINVAL;
286
287         for (tech_drivers = technology->driver_list; tech_drivers;
288              tech_drivers = g_slist_next(tech_drivers)) {
289                 struct connman_technology_driver *driver = tech_drivers->data;
290
291                 if (!driver || !driver->set_tethering)
292                         continue;
293
294                 err = driver->set_tethering(technology, ident, passphrase,
295                                 bridge, enabled);
296
297                 if (result == -EINPROGRESS)
298                         continue;
299
300                 if (err == -EINPROGRESS || err == 0)
301                         result = err;
302         }
303
304         return result;
305 }
306
307 void connman_technology_regdom_notify(struct connman_technology *technology,
308                                                         const char *alpha2)
309 {
310         DBG("");
311
312         if (!alpha2)
313                 connman_error("Failed to set regulatory domain");
314         else
315                 DBG("Regulatory domain set to %s", alpha2);
316
317         g_free(technology->regdom);
318         technology->regdom = g_strdup(alpha2);
319 }
320
321 static int set_regdom_by_device(struct connman_technology *technology,
322                                                         const char *alpha2)
323 {
324         GSList *list;
325
326         for (list = technology->device_list; list; list = list->next) {
327                 struct connman_device *device = list->data;
328
329                 if (connman_device_set_regdom(device, alpha2) != 0)
330                         return -ENOTSUP;
331         }
332
333         return 0;
334 }
335
336 int connman_technology_set_regdom(const char *alpha2)
337 {
338         GSList *list, *tech_drivers;
339
340         for (list = technology_list; list; list = list->next) {
341                 struct connman_technology *technology = list->data;
342
343                 if (set_regdom_by_device(technology, alpha2) != 0) {
344
345                         for (tech_drivers = technology->driver_list;
346                              tech_drivers;
347                              tech_drivers = g_slist_next(tech_drivers)) {
348
349                                 struct connman_technology_driver *driver =
350                                         tech_drivers->data;
351
352                                 if (driver->set_regdom)
353                                         driver->set_regdom(technology, alpha2);
354                         }
355                 }
356         }
357
358         return 0;
359 }
360
361 static struct connman_technology *technology_find(enum connman_service_type type)
362 {
363         GSList *list;
364
365         DBG("type %d", type);
366
367         for (list = technology_list; list; list = list->next) {
368                 struct connman_technology *technology = list->data;
369
370                 if (technology->type == type)
371                         return technology;
372         }
373
374         return NULL;
375 }
376
377 bool connman_technology_get_wifi_tethering(const char **ssid,
378                                                         const char **psk)
379 {
380         struct connman_technology *technology;
381
382         if (!ssid || !psk)
383                 return false;
384
385         *ssid = *psk = NULL;
386
387         technology = technology_find(CONNMAN_SERVICE_TYPE_WIFI);
388         if (!technology)
389                 return false;
390
391         if (!technology->tethering)
392                 return false;
393
394         *ssid = technology->tethering_ident;
395         *psk = technology->tethering_passphrase;
396
397         return true;
398 }
399
400 #if defined TIZEN_EXT
401 void connman_techonology_wifi_set_5ghz_supported(struct connman_technology *wifi_technology,
402                 bool is_5_0_ghz_supported)
403 {
404         DBG("");
405
406         wifi_technology->is_5_0_ghz_supported = is_5_0_ghz_supported;
407 }
408 #endif
409
410 static void free_rfkill(gpointer data)
411 {
412         struct connman_rfkill *rfkill = data;
413
414         g_free(rfkill);
415 }
416
417 static void technology_load(struct connman_technology *technology)
418 {
419         GKeyFile *keyfile;
420         gchar *identifier;
421         GError *error = NULL;
422         bool enable, need_saving = false;
423
424         DBG("technology %p", technology);
425
426         keyfile = __connman_storage_load_global();
427         /* Fallback on disabling technology if file not found. */
428         if (!keyfile) {
429                 if (technology->type == CONNMAN_SERVICE_TYPE_ETHERNET)
430                         /* We enable ethernet by default */
431                         technology->enable_persistent = true;
432                 else
433                         technology->enable_persistent = false;
434                 return;
435         }
436
437         identifier = g_strdup_printf("%s", get_name(technology->type));
438         if (!identifier)
439                 goto done;
440
441         enable = g_key_file_get_boolean(keyfile, identifier, "Enable", &error);
442         if (!error)
443                 technology->enable_persistent = enable;
444         else {
445                 if (technology->type == CONNMAN_SERVICE_TYPE_ETHERNET)
446                         technology->enable_persistent = true;
447                 else
448                         technology->enable_persistent = false;
449
450                 need_saving = true;
451                 g_clear_error(&error);
452         }
453
454         enable = g_key_file_get_boolean(keyfile, identifier,
455                                         "Tethering", &error);
456         if (!error)
457                 technology->tethering_persistent = enable;
458         else {
459                 need_saving = true;
460                 g_clear_error(&error);
461         }
462
463         if (need_saving)
464                 technology_save(technology);
465
466         technology->tethering_ident = g_key_file_get_string(keyfile,
467                                 identifier, "Tethering.Identifier", NULL);
468
469         technology->tethering_passphrase = g_key_file_get_string(keyfile,
470                                 identifier, "Tethering.Passphrase", NULL);
471 done:
472         g_free(identifier);
473
474         g_key_file_free(keyfile);
475
476         return;
477 }
478
479 bool __connman_technology_get_offlinemode(void)
480 {
481         return global_offlinemode;
482 }
483
484 static void connman_technology_save_offlinemode(void)
485 {
486         GKeyFile *keyfile;
487         GError *error = NULL;
488         bool offlinemode;
489
490         keyfile = __connman_storage_load_global();
491
492         if (!keyfile) {
493                 keyfile = g_key_file_new();
494                 g_key_file_set_boolean(keyfile, "global",
495                                         "OfflineMode", global_offlinemode);
496
497                 __connman_storage_save_global(keyfile);
498         }
499         else {
500                 offlinemode = g_key_file_get_boolean(keyfile, "global",
501                                                 "OfflineMode", &error);
502
503                 if (error || offlinemode != global_offlinemode) {
504                         g_key_file_set_boolean(keyfile, "global",
505                                         "OfflineMode", global_offlinemode);
506                         if (error)
507                                 g_clear_error(&error);
508
509                         __connman_storage_save_global(keyfile);
510                 }
511         }
512
513         g_key_file_free(keyfile);
514
515         return;
516 }
517
518 static bool connman_technology_load_offlinemode(void)
519 {
520         GKeyFile *keyfile;
521         GError *error = NULL;
522         bool offlinemode;
523
524         /* If there is a error, we enable offlinemode */
525         keyfile = __connman_storage_load_global();
526         if (!keyfile)
527                 return false;
528
529         offlinemode = g_key_file_get_boolean(keyfile, "global",
530                                                 "OfflineMode", &error);
531         if (error) {
532                 offlinemode = false;
533                 g_clear_error(&error);
534         }
535
536         g_key_file_free(keyfile);
537
538         return offlinemode;
539 }
540
541 static void append_properties(DBusMessageIter *iter,
542                 struct connman_technology *technology)
543 {
544         DBusMessageIter dict;
545         dbus_bool_t val;
546         const char *str;
547
548         connman_dbus_dict_open(iter, &dict);
549
550         str = get_name(technology->type);
551         if (str)
552                 connman_dbus_dict_append_basic(&dict, "Name",
553                                                 DBUS_TYPE_STRING, &str);
554
555         str = __connman_service_type2string(technology->type);
556         if (str)
557                 connman_dbus_dict_append_basic(&dict, "Type",
558                                                 DBUS_TYPE_STRING, &str);
559
560         __sync_synchronize();
561         val = technology->enabled;
562         connman_dbus_dict_append_basic(&dict, "Powered",
563                                         DBUS_TYPE_BOOLEAN,
564                                         &val);
565
566         val = technology->connected;
567         connman_dbus_dict_append_basic(&dict, "Connected",
568                                         DBUS_TYPE_BOOLEAN,
569                                         &val);
570
571         val = technology->tethering;
572         connman_dbus_dict_append_basic(&dict, "Tethering",
573                                         DBUS_TYPE_BOOLEAN,
574                                         &val);
575
576         if (technology->tethering_ident)
577                 connman_dbus_dict_append_basic(&dict, "TetheringIdentifier",
578                                         DBUS_TYPE_STRING,
579                                         &technology->tethering_ident);
580
581         if (technology->tethering_passphrase)
582                 connman_dbus_dict_append_basic(&dict, "TetheringPassphrase",
583                                         DBUS_TYPE_STRING,
584                                         &technology->tethering_passphrase);
585
586         val = technology->tethering_hidden;
587         connman_dbus_dict_append_basic(&dict, "Hidden",
588                                         DBUS_TYPE_BOOLEAN,
589                                         &val);
590
591         connman_dbus_dict_close(iter, &dict);
592 }
593
594 static void technology_added_signal(struct connman_technology *technology)
595 {
596         DBusMessage *signal;
597         DBusMessageIter iter;
598
599         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
600                         CONNMAN_MANAGER_INTERFACE, "TechnologyAdded");
601         if (!signal)
602                 return;
603
604         dbus_message_iter_init_append(signal, &iter);
605         dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
606                                                         &technology->path);
607         append_properties(&iter, technology);
608
609         dbus_connection_send(connection, signal, NULL);
610         dbus_message_unref(signal);
611 }
612
613 static void technology_removed_signal(struct connman_technology *technology)
614 {
615         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
616                         CONNMAN_MANAGER_INTERFACE, "TechnologyRemoved",
617                         DBUS_TYPE_OBJECT_PATH, &technology->path,
618                         DBUS_TYPE_INVALID);
619 }
620
621 static DBusMessage *get_properties(DBusConnection *conn,
622                                         DBusMessage *message, void *user_data)
623 {
624         struct connman_technology *technology = user_data;
625         DBusMessage *reply;
626         DBusMessageIter iter;
627
628         reply = dbus_message_new_method_return(message);
629         if (!reply)
630                 return NULL;
631
632         dbus_message_iter_init_append(reply, &iter);
633         append_properties(&iter, technology);
634
635         return reply;
636 }
637
638 void __connman_technology_list_struct(DBusMessageIter *array)
639 {
640         GSList *list;
641         DBusMessageIter entry;
642
643         for (list = technology_list; list; list = list->next) {
644                 struct connman_technology *technology = list->data;
645
646                 if (!technology->path ||
647                                 (technology->rfkill_driven &&
648                                  technology->hardblocked))
649                         continue;
650
651                 dbus_message_iter_open_container(array, DBUS_TYPE_STRUCT,
652                                 NULL, &entry);
653                 dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
654                                 &technology->path);
655                 append_properties(&entry, technology);
656                 dbus_message_iter_close_container(array, &entry);
657         }
658 }
659
660 static gboolean technology_pending_reply(gpointer user_data)
661 {
662         struct connman_technology *technology = user_data;
663         DBusMessage *reply;
664
665         /* Power request timedout, send ETIMEDOUT. */
666         if (technology->pending_reply) {
667                 reply = __connman_error_failed(technology->pending_reply, ETIMEDOUT);
668                 if (reply)
669                         g_dbus_send_message(connection, reply);
670
671                 dbus_message_unref(technology->pending_reply);
672                 technology->pending_reply = NULL;
673                 technology->pending_timeout = 0;
674         }
675
676         return FALSE;
677 }
678
679 static int technology_affect_devices(struct connman_technology *technology,
680                                                 bool enable_device)
681 {
682         int err = 0, err_dev;
683         GSList *list;
684
685         if (technology->type == CONNMAN_SERVICE_TYPE_P2P) {
686                 if (enable_device)
687                         __connman_technology_enabled(technology->type);
688                 else
689                         __connman_technology_disabled(technology->type);
690                 return 0;
691         }
692
693 #if defined TIZEN_EXT_WIFI_MESH
694         if (technology->type == CONNMAN_SERVICE_TYPE_MESH)
695                 return 0;
696 #endif
697
698         for (list = technology->device_list; list; list = list->next) {
699                 struct connman_device *device = list->data;
700
701                 if (enable_device)
702                         err_dev = __connman_device_enable(device);
703                 else
704                         err_dev = __connman_device_disable(device);
705
706                 if (err_dev < 0 && err_dev != -EALREADY)
707                         err = err_dev;
708         }
709
710         return err;
711 }
712
713 static void powered_changed(struct connman_technology *technology)
714 {
715         dbus_bool_t enabled;
716
717         if (!technology->dbus_registered)
718                 return;
719
720         if (technology->pending_reply) {
721                 g_dbus_send_reply(connection,
722                                 technology->pending_reply, DBUS_TYPE_INVALID);
723                 dbus_message_unref(technology->pending_reply);
724                 technology->pending_reply = NULL;
725
726                 g_source_remove(technology->pending_timeout);
727                 technology->pending_timeout = 0;
728         }
729
730         __sync_synchronize();
731         enabled = technology->enabled;
732 #if defined TIZEN_EXT
733         DBG("ConnMan, Powered : %s, %s",
734                         enabled ? "TRUE" : "FALSE",technology->path);
735 #endif
736         connman_dbus_property_changed_basic(technology->path,
737                         CONNMAN_TECHNOLOGY_INTERFACE, "Powered",
738                         DBUS_TYPE_BOOLEAN, &enabled);
739 }
740
741 static void enable_tethering(struct connman_technology *technology)
742 {
743         int ret;
744
745         if (!connman_setting_get_bool("PersistentTetheringMode"))
746                 return;
747
748         ret = set_tethering(technology, true);
749         if (ret < 0 && ret != -EALREADY)
750                 DBG("Cannot enable tethering yet for %s (%d/%s)",
751                         get_name(technology->type),
752                         -ret, strerror(-ret));
753 }
754
755 static int technology_enabled(struct connman_technology *technology)
756 {
757         __sync_synchronize();
758         if (technology->enabled)
759                 return -EALREADY;
760
761         technology->enabled = true;
762
763         if (technology->type == CONNMAN_SERVICE_TYPE_WIFI) {
764                 struct connman_technology *p2p;
765
766                 p2p = technology_find(CONNMAN_SERVICE_TYPE_P2P);
767                 if (p2p && !p2p->enabled && p2p->enable_persistent)
768                         technology_enabled(p2p);
769         }
770
771         if (technology->tethering_persistent)
772                 enable_tethering(technology);
773
774         powered_changed(technology);
775
776         return 0;
777 }
778
779 static int technology_enable(struct connman_technology *technology)
780 {
781         int err = 0;
782         int err_dev;
783
784         DBG("technology %p enable", technology);
785
786         __sync_synchronize();
787
788         if (technology->type == CONNMAN_SERVICE_TYPE_P2P) {
789                 struct connman_technology *wifi;
790
791                 wifi = technology_find(CONNMAN_SERVICE_TYPE_WIFI);
792                 if (wifi && wifi->enabled)
793                         return technology_enabled(technology);
794                 return 0;
795         }
796
797         if (technology->enabled)
798                 return -EALREADY;
799
800         if (technology->pending_reply)
801                 return -EBUSY;
802
803         if (connman_setting_get_bool("PersistentTetheringMode") &&
804                                         technology->tethering)
805                 set_tethering(technology, true);
806
807         if (technology->rfkill_driven)
808                 err = __connman_rfkill_block(technology->type, false);
809
810         err_dev = technology_affect_devices(technology, true);
811
812         if (!technology->rfkill_driven)
813                 err = err_dev;
814
815         return err;
816 }
817
818 static int technology_disabled(struct connman_technology *technology)
819 {
820         __sync_synchronize();
821         if (!technology->enabled)
822                 return -EALREADY;
823
824         technology->enabled = false;
825
826         powered_changed(technology);
827
828         return 0;
829 }
830
831 static int technology_disable(struct connman_technology *technology)
832 {
833         int err;
834
835         DBG("technology %p disable", technology);
836
837         __sync_synchronize();
838
839         if (technology->type == CONNMAN_SERVICE_TYPE_P2P) {
840                 technology->enable_persistent = false;
841                 return technology_disabled(technology);
842         } else if (technology->type == CONNMAN_SERVICE_TYPE_WIFI) {
843                 struct connman_technology *p2p;
844
845                 p2p = technology_find(CONNMAN_SERVICE_TYPE_P2P);
846                 if (p2p && p2p->enabled) {
847                         p2p->enable_persistent = true;
848                         technology_disabled(p2p);
849                 }
850         }
851
852         if (!technology->enabled)
853                 return -EALREADY;
854
855         if (technology->pending_reply)
856                 return -EBUSY;
857
858         if (technology->tethering)
859                 set_tethering(technology, false);
860
861         err = technology_affect_devices(technology, false);
862
863         if (technology->rfkill_driven)
864                 err = __connman_rfkill_block(technology->type, true);
865
866         return err;
867 }
868
869 static DBusMessage *set_powered(struct connman_technology *technology,
870                                 DBusMessage *msg, bool powered)
871 {
872         DBusMessage *reply = NULL;
873         int err = 0;
874
875         if (technology->rfkill_driven && technology->hardblocked) {
876                 err = -EACCES;
877                 goto make_reply;
878         }
879
880         if (powered)
881                 err = technology_enable(technology);
882         else
883                 err = technology_disable(technology);
884
885         if (err != -EBUSY) {
886                 technology->enable_persistent = powered;
887                 technology_save(technology);
888         }
889
890 make_reply:
891         if (err == -EINPROGRESS) {
892                 technology->pending_reply = dbus_message_ref(msg);
893                 technology->pending_timeout = g_timeout_add_seconds(10,
894                                         technology_pending_reply, technology);
895         } else if (err == -EALREADY) {
896                 if (powered)
897                         reply = __connman_error_already_enabled(msg);
898                 else
899                         reply = __connman_error_already_disabled(msg);
900         } else if (err < 0)
901                 reply = __connman_error_failed(msg, -err);
902         else
903                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
904
905         return reply;
906 }
907
908 #if defined TIZEN_EXT
909 int set_connman_bssid(enum bssid_type mode, char *bssid)
910 {
911         static unsigned char bssid_for_connect[6];
912         static int bssid_len;
913
914         DBG("mode : %d", mode);
915
916         if (mode == CHECK_BSSID) {
917                 return bssid_len;
918         }
919
920         if (mode == GET_BSSID && bssid) {
921                 memcpy(bssid, bssid_for_connect, 6);
922                 return bssid_len;
923         }
924
925         if (mode == RESET_BSSID) {
926                 bssid_len = 0;
927                 return bssid_len;
928         }
929
930         if (mode != SET_BSSID || !bssid) {
931                 DBG("Invalid parameter");
932                 return 0;
933         }
934
935         bssid_len = sscanf(bssid, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
936                 &bssid_for_connect[0], &bssid_for_connect[1], &bssid_for_connect[2],
937                 &bssid_for_connect[3], &bssid_for_connect[4], &bssid_for_connect[5]);
938         if (bssid_len != 6) {
939                 DBG("Incorrect BSSID format. bssid_len = %d", bssid_len);
940                 bssid_len = 0;
941         }
942
943         DBG("SET BSSID len : %d, BSSID : %02x:%02x:%02x:%02x:%02x:%02x", bssid_len,
944                 bssid_for_connect[0], bssid_for_connect[1], bssid_for_connect[2],
945                 bssid_for_connect[3], bssid_for_connect[4], bssid_for_connect[5]);
946
947         return bssid_len;
948 }
949 #endif
950
951 static DBusMessage *set_property(DBusConnection *conn,
952                                         DBusMessage *msg, void *data)
953 {
954         struct connman_technology *technology = data;
955         DBusMessageIter iter, value;
956         const char *name;
957         int type, err;
958
959         DBG("conn %p", conn);
960
961         if (!dbus_message_iter_init(msg, &iter))
962                 return __connman_error_invalid_arguments(msg);
963
964         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
965                 return __connman_error_invalid_arguments(msg);
966
967         dbus_message_iter_get_basic(&iter, &name);
968         dbus_message_iter_next(&iter);
969
970         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
971                 return __connman_error_invalid_arguments(msg);
972
973         dbus_message_iter_recurse(&iter, &value);
974
975         type = dbus_message_iter_get_arg_type(&value);
976
977         DBG("property %s", name);
978
979         if (technology->type == CONNMAN_SERVICE_TYPE_WIFI && technology->connected) {
980                 uid_t uid;
981                 if (connman_dbus_get_connection_unix_user_sync(conn,
982                                                 dbus_message_get_sender(msg),
983                                                 &uid) < 0) {
984                         DBG("Can not get unix user id!");
985                         return __connman_error_permission_denied(msg);
986                 }
987
988                 if (!__connman_service_is_user_allowed(CONNMAN_SERVICE_TYPE_WIFI, uid)) {
989                         DBG("Not allow this user to operate wifi technology now!");
990                         return __connman_error_permission_denied(msg);
991                 }
992         }
993
994         if (g_str_equal(name, "Tethering")) {
995                 dbus_bool_t tethering;
996                 int err;
997
998                 if (type != DBUS_TYPE_BOOLEAN)
999                         return __connman_error_invalid_arguments(msg);
1000
1001                 if (!connman_technology_is_tethering_allowed(technology->type)) {
1002                         DBG("%s tethering not allowed by config file",
1003                                 __connman_service_type2string(technology->type));
1004                         return __connman_error_not_supported(msg);
1005                 }
1006
1007                 dbus_message_iter_get_basic(&value, &tethering);
1008
1009                 if (technology->tethering == tethering) {
1010                         if (!tethering)
1011                                 return __connman_error_already_disabled(msg);
1012                         else
1013                                 return __connman_error_already_enabled(msg);
1014                 }
1015
1016                 err = set_tethering(technology, tethering);
1017                 if (err < 0)
1018                         return __connman_error_failed(msg, -err);
1019
1020                 technology->tethering_persistent = tethering;
1021
1022                 technology_save(technology);
1023
1024         } else if (g_str_equal(name, "TetheringIdentifier")) {
1025                 const char *str;
1026
1027                 dbus_message_iter_get_basic(&value, &str);
1028
1029                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
1030                         return __connman_error_not_supported(msg);
1031
1032                 if (strlen(str) < 1 || strlen(str) > 32)
1033                         return __connman_error_invalid_arguments(msg);
1034
1035                 if (g_strcmp0(technology->tethering_ident, str) != 0) {
1036                         g_free(technology->tethering_ident);
1037                         technology->tethering_ident = g_strdup(str);
1038                         technology_save(technology);
1039
1040                         connman_dbus_property_changed_basic(technology->path,
1041                                                 CONNMAN_TECHNOLOGY_INTERFACE,
1042                                                 "TetheringIdentifier",
1043                                                 DBUS_TYPE_STRING,
1044                                                 &technology->tethering_ident);
1045                 }
1046         } else if (g_str_equal(name, "TetheringPassphrase")) {
1047                 const char *str;
1048
1049                 dbus_message_iter_get_basic(&value, &str);
1050
1051                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
1052                         return __connman_error_not_supported(msg);
1053
1054                 err = __connman_service_check_passphrase(CONNMAN_SERVICE_SECURITY_PSK,
1055                                                         str);
1056                 if (err < 0)
1057                         return __connman_error_passphrase_required(msg);
1058
1059                 if (g_strcmp0(technology->tethering_passphrase, str) != 0) {
1060                         g_free(technology->tethering_passphrase);
1061                         technology->tethering_passphrase = g_strdup(str);
1062                         technology_save(technology);
1063
1064                         connman_dbus_property_changed_basic(technology->path,
1065                                         CONNMAN_TECHNOLOGY_INTERFACE,
1066                                         "TetheringPassphrase",
1067                                         DBUS_TYPE_STRING,
1068                                         &technology->tethering_passphrase);
1069                 }
1070         } else if (g_str_equal(name, "Hidden")) {
1071                 dbus_bool_t hidden;
1072
1073                 if (type != DBUS_TYPE_BOOLEAN)
1074                         return __connman_error_invalid_arguments(msg);
1075
1076                 dbus_message_iter_get_basic(&value, &hidden);
1077
1078                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
1079                         return __connman_error_not_supported(msg);
1080
1081                 technology->tethering_hidden = hidden;
1082                 technology_save(technology);
1083
1084                 connman_dbus_property_changed_basic(technology->path,
1085                                         CONNMAN_TECHNOLOGY_INTERFACE,
1086                                         "Hidden",
1087                                         DBUS_TYPE_BOOLEAN,
1088                                         &hidden);
1089         } else if (g_str_equal(name, "Powered")) {
1090                 dbus_bool_t enable;
1091
1092                 if (type != DBUS_TYPE_BOOLEAN)
1093                         return __connman_error_invalid_arguments(msg);
1094
1095                 dbus_message_iter_get_basic(&value, &enable);
1096
1097                 return set_powered(technology, msg, enable);
1098 #if defined TIZEN_EXT
1099         } else if (g_str_equal(name, "SetBSSID")) {
1100                 char *key;
1101
1102                 if (type != DBUS_TYPE_STRING)
1103                         return __connman_error_invalid_arguments(msg);
1104
1105                 dbus_message_iter_get_basic(&value, &key);
1106                 DBG("BSSID %s", key);
1107                 set_connman_bssid(SET_BSSID, key);
1108 #endif
1109         } else
1110                 return __connman_error_invalid_property(msg);
1111
1112         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1113 }
1114
1115 static void reply_scan_pending(struct connman_technology *technology, int err)
1116 {
1117         DBusMessage *reply;
1118
1119         DBG("technology %p err %d", technology, err);
1120
1121         while (technology->scan_pending) {
1122                 DBusMessage *msg = technology->scan_pending->data;
1123
1124                 DBG("reply to %s", dbus_message_get_sender(msg));
1125
1126                 if (err == 0)
1127                         reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1128                 else
1129                         reply = __connman_error_failed(msg, -err);
1130                 g_dbus_send_message(connection, reply);
1131                 dbus_message_unref(msg);
1132
1133                 technology->scan_pending =
1134                         g_slist_delete_link(technology->scan_pending,
1135                                         technology->scan_pending);
1136         }
1137 }
1138
1139 #if defined TIZEN_EXT
1140 dbus_bool_t __connman_technology_notify_scan_changed(const char *key, void *val)
1141 {
1142         DBG("key %s", key);
1143         DBusMessage *signal;
1144         DBusMessageIter iter;
1145         dbus_bool_t result = FALSE;
1146
1147         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1148                         CONNMAN_MANAGER_INTERFACE, "ScanChanged");
1149         if (!signal)
1150                 return result;
1151
1152         dbus_message_iter_init_append(signal, &iter);
1153         connman_dbus_property_append_basic(&iter, key, DBUS_TYPE_BOOLEAN, val);
1154
1155         result = dbus_connection_send(connection, signal, NULL);
1156         dbus_message_unref(signal);
1157
1158         DBG("Successfuly sent signal");
1159
1160         return result;
1161 }
1162 #endif
1163
1164 void __connman_technology_scan_started(struct connman_device *device)
1165 {
1166         DBG("device %p", device);
1167 #if defined TIZEN_EXT
1168         dbus_bool_t status = 1;
1169         __connman_technology_notify_scan_changed("scan_started", &status);
1170 #endif
1171 }
1172
1173 void __connman_technology_scan_stopped(struct connman_device *device,
1174                                         enum connman_service_type type)
1175 {
1176         int count = 0;
1177         struct connman_technology *technology;
1178         GSList *list;
1179
1180         technology = technology_find(type);
1181
1182         DBG("technology %p device %p", technology, device);
1183
1184         if (!technology)
1185                 return;
1186
1187         for (list = technology->device_list; list; list = list->next) {
1188                 struct connman_device *other_device = list->data;
1189
1190                 if (device == other_device)
1191                         continue;
1192
1193                 if (__connman_device_get_service_type(other_device) != type)
1194                         continue;
1195
1196                 if (connman_device_get_scanning(other_device))
1197                         count += 1;
1198         }
1199
1200 #if defined TIZEN_EXT
1201         if (count == 0) {
1202                 DBusMessage *signal;
1203                 DBusMessageIter iter;
1204                 dbus_bool_t status = 0;
1205                 __connman_technology_notify_scan_changed("scan_done", &status);
1206
1207                 signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1208                                 CONNMAN_MANAGER_INTERFACE, "ScanDone");
1209                 if (!signal)
1210                         return;
1211
1212                 dbus_message_iter_init_append(signal, &iter);
1213                 connman_dbus_property_append_basic(&iter, "Scantype",
1214                                 DBUS_TYPE_INT32, &g_scan_type);
1215
1216                 dbus_connection_send(connection, signal, NULL);
1217                 dbus_message_unref(signal);
1218                 reply_scan_pending(technology, 0);
1219
1220                 DBG("Successfuly sent ScanDone signal");
1221         }
1222 #else
1223         if (count == 0)
1224                 reply_scan_pending(technology, 0);
1225 #endif
1226 }
1227
1228 void __connman_technology_notify_regdom_by_device(struct connman_device *device,
1229                                                 int result, const char *alpha2)
1230 {
1231         bool regdom_set = false;
1232         struct connman_technology *technology;
1233         enum connman_service_type type;
1234         GSList *tech_drivers;
1235
1236         type = __connman_device_get_service_type(device);
1237         technology = technology_find(type);
1238
1239         if (!technology)
1240                 return;
1241
1242         if (result < 0) {
1243
1244                 for (tech_drivers = technology->driver_list;
1245                      tech_drivers;
1246                      tech_drivers = g_slist_next(tech_drivers)) {
1247                         struct connman_technology_driver *driver =
1248                                 tech_drivers->data;
1249
1250                         if (driver->set_regdom) {
1251                                 driver->set_regdom(technology, alpha2);
1252                                 regdom_set = true;
1253                         }
1254
1255                 }
1256
1257                 if (!regdom_set)
1258                         alpha2 = NULL;
1259         }
1260
1261         connman_technology_regdom_notify(technology, alpha2);
1262 }
1263
1264 static DBusMessage *scan(DBusConnection *conn, DBusMessage *msg, void *data)
1265 {
1266         struct connman_technology *technology = data;
1267         int err;
1268
1269         DBG("technology %p request from %s", technology,
1270                         dbus_message_get_sender(msg));
1271
1272         if (technology->type == CONNMAN_SERVICE_TYPE_P2P &&
1273                                 !technology->enabled)
1274                 return __connman_error_permission_denied(msg);
1275
1276         dbus_message_ref(msg);
1277 #if !defined TIZEN_EXT
1278         technology->scan_pending =
1279                 g_slist_prepend(technology->scan_pending, msg);
1280 #endif
1281
1282         err = __connman_device_request_scan(technology->type);
1283 #if defined TIZEN_EXT
1284         if (err < 0)
1285                 return __connman_error_failed(msg, -err);
1286 #else
1287         if (err < 0)
1288                 reply_scan_pending(technology, err);
1289 #endif
1290
1291 #if defined TIZEN_EXT
1292         if (err == 0) {
1293                 g_scan_type = CONNMAN_SCAN_TYPE_FULL_CHANNEL;
1294                 DBG("g_scan_type %d", g_scan_type);
1295         }
1296         technology->scan_pending =
1297                 g_slist_prepend(technology->scan_pending, msg);
1298 #endif
1299         return NULL;
1300 }
1301
1302 #if defined TIZEN_EXT
1303 static DBusMessage *specific_scan(DBusConnection *conn, DBusMessage *msg, void *data)
1304 {
1305         struct connman_technology *technology = data;
1306         GSList *specific_scan_list = NULL;
1307         int scan_type = 0;
1308         const char *name = NULL;
1309         const char *freq = NULL;
1310         DBusMessageIter iter, dict;
1311         int err;
1312
1313         DBG("technology %p request from %s", technology,
1314                         dbus_message_get_sender(msg));
1315
1316         if (!dbus_message_iter_init(msg, &iter))
1317                 return __connman_error_invalid_arguments(msg);
1318
1319         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1320                 return __connman_error_invalid_arguments(msg);
1321
1322         dbus_message_iter_recurse(&iter, &dict);
1323         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1324                 DBusMessageIter entry, value2;
1325                 const char *key;
1326                 int type;
1327
1328                 dbus_message_iter_recurse(&dict, &entry);
1329                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) {
1330                         g_slist_free_full(specific_scan_list, g_free);
1331                         return __connman_error_invalid_arguments(msg);
1332                 }
1333
1334                 dbus_message_iter_get_basic(&entry, &key);
1335                 dbus_message_iter_next(&entry);
1336
1337                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) {
1338                         g_slist_free_full(specific_scan_list, g_free);
1339                         return __connman_error_invalid_arguments(msg);
1340                 }
1341
1342                 dbus_message_iter_recurse(&entry, &value2);
1343                 type = dbus_message_iter_get_arg_type(&value2);
1344                 if (g_str_equal(key, "SSID")) {
1345                         if (type != DBUS_TYPE_STRING) {
1346                                 g_slist_free_full(specific_scan_list, g_free);
1347                                 return __connman_error_invalid_arguments(msg);
1348                         }
1349
1350                         scan_type = CONNMAN_MULTI_SCAN_SSID; /* SSID based scan */
1351                         dbus_message_iter_get_basic(&value2, &name);
1352                         DBG("name %s", name);
1353                         specific_scan_list = g_slist_append(specific_scan_list, g_strdup(name));
1354                 } else if (g_str_equal(key, "Frequency")) {
1355                         if (type != DBUS_TYPE_STRING) {
1356                                 g_slist_free_full(specific_scan_list, g_free);
1357                                 return __connman_error_invalid_arguments(msg);
1358                         }
1359
1360                         scan_type = CONNMAN_MULTI_SCAN_FREQ; /* Frequency based scan */
1361                         dbus_message_iter_get_basic(&value2, &freq);
1362                         DBG("freq %s", freq);
1363                         specific_scan_list = g_slist_append(specific_scan_list, GINT_TO_POINTER(atoi(freq)));
1364                 } else if (g_str_equal(key, "SSID_Mixed")) {
1365                         if (type != DBUS_TYPE_STRING) {
1366                                 g_slist_free_full(specific_scan_list, g_free);
1367                                 return __connman_error_invalid_arguments(msg);
1368                         }
1369
1370                         scan_type = CONNMAN_MULTI_SCAN_SSID_FREQ; /* SSID & Frequency mixed scan */
1371                         dbus_message_iter_get_basic(&value2, &name);
1372
1373                         connman_multi_scan_ap_s *ap = (connman_multi_scan_ap_s*)g_try_malloc0(sizeof(connman_multi_scan_ap_s));
1374                         if (ap) {
1375                                 g_strlcpy(ap->str, name, strlen(name) + 1);
1376                                 ap->flag = true;
1377                                 specific_scan_list = g_slist_append(specific_scan_list, ap);
1378                         } else
1379                                 DBG("Failed to allocate memory");
1380
1381                 } else if (g_str_equal(key, "Frequency_Mixed")) {
1382                         if (type != DBUS_TYPE_STRING) {
1383                                 g_slist_free_full(specific_scan_list, g_free);
1384                                 return __connman_error_invalid_arguments(msg);
1385                         }
1386
1387                         scan_type = CONNMAN_MULTI_SCAN_SSID_FREQ; /* SSID & Frequency mixed scan */
1388                         dbus_message_iter_get_basic(&value2, &freq);
1389
1390                         connman_multi_scan_ap_s *ap = (connman_multi_scan_ap_s*)g_try_malloc0(sizeof(connman_multi_scan_ap_s));
1391                         if (ap) {
1392                                 g_strlcpy(ap->str, freq, strlen(freq) + 1);
1393                                 ap->flag = false;
1394                                 specific_scan_list = g_slist_append(specific_scan_list, ap);
1395                         } else
1396                                 DBG("Failed to allocate memory");
1397                 }
1398                 dbus_message_iter_next(&dict);
1399         }
1400
1401         dbus_message_ref(msg);
1402
1403         err = __connman_device_request_specific_scan(technology->type, scan_type, specific_scan_list);
1404         if (err < 0)
1405                 return __connman_error_failed(msg, -err);
1406
1407         if (err == 0) {
1408                 guint list_size = g_slist_length(specific_scan_list);
1409                 if (list_size == 1)
1410                         g_scan_type = CONNMAN_SCAN_TYPE_SPECIFIC_AP;
1411                 else
1412                         g_scan_type = CONNMAN_SCAN_TYPE_MULTI_AP;
1413                 DBG("list_size %u g_scan_type %d", list_size, g_scan_type);
1414         }
1415         technology->scan_pending =
1416                 g_slist_prepend(technology->scan_pending, msg);
1417
1418         if (scan_type == CONNMAN_MULTI_SCAN_SSID ||
1419                         scan_type == CONNMAN_MULTI_SCAN_SSID_FREQ) {
1420                 g_slist_free_full(specific_scan_list, g_free);
1421                 scan_type = 0;
1422         }
1423         return NULL;
1424 }
1425
1426 #if defined TIZEN_EXT
1427 static DBusMessage *get_5ghz_supported(DBusConnection *conn, DBusMessage *msg, void *data)
1428 {
1429         DBusMessage *reply;
1430         DBusMessageIter iter, dict;
1431         struct connman_technology *technology = data;
1432         dbus_bool_t supported = technology->is_5_0_ghz_supported;
1433
1434         DBG("technology %p", technology);
1435
1436         reply = dbus_message_new_method_return(msg);
1437         if (!reply)
1438                 return NULL;
1439
1440         dbus_message_iter_init_append(reply, &iter);
1441
1442         connman_dbus_dict_open(&iter, &dict);
1443         connman_dbus_dict_append_basic(&dict, "Is5GhzSupported",
1444                                         DBUS_TYPE_BOOLEAN,
1445                                         &supported);
1446
1447         connman_dbus_dict_close(&iter, &dict);
1448
1449         return reply;
1450 }
1451 #endif
1452
1453 static DBusMessage *get_scan_state(DBusConnection *conn, DBusMessage *msg, void *data)
1454 {
1455         DBusMessage *reply;
1456         DBusMessageIter iter, dict;
1457         GSList *list;
1458         struct connman_technology *technology = data;
1459         dbus_bool_t scanning = false;
1460
1461         DBG("technology %p", technology);
1462
1463         for (list = technology->device_list; list; list = list->next) {
1464                 struct connman_device *device = list->data;
1465                 scanning = connman_device_get_scanning(device);
1466                 if(scanning)
1467                         break;
1468         }
1469
1470         DBG("scanning : %d", scanning);
1471         reply = dbus_message_new_method_return(msg);
1472         if (!reply)
1473                 return NULL;
1474
1475         dbus_message_iter_init_append(reply, &iter);
1476
1477         connman_dbus_dict_open(&iter, &dict);
1478         connman_dbus_dict_append_basic(&dict, "Scanstate",
1479                                         DBUS_TYPE_BOOLEAN,
1480                                         &scanning);
1481
1482         connman_dbus_dict_close(&iter, &dict);
1483
1484         return reply;
1485 }
1486 #endif
1487
1488 #if defined TIZEN_EXT_WIFI_MESH
1489 bool __connman_technology_get_connected(enum connman_service_type type)
1490 {
1491         struct connman_technology *technology;
1492
1493         technology = technology_find(type);
1494
1495         if (!technology)
1496                 return false;
1497
1498         return technology->connected;
1499 }
1500
1501 void __connman_technology_mesh_interface_create_finished(
1502                                                         enum connman_service_type type, bool success,
1503                                                         const char *error)
1504 {
1505         DBusMessage *reply;
1506         struct connman_technology *technology;
1507         DBusMessage *msg;
1508         technology = technology_find(type);
1509
1510         DBG("technology %p success %d", technology, success);
1511
1512         if (!technology)
1513                 return;
1514
1515         msg = technology->mesh_dbus_msg;
1516         if (!msg) {
1517                 DBG("No pending dbus message");
1518                 return;
1519         }
1520
1521         if (success) {
1522                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1523                 __connman_device_request_scan(technology->type);
1524         } else
1525                 reply = g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
1526                                 ".MeshInterfaceAddFailed", "%s", error);
1527         g_dbus_send_message(connection, reply);
1528         dbus_message_unref(msg);
1529         technology->mesh_dbus_msg = NULL;
1530 }
1531
1532 void __connman_technology_mesh_interface_remove_finished(
1533                                                         enum connman_service_type type, bool success)
1534 {
1535         DBusMessage *reply;
1536         struct connman_technology *technology;
1537         DBusMessage *msg;
1538         technology = technology_find(type);
1539
1540         DBG("technology %p success %d", technology, success);
1541
1542         if (!technology || !technology->mesh_dbus_msg)
1543                 return;
1544
1545         msg = technology->mesh_dbus_msg;
1546         if (!msg) {
1547                 DBG("No pending dbus message");
1548                 return;
1549         }
1550
1551         if (success)
1552                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1553         else
1554                 reply = __connman_error_failed(msg, EINVAL);
1555         g_dbus_send_message(connection, reply);
1556         dbus_message_unref(msg);
1557         technology->mesh_dbus_msg = NULL;
1558 }
1559
1560 void __connman_technology_notify_abort_scan(enum connman_service_type type,
1561                                                         int result)
1562 {
1563         DBusMessage *reply;
1564         struct connman_technology *technology;
1565         DBusMessage *msg;
1566         technology = technology_find(type);
1567
1568         DBG("technology %p result %d", technology, result);
1569
1570         if (!technology || !technology->mesh_dbus_msg)
1571                 return;
1572
1573         msg = technology->mesh_dbus_msg;
1574         if (!msg) {
1575                 DBG("No pending dbus message");
1576                 return;
1577         }
1578
1579         if (result < 0)
1580                 reply = __connman_error_scan_abort_failed(msg);
1581         else
1582                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1583
1584         g_dbus_send_message(connection, reply);
1585         dbus_message_unref(msg);
1586         technology->mesh_dbus_msg = NULL;
1587 }
1588
1589 static DBusMessage *mesh_commands(DBusConnection *conn,
1590                                   DBusMessage *msg, void *data)
1591 {
1592         struct connman_technology *technology = data;
1593         DBusMessageIter iter, value, dict;
1594         const char *cmd = NULL, *ifname = NULL, *parent_ifname = NULL;
1595         int err;
1596
1597         DBG("conn %p", conn);
1598
1599         if (technology->type != CONNMAN_SERVICE_TYPE_MESH)
1600                 return __connman_error_invalid_arguments(msg);
1601
1602         if (!dbus_message_iter_init(msg, &iter))
1603                 return __connman_error_invalid_arguments(msg);
1604
1605         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
1606                 return __connman_error_invalid_arguments(msg);
1607
1608         dbus_message_iter_get_basic(&iter, &cmd);
1609         dbus_message_iter_next(&iter);
1610
1611         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1612                 return __connman_error_invalid_arguments(msg);
1613
1614         dbus_message_iter_recurse(&iter, &value);
1615
1616         if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_ARRAY)
1617                 return __connman_error_invalid_arguments(msg);
1618
1619         DBG("Mesh Command %s", cmd);
1620         if (g_str_equal(cmd, "MeshInterfaceAdd")) {
1621                 dbus_message_iter_recurse(&value, &dict);
1622                 const char *bridge_ifname = NULL;
1623                 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1624                         DBusMessageIter entry, value2;
1625                         const char *key;
1626                         int type;
1627
1628                         dbus_message_iter_recurse(&dict, &entry);
1629
1630                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
1631                                 return __connman_error_invalid_arguments(msg);
1632
1633                         dbus_message_iter_get_basic(&entry, &key);
1634                         dbus_message_iter_next(&entry);
1635
1636                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
1637                                 return __connman_error_invalid_arguments(msg);
1638
1639                         dbus_message_iter_recurse(&entry, &value2);
1640
1641                         type = dbus_message_iter_get_arg_type(&value2);
1642
1643                         if (g_str_equal(key, "Ifname")) {
1644                                 if (type != DBUS_TYPE_STRING)
1645                                         return __connman_error_invalid_arguments(msg);
1646
1647                                 dbus_message_iter_get_basic(&value2, &ifname);
1648                         } else if (g_str_equal(key, "ParentIfname")) {
1649                                 if (type != DBUS_TYPE_STRING)
1650                                         return __connman_error_invalid_arguments(msg);
1651
1652                                 dbus_message_iter_get_basic(&value2, &parent_ifname);
1653                         } else if (g_str_equal(key, "BridgeIfname")) {
1654                                 if (type != DBUS_TYPE_STRING)
1655                                         return __connman_error_invalid_arguments(msg);
1656
1657                                 dbus_message_iter_get_basic(&value2, &bridge_ifname);
1658                         }
1659                         dbus_message_iter_next(&dict);
1660                 }
1661                 DBG("Mesh Ifname %s parent %s bridge %s", ifname, parent_ifname,
1662                                         bridge_ifname ? bridge_ifname : "NULL");
1663                 err = __connman_mesh_add_virtual_interface(ifname, parent_ifname,
1664                                                            bridge_ifname);
1665
1666                 if (err != 0) {
1667                         DBG("Failed to add virtual mesh interface");
1668                         return __connman_error_failed(msg, -err);
1669                 }
1670
1671                 DBG("Successfully added virtual mesh interface");
1672
1673                 dbus_message_ref(msg);
1674                 technology->mesh_dbus_msg = msg;
1675
1676         } else if (g_str_equal(cmd, "MeshInterfaceRemove")) {
1677                 dbus_message_iter_recurse(&value, &dict);
1678                 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1679                         DBusMessageIter entry, value2;
1680                         const char *key;
1681                         int type;
1682
1683                         dbus_message_iter_recurse(&dict, &entry);
1684
1685                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
1686                                 return __connman_error_invalid_arguments(msg);
1687
1688                         dbus_message_iter_get_basic(&entry, &key);
1689                         dbus_message_iter_next(&entry);
1690
1691                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
1692                                 return __connman_error_invalid_arguments(msg);
1693
1694                         dbus_message_iter_recurse(&entry, &value2);
1695
1696                         type = dbus_message_iter_get_arg_type(&value2);
1697
1698                         if (g_str_equal(key, "Ifname")) {
1699                                 if (type != DBUS_TYPE_STRING)
1700                                         return __connman_error_invalid_arguments(msg);
1701
1702                                 dbus_message_iter_get_basic(&value2, &ifname);
1703                         }
1704                         dbus_message_iter_next(&dict);
1705                 }
1706                 DBG("Mesh Ifname %s", ifname);
1707                 err = __connman_mesh_remove_virtual_interface(ifname);
1708
1709                 if (err != 0) {
1710                         DBG("Failed to remove virtual mesh interface");
1711                         return __connman_error_failed(msg, -err);
1712                 }
1713
1714                 DBG("Successfully removed virtual mesh interface");
1715
1716                 dbus_message_ref(msg);
1717                 technology->mesh_dbus_msg = msg;
1718
1719         } else if (g_str_equal(cmd, "MeshCreateNetwork")) {
1720                 struct connman_mesh *connman_mesh;
1721                 const char *name = NULL;
1722                 const char *sec_type = NULL;
1723                 const char *mesh_ifname = NULL;
1724                 char *identifier, *group, *address;
1725                 unsigned int freq = 0;
1726                 unsigned int ieee80211w = 0;
1727                 GString *str;
1728                 int i;
1729                 dbus_message_iter_recurse(&value, &dict);
1730                 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1731                         DBusMessageIter entry, value2;
1732                         const char *key;
1733                         int type;
1734
1735                         dbus_message_iter_recurse(&dict, &entry);
1736
1737                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
1738                                 return __connman_error_invalid_arguments(msg);
1739
1740                         dbus_message_iter_get_basic(&entry, &key);
1741                         dbus_message_iter_next(&entry);
1742
1743                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
1744                                 return __connman_error_invalid_arguments(msg);
1745
1746                         dbus_message_iter_recurse(&entry, &value2);
1747
1748                         type = dbus_message_iter_get_arg_type(&value2);
1749
1750                         if (g_str_equal(key, "Name")) {
1751                                 if (type != DBUS_TYPE_STRING)
1752                                         return __connman_error_invalid_arguments(msg);
1753
1754                                 dbus_message_iter_get_basic(&value2, &name);
1755                         } else if (g_str_equal(key, "Frequency")) {
1756                                 if (type != DBUS_TYPE_UINT16)
1757                                         return __connman_error_invalid_arguments(msg);
1758
1759                                 dbus_message_iter_get_basic(&value2, &freq);
1760                         } else if (g_str_equal(key, "Security")) {
1761                                 if (type != DBUS_TYPE_STRING)
1762                                         return __connman_error_invalid_arguments(msg);
1763
1764                                 dbus_message_iter_get_basic(&value2, &sec_type);
1765                         } else if (g_str_equal(key, "Pmf")) {
1766                                 if (type != DBUS_TYPE_UINT16)
1767                                         return __connman_error_invalid_arguments(msg);
1768
1769                                 dbus_message_iter_get_basic(&value2, &ieee80211w);
1770                         }
1771                         dbus_message_iter_next(&dict);
1772                 }
1773
1774                 if (name == NULL || sec_type == NULL || freq == 0)
1775                         return __connman_error_invalid_arguments(msg);
1776
1777                 DBG("Name %s Frequency %d Security type %s Pmf %u",
1778                     name, freq, sec_type, ieee80211w);
1779
1780                 if (g_strcmp0(sec_type, "none") != 0 &&
1781                     g_strcmp0(sec_type, "sae") != 0) {
1782                         DBG("Unsupported security");
1783                         return __connman_error_invalid_arguments(msg);
1784                 }
1785
1786                 mesh_ifname = connman_mesh_get_interface_name();
1787
1788                 if (!connman_mesh_is_interface_created()) {
1789                         DBG("Mesh interface doesn't exists");
1790                         return __connman_error_invalid_command(msg);
1791                 }
1792
1793                 str = g_string_sized_new((strlen(name) * 2) + 24);
1794
1795                 for (i = 0; name[i]; i++)
1796                         g_string_append_printf(str, "%02x", name[i]);
1797
1798                 g_string_append_printf(str, "_mesh");
1799
1800                 if (g_strcmp0(sec_type, "none") == 0)
1801                         g_string_append_printf(str, "_none");
1802                 else if (g_strcmp0(sec_type, "sae") == 0)
1803                         g_string_append_printf(str, "_sae");
1804
1805                 group = g_string_free(str, FALSE);
1806
1807                 identifier = connman_inet_ifaddr(mesh_ifname);
1808                 address = connman_inet_ifname2addr(mesh_ifname);
1809
1810                 connman_mesh = connman_mesh_create(identifier, group);
1811                 connman_mesh_set_name(connman_mesh, name);
1812                 connman_mesh_set_address(connman_mesh, address);
1813                 connman_mesh_set_security(connman_mesh, sec_type);
1814                 connman_mesh_set_frequency(connman_mesh, freq);
1815                 connman_mesh_set_index(connman_mesh, connman_inet_ifindex(mesh_ifname));
1816                 connman_mesh_set_peer_type(connman_mesh,
1817                                            CONNMAN_MESH_PEER_TYPE_CREATED);
1818                 connman_mesh_set_ieee80211w(connman_mesh, ieee80211w);
1819
1820                 connman_mesh_register(connman_mesh);
1821                 g_free(group);
1822                 g_free(identifier);
1823                 g_free(address);
1824                 DBG("Successfully Created Mesh Network");
1825                 return  g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1826
1827         } else if (g_str_equal(cmd, "AbortScan")) {
1828                 DBG("Abort Scan method");
1829                 err = __connman_device_abort_scan(technology->type);
1830                 if (err != 0) {
1831                         DBG("Failed to abort scan");
1832                         return __connman_error_failed(msg, -err);
1833                 }
1834
1835                 DBG("Successfully requested to abort scan");
1836                 dbus_message_ref(msg);
1837                 technology->mesh_dbus_msg = msg;
1838
1839         } else if (g_str_equal(cmd, "MeshSpecificScan")) {
1840                 const char *name = NULL;
1841                 unsigned int freq = 0;
1842                 dbus_message_iter_recurse(&value, &dict);
1843                 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1844                         DBusMessageIter entry, value2;
1845                         const char *key;
1846                         int type;
1847
1848                         dbus_message_iter_recurse(&dict, &entry);
1849
1850                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
1851                                 return __connman_error_invalid_arguments(msg);
1852
1853                         dbus_message_iter_get_basic(&entry, &key);
1854                         dbus_message_iter_next(&entry);
1855
1856                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
1857                                 return __connman_error_invalid_arguments(msg);
1858
1859                         dbus_message_iter_recurse(&entry, &value2);
1860
1861                         type = dbus_message_iter_get_arg_type(&value2);
1862
1863                         if (g_str_equal(key, "Name")) {
1864                                 if (type != DBUS_TYPE_STRING)
1865                                         return __connman_error_invalid_arguments(msg);
1866
1867                                 dbus_message_iter_get_basic(&value2, &name);
1868                         } else if (g_str_equal(key, "Frequency")) {
1869                                 if (type != DBUS_TYPE_UINT16)
1870                                         return __connman_error_invalid_arguments(msg);
1871
1872                                 dbus_message_iter_get_basic(&value2, &freq);
1873                         }
1874                         dbus_message_iter_next(&dict);
1875                 }
1876
1877                 DBG("MeshID %s Frequency %d sender %s", name, freq,
1878                                                 dbus_message_get_sender(msg));
1879
1880                 dbus_message_ref(msg);
1881                 technology->scan_pending =
1882                         g_slist_prepend(technology->scan_pending, msg);
1883
1884                 err = __connman_device_request_mesh_specific_scan(technology->type,
1885                                                                   name, freq);
1886                 if (err < 0)
1887                         reply_scan_pending(technology, err);
1888                 else
1889                         DBG("Successfully requested to scan specific Mesh Network");
1890
1891         } else if (g_str_equal(cmd, "SetMeshGate")) {
1892                 unsigned int hwmp_rootmode = 0;
1893                 bool gate_announce = false;
1894                 unsigned int stp = 0;
1895                 int err;
1896                 dbus_message_iter_recurse(&value, &dict);
1897                 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1898                         DBusMessageIter entry, value2;
1899                         const char *key;
1900                         int type;
1901
1902                         dbus_message_iter_recurse(&dict, &entry);
1903
1904                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
1905                                 return __connman_error_invalid_arguments(msg);
1906
1907                         dbus_message_iter_get_basic(&entry, &key);
1908                         dbus_message_iter_next(&entry);
1909
1910                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
1911                                 return __connman_error_invalid_arguments(msg);
1912
1913                         dbus_message_iter_recurse(&entry, &value2);
1914
1915                         type = dbus_message_iter_get_arg_type(&value2);
1916
1917                         if (g_str_equal(key, "GateAnnounce")) {
1918                                 if (type != DBUS_TYPE_BOOLEAN)
1919                                         return __connman_error_invalid_arguments(msg);
1920
1921                                 dbus_message_iter_get_basic(&value2, &gate_announce);
1922                         } else if (g_str_equal(key, "HWMPRootMode")) {
1923                                 if (type != DBUS_TYPE_UINT16)
1924                                         return __connman_error_invalid_arguments(msg);
1925
1926                                 dbus_message_iter_get_basic(&value2, &hwmp_rootmode);
1927                         } else if (g_str_equal(key, "STP")) {
1928                                 if (type != DBUS_TYPE_UINT16)
1929                                         return __connman_error_invalid_arguments(msg);
1930
1931                                 dbus_message_iter_get_basic(&value2, &stp);
1932                         }
1933                         dbus_message_iter_next(&dict);
1934                 }
1935
1936                 DBG("GateAnnounce %d HWMPRootMode %d STP %d sender %s",
1937                     gate_announce, hwmp_rootmode, stp, dbus_message_get_sender(msg));
1938
1939                 err = __connman_mesh_set_stp_gate_announce(gate_announce,
1940                                                            hwmp_rootmode,
1941                                                            stp);
1942
1943                 if (err < 0)
1944                         return __connman_error_failed(msg, -err);
1945
1946                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1947         } else
1948                 return __connman_error_invalid_command(msg);
1949         return NULL;
1950 }
1951 #endif
1952
1953 static const GDBusMethodTable technology_methods[] = {
1954         { GDBUS_DEPRECATED_METHOD("GetProperties",
1955                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
1956                         get_properties) },
1957         { GDBUS_ASYNC_METHOD("SetProperty",
1958                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
1959                         NULL, set_property) },
1960         { GDBUS_ASYNC_METHOD("Scan", NULL, NULL, scan) },
1961 #if defined TIZEN_EXT
1962         { GDBUS_ASYNC_METHOD("SpecificScan", GDBUS_ARGS({ "specificscan", "a{sv}" }),
1963                         NULL, specific_scan) },
1964         { GDBUS_METHOD("GetScanState", NULL, GDBUS_ARGS({ "scan_state", "a{sv}" }),
1965                         get_scan_state) },
1966         { GDBUS_METHOD("Get5GhzSupported", NULL, GDBUS_ARGS({ "supported", "a{sv}" }),
1967                         get_5ghz_supported) },
1968 #endif
1969 #if defined TIZEN_EXT_WIFI_MESH
1970         { GDBUS_ASYNC_METHOD("MeshCommands",
1971                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
1972                         NULL, mesh_commands) },
1973 #endif
1974         { },
1975 };
1976
1977 static const GDBusSignalTable technology_signals[] = {
1978         { GDBUS_SIGNAL("PropertyChanged",
1979                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
1980         { GDBUS_SIGNAL("DhcpConnected",
1981                         GDBUS_ARGS({ "aptype", "s" },
1982                                 { "ipaddr", "s" },
1983                                 { "macaddr", "s" },
1984                                 { "hostname", "s" })) },
1985         { GDBUS_SIGNAL("DhcpLeaseDeleted",
1986                         GDBUS_ARGS({ "aptype", "s" },
1987                                 { "ipaddr", "s" },
1988                                 { "macaddr", "s" },
1989                                 { "hostname", "s" })) },
1990         { },
1991 };
1992
1993 static bool technology_dbus_register(struct connman_technology *technology)
1994 {
1995         if (technology->dbus_registered ||
1996                                 (technology->rfkill_driven &&
1997                                  technology->hardblocked))
1998                 return true;
1999
2000         if (!g_dbus_register_interface(connection, technology->path,
2001                                         CONNMAN_TECHNOLOGY_INTERFACE,
2002                                         technology_methods, technology_signals,
2003                                         NULL, technology, NULL)) {
2004                 connman_error("Failed to register %s", technology->path);
2005                 return false;
2006         }
2007
2008         technology_added_signal(technology);
2009         technology->dbus_registered = true;
2010
2011         return true;
2012 }
2013
2014 static void technology_dbus_unregister(struct connman_technology *technology)
2015 {
2016         if (!technology->dbus_registered)
2017                 return;
2018
2019         technology_removed_signal(technology);
2020         g_dbus_unregister_interface(connection, technology->path,
2021                 CONNMAN_TECHNOLOGY_INTERFACE);
2022
2023         technology->dbus_registered = false;
2024 }
2025
2026 static void technology_put(struct connman_technology *technology)
2027 {
2028         DBG("technology %p", technology);
2029
2030         if (__sync_sub_and_fetch(&technology->refcount, 1) > 0)
2031                 return;
2032
2033         reply_scan_pending(technology, -EINTR);
2034
2035         while (technology->driver_list) {
2036                 struct connman_technology_driver *driver;
2037
2038                 driver = technology->driver_list->data;
2039
2040                 if (driver->remove)
2041                         driver->remove(technology);
2042
2043                 technology->driver_list =
2044                         g_slist_delete_link(technology->driver_list,
2045                                         technology->driver_list);
2046         }
2047
2048         technology_list = g_slist_remove(technology_list, technology);
2049
2050         technology_dbus_unregister(technology);
2051
2052         g_slist_free(technology->device_list);
2053
2054     if (technology->pending_reply) {
2055         dbus_message_unref(technology->pending_reply);
2056         technology->pending_reply = NULL;
2057         g_source_remove(technology->pending_timeout);
2058         technology->pending_timeout = 0;
2059     }
2060
2061         g_free(technology->path);
2062         g_free(technology->regdom);
2063         g_free(technology->tethering_ident);
2064         g_free(technology->tethering_passphrase);
2065         g_free(technology);
2066 }
2067
2068 static struct connman_technology *technology_get(enum connman_service_type type)
2069 {
2070         GSList *tech_drivers = NULL;
2071         struct connman_technology_driver *driver;
2072         struct connman_technology *technology;
2073         const char *str;
2074         GSList *list;
2075
2076         DBG("type %d", type);
2077
2078         str = __connman_service_type2string(type);
2079         if (!str)
2080                 return NULL;
2081
2082         technology = technology_find(type);
2083         if (technology) {
2084 #if defined TIZEN_EXT_WIFI_MESH
2085                 if (type != CONNMAN_SERVICE_TYPE_P2P &&
2086                         type != CONNMAN_SERVICE_TYPE_MESH)
2087 #else
2088                 if (type != CONNMAN_SERVICE_TYPE_P2P)
2089 #endif
2090                         __sync_fetch_and_add(&technology->refcount, 1);
2091                 return technology;
2092         }
2093
2094         /* First check if we have a driver for this technology type */
2095         for (list = driver_list; list; list = list->next) {
2096                 driver = list->data;
2097
2098                 if (driver->type == type) {
2099                         DBG("technology %p driver %p", technology, driver);
2100                         tech_drivers = g_slist_append(tech_drivers, driver);
2101                 }
2102         }
2103
2104         if (!tech_drivers) {
2105                 DBG("No matching drivers found for %s.",
2106                                 __connman_service_type2string(type));
2107                 return NULL;
2108         }
2109
2110         technology = g_try_new0(struct connman_technology, 1);
2111         if (!technology)
2112                 return NULL;
2113
2114         technology->refcount = 1;
2115         technology->type = type;
2116         technology->tethering_hidden = FALSE;
2117         technology->path = g_strdup_printf("%s/technology/%s",
2118                                                         CONNMAN_PATH, str);
2119
2120 #if defined TIZEN_EXT_WIFI_MESH
2121         if (type == CONNMAN_SERVICE_TYPE_MESH) {
2122                 struct connman_technology *wifi;
2123
2124                 wifi = technology_find(CONNMAN_SERVICE_TYPE_WIFI);
2125                 if (wifi)
2126                         technology->enabled = wifi->enabled;
2127         }
2128 #endif
2129
2130         technology_load(technology);
2131         technology_list = g_slist_prepend(technology_list, technology);
2132         technology->driver_list = tech_drivers;
2133
2134         for (list = tech_drivers; list; list = list->next) {
2135                 driver = list->data;
2136
2137                 if (driver->probe && driver->probe(technology) < 0)
2138                         DBG("Driver probe failed for technology %p",
2139                                         technology);
2140         }
2141
2142         if (!technology_dbus_register(technology)) {
2143                 technology_put(technology);
2144                 return NULL;
2145         }
2146
2147         if (type == CONNMAN_SERVICE_TYPE_P2P) {
2148                 struct connman_technology *wifi;
2149                 bool enable;
2150
2151                 enable = technology->enable_persistent;
2152
2153                 wifi = technology_find(CONNMAN_SERVICE_TYPE_WIFI);
2154                 if (enable && wifi)
2155                         enable = wifi->enabled;
2156
2157                 technology_affect_devices(technology, enable);
2158         }
2159
2160         DBG("technology %p %s", technology, get_name(technology->type));
2161
2162         return technology;
2163 }
2164
2165 int connman_technology_driver_register(struct connman_technology_driver *driver)
2166 {
2167         GSList *list;
2168         struct connman_device *device;
2169         enum connman_service_type type;
2170
2171         for (list = driver_list; list; list = list->next) {
2172                 if (list->data == driver)
2173                         goto exist;
2174         }
2175
2176         DBG("Registering %s driver", driver->name);
2177
2178         driver_list = g_slist_insert_sorted(driver_list, driver,
2179                                                         compare_priority);
2180
2181         /*
2182          * Check for technology less devices if this driver
2183          * can service any of them.
2184         */
2185         for (list = techless_device_list; list; list = list->next) {
2186                 device = list->data;
2187
2188                 type = __connman_device_get_service_type(device);
2189                 if (type != driver->type)
2190                         continue;
2191
2192                 techless_device_list = g_slist_remove(techless_device_list,
2193                                                                 device);
2194
2195                 __connman_technology_add_device(device);
2196         }
2197
2198         /* Check for orphaned rfkill switches. */
2199         g_hash_table_foreach(rfkill_list, rfkill_check,
2200                                         GINT_TO_POINTER(driver->type));
2201
2202 exist:
2203         if (driver->type == CONNMAN_SERVICE_TYPE_P2P) {
2204                 if (!technology_get(CONNMAN_SERVICE_TYPE_P2P))
2205                         return -ENOMEM;
2206         }
2207
2208 #if defined TIZEN_EXT_WIFI_MESH
2209         if (driver->type == CONNMAN_SERVICE_TYPE_MESH) {
2210                 if (!technology_get(CONNMAN_SERVICE_TYPE_MESH))
2211                         return -ENOMEM;
2212         }
2213 #endif
2214
2215         return 0;
2216 }
2217
2218 void connman_technology_driver_unregister(struct connman_technology_driver *driver)
2219 {
2220         GSList *list, *tech_drivers;
2221         struct connman_technology *technology;
2222         struct connman_technology_driver *current;
2223
2224         DBG("Unregistering driver %p name %s", driver, driver->name);
2225
2226         for (list = technology_list; list; list = list->next) {
2227                 technology = list->data;
2228
2229                 for (tech_drivers = technology->driver_list; tech_drivers;
2230                                 tech_drivers = g_slist_next(tech_drivers)) {
2231                         current = tech_drivers->data;
2232                         if (driver != current)
2233                                 continue;
2234
2235                         if (driver->remove)
2236                                 driver->remove(technology);
2237
2238                         technology->driver_list =
2239                                 g_slist_remove(technology->driver_list,
2240                                                                 driver);
2241                         break;
2242                 }
2243         }
2244
2245         driver_list = g_slist_remove(driver_list, driver);
2246
2247         if (driver->type == CONNMAN_SERVICE_TYPE_P2P) {
2248                 technology = technology_find(CONNMAN_SERVICE_TYPE_P2P);
2249                 if (technology)
2250                         technology_put(technology);
2251         }
2252 #if defined TIZEN_EXT_WIFI_MESH
2253         if (driver->type == CONNMAN_SERVICE_TYPE_MESH) {
2254                 technology = technology_find(CONNMAN_SERVICE_TYPE_MESH);
2255                 if (technology)
2256                         technology_put(technology);
2257         }
2258 #endif
2259 }
2260
2261 void __connman_technology_add_interface(enum connman_service_type type,
2262                                 int index, const char *ident)
2263 {
2264         struct connman_technology *technology;
2265         GSList *tech_drivers;
2266         struct connman_technology_driver *driver;
2267         char *name;
2268
2269         switch (type) {
2270         case CONNMAN_SERVICE_TYPE_UNKNOWN:
2271         case CONNMAN_SERVICE_TYPE_SYSTEM:
2272                 return;
2273         case CONNMAN_SERVICE_TYPE_ETHERNET:
2274         case CONNMAN_SERVICE_TYPE_WIFI:
2275         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
2276         case CONNMAN_SERVICE_TYPE_CELLULAR:
2277         case CONNMAN_SERVICE_TYPE_GPS:
2278         case CONNMAN_SERVICE_TYPE_VPN:
2279         case CONNMAN_SERVICE_TYPE_GADGET:
2280         case CONNMAN_SERVICE_TYPE_P2P:
2281 #if defined TIZEN_EXT_WIFI_MESH
2282         case CONNMAN_SERVICE_TYPE_MESH:
2283 #endif
2284                 break;
2285         }
2286
2287         name = connman_inet_ifname(index);
2288         connman_info("Adding interface %s [ %s ]", name,
2289                                 __connman_service_type2string(type));
2290
2291         technology = technology_find(type);
2292
2293         if (!technology)
2294                 goto out;
2295
2296         for (tech_drivers = technology->driver_list; tech_drivers;
2297              tech_drivers = g_slist_next(tech_drivers)) {
2298                 driver = tech_drivers->data;
2299
2300                 if (driver->add_interface)
2301                         driver->add_interface(technology, index, name, ident);
2302         }
2303
2304         /*
2305          * At this point we can try to enable tethering automatically as
2306          * now the interfaces are set properly.
2307          */
2308         if (technology->tethering_persistent)
2309                 enable_tethering(technology);
2310
2311 out:
2312         g_free(name);
2313 }
2314
2315 void __connman_technology_remove_interface(enum connman_service_type type,
2316                                 int index, const char *ident)
2317 {
2318         struct connman_technology *technology;
2319         GSList *tech_drivers;
2320         struct connman_technology_driver *driver;
2321         char *name;
2322
2323         switch (type) {
2324         case CONNMAN_SERVICE_TYPE_UNKNOWN:
2325         case CONNMAN_SERVICE_TYPE_SYSTEM:
2326                 return;
2327         case CONNMAN_SERVICE_TYPE_ETHERNET:
2328         case CONNMAN_SERVICE_TYPE_WIFI:
2329         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
2330         case CONNMAN_SERVICE_TYPE_CELLULAR:
2331         case CONNMAN_SERVICE_TYPE_GPS:
2332         case CONNMAN_SERVICE_TYPE_VPN:
2333         case CONNMAN_SERVICE_TYPE_GADGET:
2334         case CONNMAN_SERVICE_TYPE_P2P:
2335 #if defined TIZEN_EXT_WIFI_MESH
2336         case CONNMAN_SERVICE_TYPE_MESH:
2337 #endif
2338                 break;
2339         }
2340
2341         name = connman_inet_ifname(index);
2342         connman_info("Remove interface %s [ %s ]", name,
2343                                 __connman_service_type2string(type));
2344         g_free(name);
2345
2346         technology = technology_find(type);
2347
2348         if (!technology)
2349                 return;
2350
2351         for (tech_drivers = technology->driver_list; tech_drivers;
2352              tech_drivers = g_slist_next(tech_drivers)) {
2353                 driver = tech_drivers->data;
2354
2355                 if (driver->remove_interface)
2356                         driver->remove_interface(technology, index);
2357         }
2358 }
2359
2360 int __connman_technology_add_device(struct connman_device *device)
2361 {
2362         struct connman_technology *technology;
2363         enum connman_service_type type;
2364
2365         type = __connman_device_get_service_type(device);
2366
2367         DBG("device %p type %s", device, get_name(type));
2368
2369         technology = technology_get(type);
2370         if (!technology) {
2371                 /*
2372                  * Since no driver can be found for this device at the moment we
2373                  * add it to the techless device list.
2374                 */
2375                 techless_device_list = g_slist_prepend(techless_device_list,
2376                                                                 device);
2377
2378                 return -ENXIO;
2379         }
2380
2381         __sync_synchronize();
2382         if (technology->rfkill_driven) {
2383                 if (technology->enabled)
2384                         __connman_device_enable(device);
2385                 else
2386                         __connman_device_disable(device);
2387
2388                 goto done;
2389         }
2390
2391         if (technology->enable_persistent &&
2392                                         !global_offlinemode) {
2393                 int err = __connman_device_enable(device);
2394                 /*
2395                  * connman_technology_add_device() calls __connman_device_enable()
2396                  * but since the device is already enabled, the calls does not
2397                  * propagate through to connman_technology_enabled via
2398                  * connman_device_set_powered.
2399                  */
2400                 if (err == -EALREADY)
2401                         __connman_technology_enabled(type);
2402         }
2403         /* if technology persistent state is offline */
2404         if (!technology->enable_persistent)
2405                 __connman_device_disable(device);
2406
2407 done:
2408         technology->device_list = g_slist_prepend(technology->device_list,
2409                                                                 device);
2410
2411         return 0;
2412 }
2413
2414 int __connman_technology_remove_device(struct connman_device *device)
2415 {
2416         struct connman_technology *technology;
2417         enum connman_service_type type;
2418
2419         DBG("device %p", device);
2420
2421         type = __connman_device_get_service_type(device);
2422
2423         technology = technology_find(type);
2424         if (!technology) {
2425                 techless_device_list = g_slist_remove(techless_device_list,
2426                                                                 device);
2427                 return -ENXIO;
2428         }
2429
2430         technology->device_list = g_slist_remove(technology->device_list,
2431                                                                 device);
2432
2433         if (technology->tethering)
2434                 set_tethering(technology, false);
2435
2436         technology_put(technology);
2437
2438         return 0;
2439 }
2440
2441 int __connman_technology_enabled(enum connman_service_type type)
2442 {
2443         struct connman_technology *technology;
2444
2445         technology = technology_find(type);
2446         if (!technology)
2447                 return -ENXIO;
2448
2449         DBG("technology %p type %s rfkill %d enabled %d", technology,
2450                 get_name(type), technology->rfkill_driven,
2451                 technology->enabled);
2452 #if !defined TIZEN_EXT
2453         if (technology->rfkill_driven) {
2454                 if (technology->tethering_persistent)
2455                         enable_tethering(technology);
2456                 return 0;
2457         }
2458 #endif
2459
2460         return technology_enabled(technology);
2461 }
2462
2463 int __connman_technology_disabled(enum connman_service_type type)
2464 {
2465         struct connman_technology *technology;
2466         GSList *list;
2467
2468         technology = technology_find(type);
2469         if (!technology)
2470                 return -ENXIO;
2471 #if !defined TIZEN_EXT
2472         if (technology->rfkill_driven)
2473                 return 0;
2474 #endif
2475         for (list = technology->device_list; list; list = list->next) {
2476                 struct connman_device *device = list->data;
2477
2478                 if (connman_device_get_powered(device))
2479                         return 0;
2480         }
2481
2482         return technology_disabled(technology);
2483 }
2484
2485 int __connman_technology_set_offlinemode(bool offlinemode)
2486 {
2487         GSList *list;
2488         int err = -EINVAL, enabled_tech_count = 0;
2489
2490         if (global_offlinemode == offlinemode)
2491                 return 0;
2492
2493         DBG("offlinemode %s", offlinemode ? "On" : "Off");
2494
2495         /*
2496          * This is a bit tricky. When you set offlinemode, there is no
2497          * way to differentiate between attempting offline mode and
2498          * resuming offlinemode from last saved profile. We need that
2499          * information in rfkill_update, otherwise it falls back on the
2500          * technology's persistent state. Hence we set the offline mode here
2501          * but save it & call the notifier only if its successful.
2502          */
2503
2504         global_offlinemode = offlinemode;
2505
2506         /* Traverse technology list, enable/disable each technology. */
2507         for (list = technology_list; list; list = list->next) {
2508                 struct connman_technology *technology = list->data;
2509
2510                 if (offlinemode)
2511                         err = technology_disable(technology);
2512                 else {
2513                         if (technology->hardblocked)
2514                                 continue;
2515
2516                         if (technology->enable_persistent) {
2517                                 err = technology_enable(technology);
2518                                 enabled_tech_count++;
2519                         }
2520                 }
2521         }
2522
2523         if (err == 0 || err == -EINPROGRESS || err == -EALREADY ||
2524                         (err == -EINVAL && enabled_tech_count == 0)) {
2525                 connman_technology_save_offlinemode();
2526                 __connman_notifier_offlinemode(offlinemode);
2527         } else
2528                 global_offlinemode = connman_technology_load_offlinemode();
2529
2530         return err;
2531 }
2532
2533 #if defined TIZEN_EXT_WIFI_MESH
2534 static gboolean __add_ethernet_to_bridge(gpointer data)
2535 {
2536         DBG("");
2537         __connman_mesh_add_ethernet_to_bridge();
2538         return FALSE;
2539 }
2540 #endif
2541
2542 void __connman_technology_set_connected(enum connman_service_type type,
2543                 bool connected)
2544 {
2545         struct connman_technology *technology;
2546         dbus_bool_t val;
2547
2548         technology = technology_find(type);
2549         if (!technology)
2550                 return;
2551
2552         DBG("technology %p connected %d", technology, connected);
2553
2554         technology->connected = connected;
2555
2556 #if defined TIZEN_EXT_WIFI_MESH
2557         if (technology->type == CONNMAN_SERVICE_TYPE_ETHERNET && connected)
2558                 g_idle_add(__add_ethernet_to_bridge, NULL);
2559 #endif
2560
2561         val = connected;
2562         connman_dbus_property_changed_basic(technology->path,
2563                         CONNMAN_TECHNOLOGY_INTERFACE, "Connected",
2564                         DBUS_TYPE_BOOLEAN, &val);
2565 }
2566
2567 static bool technology_apply_rfkill_change(struct connman_technology *technology,
2568                                                 bool softblock,
2569                                                 bool hardblock,
2570                                                 bool new_rfkill)
2571 {
2572         bool hardblock_changed = false;
2573         bool apply = true;
2574         GList *start, *list;
2575
2576         DBG("technology %p --> %d/%d vs %d/%d",
2577                         technology, softblock, hardblock,
2578                         technology->softblocked, technology->hardblocked);
2579
2580         if (technology->hardblocked == hardblock)
2581                 goto softblock_change;
2582
2583         if (!(new_rfkill && !hardblock)) {
2584                 start = g_hash_table_get_values(rfkill_list);
2585
2586                 for (list = start; list; list = list->next) {
2587                         struct connman_rfkill *rfkill = list->data;
2588
2589                         if (rfkill->type != technology->type)
2590                                 continue;
2591
2592                         if (rfkill->hardblock != hardblock)
2593                                 apply = false;
2594                 }
2595
2596                 g_list_free(start);
2597         }
2598
2599         if (!apply)
2600                 goto softblock_change;
2601
2602         technology->hardblocked = hardblock;
2603         hardblock_changed = true;
2604
2605 softblock_change:
2606         if (!apply && technology->softblocked != softblock)
2607                 apply = true;
2608
2609         if (!apply)
2610                 return technology->hardblocked;
2611
2612         technology->softblocked = softblock;
2613
2614         if (technology->hardblocked ||
2615                                         technology->softblocked) {
2616                 if (technology_disabled(technology) != -EALREADY)
2617                         technology_affect_devices(technology, false);
2618         } else if (!technology->hardblocked &&
2619                                         !technology->softblocked) {
2620                 if (technology_enabled(technology) != -EALREADY)
2621                         technology_affect_devices(technology, true);
2622         }
2623
2624         if (hardblock_changed) {
2625                 if (technology->hardblocked) {
2626                         DBG("%s is switched off.", get_name(technology->type));
2627                         technology_dbus_unregister(technology);
2628                 } else {
2629                         DBG("%s is switched on.", get_name(technology->type));
2630                         technology_dbus_register(technology);
2631
2632                         if (global_offlinemode)
2633                                 __connman_rfkill_block(technology->type, true);
2634                 }
2635         }
2636
2637         return technology->hardblocked;
2638 }
2639
2640 int __connman_technology_add_rfkill(unsigned int index,
2641                                         enum connman_service_type type,
2642                                                 bool softblock,
2643                                                 bool hardblock)
2644 {
2645         struct connman_technology *technology;
2646         struct connman_rfkill *rfkill;
2647
2648         DBG("index %u type %d soft %u hard %u", index, type,
2649                                                         softblock, hardblock);
2650
2651         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
2652         if (rfkill)
2653                 goto done;
2654
2655         rfkill = g_try_new0(struct connman_rfkill, 1);
2656         if (!rfkill)
2657                 return -ENOMEM;
2658
2659         rfkill->index = index;
2660         rfkill->type = type;
2661         rfkill->softblock = softblock;
2662         rfkill->hardblock = hardblock;
2663
2664         g_hash_table_insert(rfkill_list, GINT_TO_POINTER(index), rfkill);
2665
2666 done:
2667 #if defined TIZEN_EXT
2668         /* Fix Svace Issue [WGID: 1348]. */
2669         g_free(rfkill);
2670 #endif
2671         technology = technology_get(type);
2672         /* If there is no driver for this type, ignore it. */
2673         if (!technology)
2674                 return -ENXIO;
2675
2676         technology->rfkill_driven = true;
2677
2678 #if !defined TIZEN_EXT
2679         /* If hardblocked, there is no need to handle softblocked state */
2680         if (technology_apply_rfkill_change(technology,
2681                                 softblock, hardblock, true))
2682                 return 0;
2683 #endif
2684         if (global_offlinemode)
2685                 return 0;
2686
2687         /*
2688          * Depending on softblocked state we unblock/block according to
2689          * offlinemode and persistente state.
2690          */
2691         if (technology->softblocked &&
2692                                 technology->enable_persistent)
2693                 return __connman_rfkill_block(type, false);
2694         else if (!technology->softblocked &&
2695                                 !technology->enable_persistent)
2696                 return __connman_rfkill_block(type, true);
2697
2698         return 0;
2699 }
2700
2701 int __connman_technology_update_rfkill(unsigned int index,
2702                                         enum connman_service_type type,
2703                                                 bool softblock,
2704                                                 bool hardblock)
2705 {
2706         struct connman_technology *technology;
2707         struct connman_rfkill *rfkill;
2708
2709         DBG("index %u soft %u hard %u", index, softblock, hardblock);
2710
2711         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
2712         if (!rfkill)
2713                 return -ENXIO;
2714
2715         if (rfkill->softblock == softblock &&
2716                                 rfkill->hardblock == hardblock)
2717                 return 0;
2718
2719         rfkill->softblock = softblock;
2720         rfkill->hardblock = hardblock;
2721
2722         technology = technology_find(type);
2723         /* If there is no driver for this type, ignore it. */
2724         if (!technology)
2725                 return -ENXIO;
2726
2727         technology_apply_rfkill_change(technology, softblock, hardblock,
2728                                                                 false);
2729
2730         if (technology->hardblocked)
2731                 DBG("%s hardblocked", get_name(technology->type));
2732         else
2733                 DBG("%s is%s softblocked", get_name(technology->type),
2734                         technology->softblocked ? "" : " not");
2735
2736         return 0;
2737 }
2738
2739 int __connman_technology_remove_rfkill(unsigned int index,
2740                                         enum connman_service_type type)
2741 {
2742         struct connman_technology *technology;
2743         struct connman_rfkill *rfkill;
2744
2745         DBG("index %u", index);
2746
2747         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
2748         if (!rfkill)
2749                 return -ENXIO;
2750
2751         g_hash_table_remove(rfkill_list, GINT_TO_POINTER(index));
2752
2753         technology = technology_find(type);
2754         if (!technology)
2755                 return -ENXIO;
2756
2757         technology_apply_rfkill_change(technology,
2758                 technology->softblocked, !technology->hardblocked, false);
2759
2760         technology_put(technology);
2761
2762         return 0;
2763 }
2764
2765 int __connman_technology_init(void)
2766 {
2767         DBG("");
2768
2769         connection = connman_dbus_get_connection();
2770
2771         rfkill_list = g_hash_table_new_full(g_direct_hash, g_direct_equal,
2772                                                         NULL, free_rfkill);
2773
2774         global_offlinemode = connman_technology_load_offlinemode();
2775
2776         /* This will create settings file if it is missing */
2777         connman_technology_save_offlinemode();
2778
2779         return 0;
2780 }
2781
2782 void __connman_technology_cleanup(void)
2783 {
2784         DBG("");
2785
2786         while (technology_list) {
2787                 struct connman_technology *technology = technology_list->data;
2788                 technology_list = g_slist_remove(technology_list, technology);
2789                 technology_put(technology);
2790         }
2791
2792         g_hash_table_destroy(rfkill_list);
2793
2794         dbus_connection_unref(connection);
2795 }