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