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