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