Merge "Added dbus method to get whether 6GHz band is supported" into tizen
[platform/upstream/connman.git] / src / device.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2014  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 #include <unistd.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <sys/ioctl.h>
32 #include <net/ethernet.h>
33 #include <net/if.h>
34
35 #include "connman.h"
36
37 static GSList *device_list = NULL;
38 static gchar **device_filter = NULL;
39 static gchar **nodevice_filter = NULL;
40
41 #if defined TIZEN_EXT
42 static DBusConnection *connection;
43 #endif
44
45 enum connman_pending_type {
46         PENDING_NONE    = 0,
47         PENDING_ENABLE  = 1,
48         PENDING_DISABLE = 2,
49 };
50
51 struct connman_device {
52         int refcount;
53         enum connman_device_type type;
54         enum connman_pending_type powered_pending;      /* Indicates a pending
55                                                          * enable/disable
56                                                          * request
57                                                          */
58         bool powered;
59         bool scanning[MAX_CONNMAN_SERVICE_TYPES];
60         char *name;
61         char *node;
62         char *address;
63         char *interface;
64         char *ident;
65         char *path;
66         int index;
67         guint pending_timeout;
68
69         struct connman_device_driver *driver;
70         void *driver_data;
71
72         char *last_network;
73         struct connman_network *network;
74         GHashTable *networks;
75 #if defined TIZEN_EXT
76         time_t last_user_selection_time;
77         char *last_user_selection_ident;
78         char *last_connected_ident;
79         GList *pending_reply_list; /* List of DBusMessage* for async reply to multiple
80                                     * device power dbus calls, which are made before
81                                     * connman_device_set_powered().
82                                     */
83         int max_scan_ssids;
84         bool is_5_0_ghz_supported;
85         bool is_6_0_ghz_supported;
86         unsigned int mac_policy;
87         unsigned int preassoc_mac_policy;
88         unsigned int random_mac_lifetime;
89 #endif
90 };
91
92 #if defined TIZEN_EXT
93 static void __clear_pending_trigger(gpointer data, gpointer user_data)
94 {
95         DBusMessage *msg = (DBusMessage *)data;
96         dbus_message_unref(msg);
97 }
98 #endif
99
100 static void clear_pending_trigger(struct connman_device *device)
101 {
102 #if defined TIZEN_EXT
103         if (device->pending_reply_list) {
104                 g_list_foreach(device->pending_reply_list, __clear_pending_trigger, NULL);
105                 g_list_free(device->pending_reply_list);
106                 device->pending_reply_list = NULL;
107         }
108 #endif
109         if (device->pending_timeout > 0) {
110                 g_source_remove(device->pending_timeout);
111                 device->pending_timeout = 0;
112         }
113 }
114
115 static const char *type2description(enum connman_device_type type)
116 {
117         switch (type) {
118         case CONNMAN_DEVICE_TYPE_UNKNOWN:
119         case CONNMAN_DEVICE_TYPE_VENDOR:
120                 break;
121         case CONNMAN_DEVICE_TYPE_ETHERNET:
122                 return "Ethernet";
123         case CONNMAN_DEVICE_TYPE_WIFI:
124                 return "Wireless";
125         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
126                 return "Bluetooth";
127         case CONNMAN_DEVICE_TYPE_GPS:
128                 return "GPS";
129         case CONNMAN_DEVICE_TYPE_CELLULAR:
130                 return "Cellular";
131         case CONNMAN_DEVICE_TYPE_GADGET:
132                 return "Gadget";
133
134         }
135
136         return NULL;
137 }
138
139 static const char *type2string(enum connman_device_type type)
140 {
141         switch (type) {
142         case CONNMAN_DEVICE_TYPE_UNKNOWN:
143         case CONNMAN_DEVICE_TYPE_VENDOR:
144                 break;
145         case CONNMAN_DEVICE_TYPE_ETHERNET:
146                 return "ethernet";
147         case CONNMAN_DEVICE_TYPE_WIFI:
148                 return "wifi";
149         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
150                 return "bluetooth";
151         case CONNMAN_DEVICE_TYPE_GPS:
152                 return "gps";
153         case CONNMAN_DEVICE_TYPE_CELLULAR:
154                 return "cellular";
155         case CONNMAN_DEVICE_TYPE_GADGET:
156                 return "gadget";
157
158         }
159
160         return NULL;
161 }
162
163 enum connman_service_type __connman_device_get_service_type(
164                                 struct connman_device *device)
165 {
166         enum connman_device_type type = connman_device_get_type(device);
167
168         switch (type) {
169         case CONNMAN_DEVICE_TYPE_UNKNOWN:
170         case CONNMAN_DEVICE_TYPE_VENDOR:
171         case CONNMAN_DEVICE_TYPE_GPS:
172                 break;
173         case CONNMAN_DEVICE_TYPE_ETHERNET:
174                 return CONNMAN_SERVICE_TYPE_ETHERNET;
175         case CONNMAN_DEVICE_TYPE_WIFI:
176                 return CONNMAN_SERVICE_TYPE_WIFI;
177         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
178                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
179         case CONNMAN_DEVICE_TYPE_CELLULAR:
180                 return CONNMAN_SERVICE_TYPE_CELLULAR;
181         case CONNMAN_DEVICE_TYPE_GADGET:
182                 return CONNMAN_SERVICE_TYPE_GADGET;
183
184         }
185
186         return CONNMAN_SERVICE_TYPE_UNKNOWN;
187 }
188
189 static bool device_has_service_type(struct connman_device *device,
190                                 enum connman_service_type service_type)
191 {
192         enum connman_service_type device_service_type =
193                 __connman_device_get_service_type(device);
194
195         /*
196          * For devices whose device_service_type is unknown we should
197          * allow to decide whether they support specific service_type
198          * by themself.
199          */
200         if (device_service_type == CONNMAN_SERVICE_TYPE_UNKNOWN)
201                 return true;
202
203 #if defined TIZEN_EXT_WIFI_MESH
204         if (device_service_type == CONNMAN_SERVICE_TYPE_MESH)
205                 return service_type != CONNMAN_SERVICE_TYPE_MESH;
206 #endif
207
208         if (device_service_type == CONNMAN_SERVICE_TYPE_WIFI) {
209                 return service_type == CONNMAN_SERVICE_TYPE_WIFI ||
210                         service_type == CONNMAN_SERVICE_TYPE_P2P;
211         }
212
213         return service_type == device_service_type;
214 }
215
216 #if defined TIZEN_EXT
217 static void __device_pending_reset(gpointer data, gpointer user_data)
218 {
219         DBusMessage *msg = (DBusMessage *)data;
220         DBusMessage *reply;
221
222         reply = __connman_error_failed(msg, ETIMEDOUT);
223         if (reply)
224                 g_dbus_send_message(connection, reply);
225
226         dbus_message_unref(msg);
227 }
228 #endif
229
230 static gboolean device_pending_reset(gpointer user_data)
231 {
232         struct connman_device *device = user_data;
233
234         DBG("device %p", device);
235
236 #if defined TIZEN_EXT
237         /* Power request timed out, send ETIMEDOUT. */
238         if (device->pending_reply_list) {
239                 g_list_foreach(device->pending_reply_list, __device_pending_reset, NULL);
240                 g_list_free(device->pending_reply_list);
241                 device->pending_reply_list = NULL;
242         }
243 #endif
244         /* Power request timedout, reset power pending state. */
245         device->pending_timeout = 0;
246         device->powered_pending = PENDING_NONE;
247
248         return FALSE;
249 }
250
251 int __connman_device_enable(struct connman_device *device)
252 {
253         int err;
254
255         DBG("device %p", device);
256
257         if (!device->driver || !device->driver->enable)
258                 return -EOPNOTSUPP;
259
260         /* There is an ongoing power disable request. */
261         if (device->powered_pending == PENDING_DISABLE)
262                 return -EBUSY;
263
264         if (device->powered_pending == PENDING_ENABLE)
265                 return -EINPROGRESS;
266
267         if (device->powered_pending == PENDING_NONE && device->powered)
268                 return -EALREADY;
269
270         if (device->index > 0) {
271                 err = connman_inet_ifup(device->index);
272                 if (err < 0 && err != -EALREADY)
273                         return err;
274         }
275
276         device->powered_pending = PENDING_ENABLE;
277
278         err = device->driver->enable(device);
279         /*
280          * device gets enabled right away.
281          * Invoke the callback
282          */
283         if (err == 0) {
284                 connman_device_set_powered(device, true);
285                 goto done;
286         }
287
288         if (err == -EALREADY) {
289                 /* If device is already powered, but connman is not updated */
290                 connman_device_set_powered(device, true);
291 #ifdef TIZEN_EXT
292                 if (device->type == CONNMAN_DEVICE_TYPE_WIFI) {
293                         device->driver->set_mac_policy(device, device->mac_policy);
294                         device->driver->set_preassoc_mac_policy(device, device->preassoc_mac_policy);
295                         device->driver->set_random_mac_lifetime(device, device->random_mac_lifetime);
296                 }
297 #endif /* TIZEN_EXT */
298                 goto done;
299         }
300         /*
301          * if err == -EINPROGRESS, then the DBus call to the respective daemon
302          * was successful. We set a 4 sec timeout so if the daemon never
303          * returns a reply, we would reset the pending request.
304          */
305         if (err == -EINPROGRESS)
306                 device->pending_timeout = g_timeout_add_seconds(4,
307                                         device_pending_reset, device);
308 done:
309         return err;
310 }
311
312 int __connman_device_disable(struct connman_device *device)
313 {
314         int err;
315
316         DBG("device %p", device);
317
318         /* Ongoing power enable request */
319         if (device->powered_pending == PENDING_ENABLE)
320                 return -EBUSY;
321
322         if (device->powered_pending == PENDING_DISABLE)
323                 return -EINPROGRESS;
324
325         if (device->powered_pending == PENDING_NONE && !device->powered)
326                 return -EALREADY;
327
328         device->powered_pending = PENDING_DISABLE;
329
330         if (device->network) {
331                 struct connman_service *service =
332                         connman_service_lookup_from_network(device->network);
333
334                 if (service)
335                         __connman_service_disconnect(service);
336                 else
337                         connman_network_set_connected(device->network, false);
338         }
339
340         if (!device->driver || !device->driver->disable)
341                 return -EOPNOTSUPP;
342
343         err = device->driver->disable(device);
344         if (err == 0 || err == -EALREADY) {
345                 connman_device_set_powered(device, false);
346                 goto done;
347         }
348
349         if (err == -EINPROGRESS)
350                 device->pending_timeout = g_timeout_add_seconds(4,
351                                         device_pending_reset, device);
352 done:
353         return err;
354 }
355
356 static void probe_driver(struct connman_device_driver *driver)
357 {
358         GSList *list;
359
360         DBG("driver %p name %s", driver, driver->name);
361
362         for (list = device_list; list; list = list->next) {
363                 struct connman_device *device = list->data;
364
365                 if (device->driver)
366                         continue;
367
368                 if (driver->type != device->type)
369                         continue;
370
371                 if (driver->probe(device) < 0)
372                         continue;
373
374                 device->driver = driver;
375
376                 __connman_technology_add_device(device);
377         }
378 }
379
380 static void remove_device(struct connman_device *device)
381 {
382         DBG("device %p", device);
383
384         __connman_device_disable(device);
385
386         __connman_technology_remove_device(device);
387
388         if (device->driver->remove)
389                 device->driver->remove(device);
390
391         device->driver = NULL;
392 }
393
394 static void remove_driver(struct connman_device_driver *driver)
395 {
396         GSList *list;
397
398         DBG("driver %p name %s", driver, driver->name);
399
400         for (list = device_list; list; list = list->next) {
401                 struct connman_device *device = list->data;
402
403                 if (device->driver == driver)
404                         remove_device(device);
405         }
406 }
407
408 bool __connman_device_has_driver(struct connman_device *device)
409 {
410         if (!device || !device->driver)
411                 return false;
412
413         return true;
414 }
415
416 static GSList *driver_list = NULL;
417
418 static gint compare_priority(gconstpointer a, gconstpointer b)
419 {
420         const struct connman_device_driver *driver1 = a;
421         const struct connman_device_driver *driver2 = b;
422
423         return driver2->priority - driver1->priority;
424 }
425
426 /**
427  * connman_device_driver_register:
428  * @driver: device driver definition
429  *
430  * Register a new device driver
431  *
432  * Returns: %0 on success
433  */
434 int connman_device_driver_register(struct connman_device_driver *driver)
435 {
436         DBG("driver %p name %s", driver, driver->name);
437
438         driver_list = g_slist_insert_sorted(driver_list, driver,
439                                                         compare_priority);
440         probe_driver(driver);
441
442         return 0;
443 }
444
445 /**
446  * connman_device_driver_unregister:
447  * @driver: device driver definition
448  *
449  * Remove a previously registered device driver
450  */
451 void connman_device_driver_unregister(struct connman_device_driver *driver)
452 {
453         DBG("driver %p name %s", driver, driver->name);
454
455         driver_list = g_slist_remove(driver_list, driver);
456
457         remove_driver(driver);
458 }
459
460 static void free_network(gpointer data)
461 {
462         struct connman_network *network = data;
463
464         DBG("network %p", network);
465
466         __connman_network_set_device(network, NULL);
467
468         connman_network_unref(network);
469 }
470
471 static void device_destruct(struct connman_device *device)
472 {
473         DBG("device %p name %s", device, device->name);
474
475         clear_pending_trigger(device);
476
477         g_hash_table_destroy(device->networks);
478         device->networks = NULL;
479
480         g_free(device->ident);
481         g_free(device->node);
482         g_free(device->name);
483         g_free(device->address);
484         g_free(device->interface);
485         g_free(device->path);
486
487         g_free(device->last_network);
488
489 #if defined TIZEN_EXT
490         g_free(device->last_user_selection_ident);
491         g_free(device->last_connected_ident);
492 #endif
493
494         g_free(device);
495 }
496
497 #if defined TIZEN_EXT
498 static void device_send_changed(const char *ifname, enum connman_service_type type,
499                                                                 const char *key, bool state)
500 {
501         DBusMessage *signal;
502         DBusMessageIter iter, dict;
503         dbus_bool_t value = state;
504         const char *tech_path = connman_techonology_get_path(type);
505
506         if (!tech_path || !ifname)
507                 return;
508
509         DBG("%s %s %s", ifname, key, state ? "TRUE" : "FALSE");
510
511         signal = dbus_message_new_signal(tech_path,
512                         CONNMAN_TECHNOLOGY_INTERFACE, "DeviceChanged");
513         if (!signal)
514                 return;
515
516         dbus_message_iter_init_append(signal, &iter);
517
518         connman_dbus_dict_open(&iter, &dict);
519         connman_dbus_dict_append_basic(&dict, "Ifname",
520                                         DBUS_TYPE_STRING,
521                                         &ifname);
522         connman_dbus_dict_append_basic(&dict, key,
523                                         DBUS_TYPE_BOOLEAN,
524                                         &value);
525         connman_dbus_dict_close(&iter, &dict);
526
527         dbus_connection_send(connection, signal, NULL);
528         dbus_message_unref(signal);
529 }
530
531 static void __device_send_reply(gpointer data, gpointer user_data)
532 {
533         DBusMessage *msg = (DBusMessage *)data;
534         g_dbus_send_reply(connection, msg, DBUS_TYPE_INVALID);
535         dbus_message_unref(msg);
536 }
537
538 static void device_send_reply(struct connman_device *device)
539 {
540         if (device->pending_reply_list) {
541                 g_list_foreach(device->pending_reply_list, __device_send_reply, NULL);
542                 g_list_free(device->pending_reply_list);
543                 device->pending_reply_list = NULL;
544         }
545 }
546 #endif
547
548 /**
549  * connman_device_create:
550  * @node: device node name (for example an address)
551  * @type: device type
552  *
553  * Allocate a new device of given #type and assign the #node name to it.
554  *
555  * Returns: a newly-allocated #connman_device structure
556  */
557 struct connman_device *connman_device_create(const char *node,
558                                                 enum connman_device_type type)
559 {
560         struct connman_device *device;
561
562         DBG("node %s type %d", node, type);
563
564         device = g_try_new0(struct connman_device, 1);
565         if (!device)
566                 return NULL;
567
568         DBG("device %p", device);
569
570         device->refcount = 1;
571
572         device->type = type;
573         device->name = g_strdup(type2description(device->type));
574
575         device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
576                                                 g_free, free_network);
577
578         device_list = g_slist_prepend(device_list, device);
579
580         return device;
581 }
582
583 /**
584  * connman_device_ref:
585  * @device: device structure
586  *
587  * Increase reference counter of device
588  */
589 struct connman_device *connman_device_ref_debug(struct connman_device *device,
590                                 const char *file, int line, const char *caller)
591 {
592         DBG("%p ref %d by %s:%d:%s()", device, device->refcount + 1,
593                 file, line, caller);
594
595         __sync_fetch_and_add(&device->refcount, 1);
596
597         return device;
598 }
599
600 /**
601  * connman_device_unref:
602  * @device: device structure
603  *
604  * Decrease reference counter of device
605  */
606 void connman_device_unref_debug(struct connman_device *device,
607                                 const char *file, int line, const char *caller)
608 {
609         DBG("%p ref %d by %s:%d:%s()", device, device->refcount - 1,
610                 file, line, caller);
611
612         if (__sync_fetch_and_sub(&device->refcount, 1) != 1)
613                 return;
614
615         if (device->driver) {
616                 device->driver->remove(device);
617                 device->driver = NULL;
618         }
619
620         device_list = g_slist_remove(device_list, device);
621
622         device_destruct(device);
623 }
624
625 const char *__connman_device_get_type(struct connman_device *device)
626 {
627         return type2string(device->type);
628 }
629
630 /**
631  * connman_device_get_type:
632  * @device: device structure
633  *
634  * Get type of device
635  */
636 enum connman_device_type connman_device_get_type(struct connman_device *device)
637 {
638         return device->type;
639 }
640
641 /**
642  * connman_device_set_index:
643  * @device: device structure
644  * @index: index number
645  *
646  * Set index number of device
647  */
648 void connman_device_set_index(struct connman_device *device, int index)
649 {
650         device->index = index;
651 }
652
653 /**
654  * connman_device_get_index:
655  * @device: device structure
656  *
657  * Get index number of device
658  */
659 int connman_device_get_index(struct connman_device *device)
660 {
661         return device->index;
662 }
663
664 /**
665  * connman_device_set_interface:
666  * @device: device structure
667  * @interface: interface name
668  *
669  * Set interface name of device
670  */
671 void connman_device_set_interface(struct connman_device *device,
672                                                 const char *interface)
673 {
674         g_free(device->interface);
675         device->interface = g_strdup(interface);
676
677         if (!device->name) {
678                 const char *str = type2description(device->type);
679                 if (str && device->interface)
680                         device->name = g_strdup_printf("%s (%s)", str,
681                                                         device->interface);
682         }
683 }
684
685 /**
686  * connman_device_set_ident:
687  * @device: device structure
688  * @ident: unique identifier
689  *
690  * Set unique identifier of device
691  */
692 void connman_device_set_ident(struct connman_device *device,
693                                                         const char *ident)
694 {
695 #ifdef TIZEN_EXT
696         if (device->ident && device->powered)
697                 return;
698         else
699 #endif
700         g_free(device->ident);
701         device->ident = g_strdup(ident);
702 }
703
704 const char *connman_device_get_ident(struct connman_device *device)
705 {
706         return device->ident;
707 }
708
709 /**
710  * connman_device_set_powered:
711  * @device: device structure
712  * @powered: powered state
713  *
714  * Change power state of device
715  */
716 int connman_device_set_powered(struct connman_device *device,
717                                                 bool powered)
718 {
719         struct connman_device_scan_params params;
720         enum connman_service_type type;
721         int i;
722
723         DBG("device %p powered %d", device, powered);
724
725         if (device->powered == powered)
726                 return -EALREADY;
727
728 #if defined TIZEN_EXT
729         device_send_reply(device);
730 #endif
731
732         clear_pending_trigger(device);
733
734         device->powered_pending = PENDING_NONE;
735
736         device->powered = powered;
737
738         type = __connman_device_get_service_type(device);
739
740 #if defined TIZEN_EXT
741         device_send_changed(device->interface, type, "Powered", powered);
742         technology_save_device(device);
743 #endif
744
745         if (!device->powered) {
746                 __connman_technology_disabled(type);
747                 return 0;
748         }
749
750         __connman_technology_enabled(type);
751
752         for (i = 0; i < MAX_CONNMAN_SERVICE_TYPES; i++)
753                 device->scanning[i] = false;
754
755         if (device->driver && device->driver->scan) {
756                 memset(&params, 0, sizeof(params));
757                 params.type = CONNMAN_SERVICE_TYPE_UNKNOWN;
758
759                 device->driver->scan(device, &params);
760         }
761
762         return 0;
763 }
764
765 bool connman_device_get_powered(struct connman_device *device)
766 {
767         return device->powered;
768 }
769
770 static int device_scan(enum connman_service_type type,
771                                 struct connman_device *device,
772                                 bool force_full_scan)
773 {
774         struct connman_device_scan_params params;
775
776         if (!device->driver || !device->driver->scan)
777                 return -EOPNOTSUPP;
778
779         if (!device->powered)
780                 return -ENOLINK;
781
782         memset(&params, 0, sizeof(params));
783         params.type = type;
784         params.force_full_scan = force_full_scan;
785
786         return device->driver->scan(device, &params);
787 }
788
789 int __connman_device_disconnect(struct connman_device *device)
790 {
791         GHashTableIter iter;
792         gpointer key, value;
793
794         DBG("device %p", device);
795
796         g_hash_table_iter_init(&iter, device->networks);
797
798         while (g_hash_table_iter_next(&iter, &key, &value)) {
799                 struct connman_network *network = value;
800
801                 if (connman_network_get_connecting(network)) {
802                         /*
803                          * Skip network in the process of connecting.
804                          * This is a workaround for WiFi networks serviced
805                          * by the supplicant plugin that hold a reference
806                          * to the network.  If we disconnect the network
807                          * here then the referenced object will not be
808                          * registered and usage (like launching DHCP client)
809                          * will fail.  There is nothing to be gained by
810                          * removing the network here anyway.
811                          */
812                         connman_warn("Skipping disconnect of %s, network is connecting.",
813                                 connman_network_get_identifier(network));
814                         continue;
815                 }
816
817                 __connman_network_disconnect(network);
818         }
819
820         return 0;
821 }
822
823 int connman_device_reconnect_service(struct connman_device *device)
824 {
825         DBG("device %p", device);
826
827         __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
828
829         return 0;
830 }
831
832 #if defined TIZEN_EXT
833 bool connman_device_set_last_user_selection_time(struct connman_device *device,
834                                                 time_t time)
835 {
836         if (device->last_user_selection_time != time) {
837                 device->last_user_selection_time = time;
838                 return true;
839         }
840
841         return false;
842 }
843
844 time_t connman_device_get_last_user_selection_time(struct connman_device *device)
845 {
846         return device->last_user_selection_time;
847 }
848
849 bool connman_device_set_last_user_selection_ident(struct connman_device *device,
850                                                 const char *ident)
851 {
852         if (g_strcmp0(device->last_user_selection_ident, ident) != 0) {
853                 g_free(device->last_user_selection_ident);
854                 device->last_user_selection_ident = g_strdup(ident);
855
856                 return true;
857         }
858
859         return false;
860 }
861
862 const char *connman_device_get_last_user_selection_ident(struct connman_device *device)
863 {
864         return device->last_user_selection_ident;
865 }
866
867 bool connman_device_set_last_connected_ident(struct connman_device *device,
868                                                 const char *ident)
869 {
870         if (g_strcmp0(device->last_connected_ident, ident) != 0) {
871                 g_free(device->last_connected_ident);
872                 device->last_connected_ident = g_strdup(ident);
873
874                 return true;
875         }
876
877         return false;
878 }
879
880 const char *connman_device_get_last_connected_ident(struct connman_device *device)
881 {
882         return device->last_connected_ident;
883 }
884 #endif
885
886 #if defined TIZEN_EXT && defined TIZEN_EXT_INS
887 void connman_device_save_last_user_selection(struct connman_device *device)
888 {
889         GKeyFile *keyfile;
890         gchar *get_str;
891         gchar *selection_str;
892
893         keyfile = __connman_storage_load_ins();
894
895         selection_str = g_strdup_printf("%s:%ld",
896                         device->last_user_selection_ident, device->last_user_selection_time);
897
898         if (!keyfile) {
899                 keyfile = g_key_file_new();
900
901                 g_key_file_set_string(keyfile, device->interface, "LastUserSelection", selection_str);
902                 DBG("%s", selection_str);
903                 __connman_storage_save_ins(keyfile);
904
905         } else {
906                 get_str = g_key_file_get_string(keyfile, device->interface, "LastUserSelection", NULL);
907                 if (!get_str || g_strcmp0(get_str, selection_str) != 0) {
908                         g_key_file_set_string(keyfile, device->interface, "LastUserSelection", selection_str);
909                         DBG("%s -> %s", get_str, selection_str);
910                         __connman_storage_save_ins(keyfile);
911                 }
912
913                 g_free(get_str);
914         }
915
916         g_free(selection_str);
917         g_key_file_free(keyfile);
918 }
919
920 void connman_device_load_last_user_selection(struct connman_device *device)
921 {
922         GKeyFile *keyfile;
923         gchar *get_str;
924         char **selection_str;
925
926         keyfile = __connman_storage_load_ins();
927         if (!keyfile)
928                 return;
929
930         get_str = g_key_file_get_string(keyfile, device->interface, "LastUserSelection", NULL);
931         if (get_str) {
932                 selection_str = g_strsplit(get_str, ":", 0);
933                 if (selection_str) {
934                         time_t ref_time;
935                         struct tm* timeinfo;
936                         time_t last_user_selection_time;
937
938                         /* Only events that occur within 8 hours are counted. */
939                         ref_time = time(NULL);
940                         timeinfo = localtime(&ref_time);
941                         timeinfo->tm_hour -= 8;
942                         ref_time = mktime(timeinfo);
943
944                         last_user_selection_time = strtol(selection_str[1], NULL, 10);
945
946                         if (last_user_selection_time > ref_time) {
947                                 if (g_strcmp0(selection_str[0], device->last_user_selection_ident) != 0) {
948                                         g_free(device->last_user_selection_ident);
949                                         device->last_user_selection_ident = g_strdup(selection_str[0]);
950                                 }
951
952                                 device->last_user_selection_time = last_user_selection_time;
953
954                                 DBG("%s %ld", device->last_user_selection_ident, device->last_user_selection_time);
955                         }
956
957                         g_strfreev(selection_str);
958                 }
959
960                 g_free(get_str);
961         }
962
963         g_key_file_free(keyfile);
964 }
965
966 void connman_device_save_last_connected(struct connman_device *device)
967 {
968         GKeyFile *keyfile;
969         gchar *get_str;
970
971         if (!device->last_connected_ident)
972                 return;
973
974         keyfile = __connman_storage_load_ins();
975
976         if (!keyfile) {
977                 keyfile = g_key_file_new();
978
979                 g_key_file_set_string(keyfile, device->interface, "LastConnected", device->last_connected_ident);
980                 DBG("%s", device->last_connected_ident);
981                 __connman_storage_save_ins(keyfile);
982
983         } else {
984                 get_str = g_key_file_get_string(keyfile, device->interface, "LastConnected", NULL);
985                 if (!get_str || g_strcmp0(get_str, device->last_connected_ident) != 0) {
986                         g_key_file_set_string(keyfile, device->interface, "LastConnected", device->last_connected_ident);
987                         DBG("%s -> %s", get_str, device->last_connected_ident);
988                         __connman_storage_save_ins(keyfile);
989                 }
990
991                 g_free(get_str);
992         }
993
994         g_key_file_free(keyfile);
995 }
996
997 void connman_device_load_last_connected(struct connman_device *device)
998 {
999         GKeyFile *keyfile;
1000         gchar *get_str;
1001
1002         keyfile = __connman_storage_load_ins();
1003         if (!keyfile)
1004                 return;
1005
1006         get_str = g_key_file_get_string(keyfile, device->interface, "LastConnected", NULL);
1007         if (get_str) {
1008                 if (g_strcmp0(get_str, device->last_connected_ident) != 0) {
1009                         g_free(device->last_connected_ident);
1010                         device->last_connected_ident = g_strdup(get_str);
1011                 }
1012
1013                 DBG("%s", device->last_connected_ident);
1014
1015                 g_free(get_str);
1016         }
1017
1018         g_key_file_free(keyfile);
1019 }
1020 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
1021
1022 static void mark_network_available(gpointer key, gpointer value,
1023                                                         gpointer user_data)
1024 {
1025         struct connman_network *network = value;
1026
1027         connman_network_set_available(network, true);
1028 }
1029
1030 static void mark_network_unavailable(gpointer key, gpointer value,
1031                                                         gpointer user_data)
1032 {
1033         struct connman_network *network = value;
1034
1035         if (connman_network_get_connected(network) ||
1036                         connman_network_get_connecting(network))
1037                 return;
1038
1039         connman_network_set_available(network, false);
1040 }
1041
1042 static gboolean remove_unavailable_network(gpointer key, gpointer value,
1043                                                         gpointer user_data)
1044 {
1045         struct connman_network *network = value;
1046
1047         if (connman_network_get_connected(network) ||
1048                         connman_network_get_connecting(network))
1049                 return FALSE;
1050
1051         if (connman_network_get_available(network))
1052                 return FALSE;
1053
1054         return TRUE;
1055 }
1056
1057 void __connman_device_cleanup_networks(struct connman_device *device)
1058 {
1059         g_hash_table_foreach_remove(device->networks,
1060                                         remove_unavailable_network, NULL);
1061 }
1062
1063 bool connman_device_get_scanning(struct connman_device *device,
1064                                 enum connman_service_type type)
1065 {
1066         int i;
1067
1068         if (type != CONNMAN_SERVICE_TYPE_UNKNOWN)
1069                 return device->scanning[type];
1070
1071         for (i = 0; i < MAX_CONNMAN_SERVICE_TYPES; i++)
1072                 if (device->scanning[i])
1073                         return true;
1074
1075         return false;
1076 }
1077
1078 void connman_device_reset_scanning(struct connman_device *device)
1079 {
1080         g_hash_table_foreach(device->networks,
1081                                 mark_network_available, NULL);
1082 }
1083
1084 /**
1085  * connman_device_set_scanning:
1086  * @device: device structure
1087  * @scanning: scanning state
1088  *
1089  * Change scanning state of device
1090  */
1091 int connman_device_set_scanning(struct connman_device *device,
1092                                 enum connman_service_type type, bool scanning)
1093 {
1094         DBG("device %p scanning %d", device, scanning);
1095
1096         if (!device->driver || !device->driver->scan)
1097                 return -EINVAL;
1098
1099         if (type == CONNMAN_SERVICE_TYPE_UNKNOWN)
1100                 return -EINVAL;
1101
1102         if (device->scanning[type] == scanning)
1103                 return -EALREADY;
1104
1105         device->scanning[type] = scanning;
1106
1107         if (scanning) {
1108                 __connman_technology_scan_started(device);
1109
1110                 g_hash_table_foreach(device->networks,
1111                                         mark_network_unavailable, NULL);
1112
1113                 return 0;
1114         }
1115
1116         __connman_device_cleanup_networks(device);
1117
1118         __connman_technology_scan_stopped(device, type);
1119
1120         __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
1121
1122 #if defined TIZEN_EXT_WIFI_MESH
1123         if (type == CONNMAN_SERVICE_TYPE_MESH)
1124                 __connman_mesh_auto_connect();
1125 #endif
1126
1127         return 0;
1128 }
1129
1130 /**
1131  * connman_device_set_string:
1132  * @device: device structure
1133  * @key: unique identifier
1134  * @value: string value
1135  *
1136  * Set string value for specific key
1137  */
1138 int connman_device_set_string(struct connman_device *device,
1139                                         const char *key, const char *value)
1140 {
1141         DBG("device %p key %s value %s", device, key, value);
1142
1143         if (g_str_equal(key, "Address")) {
1144 #ifdef TIZEN_EXT
1145                 if (device->address && device->powered)
1146                         return 0;
1147                 else
1148 #endif
1149                 g_free(device->address);
1150                 device->address = g_strdup(value);
1151         } else if (g_str_equal(key, "Name")) {
1152                 g_free(device->name);
1153                 device->name = g_strdup(value);
1154         } else if (g_str_equal(key, "Node")) {
1155                 g_free(device->node);
1156                 device->node = g_strdup(value);
1157         } else if (g_str_equal(key, "Path")) {
1158                 g_free(device->path);
1159                 device->path = g_strdup(value);
1160         } else {
1161                 return -EINVAL;
1162         }
1163
1164         return 0;
1165 }
1166
1167 /**
1168  * connman_device_get_string:
1169  * @device: device structure
1170  * @key: unique identifier
1171  *
1172  * Get string value for specific key
1173  */
1174 const char *connman_device_get_string(struct connman_device *device,
1175                                                         const char *key)
1176 {
1177 #if defined TIZEN_EXT
1178         if (!simplified_log)
1179 #endif
1180         DBG("device %p key %s", device, key);
1181
1182         if (g_str_equal(key, "Address"))
1183                 return device->address;
1184         else if (g_str_equal(key, "Name"))
1185                 return device->name;
1186         else if (g_str_equal(key, "Node"))
1187                 return device->node;
1188         else if (g_str_equal(key, "Interface"))
1189                 return device->interface;
1190         else if (g_str_equal(key, "Path"))
1191                 return device->path;
1192
1193         return NULL;
1194 }
1195
1196 /**
1197  * connman_device_add_network:
1198  * @device: device structure
1199  * @network: network structure
1200  *
1201  * Add new network to the device
1202  */
1203 int connman_device_add_network(struct connman_device *device,
1204                                         struct connman_network *network)
1205 {
1206         const char *identifier = connman_network_get_identifier(network);
1207 #if defined TIZEN_EXT
1208         if (!simplified_log)
1209 #endif
1210         DBG("device %p network %p", device, network);
1211
1212         if (!identifier)
1213                 return -EINVAL;
1214
1215         connman_network_ref(network);
1216
1217         __connman_network_set_device(network, device);
1218
1219         g_hash_table_replace(device->networks, g_strdup(identifier),
1220                                                                 network);
1221
1222         return 0;
1223 }
1224
1225 /**
1226  * connman_device_get_network:
1227  * @device: device structure
1228  * @identifier: network identifier
1229  *
1230  * Get network for given identifier
1231  */
1232 struct connman_network *connman_device_get_network(struct connman_device *device,
1233                                                         const char *identifier)
1234 {
1235 #if defined TIZEN_EXT
1236         if (!simplified_log)
1237 #endif
1238         DBG("device %p identifier %s", device, identifier);
1239
1240         return g_hash_table_lookup(device->networks, identifier);
1241 }
1242
1243 #if defined TIZEN_EXT
1244 struct connman_network *connman_device_get_default_network(
1245                                                         struct connman_device *device)
1246 {
1247         return device->network;
1248 }
1249
1250 void connman_device_set_pending_reply(struct connman_device *device,
1251                                                         DBusMessage *msg)
1252 {
1253         device->pending_reply_list = g_list_prepend(device->pending_reply_list, dbus_message_ref(msg));
1254 }
1255
1256 void connman_device_send_connected_signal(struct connman_device *device,
1257                                                         bool connected)
1258 {
1259         enum connman_service_type type;
1260
1261         if (!device)
1262                 return;
1263
1264         type = __connman_device_get_service_type(device);
1265         device_send_changed(device->interface, type, "Connected", connected);
1266 }
1267
1268 void connman_device_set_max_scan_ssids(struct connman_device *device,
1269                                                         int max_scan_ssids)
1270 {
1271         device->max_scan_ssids = max_scan_ssids;
1272 }
1273
1274 int connman_device_get_max_scan_ssids(struct connman_device *device)
1275 {
1276         return device->max_scan_ssids;
1277 }
1278
1279 void connman_device_set_wifi_5ghz_supported(struct connman_device *device,
1280                                                         bool is_5_0_ghz_supported)
1281 {
1282         device->is_5_0_ghz_supported = is_5_0_ghz_supported;
1283 }
1284
1285 void connman_device_set_wifi_6ghz_supported(struct connman_device *device,
1286                                                         bool is_6_0_ghz_supported)
1287 {
1288         device->is_6_0_ghz_supported = is_6_0_ghz_supported;
1289 }
1290
1291 bool connman_device_get_wifi_5ghz_supported(struct connman_device *device)
1292 {
1293         return device->is_5_0_ghz_supported;
1294 }
1295
1296 bool connman_device_get_wifi_6ghz_supported(struct connman_device *device)
1297 {
1298         return device->is_6_0_ghz_supported;
1299 }
1300 #endif
1301
1302 /**
1303  * connman_device_remove_network:
1304  * @device: device structure
1305  * @identifier: network identifier
1306  *
1307  * Remove network for given identifier
1308  */
1309 int connman_device_remove_network(struct connman_device *device,
1310                                                 struct connman_network *network)
1311 {
1312         const char *identifier;
1313
1314         DBG("device %p network %p", device, network);
1315
1316         if (!network)
1317                 return 0;
1318
1319         identifier = connman_network_get_identifier(network);
1320         g_hash_table_remove(device->networks, identifier);
1321
1322         return 0;
1323 }
1324
1325 void __connman_device_set_network(struct connman_device *device,
1326                                         struct connman_network *network)
1327 {
1328         const char *name;
1329
1330         if (!device)
1331                 return;
1332
1333         if (device->network == network)
1334                 return;
1335
1336         if (network) {
1337                 name = connman_network_get_string(network, "Name");
1338                 g_free(device->last_network);
1339                 device->last_network = g_strdup(name);
1340
1341                 device->network = network;
1342         } else {
1343                 g_free(device->last_network);
1344                 device->last_network = NULL;
1345
1346                 device->network = NULL;
1347         }
1348 }
1349
1350 static bool match_driver(struct connman_device *device,
1351                                         struct connman_device_driver *driver)
1352 {
1353         if (device->type == driver->type ||
1354                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
1355                 return true;
1356
1357         return false;
1358 }
1359
1360 /**
1361  * connman_device_register:
1362  * @device: device structure
1363  *
1364  * Register device with the system
1365  */
1366 int connman_device_register(struct connman_device *device)
1367 {
1368         GSList *list;
1369
1370         DBG("device %p name %s", device, device->name);
1371
1372         if (device->driver)
1373                 return -EALREADY;
1374
1375         for (list = driver_list; list; list = list->next) {
1376                 struct connman_device_driver *driver = list->data;
1377
1378                 if (!match_driver(device, driver))
1379                         continue;
1380
1381                 DBG("driver %p name %s", driver, driver->name);
1382
1383                 if (driver->probe(device) == 0) {
1384                         device->driver = driver;
1385                         break;
1386                 }
1387         }
1388
1389         if (!device->driver)
1390                 return 0;
1391
1392         return __connman_technology_add_device(device);
1393 }
1394
1395 /**
1396  * connman_device_unregister:
1397  * @device: device structure
1398  *
1399  * Unregister device with the system
1400  */
1401 void connman_device_unregister(struct connman_device *device)
1402 {
1403         DBG("device %p name %s", device, device->name);
1404
1405         if (!device->driver)
1406                 return;
1407
1408         remove_device(device);
1409 }
1410
1411 /**
1412  * connman_device_get_data:
1413  * @device: device structure
1414  *
1415  * Get private device data pointer
1416  */
1417 void *connman_device_get_data(struct connman_device *device)
1418 {
1419         return device->driver_data;
1420 }
1421
1422 /**
1423  * connman_device_set_data:
1424  * @device: device structure
1425  * @data: data pointer
1426  *
1427  * Set private device data pointer
1428  */
1429 void connman_device_set_data(struct connman_device *device, void *data)
1430 {
1431         device->driver_data = data;
1432 }
1433
1434 struct connman_device *__connman_device_find_device(
1435                                 enum connman_service_type type)
1436 {
1437         GSList *list;
1438
1439         for (list = device_list; list; list = list->next) {
1440                 struct connman_device *device = list->data;
1441                 enum connman_service_type service_type =
1442                         __connman_device_get_service_type(device);
1443
1444                 if (service_type != type)
1445                         continue;
1446
1447                 return device;
1448         }
1449
1450         return NULL;
1451 }
1452
1453 struct connman_device *connman_device_find_by_index(int index)
1454 {
1455         GSList *list;
1456
1457         for (list = device_list; list; list = list->next) {
1458                 struct connman_device *device = list->data;
1459                 if (device->index == index)
1460                         return device;
1461         }
1462
1463         return NULL;
1464 }
1465
1466 /**
1467  * connman_device_set_regdom
1468  * @device: device structure
1469  * @alpha2: string representing regulatory domain
1470  *
1471  * Set regulatory domain on device basis
1472  */
1473 int connman_device_set_regdom(struct connman_device *device,
1474                                                 const char *alpha2)
1475 {
1476         if (!device->driver || !device->driver->set_regdom)
1477                 return -ENOTSUP;
1478
1479         if (!device->powered)
1480                 return -EINVAL;
1481
1482         return device->driver->set_regdom(device, alpha2);
1483 }
1484
1485 /**
1486  * connman_device_regdom_notify
1487  * @device: device structure
1488  * @alpha2: string representing regulatory domain
1489  *
1490  * Notify on setting regulatory domain on device basis
1491  */
1492 void connman_device_regdom_notify(struct connman_device *device,
1493                                         int result, const char *alpha2)
1494 {
1495         __connman_technology_notify_regdom_by_device(device, result, alpha2);
1496 }
1497
1498 #if defined TIZEN_EXT
1499 static int device_specific_scan(enum connman_service_type type,
1500                                 struct connman_device *device,
1501                                 int scan_type, GSList *specific_scan_list)
1502 {
1503         if (!device->driver || !device->driver->specific_scan)
1504                 return -EOPNOTSUPP;
1505
1506         if (!device->powered)
1507                 return -ENOLINK;
1508
1509         return device->driver->specific_scan(type, device, scan_type,
1510                         specific_scan_list, NULL);
1511 }
1512
1513 int __connman_device_request_specific_scan(enum connman_service_type type,
1514                                 const char *ifname, int scan_type, GSList *specific_scan_list)
1515 {
1516         bool success = false;
1517         int last_err = -ENOSYS;
1518         GSList *list;
1519         int err;
1520
1521         switch (type) {
1522         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1523         case CONNMAN_SERVICE_TYPE_SYSTEM:
1524         case CONNMAN_SERVICE_TYPE_ETHERNET:
1525         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1526         case CONNMAN_SERVICE_TYPE_CELLULAR:
1527         case CONNMAN_SERVICE_TYPE_GPS:
1528         case CONNMAN_SERVICE_TYPE_VPN:
1529         case CONNMAN_SERVICE_TYPE_GADGET:
1530                 return -EOPNOTSUPP;
1531         case CONNMAN_SERVICE_TYPE_WIFI:
1532         case CONNMAN_SERVICE_TYPE_P2P:
1533 #if defined TIZEN_EXT_WIFI_MESH
1534         case CONNMAN_SERVICE_TYPE_MESH:
1535 #endif
1536                 break;
1537         }
1538
1539         for (list = device_list; list; list = list->next) {
1540                 struct connman_device *device = list->data;
1541                 enum connman_service_type service_type =
1542                         __connman_device_get_service_type(device);
1543
1544                 if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN) {
1545                         if (type == CONNMAN_SERVICE_TYPE_P2P) {
1546                                 if (service_type != CONNMAN_SERVICE_TYPE_WIFI)
1547                                         continue;
1548                         } else if (service_type != type)
1549                                 continue;
1550                 }
1551
1552                 if (ifname && g_strcmp0(device->interface, ifname) != 0)
1553                         continue;
1554
1555                 err = device_specific_scan(type, device, scan_type, specific_scan_list);
1556                 if (err == 0 || err == -EINPROGRESS) {
1557                         success = true;
1558                 } else {
1559                         last_err = err;
1560                         DBG("device %p err %d", device, err);
1561                 }
1562         }
1563
1564         if (success)
1565                 return 0;
1566
1567         return last_err;
1568 }
1569
1570 int connman_device_request_device_scan(enum connman_service_type type,
1571                                 const char * ifname, bool force_full_scan)
1572 {
1573         bool success = false;
1574         int last_err = -ENOSYS;
1575         GSList *list;
1576         int err;
1577
1578         switch (type) {
1579         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1580         case CONNMAN_SERVICE_TYPE_SYSTEM:
1581         case CONNMAN_SERVICE_TYPE_ETHERNET:
1582         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1583         case CONNMAN_SERVICE_TYPE_CELLULAR:
1584         case CONNMAN_SERVICE_TYPE_GPS:
1585         case CONNMAN_SERVICE_TYPE_VPN:
1586         case CONNMAN_SERVICE_TYPE_GADGET:
1587                 return -EOPNOTSUPP;
1588         case CONNMAN_SERVICE_TYPE_WIFI:
1589         case CONNMAN_SERVICE_TYPE_P2P:
1590 #if defined TIZEN_EXT_WIFI_MESH
1591         case CONNMAN_SERVICE_TYPE_MESH:
1592 #endif
1593                 break;
1594         }
1595
1596         for (list = device_list; list; list = list->next) {
1597                 struct connman_device *device = list->data;
1598
1599                 if (!device_has_service_type(device, type))
1600                         continue;
1601
1602                 if (g_strcmp0(device->interface, ifname) != 0)
1603                         continue;
1604
1605                 err = device_scan(type, device, force_full_scan);
1606
1607                 if (err == 0 || err == -EINPROGRESS) {
1608                         success = true;
1609                 } else {
1610                         last_err = err;
1611                         DBG("device %p err %d", device, err);
1612                 }
1613                 break;
1614         }
1615
1616         if (success)
1617                 return 0;
1618
1619         return last_err;
1620 }
1621
1622 #if defined TIZEN_EXT_WIFI_MESH
1623 static int device_abort_scan(enum connman_service_type type,
1624                                 struct connman_device *device)
1625 {
1626         if (!device->driver || !device->driver->scan)
1627                 return -EOPNOTSUPP;
1628
1629         if (!device->powered)
1630                 return -ENOLINK;
1631
1632         return device->driver->abort_scan(type, device);
1633 }
1634
1635 int __connman_device_abort_scan(enum connman_service_type type)
1636 {
1637         GSList *list;
1638         int err = -EINVAL;
1639
1640         if (type != CONNMAN_SERVICE_TYPE_MESH)
1641                 return -EINVAL;
1642
1643         for (list = device_list; list; list = list->next) {
1644                 struct connman_device *device = list->data;
1645                 enum connman_service_type service_type =
1646                         __connman_device_get_service_type(device);
1647
1648                 if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN) {
1649                         if (type == CONNMAN_SERVICE_TYPE_MESH)
1650                                 if (service_type != CONNMAN_SERVICE_TYPE_WIFI)
1651                                         continue;
1652
1653                         if (!device->scanning) {
1654                                 err = -EEXIST;
1655                                 continue;
1656                         }
1657
1658                         err = device_abort_scan(type, device);
1659                 }
1660         }
1661         return err;
1662 }
1663
1664 static int device_mesh_specific_scan(enum connman_service_type type,
1665                                 struct connman_device *device, const char *name,
1666                                 unsigned int freq)
1667 {
1668         if (!device->driver || !device->driver->mesh_specific_scan)
1669                 return -EOPNOTSUPP;
1670
1671         if (!device->powered)
1672                 return -ENOLINK;
1673
1674         return device->driver->mesh_specific_scan(type, device, name, freq, NULL);
1675 }
1676
1677 int __connman_device_request_mesh_specific_scan(enum connman_service_type type,
1678                                                 const char *name,
1679                                                 unsigned int freq)
1680 {
1681         bool success = false;
1682         int last_err = -ENOSYS;
1683         GSList *list;
1684         int err;
1685
1686         if (type != CONNMAN_SERVICE_TYPE_MESH)
1687                 return -EINVAL;
1688
1689         for (list = device_list; list; list = list->next) {
1690                 struct connman_device *device = list->data;
1691                 enum connman_service_type service_type =
1692                         __connman_device_get_service_type(device);
1693
1694                 if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN) {
1695                         if (type == CONNMAN_SERVICE_TYPE_MESH)
1696                                 if (service_type != CONNMAN_SERVICE_TYPE_WIFI)
1697                                         continue;
1698                 }
1699
1700                 err = device_mesh_specific_scan(type, device, name, freq);
1701                 if (err == 0 || err == -EALREADY || err == -EINPROGRESS) {
1702                         success = true;
1703                 } else {
1704                         last_err = err;
1705                         DBG("device %p err %d", device, err);
1706                 }
1707         }
1708
1709         if (success)
1710                 return 0;
1711
1712         return last_err;
1713 }
1714 #endif /* TIZEN_EXT_WIFI_MESH */
1715 #endif
1716
1717 static int connman_device_request_scan(enum connman_service_type type,
1718                                         bool force_full_scan)
1719 {
1720         bool success = false;
1721         int last_err = -ENOSYS;
1722         GSList *list;
1723         int err;
1724
1725         switch (type) {
1726         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1727         case CONNMAN_SERVICE_TYPE_SYSTEM:
1728         case CONNMAN_SERVICE_TYPE_ETHERNET:
1729         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1730         case CONNMAN_SERVICE_TYPE_CELLULAR:
1731         case CONNMAN_SERVICE_TYPE_GPS:
1732         case CONNMAN_SERVICE_TYPE_VPN:
1733         case CONNMAN_SERVICE_TYPE_GADGET:
1734                 return -EOPNOTSUPP;
1735         case CONNMAN_SERVICE_TYPE_WIFI:
1736         case CONNMAN_SERVICE_TYPE_P2P:
1737 #if defined TIZEN_EXT_WIFI_MESH
1738         case CONNMAN_SERVICE_TYPE_MESH:
1739 #endif
1740                 break;
1741         }
1742
1743         for (list = device_list; list; list = list->next) {
1744                 struct connman_device *device = list->data;
1745
1746                 if (!device_has_service_type(device, type))
1747                         continue;
1748
1749                 err = device_scan(type, device, force_full_scan);
1750 #if defined TIZEN_EXT
1751                 /* When Scan is already in progress then return Error so that
1752                  * wifi-manager can block the scan-done signal to be sent to
1753                  * application and start requested scan after scan already in progress
1754                  * is completed then notify to application about the scan event */
1755                 if (err == 0 || err == -EINPROGRESS) {
1756 #else
1757                 if (err == 0 || err == -EALREADY || err == -EINPROGRESS) {
1758 #endif
1759                         success = true;
1760                 } else {
1761                         last_err = err;
1762                         DBG("device %p err %d", device, err);
1763                 }
1764         }
1765
1766         if (success)
1767                 return 0;
1768
1769         return last_err;
1770 }
1771
1772 int __connman_device_request_scan(enum connman_service_type type)
1773 {
1774         return connman_device_request_scan(type, false);
1775 }
1776
1777 int __connman_device_request_scan_full(enum connman_service_type type)
1778 {
1779         return connman_device_request_scan(type, true);
1780 }
1781
1782 int __connman_device_request_hidden_scan(struct connman_device *device,
1783                                 const char *ssid, unsigned int ssid_len,
1784                                 const char *identity, const char *passphrase,
1785                                 const char *security, void *user_data)
1786 {
1787         struct connman_device_scan_params params;
1788
1789         DBG("device %p", device);
1790
1791         if (!device || !device->driver ||
1792                         !device->driver->scan)
1793                 return -EINVAL;
1794
1795         params.type = CONNMAN_SERVICE_TYPE_UNKNOWN;
1796         params.ssid = ssid;
1797         params.ssid_len = ssid_len;
1798         params.identity = identity;
1799         params.passphrase = passphrase;
1800         params.security = security;
1801         params.user_data = user_data;
1802
1803         return device->driver->scan(device, &params);
1804 }
1805
1806 void __connman_device_stop_scan(enum connman_service_type type)
1807 {
1808         GSList *list;
1809
1810         for (list = device_list; list; list = list->next) {
1811                 struct connman_device *device = list->data;
1812
1813                 if (!device_has_service_type(device, type))
1814                         continue;
1815
1816                 if (device->driver && device->driver->stop_scan)
1817                         device->driver->stop_scan(type, device);
1818         }
1819 }
1820
1821 #if defined TIZEN_EXT
1822 #define WIFI_MAC "/opt/etc/.mac.info"
1823 #define MAC_ADDR_LEN 18
1824
1825 char *_get_wifi_addr(void)
1826 {
1827         FILE *fp = NULL;
1828         char* rv = 0;
1829         char wifi_mac[MAC_ADDR_LEN + 1];
1830         char *str;
1831
1832         fp = fopen(WIFI_MAC, "r");
1833         if (!fp){
1834                 connman_error("[%s] not present", WIFI_MAC);
1835                 return NULL;
1836         }
1837
1838         rv = fgets(wifi_mac, MAC_ADDR_LEN, fp);
1839         if (!rv) {
1840                 connman_error("Failed to get wifi mac address");
1841                 fclose(fp);
1842                 return NULL;
1843         }
1844
1845         str = g_try_malloc0(MAC_ADDR_LEN);
1846         if (!str) {
1847                 connman_error("memory allocation failed");
1848                 fclose(fp);
1849                 return NULL;
1850         }
1851
1852         snprintf(str, MAC_ADDR_LEN, "%c%c:%c%c:%c%c:%c%c:%c%c:%c%c",
1853                         g_ascii_tolower(wifi_mac[0]), g_ascii_tolower(wifi_mac[1]),
1854                         g_ascii_tolower(wifi_mac[3]), g_ascii_tolower(wifi_mac[4]),
1855                         g_ascii_tolower(wifi_mac[6]), g_ascii_tolower(wifi_mac[7]),
1856                         g_ascii_tolower(wifi_mac[9]), g_ascii_tolower(wifi_mac[10]),
1857                         g_ascii_tolower(wifi_mac[12]), g_ascii_tolower(wifi_mac[13]),
1858                         g_ascii_tolower(wifi_mac[15]), g_ascii_tolower(wifi_mac[16]));
1859         fclose(fp);
1860         return str;
1861 }
1862
1863 char *_get_wifi_ident(void)
1864 {
1865         FILE *fp = NULL;
1866         char* rv = 0;
1867         char wifi_mac[MAC_ADDR_LEN + 1];
1868         char *str;
1869
1870         fp = fopen(WIFI_MAC, "r");
1871         if (!fp){
1872                 connman_error("[%s] not present", WIFI_MAC);
1873                 return NULL;
1874         }
1875
1876         rv = fgets(wifi_mac, MAC_ADDR_LEN, fp);
1877         if (!rv) {
1878                 connman_error("Failed to get wifi mac address");
1879                 fclose(fp);
1880                 return NULL;
1881         }
1882
1883         str = g_try_malloc0(MAC_ADDR_LEN);
1884         if (!str) {
1885                 connman_error("memory allocation failed");
1886                 fclose(fp);
1887                 return NULL;
1888         }
1889
1890         snprintf(str, MAC_ADDR_LEN, "%c%c%c%c%c%c%c%c%c%c%c%c",
1891                         g_ascii_tolower(wifi_mac[0]), g_ascii_tolower(wifi_mac[1]),
1892                         g_ascii_tolower(wifi_mac[3]), g_ascii_tolower(wifi_mac[4]),
1893                         g_ascii_tolower(wifi_mac[6]), g_ascii_tolower(wifi_mac[7]),
1894                         g_ascii_tolower(wifi_mac[9]), g_ascii_tolower(wifi_mac[10]),
1895                         g_ascii_tolower(wifi_mac[12]), g_ascii_tolower(wifi_mac[13]),
1896                         g_ascii_tolower(wifi_mac[15]), g_ascii_tolower(wifi_mac[16]));
1897         fclose(fp);
1898         return str;
1899 }
1900 #endif
1901
1902 #if defined TIZEN_EXT
1903 char *index2ident(int index, const char *prefix)
1904 #else
1905 static char *index2ident(int index, const char *prefix)
1906 #endif
1907 {
1908         struct ifreq ifr;
1909         struct ether_addr eth;
1910         char *str;
1911         int sk, err, len;
1912
1913         if (index < 0)
1914                 return NULL;
1915
1916         sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
1917         if (sk < 0)
1918                 return NULL;
1919
1920         memset(&ifr, 0, sizeof(ifr));
1921         ifr.ifr_ifindex = index;
1922
1923         err = ioctl(sk, SIOCGIFNAME, &ifr);
1924
1925         if (err == 0)
1926                 err = ioctl(sk, SIOCGIFHWADDR, &ifr);
1927
1928         close(sk);
1929
1930         if (err < 0)
1931                 return NULL;
1932
1933         len = prefix ? strlen(prefix) + 18 : 18;
1934
1935         str = g_malloc(len);
1936         if (!str)
1937                 return NULL;
1938
1939         memcpy(&eth, &ifr.ifr_hwaddr.sa_data, sizeof(eth));
1940         snprintf(str, len, "%s%02x%02x%02x%02x%02x%02x",
1941                                                 prefix ? prefix : "",
1942                                                 eth.ether_addr_octet[0],
1943                                                 eth.ether_addr_octet[1],
1944                                                 eth.ether_addr_octet[2],
1945                                                 eth.ether_addr_octet[3],
1946                                                 eth.ether_addr_octet[4],
1947                                                 eth.ether_addr_octet[5]);
1948
1949         return str;
1950 }
1951
1952 #if defined TIZEN_EXT
1953 char *index2addr(int index)
1954 #else
1955 static char *index2addr(int index)
1956 #endif
1957 {
1958         struct ifreq ifr;
1959         struct ether_addr eth;
1960         char *str;
1961         int sk, err;
1962
1963         if (index < 0)
1964                 return NULL;
1965
1966         sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
1967         if (sk < 0)
1968                 return NULL;
1969
1970         memset(&ifr, 0, sizeof(ifr));
1971         ifr.ifr_ifindex = index;
1972
1973         err = ioctl(sk, SIOCGIFNAME, &ifr);
1974
1975         if (err == 0)
1976                 err = ioctl(sk, SIOCGIFHWADDR, &ifr);
1977
1978         close(sk);
1979
1980         if (err < 0)
1981                 return NULL;
1982
1983         str = g_malloc(18);
1984         if (!str)
1985                 return NULL;
1986
1987         memcpy(&eth, &ifr.ifr_hwaddr.sa_data, sizeof(eth));
1988         snprintf(str, 18, "%02X:%02X:%02X:%02X:%02X:%02X",
1989                                                 eth.ether_addr_octet[0],
1990                                                 eth.ether_addr_octet[1],
1991                                                 eth.ether_addr_octet[2],
1992                                                 eth.ether_addr_octet[3],
1993                                                 eth.ether_addr_octet[4],
1994                                                 eth.ether_addr_octet[5]);
1995
1996         return str;
1997 }
1998
1999 struct connman_device *connman_device_create_from_index(int index)
2000 {
2001         enum connman_device_type type;
2002         struct connman_device *device;
2003         char *devname, *ident = NULL;
2004         char *addr = NULL, *name = NULL;
2005
2006         if (index < 0)
2007                 return NULL;
2008
2009         devname = connman_inet_ifname(index);
2010         if (!devname)
2011                 return NULL;
2012
2013         if (__connman_device_isfiltered(devname)) {
2014                 connman_info("Ignoring interface %s (filtered)", devname);
2015                 g_free(devname);
2016                 return NULL;
2017         }
2018
2019         type = __connman_rtnl_get_device_type(index);
2020
2021         switch (type) {
2022         case CONNMAN_DEVICE_TYPE_UNKNOWN:
2023                 connman_info("Ignoring interface %s (type unknown)", devname);
2024                 g_free(devname);
2025                 return NULL;
2026         case CONNMAN_DEVICE_TYPE_ETHERNET:
2027         case CONNMAN_DEVICE_TYPE_GADGET:
2028         case CONNMAN_DEVICE_TYPE_WIFI:
2029                 name = index2ident(index, "");
2030                 addr = index2addr(index);
2031                 break;
2032         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
2033         case CONNMAN_DEVICE_TYPE_CELLULAR:
2034         case CONNMAN_DEVICE_TYPE_GPS:
2035         case CONNMAN_DEVICE_TYPE_VENDOR:
2036                 name = g_strdup(devname);
2037                 break;
2038         }
2039
2040         device = connman_device_create(name, type);
2041         if (!device)
2042                 goto done;
2043
2044         switch (type) {
2045         case CONNMAN_DEVICE_TYPE_UNKNOWN:
2046         case CONNMAN_DEVICE_TYPE_VENDOR:
2047         case CONNMAN_DEVICE_TYPE_GPS:
2048                 break;
2049         case CONNMAN_DEVICE_TYPE_ETHERNET:
2050         case CONNMAN_DEVICE_TYPE_GADGET:
2051                 ident = index2ident(index, NULL);
2052                 break;
2053         case CONNMAN_DEVICE_TYPE_WIFI:
2054                 ident = index2ident(index, NULL);
2055                 break;
2056         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
2057                 break;
2058         case CONNMAN_DEVICE_TYPE_CELLULAR:
2059                 ident = index2ident(index, NULL);
2060                 break;
2061         }
2062
2063         connman_device_set_index(device, index);
2064         connman_device_set_interface(device, devname);
2065 #if defined TIZEN_EXT && defined TIZEN_EXT_INS
2066         connman_device_load_last_connected(device);
2067         connman_device_load_last_user_selection(device);
2068 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
2069
2070         if (ident) {
2071                 connman_device_set_ident(device, ident);
2072                 g_free(ident);
2073         }
2074
2075         connman_device_set_string(device, "Address", addr);
2076
2077 done:
2078         g_free(devname);
2079         g_free(name);
2080         g_free(addr);
2081
2082         return device;
2083 }
2084
2085 bool __connman_device_isfiltered(const char *devname)
2086 {
2087         char **pattern;
2088         char **blacklisted_interfaces;
2089         bool match;
2090
2091         if (!device_filter)
2092                 goto nodevice;
2093
2094         for (pattern = device_filter, match = false; *pattern; pattern++) {
2095                 if (g_pattern_match_simple(*pattern, devname)) {
2096                         match = true;
2097                         break;
2098                 }
2099         }
2100
2101         if (!match) {
2102                 DBG("ignoring device %s (match)", devname);
2103                 return true;
2104         }
2105
2106 nodevice:
2107         if (g_pattern_match_simple("dummy*", devname)) {
2108                 DBG("ignoring dummy networking devices");
2109                 return true;
2110         }
2111
2112         if (!nodevice_filter)
2113                 goto list;
2114
2115         for (pattern = nodevice_filter; *pattern; pattern++) {
2116                 if (g_pattern_match_simple(*pattern, devname)) {
2117                         DBG("ignoring device %s (no match)", devname);
2118                         return true;
2119                 }
2120         }
2121
2122 list:
2123         if (__connman_inet_isrootnfs_device(devname)) {
2124                 DBG("ignoring device %s (rootnfs)", devname);
2125                 return true;
2126         }
2127
2128         blacklisted_interfaces =
2129                 connman_setting_get_string_list("NetworkInterfaceBlacklist");
2130         if (!blacklisted_interfaces)
2131                 return false;
2132
2133         for (pattern = blacklisted_interfaces; *pattern; pattern++) {
2134                 if (g_str_has_prefix(devname, *pattern)) {
2135                         DBG("ignoring device %s (blacklist)", devname);
2136                         return true;
2137                 }
2138         }
2139
2140         return false;
2141 }
2142
2143 static void cleanup_devices(void)
2144 {
2145         /*
2146          * Check what interfaces are currently up and if connman is
2147          * suppose to handle the interface, then cleanup the mess
2148          * related to that interface. There might be weird routes etc
2149          * that are related to that interface and that might confuse
2150          * connmand. So in this case we just turn the interface down
2151          * so that kernel removes routes/addresses automatically and
2152          * then proceed the startup.
2153          *
2154          * Note that this cleanup must be done before rtnl/detect code
2155          * has activated interface watches.
2156          */
2157
2158         char **interfaces;
2159         int i;
2160
2161         interfaces = __connman_inet_get_running_interfaces();
2162
2163         if (!interfaces)
2164                 return;
2165
2166         for (i = 0; interfaces[i]; i++) {
2167                 bool filtered;
2168                 int index;
2169                 struct sockaddr_in sin_addr, sin_mask;
2170
2171                 filtered = __connman_device_isfiltered(interfaces[i]);
2172                 if (filtered)
2173                         continue;
2174
2175                 index = connman_inet_ifindex(interfaces[i]);
2176                 if (index < 0)
2177                         continue;
2178
2179                 if (!__connman_inet_get_address_netmask(index, &sin_addr,
2180                                                         &sin_mask)) {
2181                         char *address = g_strdup(inet_ntoa(sin_addr.sin_addr));
2182                         char *netmask = g_strdup(inet_ntoa(sin_mask.sin_addr));
2183
2184                         if (__connman_config_address_provisioned(address,
2185                                                                 netmask)) {
2186                                 DBG("Skip %s which is already provisioned "
2187                                         "with %s/%s", interfaces[i], address,
2188                                         netmask);
2189                                 g_free(address);
2190                                 g_free(netmask);
2191                                 continue;
2192                         }
2193
2194                         g_free(address);
2195                         g_free(netmask);
2196                 }
2197
2198                 DBG("cleaning up %s index %d", interfaces[i], index);
2199
2200 #if defined TIZEN_EXT
2201                 if (strcmp(interfaces[i], "wlan0") != 0)
2202 #endif
2203                 connman_inet_ifdown(index);
2204
2205                 /*
2206                  * ConnMan will turn the interface UP automatically so
2207                  * no need to do it here.
2208                  */
2209         }
2210
2211         g_strfreev(interfaces);
2212 }
2213
2214 int __connman_device_init(const char *device, const char *nodevice)
2215 {
2216         DBG("");
2217
2218 #if defined TIZEN_EXT
2219         connection = connman_dbus_get_connection();
2220 #endif
2221
2222         if (device)
2223                 device_filter = g_strsplit(device, ",", -1);
2224
2225         if (nodevice)
2226                 nodevice_filter = g_strsplit(nodevice, ",", -1);
2227
2228         cleanup_devices();
2229
2230         return 0;
2231 }
2232
2233 void __connman_device_cleanup(void)
2234 {
2235         DBG("");
2236
2237         g_strfreev(nodevice_filter);
2238         g_strfreev(device_filter);
2239
2240 #if defined TIZEN_EXT
2241         dbus_connection_unref(connection);
2242 #endif
2243 }
2244
2245 #ifdef TIZEN_EXT
2246 void connman_device_mac_policy_notify(struct connman_device *device,
2247                                         int result, unsigned int policy)
2248 {
2249         device->mac_policy = policy;
2250         __connman_technology_notify_mac_policy_by_device(device, result, policy);
2251 }
2252
2253 int connman_device_set_mac_policy(struct connman_device *device,
2254                                         unsigned int policy)
2255 {
2256         int err = 0;
2257
2258         if (!device || !device->driver || !device->driver->set_mac_policy)
2259                 return -EOPNOTSUPP;
2260
2261         device->mac_policy = policy;
2262         err = device->driver->set_mac_policy(device, policy);
2263         return err;
2264 }
2265
2266 unsigned int connman_device_get_mac_policy(struct connman_device *device)
2267 {
2268         return device->mac_policy;
2269 }
2270
2271 void connman_device_preassoc_mac_policy_notify(struct connman_device *device,
2272                                         int result, unsigned int policy)
2273 {
2274         device->preassoc_mac_policy = policy;
2275         __connman_technology_notify_preassoc_mac_policy_by_device(device, result, policy);
2276 }
2277
2278 int connman_device_set_preassoc_mac_policy(struct connman_device *device,
2279                                         unsigned int policy)
2280 {
2281         int err = 0;
2282
2283         if (!device || !device->driver || !device->driver->set_preassoc_mac_policy)
2284                 return -EOPNOTSUPP;
2285
2286         device->preassoc_mac_policy = policy;
2287         err = device->driver->set_preassoc_mac_policy(device, policy);
2288         return err;
2289 }
2290
2291 unsigned int connman_device_get_preassoc_mac_policy(struct connman_device *device)
2292 {
2293         return device->preassoc_mac_policy;
2294 }
2295
2296 void connman_device_random_mac_lifetime_notify(struct connman_device *device,
2297                                         int result, unsigned int lifetime)
2298 {
2299         device->random_mac_lifetime = lifetime;
2300         __connman_technology_notify_random_mac_lifetime_by_device(device, result, lifetime);
2301 }
2302
2303 int connman_device_set_random_mac_lifetime(struct connman_device *device,
2304                                         unsigned int lifetime)
2305 {
2306         int err = 0;
2307
2308         if (!device || !device->driver || !device->driver->set_random_mac_lifetime)
2309                 return -EOPNOTSUPP;
2310
2311         device->random_mac_lifetime = lifetime;
2312         err = device->driver->set_random_mac_lifetime(device, lifetime);
2313         return err;
2314 }
2315
2316 unsigned int connman_device_get_random_mac_lifetime(struct connman_device *device)
2317 {
2318         return device->random_mac_lifetime;
2319 }
2320
2321 #endif