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