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