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