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