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