Fix incorrect handling in multi-interface environment
[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 #endif
744
745         if (!device->powered) {
746                 __connman_technology_disabled(type);
747                 return 0;
748         }
749
750         __connman_technology_enabled(type);
751
752         for (i = 0; i < MAX_CONNMAN_SERVICE_TYPES; i++)
753                 device->scanning[i] = false;
754
755         if (device->driver && device->driver->scan) {
756                 memset(&params, 0, sizeof(params));
757                 params.type = CONNMAN_SERVICE_TYPE_UNKNOWN;
758
759                 device->driver->scan(device, &params);
760         }
761
762         return 0;
763 }
764
765 bool connman_device_get_powered(struct connman_device *device)
766 {
767         return device->powered;
768 }
769
770 static int device_scan(enum connman_service_type type,
771                                 struct connman_device *device,
772                                 bool force_full_scan)
773 {
774         struct connman_device_scan_params params;
775
776         if (!device->driver || !device->driver->scan)
777                 return -EOPNOTSUPP;
778
779         if (!device->powered)
780                 return -ENOLINK;
781
782         memset(&params, 0, sizeof(params));
783         params.type = type;
784         params.force_full_scan = force_full_scan;
785
786         return device->driver->scan(device, &params);
787 }
788
789 int __connman_device_disconnect(struct connman_device *device)
790 {
791         GHashTableIter iter;
792         gpointer key, value;
793
794         DBG("device %p", device);
795
796         g_hash_table_iter_init(&iter, device->networks);
797
798         while (g_hash_table_iter_next(&iter, &key, &value)) {
799                 struct connman_network *network = value;
800
801                 if (connman_network_get_connecting(network)) {
802                         /*
803                          * Skip network in the process of connecting.
804                          * This is a workaround for WiFi networks serviced
805                          * by the supplicant plugin that hold a reference
806                          * to the network.  If we disconnect the network
807                          * here then the referenced object will not be
808                          * registered and usage (like launching DHCP client)
809                          * will fail.  There is nothing to be gained by
810                          * removing the network here anyway.
811                          */
812                         connman_warn("Skipping disconnect of %s, network is connecting.",
813                                 connman_network_get_identifier(network));
814                         continue;
815                 }
816
817                 __connman_network_disconnect(network);
818         }
819
820         return 0;
821 }
822
823 int connman_device_reconnect_service(struct connman_device *device)
824 {
825         DBG("device %p", device);
826
827         __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
828
829         return 0;
830 }
831
832 #if defined TIZEN_EXT
833 bool connman_device_set_last_user_selection_time(struct connman_device *device,
834                                                 time_t time)
835 {
836         if (device->last_user_selection_time != time) {
837                 device->last_user_selection_time = time;
838                 return true;
839         }
840
841         return false;
842 }
843
844 time_t connman_device_get_last_user_selection_time(struct connman_device *device)
845 {
846         return device->last_user_selection_time;
847 }
848
849 bool connman_device_set_last_user_selection_ident(struct connman_device *device,
850                                                 const char *ident)
851 {
852         if (g_strcmp0(device->last_user_selection_ident, ident) != 0) {
853                 g_free(device->last_user_selection_ident);
854                 device->last_user_selection_ident = g_strdup(ident);
855
856                 return true;
857         }
858
859         return false;
860 }
861
862 const char *connman_device_get_last_user_selection_ident(struct connman_device *device)
863 {
864         return device->last_user_selection_ident;
865 }
866
867 bool connman_device_set_last_connected_ident(struct connman_device *device,
868                                                 const char *ident)
869 {
870         if (g_strcmp0(device->last_connected_ident, ident) != 0) {
871                 g_free(device->last_connected_ident);
872                 device->last_connected_ident = g_strdup(ident);
873
874                 return true;
875         }
876
877         return false;
878 }
879
880 const char *connman_device_get_last_connected_ident(struct connman_device *device)
881 {
882         return device->last_connected_ident;
883 }
884
885 void connman_device_save_last_user_selection(struct connman_device *device)
886 {
887         GKeyFile *keyfile;
888         gchar *get_str;
889         gchar *selection_str;
890
891         keyfile = __connman_storage_load_ins();
892
893         selection_str = g_strdup_printf("%s:%ld",
894                         device->last_user_selection_ident, device->last_user_selection_time);
895
896         if (!keyfile) {
897                 keyfile = g_key_file_new();
898
899                 g_key_file_set_string(keyfile, device->interface, "LastUserSelection", selection_str);
900                 DBG("%s", selection_str);
901                 __connman_storage_save_ins(keyfile);
902
903         } else {
904                 get_str = g_key_file_get_string(keyfile, device->interface, "LastUserSelection", NULL);
905                 if (!get_str || g_strcmp0(get_str, selection_str) != 0) {
906                         g_key_file_set_string(keyfile, device->interface, "LastUserSelection", selection_str);
907                         DBG("%s -> %s", get_str, selection_str);
908                         __connman_storage_save_ins(keyfile);
909                 }
910
911                 g_free(get_str);
912         }
913
914         g_free(selection_str);
915         g_key_file_free(keyfile);
916 }
917
918 void connman_device_load_last_user_selection(struct connman_device *device)
919 {
920         GKeyFile *keyfile;
921         gchar *get_str;
922         char **selection_str;
923
924         keyfile = __connman_storage_load_ins();
925         if (!keyfile)
926                 return;
927
928         get_str = g_key_file_get_string(keyfile, device->interface, "LastUserSelection", NULL);
929         if (get_str) {
930                 selection_str = g_strsplit(get_str, ":", 0);
931                 if (selection_str) {
932                         time_t ref_time;
933                         struct tm* timeinfo;
934                         time_t last_user_selection_time;
935
936                         /* Only events that occur within 8 hours are counted. */
937                         ref_time = time(NULL);
938                         timeinfo = localtime(&ref_time);
939                         timeinfo->tm_hour -= 8;
940                         ref_time = mktime(timeinfo);
941
942                         last_user_selection_time = strtol(selection_str[1], NULL, 10);
943
944                         if (last_user_selection_time > ref_time) {
945                                 if (g_strcmp0(selection_str[0], device->last_user_selection_ident) != 0) {
946                                         g_free(device->last_user_selection_ident);
947                                         device->last_user_selection_ident = g_strdup(selection_str[0]);
948                                 }
949
950                                 device->last_user_selection_time = last_user_selection_time;
951
952                                 DBG("%s %ld", device->last_user_selection_ident, device->last_user_selection_time);
953                         }
954
955                         g_strfreev(selection_str);
956                 }
957
958                 g_free(get_str);
959         }
960
961         g_key_file_free(keyfile);
962 }
963
964 void connman_device_save_last_connected(struct connman_device *device)
965 {
966         GKeyFile *keyfile;
967         gchar *get_str;
968
969         if (!device->last_connected_ident)
970                 return;
971
972         keyfile = __connman_storage_load_ins();
973
974         if (!keyfile) {
975                 keyfile = g_key_file_new();
976
977                 g_key_file_set_string(keyfile, device->interface, "LastConnected", device->last_connected_ident);
978                 DBG("%s", device->last_connected_ident);
979                 __connman_storage_save_ins(keyfile);
980
981         } else {
982                 get_str = g_key_file_get_string(keyfile, device->interface, "LastConnected", NULL);
983                 if (!get_str || g_strcmp0(get_str, device->last_connected_ident) != 0) {
984                         g_key_file_set_string(keyfile, device->interface, "LastConnected", device->last_connected_ident);
985                         DBG("%s -> %s", get_str, device->last_connected_ident);
986                         __connman_storage_save_ins(keyfile);
987                 }
988
989                 g_free(get_str);
990         }
991
992         g_key_file_free(keyfile);
993 }
994
995 void connman_device_load_last_connected(struct connman_device *device)
996 {
997         GKeyFile *keyfile;
998         gchar *get_str;
999
1000         keyfile = __connman_storage_load_ins();
1001         if (!keyfile)
1002                 return;
1003
1004         get_str = g_key_file_get_string(keyfile, device->interface, "LastConnected", NULL);
1005         if (get_str) {
1006                 if (g_strcmp0(get_str, device->last_connected_ident) != 0) {
1007                         g_free(device->last_connected_ident);
1008                         device->last_connected_ident = g_strdup(get_str);
1009                 }
1010
1011                 DBG("%s", device->last_connected_ident);
1012
1013                 g_free(get_str);
1014         }
1015
1016         g_key_file_free(keyfile);
1017 }
1018 #endif
1019
1020 static void mark_network_available(gpointer key, gpointer value,
1021                                                         gpointer user_data)
1022 {
1023         struct connman_network *network = value;
1024
1025         connman_network_set_available(network, true);
1026 }
1027
1028 static void mark_network_unavailable(gpointer key, gpointer value,
1029                                                         gpointer user_data)
1030 {
1031         struct connman_network *network = value;
1032
1033         if (connman_network_get_connected(network) ||
1034                         connman_network_get_connecting(network))
1035                 return;
1036
1037         connman_network_set_available(network, false);
1038 }
1039
1040 static gboolean remove_unavailable_network(gpointer key, gpointer value,
1041                                                         gpointer user_data)
1042 {
1043         struct connman_network *network = value;
1044
1045         if (connman_network_get_connected(network) ||
1046                         connman_network_get_connecting(network))
1047                 return FALSE;
1048
1049         if (connman_network_get_available(network))
1050                 return FALSE;
1051
1052         return TRUE;
1053 }
1054
1055 void __connman_device_cleanup_networks(struct connman_device *device)
1056 {
1057         g_hash_table_foreach_remove(device->networks,
1058                                         remove_unavailable_network, NULL);
1059 }
1060
1061 bool connman_device_get_scanning(struct connman_device *device,
1062                                 enum connman_service_type type)
1063 {
1064         int i;
1065
1066         if (type != CONNMAN_SERVICE_TYPE_UNKNOWN)
1067                 return device->scanning[type];
1068
1069         for (i = 0; i < MAX_CONNMAN_SERVICE_TYPES; i++)
1070                 if (device->scanning[i])
1071                         return true;
1072
1073         return false;
1074 }
1075
1076 void connman_device_reset_scanning(struct connman_device *device)
1077 {
1078         g_hash_table_foreach(device->networks,
1079                                 mark_network_available, NULL);
1080 }
1081
1082 /**
1083  * connman_device_set_scanning:
1084  * @device: device structure
1085  * @scanning: scanning state
1086  *
1087  * Change scanning state of device
1088  */
1089 int connman_device_set_scanning(struct connman_device *device,
1090                                 enum connman_service_type type, bool scanning)
1091 {
1092         DBG("device %p scanning %d", device, scanning);
1093
1094         if (!device->driver || !device->driver->scan)
1095                 return -EINVAL;
1096
1097         if (type == CONNMAN_SERVICE_TYPE_UNKNOWN)
1098                 return -EINVAL;
1099
1100         if (device->scanning[type] == scanning)
1101                 return -EALREADY;
1102
1103         device->scanning[type] = scanning;
1104
1105         if (scanning) {
1106                 __connman_technology_scan_started(device);
1107
1108                 g_hash_table_foreach(device->networks,
1109                                         mark_network_unavailable, NULL);
1110
1111                 return 0;
1112         }
1113
1114         __connman_device_cleanup_networks(device);
1115
1116         __connman_technology_scan_stopped(device, type);
1117
1118         __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
1119
1120 #if defined TIZEN_EXT_WIFI_MESH
1121         if (type == CONNMAN_SERVICE_TYPE_MESH)
1122                 __connman_mesh_auto_connect();
1123 #endif
1124
1125         return 0;
1126 }
1127
1128 /**
1129  * connman_device_set_string:
1130  * @device: device structure
1131  * @key: unique identifier
1132  * @value: string value
1133  *
1134  * Set string value for specific key
1135  */
1136 int connman_device_set_string(struct connman_device *device,
1137                                         const char *key, const char *value)
1138 {
1139         DBG("device %p key %s value %s", device, key, value);
1140
1141         if (g_str_equal(key, "Address")) {
1142 #ifdef TIZEN_EXT
1143                 if (device->address && device->powered)
1144                         return 0;
1145                 else
1146 #endif
1147                 g_free(device->address);
1148                 device->address = g_strdup(value);
1149         } else if (g_str_equal(key, "Name")) {
1150                 g_free(device->name);
1151                 device->name = g_strdup(value);
1152         } else if (g_str_equal(key, "Node")) {
1153                 g_free(device->node);
1154                 device->node = g_strdup(value);
1155         } else if (g_str_equal(key, "Path")) {
1156                 g_free(device->path);
1157                 device->path = g_strdup(value);
1158         } else {
1159                 return -EINVAL;
1160         }
1161
1162         return 0;
1163 }
1164
1165 /**
1166  * connman_device_get_string:
1167  * @device: device structure
1168  * @key: unique identifier
1169  *
1170  * Get string value for specific key
1171  */
1172 const char *connman_device_get_string(struct connman_device *device,
1173                                                         const char *key)
1174 {
1175 #if defined TIZEN_EXT
1176         if (!simplified_log)
1177 #endif
1178         DBG("device %p key %s", device, key);
1179
1180         if (g_str_equal(key, "Address"))
1181                 return device->address;
1182         else if (g_str_equal(key, "Name"))
1183                 return device->name;
1184         else if (g_str_equal(key, "Node"))
1185                 return device->node;
1186         else if (g_str_equal(key, "Interface"))
1187                 return device->interface;
1188         else if (g_str_equal(key, "Path"))
1189                 return device->path;
1190
1191         return NULL;
1192 }
1193
1194 /**
1195  * connman_device_add_network:
1196  * @device: device structure
1197  * @network: network structure
1198  *
1199  * Add new network to the device
1200  */
1201 int connman_device_add_network(struct connman_device *device,
1202                                         struct connman_network *network)
1203 {
1204         const char *identifier = connman_network_get_identifier(network);
1205 #if defined TIZEN_EXT
1206         if (!simplified_log)
1207 #endif
1208         DBG("device %p network %p", device, network);
1209
1210         if (!identifier)
1211                 return -EINVAL;
1212
1213         connman_network_ref(network);
1214
1215         __connman_network_set_device(network, device);
1216
1217         g_hash_table_replace(device->networks, g_strdup(identifier),
1218                                                                 network);
1219
1220         return 0;
1221 }
1222
1223 /**
1224  * connman_device_get_network:
1225  * @device: device structure
1226  * @identifier: network identifier
1227  *
1228  * Get network for given identifier
1229  */
1230 struct connman_network *connman_device_get_network(struct connman_device *device,
1231                                                         const char *identifier)
1232 {
1233 #if defined TIZEN_EXT
1234         if (!simplified_log)
1235 #endif
1236         DBG("device %p identifier %s", device, identifier);
1237
1238         return g_hash_table_lookup(device->networks, identifier);
1239 }
1240
1241 #if defined TIZEN_EXT
1242 struct connman_network *connman_device_get_default_network(
1243                                                         struct connman_device *device)
1244 {
1245         return device->network;
1246 }
1247
1248 void connman_device_set_pending_reply(struct connman_device *device,
1249                                                         DBusMessage *msg)
1250 {
1251         device->pending_reply_list = g_list_prepend(device->pending_reply_list, dbus_message_ref(msg));
1252 }
1253
1254 void connman_device_send_connected_signal(struct connman_device *device,
1255                                                         bool connected)
1256 {
1257         enum connman_service_type type;
1258
1259         if (!device)
1260                 return;
1261
1262         type = __connman_device_get_service_type(device);
1263         device_send_changed(device->interface, type, "Connected", connected);
1264 }
1265
1266 void connman_device_set_max_scan_ssids(struct connman_device *device,
1267                                                         int max_scan_ssids)
1268 {
1269         device->max_scan_ssids = max_scan_ssids;
1270 }
1271
1272 int connman_device_get_max_scan_ssids(struct connman_device *device)
1273 {
1274         return device->max_scan_ssids;
1275 }
1276
1277 void connman_device_set_wifi_5ghz_supported(struct connman_device *device,
1278                                                         bool is_5_0_ghz_supported)
1279 {
1280         device->is_5_0_ghz_supported = is_5_0_ghz_supported;
1281 }
1282
1283 bool connman_device_get_wifi_5ghz_supported(struct connman_device *device)
1284 {
1285         return device->is_5_0_ghz_supported;
1286 }
1287 #endif
1288
1289 /**
1290  * connman_device_remove_network:
1291  * @device: device structure
1292  * @identifier: network identifier
1293  *
1294  * Remove network for given identifier
1295  */
1296 int connman_device_remove_network(struct connman_device *device,
1297                                                 struct connman_network *network)
1298 {
1299         const char *identifier;
1300
1301         DBG("device %p network %p", device, network);
1302
1303         if (!network)
1304                 return 0;
1305
1306         identifier = connman_network_get_identifier(network);
1307         g_hash_table_remove(device->networks, identifier);
1308
1309         return 0;
1310 }
1311
1312 void __connman_device_set_network(struct connman_device *device,
1313                                         struct connman_network *network)
1314 {
1315         const char *name;
1316
1317         if (!device)
1318                 return;
1319
1320         if (device->network == network)
1321                 return;
1322
1323         if (network) {
1324                 name = connman_network_get_string(network, "Name");
1325                 g_free(device->last_network);
1326                 device->last_network = g_strdup(name);
1327
1328                 device->network = network;
1329         } else {
1330                 g_free(device->last_network);
1331                 device->last_network = NULL;
1332
1333                 device->network = NULL;
1334         }
1335 }
1336
1337 static bool match_driver(struct connman_device *device,
1338                                         struct connman_device_driver *driver)
1339 {
1340         if (device->type == driver->type ||
1341                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
1342                 return true;
1343
1344         return false;
1345 }
1346
1347 /**
1348  * connman_device_register:
1349  * @device: device structure
1350  *
1351  * Register device with the system
1352  */
1353 int connman_device_register(struct connman_device *device)
1354 {
1355         GSList *list;
1356
1357         DBG("device %p name %s", device, device->name);
1358
1359         if (device->driver)
1360                 return -EALREADY;
1361
1362         for (list = driver_list; list; list = list->next) {
1363                 struct connman_device_driver *driver = list->data;
1364
1365                 if (!match_driver(device, driver))
1366                         continue;
1367
1368                 DBG("driver %p name %s", driver, driver->name);
1369
1370                 if (driver->probe(device) == 0) {
1371                         device->driver = driver;
1372                         break;
1373                 }
1374         }
1375
1376         if (!device->driver)
1377                 return 0;
1378
1379         return __connman_technology_add_device(device);
1380 }
1381
1382 /**
1383  * connman_device_unregister:
1384  * @device: device structure
1385  *
1386  * Unregister device with the system
1387  */
1388 void connman_device_unregister(struct connman_device *device)
1389 {
1390         DBG("device %p name %s", device, device->name);
1391
1392         if (!device->driver)
1393                 return;
1394
1395         remove_device(device);
1396 }
1397
1398 /**
1399  * connman_device_get_data:
1400  * @device: device structure
1401  *
1402  * Get private device data pointer
1403  */
1404 void *connman_device_get_data(struct connman_device *device)
1405 {
1406         return device->driver_data;
1407 }
1408
1409 /**
1410  * connman_device_set_data:
1411  * @device: device structure
1412  * @data: data pointer
1413  *
1414  * Set private device data pointer
1415  */
1416 void connman_device_set_data(struct connman_device *device, void *data)
1417 {
1418         device->driver_data = data;
1419 }
1420
1421 struct connman_device *__connman_device_find_device(
1422                                 enum connman_service_type type)
1423 {
1424         GSList *list;
1425
1426         for (list = device_list; list; list = list->next) {
1427                 struct connman_device *device = list->data;
1428                 enum connman_service_type service_type =
1429                         __connman_device_get_service_type(device);
1430
1431                 if (service_type != type)
1432                         continue;
1433
1434                 return device;
1435         }
1436
1437         return NULL;
1438 }
1439
1440 struct connman_device *connman_device_find_by_index(int index)
1441 {
1442         GSList *list;
1443
1444         for (list = device_list; list; list = list->next) {
1445                 struct connman_device *device = list->data;
1446                 if (device->index == index)
1447                         return device;
1448         }
1449
1450         return NULL;
1451 }
1452
1453 /**
1454  * connman_device_set_regdom
1455  * @device: device structure
1456  * @alpha2: string representing regulatory domain
1457  *
1458  * Set regulatory domain on device basis
1459  */
1460 int connman_device_set_regdom(struct connman_device *device,
1461                                                 const char *alpha2)
1462 {
1463         if (!device->driver || !device->driver->set_regdom)
1464                 return -ENOTSUP;
1465
1466         if (!device->powered)
1467                 return -EINVAL;
1468
1469         return device->driver->set_regdom(device, alpha2);
1470 }
1471
1472 /**
1473  * connman_device_regdom_notify
1474  * @device: device structure
1475  * @alpha2: string representing regulatory domain
1476  *
1477  * Notify on setting regulatory domain on device basis
1478  */
1479 void connman_device_regdom_notify(struct connman_device *device,
1480                                         int result, const char *alpha2)
1481 {
1482         __connman_technology_notify_regdom_by_device(device, result, alpha2);
1483 }
1484
1485 #if defined TIZEN_EXT
1486 static int device_specific_scan(enum connman_service_type type,
1487                                 struct connman_device *device,
1488                                 int scan_type, GSList *specific_scan_list)
1489 {
1490         if (!device->driver || !device->driver->specific_scan)
1491                 return -EOPNOTSUPP;
1492
1493         if (!device->powered)
1494                 return -ENOLINK;
1495
1496         return device->driver->specific_scan(type, device, scan_type,
1497                         specific_scan_list, NULL);
1498 }
1499
1500 int __connman_device_request_specific_scan(enum connman_service_type type,
1501                                 const char *ifname, int scan_type, GSList *specific_scan_list)
1502 {
1503         bool success = false;
1504         int last_err = -ENOSYS;
1505         GSList *list;
1506         int err;
1507
1508         switch (type) {
1509         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1510         case CONNMAN_SERVICE_TYPE_SYSTEM:
1511         case CONNMAN_SERVICE_TYPE_ETHERNET:
1512         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1513         case CONNMAN_SERVICE_TYPE_CELLULAR:
1514         case CONNMAN_SERVICE_TYPE_GPS:
1515         case CONNMAN_SERVICE_TYPE_VPN:
1516         case CONNMAN_SERVICE_TYPE_GADGET:
1517                 return -EOPNOTSUPP;
1518         case CONNMAN_SERVICE_TYPE_WIFI:
1519         case CONNMAN_SERVICE_TYPE_P2P:
1520 #if defined TIZEN_EXT_WIFI_MESH
1521         case CONNMAN_SERVICE_TYPE_MESH:
1522 #endif
1523                 break;
1524         }
1525
1526         for (list = device_list; list; list = list->next) {
1527                 struct connman_device *device = list->data;
1528                 enum connman_service_type service_type =
1529                         __connman_device_get_service_type(device);
1530
1531                 if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN) {
1532                         if (type == CONNMAN_SERVICE_TYPE_P2P) {
1533                                 if (service_type != CONNMAN_SERVICE_TYPE_WIFI)
1534                                         continue;
1535                         } else if (service_type != type)
1536                                 continue;
1537                 }
1538
1539                 if (ifname && g_strcmp0(device->interface, ifname) != 0)
1540                         continue;
1541
1542                 err = device_specific_scan(type, device, scan_type, specific_scan_list);
1543                 if (err == 0 || err == -EINPROGRESS) {
1544                         success = true;
1545                 } else {
1546                         last_err = err;
1547                         DBG("device %p err %d", device, err);
1548                 }
1549         }
1550
1551         if (success)
1552                 return 0;
1553
1554         return last_err;
1555 }
1556
1557 int connman_device_request_device_scan(enum connman_service_type type,
1558                                 const char * ifname, bool force_full_scan)
1559 {
1560         bool success = false;
1561         int last_err = -ENOSYS;
1562         GSList *list;
1563         int err;
1564
1565         switch (type) {
1566         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1567         case CONNMAN_SERVICE_TYPE_SYSTEM:
1568         case CONNMAN_SERVICE_TYPE_ETHERNET:
1569         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1570         case CONNMAN_SERVICE_TYPE_CELLULAR:
1571         case CONNMAN_SERVICE_TYPE_GPS:
1572         case CONNMAN_SERVICE_TYPE_VPN:
1573         case CONNMAN_SERVICE_TYPE_GADGET:
1574                 return -EOPNOTSUPP;
1575         case CONNMAN_SERVICE_TYPE_WIFI:
1576         case CONNMAN_SERVICE_TYPE_P2P:
1577 #if defined TIZEN_EXT_WIFI_MESH
1578         case CONNMAN_SERVICE_TYPE_MESH:
1579 #endif
1580                 break;
1581         }
1582
1583         for (list = device_list; list; list = list->next) {
1584                 struct connman_device *device = list->data;
1585
1586                 if (!device_has_service_type(device, type))
1587                         continue;
1588
1589                 if (g_strcmp0(device->interface, ifname) != 0)
1590                         continue;
1591
1592                 err = device_scan(type, device, force_full_scan);
1593
1594                 if (err == 0 || err == -EINPROGRESS) {
1595                         success = true;
1596                 } else {
1597                         last_err = err;
1598                         DBG("device %p err %d", device, err);
1599                 }
1600                 break;
1601         }
1602
1603         if (success)
1604                 return 0;
1605
1606         return last_err;
1607 }
1608
1609 #if defined TIZEN_EXT_WIFI_MESH
1610 static int device_abort_scan(enum connman_service_type type,
1611                                 struct connman_device *device)
1612 {
1613         if (!device->driver || !device->driver->scan)
1614                 return -EOPNOTSUPP;
1615
1616         if (!device->powered)
1617                 return -ENOLINK;
1618
1619         return device->driver->abort_scan(type, device);
1620 }
1621
1622 int __connman_device_abort_scan(enum connman_service_type type)
1623 {
1624         GSList *list;
1625         int err = -EINVAL;
1626
1627         if (type != CONNMAN_SERVICE_TYPE_MESH)
1628                 return -EINVAL;
1629
1630         for (list = device_list; list; list = list->next) {
1631                 struct connman_device *device = list->data;
1632                 enum connman_service_type service_type =
1633                         __connman_device_get_service_type(device);
1634
1635                 if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN) {
1636                         if (type == CONNMAN_SERVICE_TYPE_MESH)
1637                                 if (service_type != CONNMAN_SERVICE_TYPE_WIFI)
1638                                         continue;
1639
1640                         if (!device->scanning) {
1641                                 err = -EEXIST;
1642                                 continue;
1643                         }
1644
1645                         err = device_abort_scan(type, device);
1646                 }
1647         }
1648         return err;
1649 }
1650
1651 static int device_mesh_specific_scan(enum connman_service_type type,
1652                                 struct connman_device *device, const char *name,
1653                                 unsigned int freq)
1654 {
1655         if (!device->driver || !device->driver->mesh_specific_scan)
1656                 return -EOPNOTSUPP;
1657
1658         if (!device->powered)
1659                 return -ENOLINK;
1660
1661         return device->driver->mesh_specific_scan(type, device, name, freq, NULL);
1662 }
1663
1664 int __connman_device_request_mesh_specific_scan(enum connman_service_type type,
1665                                                 const char *name,
1666                                                 unsigned int freq)
1667 {
1668         bool success = false;
1669         int last_err = -ENOSYS;
1670         GSList *list;
1671         int err;
1672
1673         if (type != CONNMAN_SERVICE_TYPE_MESH)
1674                 return -EINVAL;
1675
1676         for (list = device_list; list; list = list->next) {
1677                 struct connman_device *device = list->data;
1678                 enum connman_service_type service_type =
1679                         __connman_device_get_service_type(device);
1680
1681                 if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN) {
1682                         if (type == CONNMAN_SERVICE_TYPE_MESH)
1683                                 if (service_type != CONNMAN_SERVICE_TYPE_WIFI)
1684                                         continue;
1685                 }
1686
1687                 err = device_mesh_specific_scan(type, device, name, freq);
1688                 if (err == 0 || err == -EALREADY || err == -EINPROGRESS) {
1689                         success = true;
1690                 } else {
1691                         last_err = err;
1692                         DBG("device %p err %d", device, err);
1693                 }
1694         }
1695
1696         if (success)
1697                 return 0;
1698
1699         return last_err;
1700 }
1701 #endif /* TIZEN_EXT_WIFI_MESH */
1702 #endif
1703
1704 static int connman_device_request_scan(enum connman_service_type type,
1705                                         bool force_full_scan)
1706 {
1707         bool success = false;
1708         int last_err = -ENOSYS;
1709         GSList *list;
1710         int err;
1711
1712         switch (type) {
1713         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1714         case CONNMAN_SERVICE_TYPE_SYSTEM:
1715         case CONNMAN_SERVICE_TYPE_ETHERNET:
1716         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1717         case CONNMAN_SERVICE_TYPE_CELLULAR:
1718         case CONNMAN_SERVICE_TYPE_GPS:
1719         case CONNMAN_SERVICE_TYPE_VPN:
1720         case CONNMAN_SERVICE_TYPE_GADGET:
1721                 return -EOPNOTSUPP;
1722         case CONNMAN_SERVICE_TYPE_WIFI:
1723         case CONNMAN_SERVICE_TYPE_P2P:
1724 #if defined TIZEN_EXT_WIFI_MESH
1725         case CONNMAN_SERVICE_TYPE_MESH:
1726 #endif
1727                 break;
1728         }
1729
1730         for (list = device_list; list; list = list->next) {
1731                 struct connman_device *device = list->data;
1732
1733                 if (!device_has_service_type(device, type))
1734                         continue;
1735
1736                 err = device_scan(type, device, force_full_scan);
1737 #if defined TIZEN_EXT
1738                 /* When Scan is already in progress then return Error so that
1739                  * wifi-manager can block the scan-done signal to be sent to
1740                  * application and start requested scan after scan already in progress
1741                  * is completed then notify to application about the scan event */
1742                 if (err == 0 || err == -EINPROGRESS) {
1743 #else
1744                 if (err == 0 || err == -EALREADY || err == -EINPROGRESS) {
1745 #endif
1746                         success = true;
1747                 } else {
1748                         last_err = err;
1749                         DBG("device %p err %d", device, err);
1750                 }
1751         }
1752
1753         if (success)
1754                 return 0;
1755
1756         return last_err;
1757 }
1758
1759 int __connman_device_request_scan(enum connman_service_type type)
1760 {
1761         return connman_device_request_scan(type, false);
1762 }
1763
1764 int __connman_device_request_scan_full(enum connman_service_type type)
1765 {
1766         return connman_device_request_scan(type, true);
1767 }
1768
1769 int __connman_device_request_hidden_scan(struct connman_device *device,
1770                                 const char *ssid, unsigned int ssid_len,
1771                                 const char *identity, const char *passphrase,
1772                                 const char *security, void *user_data)
1773 {
1774         struct connman_device_scan_params params;
1775
1776         DBG("device %p", device);
1777
1778         if (!device || !device->driver ||
1779                         !device->driver->scan)
1780                 return -EINVAL;
1781
1782         params.type = CONNMAN_SERVICE_TYPE_UNKNOWN;
1783         params.ssid = ssid;
1784         params.ssid_len = ssid_len;
1785         params.identity = identity;
1786         params.passphrase = passphrase;
1787         params.security = security;
1788         params.user_data = user_data;
1789
1790         return device->driver->scan(device, &params);
1791 }
1792
1793 void __connman_device_stop_scan(enum connman_service_type type)
1794 {
1795         GSList *list;
1796
1797         for (list = device_list; list; list = list->next) {
1798                 struct connman_device *device = list->data;
1799
1800                 if (!device_has_service_type(device, type))
1801                         continue;
1802
1803                 if (device->driver && device->driver->stop_scan)
1804                         device->driver->stop_scan(type, device);
1805         }
1806 }
1807
1808 #if defined TIZEN_EXT
1809 #define WIFI_MAC "/opt/etc/.mac.info"
1810 #define MAC_ADDR_LEN 18
1811
1812 char *_get_wifi_addr(void)
1813 {
1814         FILE *fp = NULL;
1815         char* rv = 0;
1816         char wifi_mac[MAC_ADDR_LEN + 1];
1817         char *str;
1818
1819         fp = fopen(WIFI_MAC, "r");
1820         if (!fp){
1821                 connman_error("[%s] not present", WIFI_MAC);
1822                 return NULL;
1823         }
1824
1825         rv = fgets(wifi_mac, MAC_ADDR_LEN, fp);
1826         if (!rv) {
1827                 connman_error("Failed to get wifi mac address");
1828                 fclose(fp);
1829                 return NULL;
1830         }
1831
1832         str = g_try_malloc0(MAC_ADDR_LEN);
1833         if (!str) {
1834                 connman_error("memory allocation failed");
1835                 fclose(fp);
1836                 return NULL;
1837         }
1838
1839         snprintf(str, MAC_ADDR_LEN, "%c%c:%c%c:%c%c:%c%c:%c%c:%c%c",
1840                         g_ascii_tolower(wifi_mac[0]), g_ascii_tolower(wifi_mac[1]),
1841                         g_ascii_tolower(wifi_mac[3]), g_ascii_tolower(wifi_mac[4]),
1842                         g_ascii_tolower(wifi_mac[6]), g_ascii_tolower(wifi_mac[7]),
1843                         g_ascii_tolower(wifi_mac[9]), g_ascii_tolower(wifi_mac[10]),
1844                         g_ascii_tolower(wifi_mac[12]), g_ascii_tolower(wifi_mac[13]),
1845                         g_ascii_tolower(wifi_mac[15]), g_ascii_tolower(wifi_mac[16]));
1846         fclose(fp);
1847         return str;
1848 }
1849
1850 char *_get_wifi_ident(void)
1851 {
1852         FILE *fp = NULL;
1853         char* rv = 0;
1854         char wifi_mac[MAC_ADDR_LEN + 1];
1855         char *str;
1856
1857         fp = fopen(WIFI_MAC, "r");
1858         if (!fp){
1859                 connman_error("[%s] not present", WIFI_MAC);
1860                 return NULL;
1861         }
1862
1863         rv = fgets(wifi_mac, MAC_ADDR_LEN, fp);
1864         if (!rv) {
1865                 connman_error("Failed to get wifi mac address");
1866                 fclose(fp);
1867                 return NULL;
1868         }
1869
1870         str = g_try_malloc0(MAC_ADDR_LEN);
1871         if (!str) {
1872                 connman_error("memory allocation failed");
1873                 fclose(fp);
1874                 return NULL;
1875         }
1876
1877         snprintf(str, MAC_ADDR_LEN, "%c%c%c%c%c%c%c%c%c%c%c%c",
1878                         g_ascii_tolower(wifi_mac[0]), g_ascii_tolower(wifi_mac[1]),
1879                         g_ascii_tolower(wifi_mac[3]), g_ascii_tolower(wifi_mac[4]),
1880                         g_ascii_tolower(wifi_mac[6]), g_ascii_tolower(wifi_mac[7]),
1881                         g_ascii_tolower(wifi_mac[9]), g_ascii_tolower(wifi_mac[10]),
1882                         g_ascii_tolower(wifi_mac[12]), g_ascii_tolower(wifi_mac[13]),
1883                         g_ascii_tolower(wifi_mac[15]), g_ascii_tolower(wifi_mac[16]));
1884         fclose(fp);
1885         return str;
1886 }
1887 #endif
1888
1889 #if defined TIZEN_EXT
1890 char *index2ident(int index, const char *prefix)
1891 #else
1892 static char *index2ident(int index, const char *prefix)
1893 #endif
1894 {
1895         struct ifreq ifr;
1896         struct ether_addr eth;
1897         char *str;
1898         int sk, err, len;
1899
1900         if (index < 0)
1901                 return NULL;
1902
1903         sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
1904         if (sk < 0)
1905                 return NULL;
1906
1907         memset(&ifr, 0, sizeof(ifr));
1908         ifr.ifr_ifindex = index;
1909
1910         err = ioctl(sk, SIOCGIFNAME, &ifr);
1911
1912         if (err == 0)
1913                 err = ioctl(sk, SIOCGIFHWADDR, &ifr);
1914
1915         close(sk);
1916
1917         if (err < 0)
1918                 return NULL;
1919
1920         len = prefix ? strlen(prefix) + 18 : 18;
1921
1922         str = g_malloc(len);
1923         if (!str)
1924                 return NULL;
1925
1926         memcpy(&eth, &ifr.ifr_hwaddr.sa_data, sizeof(eth));
1927         snprintf(str, len, "%s%02x%02x%02x%02x%02x%02x",
1928                                                 prefix ? prefix : "",
1929                                                 eth.ether_addr_octet[0],
1930                                                 eth.ether_addr_octet[1],
1931                                                 eth.ether_addr_octet[2],
1932                                                 eth.ether_addr_octet[3],
1933                                                 eth.ether_addr_octet[4],
1934                                                 eth.ether_addr_octet[5]);
1935
1936         return str;
1937 }
1938
1939 #if defined TIZEN_EXT
1940 char *index2addr(int index)
1941 #else
1942 static char *index2addr(int index)
1943 #endif
1944 {
1945         struct ifreq ifr;
1946         struct ether_addr eth;
1947         char *str;
1948         int sk, err;
1949
1950         if (index < 0)
1951                 return NULL;
1952
1953         sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
1954         if (sk < 0)
1955                 return NULL;
1956
1957         memset(&ifr, 0, sizeof(ifr));
1958         ifr.ifr_ifindex = index;
1959
1960         err = ioctl(sk, SIOCGIFNAME, &ifr);
1961
1962         if (err == 0)
1963                 err = ioctl(sk, SIOCGIFHWADDR, &ifr);
1964
1965         close(sk);
1966
1967         if (err < 0)
1968                 return NULL;
1969
1970         str = g_malloc(18);
1971         if (!str)
1972                 return NULL;
1973
1974         memcpy(&eth, &ifr.ifr_hwaddr.sa_data, sizeof(eth));
1975         snprintf(str, 18, "%02X:%02X:%02X:%02X:%02X:%02X",
1976                                                 eth.ether_addr_octet[0],
1977                                                 eth.ether_addr_octet[1],
1978                                                 eth.ether_addr_octet[2],
1979                                                 eth.ether_addr_octet[3],
1980                                                 eth.ether_addr_octet[4],
1981                                                 eth.ether_addr_octet[5]);
1982
1983         return str;
1984 }
1985
1986 struct connman_device *connman_device_create_from_index(int index)
1987 {
1988         enum connman_device_type type;
1989         struct connman_device *device;
1990         char *devname, *ident = NULL;
1991         char *addr = NULL, *name = NULL;
1992
1993         if (index < 0)
1994                 return NULL;
1995
1996         devname = connman_inet_ifname(index);
1997         if (!devname)
1998                 return NULL;
1999
2000         if (__connman_device_isfiltered(devname)) {
2001                 connman_info("Ignoring interface %s (filtered)", devname);
2002                 g_free(devname);
2003                 return NULL;
2004         }
2005
2006         type = __connman_rtnl_get_device_type(index);
2007
2008         switch (type) {
2009         case CONNMAN_DEVICE_TYPE_UNKNOWN:
2010                 connman_info("Ignoring interface %s (type unknown)", devname);
2011                 g_free(devname);
2012                 return NULL;
2013         case CONNMAN_DEVICE_TYPE_ETHERNET:
2014         case CONNMAN_DEVICE_TYPE_GADGET:
2015         case CONNMAN_DEVICE_TYPE_WIFI:
2016                 name = index2ident(index, "");
2017                 addr = index2addr(index);
2018                 break;
2019         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
2020         case CONNMAN_DEVICE_TYPE_CELLULAR:
2021         case CONNMAN_DEVICE_TYPE_GPS:
2022         case CONNMAN_DEVICE_TYPE_VENDOR:
2023                 name = g_strdup(devname);
2024                 break;
2025         }
2026
2027         device = connman_device_create(name, type);
2028         if (!device)
2029                 goto done;
2030
2031         switch (type) {
2032         case CONNMAN_DEVICE_TYPE_UNKNOWN:
2033         case CONNMAN_DEVICE_TYPE_VENDOR:
2034         case CONNMAN_DEVICE_TYPE_GPS:
2035                 break;
2036         case CONNMAN_DEVICE_TYPE_ETHERNET:
2037         case CONNMAN_DEVICE_TYPE_GADGET:
2038                 ident = index2ident(index, NULL);
2039                 break;
2040         case CONNMAN_DEVICE_TYPE_WIFI:
2041                 ident = index2ident(index, NULL);
2042                 break;
2043         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
2044                 break;
2045         case CONNMAN_DEVICE_TYPE_CELLULAR:
2046                 ident = index2ident(index, NULL);
2047                 break;
2048         }
2049
2050         connman_device_set_index(device, index);
2051         connman_device_set_interface(device, devname);
2052 #if defined TIZEN_EXT
2053         connman_device_load_last_connected(device);
2054         connman_device_load_last_user_selection(device);
2055 #endif
2056
2057         if (ident) {
2058                 connman_device_set_ident(device, ident);
2059                 g_free(ident);
2060         }
2061
2062         connman_device_set_string(device, "Address", addr);
2063
2064 done:
2065         g_free(devname);
2066         g_free(name);
2067         g_free(addr);
2068
2069         return device;
2070 }
2071
2072 bool __connman_device_isfiltered(const char *devname)
2073 {
2074         char **pattern;
2075         char **blacklisted_interfaces;
2076         bool match;
2077
2078         if (!device_filter)
2079                 goto nodevice;
2080
2081         for (pattern = device_filter, match = false; *pattern; pattern++) {
2082                 if (g_pattern_match_simple(*pattern, devname)) {
2083                         match = true;
2084                         break;
2085                 }
2086         }
2087
2088         if (!match) {
2089                 DBG("ignoring device %s (match)", devname);
2090                 return true;
2091         }
2092
2093 nodevice:
2094         if (g_pattern_match_simple("dummy*", devname)) {
2095                 DBG("ignoring dummy networking devices");
2096                 return true;
2097         }
2098
2099         if (!nodevice_filter)
2100                 goto list;
2101
2102         for (pattern = nodevice_filter; *pattern; pattern++) {
2103                 if (g_pattern_match_simple(*pattern, devname)) {
2104                         DBG("ignoring device %s (no match)", devname);
2105                         return true;
2106                 }
2107         }
2108
2109 list:
2110         if (__connman_inet_isrootnfs_device(devname)) {
2111                 DBG("ignoring device %s (rootnfs)", devname);
2112                 return true;
2113         }
2114
2115         blacklisted_interfaces =
2116                 connman_setting_get_string_list("NetworkInterfaceBlacklist");
2117         if (!blacklisted_interfaces)
2118                 return false;
2119
2120         for (pattern = blacklisted_interfaces; *pattern; pattern++) {
2121                 if (g_str_has_prefix(devname, *pattern)) {
2122                         DBG("ignoring device %s (blacklist)", devname);
2123                         return true;
2124                 }
2125         }
2126
2127         return false;
2128 }
2129
2130 static void cleanup_devices(void)
2131 {
2132         /*
2133          * Check what interfaces are currently up and if connman is
2134          * suppose to handle the interface, then cleanup the mess
2135          * related to that interface. There might be weird routes etc
2136          * that are related to that interface and that might confuse
2137          * connmand. So in this case we just turn the interface down
2138          * so that kernel removes routes/addresses automatically and
2139          * then proceed the startup.
2140          *
2141          * Note that this cleanup must be done before rtnl/detect code
2142          * has activated interface watches.
2143          */
2144
2145         char **interfaces;
2146         int i;
2147
2148         interfaces = __connman_inet_get_running_interfaces();
2149
2150         if (!interfaces)
2151                 return;
2152
2153         for (i = 0; interfaces[i]; i++) {
2154                 bool filtered;
2155                 int index;
2156                 struct sockaddr_in sin_addr, sin_mask;
2157
2158                 filtered = __connman_device_isfiltered(interfaces[i]);
2159                 if (filtered)
2160                         continue;
2161
2162                 index = connman_inet_ifindex(interfaces[i]);
2163                 if (index < 0)
2164                         continue;
2165
2166                 if (!__connman_inet_get_address_netmask(index, &sin_addr,
2167                                                         &sin_mask)) {
2168                         char *address = g_strdup(inet_ntoa(sin_addr.sin_addr));
2169                         char *netmask = g_strdup(inet_ntoa(sin_mask.sin_addr));
2170
2171                         if (__connman_config_address_provisioned(address,
2172                                                                 netmask)) {
2173                                 DBG("Skip %s which is already provisioned "
2174                                         "with %s/%s", interfaces[i], address,
2175                                         netmask);
2176                                 g_free(address);
2177                                 g_free(netmask);
2178                                 continue;
2179                         }
2180
2181                         g_free(address);
2182                         g_free(netmask);
2183                 }
2184
2185                 DBG("cleaning up %s index %d", interfaces[i], index);
2186
2187 #if defined TIZEN_EXT
2188                 if (strcmp(interfaces[i], "wlan0") != 0)
2189 #endif
2190                 connman_inet_ifdown(index);
2191
2192                 /*
2193                  * ConnMan will turn the interface UP automatically so
2194                  * no need to do it here.
2195                  */
2196         }
2197
2198         g_strfreev(interfaces);
2199 }
2200
2201 int __connman_device_init(const char *device, const char *nodevice)
2202 {
2203         DBG("");
2204
2205 #if defined TIZEN_EXT
2206         connection = connman_dbus_get_connection();
2207 #endif
2208
2209         if (device)
2210                 device_filter = g_strsplit(device, ",", -1);
2211
2212         if (nodevice)
2213                 nodevice_filter = g_strsplit(nodevice, ",", -1);
2214
2215         cleanup_devices();
2216
2217         return 0;
2218 }
2219
2220 void __connman_device_cleanup(void)
2221 {
2222         DBG("");
2223
2224         g_strfreev(nodevice_filter);
2225         g_strfreev(device_filter);
2226
2227 #if defined TIZEN_EXT
2228         dbus_connection_unref(connection);
2229 #endif
2230 }
2231
2232 #ifdef TIZEN_EXT
2233 void connman_device_mac_policy_notify(struct connman_device *device,
2234                                         int result, unsigned int policy)
2235 {
2236         device->mac_policy = policy;
2237         __connman_technology_notify_mac_policy_by_device(device, result, policy);
2238 }
2239
2240 int connman_device_set_mac_policy(struct connman_device *device,
2241                                         unsigned int policy)
2242 {
2243         int err = 0;
2244
2245         if (!device || !device->driver || !device->driver->set_mac_policy)
2246                 return -EOPNOTSUPP;
2247
2248         device->mac_policy = policy;
2249         err = device->driver->set_mac_policy(device, policy);
2250         return err;
2251 }
2252
2253 unsigned int connman_device_get_mac_policy(struct connman_device *device)
2254 {
2255         return device->mac_policy;
2256 }
2257
2258 void connman_device_preassoc_mac_policy_notify(struct connman_device *device,
2259                                         int result, unsigned int policy)
2260 {
2261         device->preassoc_mac_policy = policy;
2262         __connman_technology_notify_preassoc_mac_policy_by_device(device, result, policy);
2263 }
2264
2265 int connman_device_set_preassoc_mac_policy(struct connman_device *device,
2266                                         unsigned int policy)
2267 {
2268         int err = 0;
2269
2270         if (!device || !device->driver || !device->driver->set_preassoc_mac_policy)
2271                 return -EOPNOTSUPP;
2272
2273         device->preassoc_mac_policy = policy;
2274         err = device->driver->set_preassoc_mac_policy(device, policy);
2275         return err;
2276 }
2277
2278 unsigned int connman_device_get_preassoc_mac_policy(struct connman_device *device)
2279 {
2280         return device->preassoc_mac_policy;
2281 }
2282
2283 void connman_device_random_mac_lifetime_notify(struct connman_device *device,
2284                                         int result, unsigned int lifetime)
2285 {
2286         device->random_mac_lifetime = lifetime;
2287         __connman_technology_notify_random_mac_lifetime_by_device(device, result, lifetime);
2288 }
2289
2290 int connman_device_set_random_mac_lifetime(struct connman_device *device,
2291                                         unsigned int lifetime)
2292 {
2293         int err = 0;
2294
2295         if (!device || !device->driver || !device->driver->set_random_mac_lifetime)
2296                 return -EOPNOTSUPP;
2297
2298         device->random_mac_lifetime = lifetime;
2299         err = device->driver->set_random_mac_lifetime(device, lifetime);
2300         return err;
2301 }
2302
2303 unsigned int connman_device_get_random_mac_lifetime(struct connman_device *device)
2304 {
2305         return device->random_mac_lifetime;
2306 }
2307
2308 #endif