Merge "Modified logic to process each VSIE of all vendors." 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 enum connman_pending_type {
42         PENDING_NONE    = 0,
43         PENDING_ENABLE  = 1,
44         PENDING_DISABLE = 2,
45 };
46
47 struct connman_device {
48         int refcount;
49         enum connman_device_type type;
50         enum connman_pending_type powered_pending;      /* Indicates a pending
51                                                          * enable/disable
52                                                          * request
53                                                          */
54         bool powered;
55         bool scanning;
56         bool disconnected;
57         char *name;
58         char *node;
59         char *address;
60         char *interface;
61         char *ident;
62         char *path;
63         int index;
64         guint pending_timeout;
65
66         struct connman_device_driver *driver;
67         void *driver_data;
68
69         char *last_network;
70         struct connman_network *network;
71         GHashTable *networks;
72 };
73
74 static void clear_pending_trigger(struct connman_device *device)
75 {
76         if (device->pending_timeout > 0) {
77                 g_source_remove(device->pending_timeout);
78                 device->pending_timeout = 0;
79         }
80 }
81
82 static const char *type2description(enum connman_device_type type)
83 {
84         switch (type) {
85         case CONNMAN_DEVICE_TYPE_UNKNOWN:
86         case CONNMAN_DEVICE_TYPE_VENDOR:
87                 break;
88         case CONNMAN_DEVICE_TYPE_ETHERNET:
89                 return "Ethernet";
90         case CONNMAN_DEVICE_TYPE_WIFI:
91                 return "Wireless";
92         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
93                 return "Bluetooth";
94         case CONNMAN_DEVICE_TYPE_GPS:
95                 return "GPS";
96         case CONNMAN_DEVICE_TYPE_CELLULAR:
97                 return "Cellular";
98         case CONNMAN_DEVICE_TYPE_GADGET:
99                 return "Gadget";
100
101         }
102
103         return NULL;
104 }
105
106 static const char *type2string(enum connman_device_type type)
107 {
108         switch (type) {
109         case CONNMAN_DEVICE_TYPE_UNKNOWN:
110         case CONNMAN_DEVICE_TYPE_VENDOR:
111                 break;
112         case CONNMAN_DEVICE_TYPE_ETHERNET:
113                 return "ethernet";
114         case CONNMAN_DEVICE_TYPE_WIFI:
115                 return "wifi";
116         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
117                 return "bluetooth";
118         case CONNMAN_DEVICE_TYPE_GPS:
119                 return "gps";
120         case CONNMAN_DEVICE_TYPE_CELLULAR:
121                 return "cellular";
122         case CONNMAN_DEVICE_TYPE_GADGET:
123                 return "gadget";
124
125         }
126
127         return NULL;
128 }
129
130 enum connman_service_type __connman_device_get_service_type(
131                                 struct connman_device *device)
132 {
133         enum connman_device_type type = connman_device_get_type(device);
134
135         switch (type) {
136         case CONNMAN_DEVICE_TYPE_UNKNOWN:
137         case CONNMAN_DEVICE_TYPE_VENDOR:
138         case CONNMAN_DEVICE_TYPE_GPS:
139                 break;
140         case CONNMAN_DEVICE_TYPE_ETHERNET:
141                 return CONNMAN_SERVICE_TYPE_ETHERNET;
142         case CONNMAN_DEVICE_TYPE_WIFI:
143                 return CONNMAN_SERVICE_TYPE_WIFI;
144         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
145                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
146         case CONNMAN_DEVICE_TYPE_CELLULAR:
147                 return CONNMAN_SERVICE_TYPE_CELLULAR;
148         case CONNMAN_DEVICE_TYPE_GADGET:
149                 return CONNMAN_SERVICE_TYPE_GADGET;
150
151         }
152
153         return CONNMAN_SERVICE_TYPE_UNKNOWN;
154 }
155
156 static gboolean device_pending_reset(gpointer user_data)
157 {
158         struct connman_device *device = user_data;
159
160         DBG("device %p", device);
161
162         /* Power request timedout, reset power pending state. */
163         device->pending_timeout = 0;
164         device->powered_pending = PENDING_NONE;
165
166         return FALSE;
167 }
168
169 int __connman_device_enable(struct connman_device *device)
170 {
171         int err;
172
173         DBG("device %p", device);
174
175         if (!device->driver || !device->driver->enable)
176                 return -EOPNOTSUPP;
177
178         /* There is an ongoing power disable request. */
179         if (device->powered_pending == PENDING_DISABLE)
180                 return -EBUSY;
181
182         if (device->powered_pending == PENDING_ENABLE)
183                 return -EALREADY;
184
185         if (device->powered_pending == PENDING_NONE && device->powered)
186                 return -EALREADY;
187
188         if (device->index > 0) {
189                 err = connman_inet_ifup(device->index);
190                 if (err < 0 && err != -EALREADY)
191                         return err;
192         }
193
194         device->powered_pending = PENDING_ENABLE;
195
196         err = device->driver->enable(device);
197         /*
198          * device gets enabled right away.
199          * Invoke the callback
200          */
201         if (err == 0) {
202                 connman_device_set_powered(device, true);
203                 goto done;
204         }
205
206         if (err == -EALREADY) {
207                 /* If device is already powered, but connman is not updated */
208                 connman_device_set_powered(device, true);
209                 goto done;
210         }
211         /*
212          * if err == -EINPROGRESS, then the DBus call to the respective daemon
213          * was successful. We set a 4 sec timeout so if the daemon never
214          * returns a reply, we would reset the pending request.
215          */
216         if (err == -EINPROGRESS)
217                 device->pending_timeout = g_timeout_add_seconds(4,
218                                         device_pending_reset, device);
219 done:
220         return err;
221 }
222
223 int __connman_device_disable(struct connman_device *device)
224 {
225         int err;
226
227         DBG("device %p", device);
228
229         /* Ongoing power enable request */
230         if (device->powered_pending == PENDING_ENABLE)
231                 return -EBUSY;
232
233         if (device->powered_pending == PENDING_DISABLE)
234                 return -EALREADY;
235
236         if (device->powered_pending == PENDING_NONE && !device->powered)
237                 return -EALREADY;
238
239         device->powered_pending = PENDING_DISABLE;
240
241         if (device->network) {
242                 struct connman_service *service =
243                         connman_service_lookup_from_network(device->network);
244
245                 if (service)
246                         __connman_service_disconnect(service);
247                 else
248                         connman_network_set_connected(device->network, false);
249         }
250
251         if (!device->driver || !device->driver->disable)
252                 return -EOPNOTSUPP;
253
254         err = device->driver->disable(device);
255         if (err == 0 || err == -EALREADY) {
256                 connman_device_set_powered(device, false);
257                 goto done;
258         }
259
260         if (err == -EINPROGRESS)
261                 device->pending_timeout = g_timeout_add_seconds(4,
262                                         device_pending_reset, device);
263 done:
264         return err;
265 }
266
267 static void probe_driver(struct connman_device_driver *driver)
268 {
269         GSList *list;
270
271         DBG("driver %p name %s", driver, driver->name);
272
273         for (list = device_list; list; list = list->next) {
274                 struct connman_device *device = list->data;
275
276                 if (device->driver)
277                         continue;
278
279                 if (driver->type != device->type)
280                         continue;
281
282                 if (driver->probe(device) < 0)
283                         continue;
284
285                 device->driver = driver;
286
287                 __connman_technology_add_device(device);
288         }
289 }
290
291 static void remove_device(struct connman_device *device)
292 {
293         DBG("device %p", device);
294
295         __connman_device_disable(device);
296
297         __connman_technology_remove_device(device);
298
299         if (device->driver->remove)
300                 device->driver->remove(device);
301
302         device->driver = NULL;
303 }
304
305 static void remove_driver(struct connman_device_driver *driver)
306 {
307         GSList *list;
308
309         DBG("driver %p name %s", driver, driver->name);
310
311         for (list = device_list; list; list = list->next) {
312                 struct connman_device *device = list->data;
313
314                 if (device->driver == driver)
315                         remove_device(device);
316         }
317 }
318
319 bool __connman_device_has_driver(struct connman_device *device)
320 {
321         if (!device || !device->driver)
322                 return false;
323
324         return true;
325 }
326
327 static GSList *driver_list = NULL;
328
329 static gint compare_priority(gconstpointer a, gconstpointer b)
330 {
331         const struct connman_device_driver *driver1 = a;
332         const struct connman_device_driver *driver2 = b;
333
334         return driver2->priority - driver1->priority;
335 }
336
337 /**
338  * connman_device_driver_register:
339  * @driver: device driver definition
340  *
341  * Register a new device driver
342  *
343  * Returns: %0 on success
344  */
345 int connman_device_driver_register(struct connman_device_driver *driver)
346 {
347         DBG("driver %p name %s", driver, driver->name);
348
349         driver_list = g_slist_insert_sorted(driver_list, driver,
350                                                         compare_priority);
351         probe_driver(driver);
352
353         return 0;
354 }
355
356 /**
357  * connman_device_driver_unregister:
358  * @driver: device driver definition
359  *
360  * Remove a previously registered device driver
361  */
362 void connman_device_driver_unregister(struct connman_device_driver *driver)
363 {
364         DBG("driver %p name %s", driver, driver->name);
365
366         driver_list = g_slist_remove(driver_list, driver);
367
368         remove_driver(driver);
369 }
370
371 static void free_network(gpointer data)
372 {
373         struct connman_network *network = data;
374
375         DBG("network %p", network);
376
377         __connman_network_set_device(network, NULL);
378
379         connman_network_unref(network);
380 }
381
382 static void device_destruct(struct connman_device *device)
383 {
384         DBG("device %p name %s", device, device->name);
385
386         clear_pending_trigger(device);
387
388         g_free(device->ident);
389         g_free(device->node);
390         g_free(device->name);
391         g_free(device->address);
392         g_free(device->interface);
393         g_free(device->path);
394
395         g_free(device->last_network);
396
397         g_hash_table_destroy(device->networks);
398         device->networks = NULL;
399
400         g_free(device);
401 }
402
403 /**
404  * connman_device_create:
405  * @node: device node name (for example an address)
406  * @type: device type
407  *
408  * Allocate a new device of given #type and assign the #node name to it.
409  *
410  * Returns: a newly-allocated #connman_device structure
411  */
412 struct connman_device *connman_device_create(const char *node,
413                                                 enum connman_device_type type)
414 {
415         struct connman_device *device;
416
417         DBG("node %s type %d", node, type);
418
419         device = g_try_new0(struct connman_device, 1);
420         if (!device)
421                 return NULL;
422
423         DBG("device %p", device);
424
425         device->refcount = 1;
426
427         device->type = type;
428         device->name = g_strdup(type2description(device->type));
429
430         device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
431                                                 g_free, free_network);
432
433         device_list = g_slist_prepend(device_list, device);
434
435         return device;
436 }
437
438 /**
439  * connman_device_ref:
440  * @device: device structure
441  *
442  * Increase reference counter of device
443  */
444 struct connman_device *connman_device_ref_debug(struct connman_device *device,
445                                 const char *file, int line, const char *caller)
446 {
447         DBG("%p ref %d by %s:%d:%s()", device, device->refcount + 1,
448                 file, line, caller);
449
450         __sync_fetch_and_add(&device->refcount, 1);
451
452         return device;
453 }
454
455 /**
456  * connman_device_unref:
457  * @device: device structure
458  *
459  * Decrease reference counter of device
460  */
461 void connman_device_unref_debug(struct connman_device *device,
462                                 const char *file, int line, const char *caller)
463 {
464         DBG("%p ref %d by %s:%d:%s()", device, device->refcount - 1,
465                 file, line, caller);
466
467         if (__sync_fetch_and_sub(&device->refcount, 1) != 1)
468                 return;
469
470         if (device->driver) {
471                 device->driver->remove(device);
472                 device->driver = NULL;
473         }
474
475         device_list = g_slist_remove(device_list, device);
476
477         device_destruct(device);
478 }
479
480 const char *__connman_device_get_type(struct connman_device *device)
481 {
482         return type2string(device->type);
483 }
484
485 /**
486  * connman_device_get_type:
487  * @device: device structure
488  *
489  * Get type of device
490  */
491 enum connman_device_type connman_device_get_type(struct connman_device *device)
492 {
493         return device->type;
494 }
495
496 /**
497  * connman_device_set_index:
498  * @device: device structure
499  * @index: index number
500  *
501  * Set index number of device
502  */
503 void connman_device_set_index(struct connman_device *device, int index)
504 {
505         device->index = index;
506 }
507
508 /**
509  * connman_device_get_index:
510  * @device: device structure
511  *
512  * Get index number of device
513  */
514 int connman_device_get_index(struct connman_device *device)
515 {
516         return device->index;
517 }
518
519 /**
520  * connman_device_set_interface:
521  * @device: device structure
522  * @interface: interface name
523  *
524  * Set interface name of device
525  */
526 void connman_device_set_interface(struct connman_device *device,
527                                                 const char *interface)
528 {
529         g_free(device->interface);
530         device->interface = g_strdup(interface);
531
532         if (!device->name) {
533                 const char *str = type2description(device->type);
534                 if (str && device->interface)
535                         device->name = g_strdup_printf("%s (%s)", str,
536                                                         device->interface);
537         }
538 }
539
540 /**
541  * connman_device_set_ident:
542  * @device: device structure
543  * @ident: unique identifier
544  *
545  * Set unique identifier of device
546  */
547 void connman_device_set_ident(struct connman_device *device,
548                                                         const char *ident)
549 {
550         g_free(device->ident);
551         device->ident = g_strdup(ident);
552 }
553
554 const char *connman_device_get_ident(struct connman_device *device)
555 {
556         return device->ident;
557 }
558
559 /**
560  * connman_device_set_powered:
561  * @device: device structure
562  * @powered: powered state
563  *
564  * Change power state of device
565  */
566 int connman_device_set_powered(struct connman_device *device,
567                                                 bool powered)
568 {
569         enum connman_service_type type;
570
571         DBG("driver %p powered %d", device, powered);
572
573         if (device->powered == powered)
574                 return -EALREADY;
575
576         clear_pending_trigger(device);
577
578         device->powered_pending = PENDING_NONE;
579
580         device->powered = powered;
581
582         type = __connman_device_get_service_type(device);
583
584         if (!device->powered) {
585                 __connman_technology_disabled(type);
586                 return 0;
587         }
588
589         __connman_technology_enabled(type);
590
591         connman_device_set_disconnected(device, false);
592         device->scanning = false;
593
594         if (device->driver && device->driver->scan)
595                 device->driver->scan(CONNMAN_SERVICE_TYPE_UNKNOWN, device,
596                                         NULL, 0, NULL, NULL, NULL, NULL);
597
598         return 0;
599 }
600
601 bool connman_device_get_powered(struct connman_device *device)
602 {
603         return device->powered;
604 }
605
606 static int device_scan(enum connman_service_type type,
607                                 struct connman_device *device)
608 {
609         if (!device->driver || !device->driver->scan)
610                 return -EOPNOTSUPP;
611
612         if (!device->powered)
613                 return -ENOLINK;
614
615         return device->driver->scan(type, device, NULL, 0,
616                                         NULL, NULL, NULL, NULL);
617 }
618
619 int __connman_device_disconnect(struct connman_device *device)
620 {
621         GHashTableIter iter;
622         gpointer key, value;
623
624         DBG("device %p", device);
625
626         connman_device_set_disconnected(device, true);
627
628         g_hash_table_iter_init(&iter, device->networks);
629
630         while (g_hash_table_iter_next(&iter, &key, &value)) {
631                 struct connman_network *network = value;
632
633                 if (connman_network_get_connecting(network)) {
634                         /*
635                          * Skip network in the process of connecting.
636                          * This is a workaround for WiFi networks serviced
637                          * by the supplicant plugin that hold a reference
638                          * to the network.  If we disconnect the network
639                          * here then the referenced object will not be
640                          * registered and usage (like launching DHCP client)
641                          * will fail.  There is nothing to be gained by
642                          * removing the network here anyway.
643                          */
644                         connman_warn("Skipping disconnect of %s, network is connecting.",
645                                 connman_network_get_identifier(network));
646                         continue;
647                 }
648
649                 __connman_network_disconnect(network);
650         }
651
652         return 0;
653 }
654
655 int connman_device_reconnect_service(struct connman_device *device)
656 {
657         DBG("device %p", device);
658
659         __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
660
661         return 0;
662 }
663
664 static void mark_network_available(gpointer key, gpointer value,
665                                                         gpointer user_data)
666 {
667         struct connman_network *network = value;
668
669         connman_network_set_available(network, true);
670 }
671
672 static void mark_network_unavailable(gpointer key, gpointer value,
673                                                         gpointer user_data)
674 {
675         struct connman_network *network = value;
676
677         if (connman_network_get_connected(network) ||
678                         connman_network_get_connecting(network))
679                 return;
680
681         connman_network_set_available(network, false);
682 }
683
684 static gboolean remove_unavailable_network(gpointer key, gpointer value,
685                                                         gpointer user_data)
686 {
687         struct connman_network *network = value;
688
689         if (connman_network_get_connected(network))
690                 return FALSE;
691
692         if (connman_network_get_available(network))
693                 return FALSE;
694
695         return TRUE;
696 }
697
698 void __connman_device_cleanup_networks(struct connman_device *device)
699 {
700         g_hash_table_foreach_remove(device->networks,
701                                         remove_unavailable_network, NULL);
702 }
703
704 bool connman_device_get_scanning(struct connman_device *device)
705 {
706         return device->scanning;
707 }
708
709 void connman_device_reset_scanning(struct connman_device *device)
710 {
711         g_hash_table_foreach(device->networks,
712                                 mark_network_available, NULL);
713 }
714
715 /**
716  * connman_device_set_scanning:
717  * @device: device structure
718  * @scanning: scanning state
719  *
720  * Change scanning state of device
721  */
722 int connman_device_set_scanning(struct connman_device *device,
723                                 enum connman_service_type type, bool scanning)
724 {
725         DBG("device %p scanning %d", device, scanning);
726
727         if (!device->driver || !device->driver->scan)
728                 return -EINVAL;
729
730         if (device->scanning == scanning)
731                 return -EALREADY;
732
733         device->scanning = scanning;
734
735         if (scanning) {
736                 __connman_technology_scan_started(device);
737
738                 g_hash_table_foreach(device->networks,
739                                         mark_network_unavailable, NULL);
740
741                 return 0;
742         }
743
744         __connman_device_cleanup_networks(device);
745
746         __connman_technology_scan_stopped(device, type);
747
748         __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
749
750         return 0;
751 }
752
753 /**
754  * connman_device_set_disconnected:
755  * @device: device structure
756  * @disconnected: disconnected state
757  *
758  * Change disconnected state of device (only for device with networks)
759  */
760 int connman_device_set_disconnected(struct connman_device *device,
761                                                 bool disconnected)
762 {
763         DBG("device %p disconnected %d", device, disconnected);
764
765         if (device->disconnected == disconnected)
766                 return -EALREADY;
767
768         device->disconnected = disconnected;
769
770         return 0;
771 }
772
773 /**
774  * connman_device_get_disconnected:
775  * @device: device structure
776  *
777  * Get device disconnected state
778  */
779 bool connman_device_get_disconnected(struct connman_device *device)
780 {
781         return device->disconnected;
782 }
783
784 /**
785  * connman_device_set_string:
786  * @device: device structure
787  * @key: unique identifier
788  * @value: string value
789  *
790  * Set string value for specific key
791  */
792 int connman_device_set_string(struct connman_device *device,
793                                         const char *key, const char *value)
794 {
795         DBG("device %p key %s value %s", device, key, value);
796
797         if (g_str_equal(key, "Address")) {
798                 g_free(device->address);
799                 device->address = g_strdup(value);
800         } else if (g_str_equal(key, "Name")) {
801                 g_free(device->name);
802                 device->name = g_strdup(value);
803         } else if (g_str_equal(key, "Node")) {
804                 g_free(device->node);
805                 device->node = g_strdup(value);
806         } else if (g_str_equal(key, "Path")) {
807                 g_free(device->path);
808                 device->path = g_strdup(value);
809         } else {
810                 return -EINVAL;
811         }
812
813         return 0;
814 }
815
816 /**
817  * connman_device_get_string:
818  * @device: device structure
819  * @key: unique identifier
820  *
821  * Get string value for specific key
822  */
823 const char *connman_device_get_string(struct connman_device *device,
824                                                         const char *key)
825 {
826         DBG("device %p key %s", device, key);
827
828         if (g_str_equal(key, "Address"))
829                 return device->address;
830         else if (g_str_equal(key, "Name"))
831                 return device->name;
832         else if (g_str_equal(key, "Node"))
833                 return device->node;
834         else if (g_str_equal(key, "Interface"))
835                 return device->interface;
836         else if (g_str_equal(key, "Path"))
837                 return device->path;
838
839         return NULL;
840 }
841
842 /**
843  * connman_device_add_network:
844  * @device: device structure
845  * @network: network structure
846  *
847  * Add new network to the device
848  */
849 int connman_device_add_network(struct connman_device *device,
850                                         struct connman_network *network)
851 {
852         const char *identifier = connman_network_get_identifier(network);
853
854         DBG("device %p network %p", device, network);
855
856         if (!identifier)
857                 return -EINVAL;
858
859         connman_network_ref(network);
860
861         __connman_network_set_device(network, device);
862
863         g_hash_table_replace(device->networks, g_strdup(identifier),
864                                                                 network);
865
866         return 0;
867 }
868
869 /**
870  * connman_device_get_network:
871  * @device: device structure
872  * @identifier: network identifier
873  *
874  * Get network for given identifier
875  */
876 struct connman_network *connman_device_get_network(struct connman_device *device,
877                                                         const char *identifier)
878 {
879         DBG("device %p identifier %s", device, identifier);
880
881         return g_hash_table_lookup(device->networks, identifier);
882 }
883
884 /**
885  * connman_device_remove_network:
886  * @device: device structure
887  * @identifier: network identifier
888  *
889  * Remove network for given identifier
890  */
891 int connman_device_remove_network(struct connman_device *device,
892                                                 struct connman_network *network)
893 {
894         const char *identifier;
895
896         DBG("device %p network %p", device, network);
897
898         if (!network)
899                 return 0;
900
901         identifier = connman_network_get_identifier(network);
902         g_hash_table_remove(device->networks, identifier);
903
904         return 0;
905 }
906
907 void __connman_device_set_network(struct connman_device *device,
908                                         struct connman_network *network)
909 {
910         const char *name;
911
912         if (!device)
913                 return;
914
915         if (device->network == network)
916                 return;
917
918         if (network) {
919                 name = connman_network_get_string(network, "Name");
920                 g_free(device->last_network);
921                 device->last_network = g_strdup(name);
922
923                 device->network = network;
924         } else {
925                 g_free(device->last_network);
926                 device->last_network = NULL;
927
928                 device->network = NULL;
929         }
930 }
931
932 static bool match_driver(struct connman_device *device,
933                                         struct connman_device_driver *driver)
934 {
935         if (device->type == driver->type ||
936                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
937                 return true;
938
939         return false;
940 }
941
942 /**
943  * connman_device_register:
944  * @device: device structure
945  *
946  * Register device with the system
947  */
948 int connman_device_register(struct connman_device *device)
949 {
950         GSList *list;
951
952         DBG("device %p name %s", device, device->name);
953
954         if (device->driver)
955                 return -EALREADY;
956
957         for (list = driver_list; list; list = list->next) {
958                 struct connman_device_driver *driver = list->data;
959
960                 if (!match_driver(device, driver))
961                         continue;
962
963                 DBG("driver %p name %s", driver, driver->name);
964
965                 if (driver->probe(device) == 0) {
966                         device->driver = driver;
967                         break;
968                 }
969         }
970
971         if (!device->driver)
972                 return 0;
973
974         return __connman_technology_add_device(device);
975 }
976
977 /**
978  * connman_device_unregister:
979  * @device: device structure
980  *
981  * Unregister device with the system
982  */
983 void connman_device_unregister(struct connman_device *device)
984 {
985         DBG("device %p name %s", device, device->name);
986
987         if (!device->driver)
988                 return;
989
990         remove_device(device);
991 }
992
993 /**
994  * connman_device_get_data:
995  * @device: device structure
996  *
997  * Get private device data pointer
998  */
999 void *connman_device_get_data(struct connman_device *device)
1000 {
1001         return device->driver_data;
1002 }
1003
1004 /**
1005  * connman_device_set_data:
1006  * @device: device structure
1007  * @data: data pointer
1008  *
1009  * Set private device data pointer
1010  */
1011 void connman_device_set_data(struct connman_device *device, void *data)
1012 {
1013         device->driver_data = data;
1014 }
1015
1016 struct connman_device *__connman_device_find_device(
1017                                 enum connman_service_type type)
1018 {
1019         GSList *list;
1020
1021         for (list = device_list; list; list = list->next) {
1022                 struct connman_device *device = list->data;
1023                 enum connman_service_type service_type =
1024                         __connman_device_get_service_type(device);
1025
1026                 if (service_type != type)
1027                         continue;
1028
1029                 return device;
1030         }
1031
1032         return NULL;
1033 }
1034
1035 struct connman_device *connman_device_find_by_index(int index)
1036 {
1037         GSList *list;
1038
1039         for (list = device_list; list; list = list->next) {
1040                 struct connman_device *device = list->data;
1041                 if (device->index == index)
1042                         return device;
1043         }
1044
1045         return NULL;
1046 }
1047
1048 /**
1049  * connman_device_set_regdom
1050  * @device: device structure
1051  * @alpha2: string representing regulatory domain
1052  *
1053  * Set regulatory domain on device basis
1054  */
1055 int connman_device_set_regdom(struct connman_device *device,
1056                                                 const char *alpha2)
1057 {
1058         if (!device->driver || !device->driver->set_regdom)
1059                 return -ENOTSUP;
1060
1061         if (!device->powered)
1062                 return -EINVAL;
1063
1064         return device->driver->set_regdom(device, alpha2);
1065 }
1066
1067 /**
1068  * connman_device_regdom_notify
1069  * @device: device structure
1070  * @alpha2: string representing regulatory domain
1071  *
1072  * Notify on setting regulatory domain on device basis
1073  */
1074 void connman_device_regdom_notify(struct connman_device *device,
1075                                         int result, const char *alpha2)
1076 {
1077         __connman_technology_notify_regdom_by_device(device, result, alpha2);
1078 }
1079
1080 #if defined TIZEN_EXT
1081 static int device_specific_scan(enum connman_service_type type,
1082                                 struct connman_device *device,
1083                                 int scan_type, GSList *specific_scan_list)
1084 {
1085         if (!device->driver || !device->driver->specific_scan)
1086                 return -EOPNOTSUPP;
1087
1088         if (!device->powered)
1089                 return -ENOLINK;
1090
1091         return device->driver->specific_scan(type, device, scan_type,
1092                         specific_scan_list, NULL);
1093 }
1094
1095 int __connman_device_request_specific_scan(enum connman_service_type type,
1096                                 int scan_type, GSList *specific_scan_list)
1097 {
1098         bool success = false;
1099         int last_err = -ENOSYS;
1100         GSList *list;
1101         int err;
1102
1103         switch (type) {
1104         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1105         case CONNMAN_SERVICE_TYPE_SYSTEM:
1106         case CONNMAN_SERVICE_TYPE_ETHERNET:
1107         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1108         case CONNMAN_SERVICE_TYPE_CELLULAR:
1109         case CONNMAN_SERVICE_TYPE_GPS:
1110         case CONNMAN_SERVICE_TYPE_VPN:
1111         case CONNMAN_SERVICE_TYPE_GADGET:
1112                 return -EOPNOTSUPP;
1113         case CONNMAN_SERVICE_TYPE_WIFI:
1114         case CONNMAN_SERVICE_TYPE_P2P:
1115                 break;
1116         }
1117
1118         for (list = device_list; list; list = list->next) {
1119                 struct connman_device *device = list->data;
1120                 enum connman_service_type service_type =
1121                         __connman_device_get_service_type(device);
1122
1123                 if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN) {
1124                         if (type == CONNMAN_SERVICE_TYPE_P2P) {
1125                                 if (service_type != CONNMAN_SERVICE_TYPE_WIFI)
1126                                         continue;
1127                         } else if (service_type != type)
1128                                 continue;
1129                 }
1130
1131                 err = device_specific_scan(type, device, scan_type, specific_scan_list);
1132                 if (err == 0 || err == -EINPROGRESS) {
1133                         success = true;
1134                 } else {
1135                         last_err = err;
1136                         DBG("device %p err %d", device, err);
1137                 }
1138         }
1139
1140         if (success)
1141                 return 0;
1142
1143         return last_err;
1144 }
1145 #endif
1146
1147 int __connman_device_request_scan(enum connman_service_type type)
1148 {
1149         bool success = false;
1150         int last_err = -ENOSYS;
1151         GSList *list;
1152         int err;
1153
1154         switch (type) {
1155         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1156         case CONNMAN_SERVICE_TYPE_SYSTEM:
1157         case CONNMAN_SERVICE_TYPE_ETHERNET:
1158         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1159         case CONNMAN_SERVICE_TYPE_CELLULAR:
1160         case CONNMAN_SERVICE_TYPE_GPS:
1161         case CONNMAN_SERVICE_TYPE_VPN:
1162         case CONNMAN_SERVICE_TYPE_GADGET:
1163                 return -EOPNOTSUPP;
1164         case CONNMAN_SERVICE_TYPE_WIFI:
1165         case CONNMAN_SERVICE_TYPE_P2P:
1166                 break;
1167         }
1168
1169         for (list = device_list; list; list = list->next) {
1170                 struct connman_device *device = list->data;
1171                 enum connman_service_type service_type =
1172                         __connman_device_get_service_type(device);
1173
1174                 if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN) {
1175                         if (type == CONNMAN_SERVICE_TYPE_P2P) {
1176                                 if (service_type != CONNMAN_SERVICE_TYPE_WIFI)
1177                                         continue;
1178                         } else if (service_type != type)
1179                                 continue;
1180                 }
1181
1182                 err = device_scan(type, device);
1183 #if defined TIZEN_EXT
1184                 /* When Scan is already in progress then return Error so that
1185                  * wifi-manager can block the scan-done signal to be sent to
1186                  * application and start requested scan after scan already in progress
1187                  * is completed then notify to application about the scan event */
1188                 if (err == 0 || err == -EINPROGRESS) {
1189 #else
1190                 if (err == 0 || err == -EALREADY || err == -EINPROGRESS) {
1191 #endif
1192                         success = true;
1193                 } else {
1194                         last_err = err;
1195                         DBG("device %p err %d", device, err);
1196                 }
1197         }
1198
1199         if (success)
1200                 return 0;
1201
1202         return last_err;
1203 }
1204
1205 int __connman_device_request_hidden_scan(struct connman_device *device,
1206                                 const char *ssid, unsigned int ssid_len,
1207                                 const char *identity, const char *passphrase,
1208                                 const char *security, void *user_data)
1209 {
1210         DBG("device %p", device);
1211
1212         if (!device || !device->driver ||
1213                         !device->driver->scan)
1214                 return -EINVAL;
1215
1216         return device->driver->scan(CONNMAN_SERVICE_TYPE_UNKNOWN,
1217                                         device, ssid, ssid_len, identity,
1218                                         passphrase, security, user_data);
1219 }
1220
1221 #if defined TIZEN_EXT
1222 char *index2ident(int index, const char *prefix)
1223 #else
1224 static char *index2ident(int index, const char *prefix)
1225 #endif
1226 {
1227         struct ifreq ifr;
1228         struct ether_addr eth;
1229         char *str;
1230         int sk, err, len;
1231
1232         if (index < 0)
1233                 return NULL;
1234
1235         sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
1236         if (sk < 0)
1237                 return NULL;
1238
1239         memset(&ifr, 0, sizeof(ifr));
1240         ifr.ifr_ifindex = index;
1241
1242         err = ioctl(sk, SIOCGIFNAME, &ifr);
1243
1244         if (err == 0)
1245                 err = ioctl(sk, SIOCGIFHWADDR, &ifr);
1246
1247         close(sk);
1248
1249         if (err < 0)
1250                 return NULL;
1251
1252         len = prefix ? strlen(prefix) + 18 : 18;
1253
1254         str = g_malloc(len);
1255         if (!str)
1256                 return NULL;
1257
1258         memcpy(&eth, &ifr.ifr_hwaddr.sa_data, sizeof(eth));
1259         snprintf(str, len, "%s%02x%02x%02x%02x%02x%02x",
1260                                                 prefix ? prefix : "",
1261                                                 eth.ether_addr_octet[0],
1262                                                 eth.ether_addr_octet[1],
1263                                                 eth.ether_addr_octet[2],
1264                                                 eth.ether_addr_octet[3],
1265                                                 eth.ether_addr_octet[4],
1266                                                 eth.ether_addr_octet[5]);
1267
1268         return str;
1269 }
1270
1271 #if defined TIZEN_EXT
1272 char *index2addr(int index)
1273 #else
1274 static char *index2addr(int index)
1275 #endif
1276 {
1277         struct ifreq ifr;
1278         struct ether_addr eth;
1279         char *str;
1280         int sk, err;
1281
1282         if (index < 0)
1283                 return NULL;
1284
1285         sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
1286         if (sk < 0)
1287                 return NULL;
1288
1289         memset(&ifr, 0, sizeof(ifr));
1290         ifr.ifr_ifindex = index;
1291
1292         err = ioctl(sk, SIOCGIFNAME, &ifr);
1293
1294         if (err == 0)
1295                 err = ioctl(sk, SIOCGIFHWADDR, &ifr);
1296
1297         close(sk);
1298
1299         if (err < 0)
1300                 return NULL;
1301
1302         str = g_malloc(18);
1303         if (!str)
1304                 return NULL;
1305
1306         memcpy(&eth, &ifr.ifr_hwaddr.sa_data, sizeof(eth));
1307         snprintf(str, 18, "%02X:%02X:%02X:%02X:%02X:%02X",
1308                                                 eth.ether_addr_octet[0],
1309                                                 eth.ether_addr_octet[1],
1310                                                 eth.ether_addr_octet[2],
1311                                                 eth.ether_addr_octet[3],
1312                                                 eth.ether_addr_octet[4],
1313                                                 eth.ether_addr_octet[5]);
1314
1315         return str;
1316 }
1317
1318 struct connman_device *connman_device_create_from_index(int index)
1319 {
1320         enum connman_device_type type;
1321         struct connman_device *device;
1322         char *devname, *ident = NULL;
1323         char *addr = NULL, *name = NULL;
1324
1325         if (index < 0)
1326                 return NULL;
1327
1328         devname = connman_inet_ifname(index);
1329         if (!devname)
1330                 return NULL;
1331
1332         if (__connman_device_isfiltered(devname)) {
1333                 connman_info("Ignoring interface %s (filtered)", devname);
1334                 g_free(devname);
1335                 return NULL;
1336         }
1337
1338         type = __connman_rtnl_get_device_type(index);
1339
1340         switch (type) {
1341         case CONNMAN_DEVICE_TYPE_UNKNOWN:
1342                 connman_info("Ignoring interface %s (type unknown)", devname);
1343                 g_free(devname);
1344                 return NULL;
1345         case CONNMAN_DEVICE_TYPE_ETHERNET:
1346         case CONNMAN_DEVICE_TYPE_GADGET:
1347         case CONNMAN_DEVICE_TYPE_WIFI:
1348                 name = index2ident(index, "");
1349                 addr = index2addr(index);
1350                 break;
1351         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
1352         case CONNMAN_DEVICE_TYPE_CELLULAR:
1353         case CONNMAN_DEVICE_TYPE_GPS:
1354         case CONNMAN_DEVICE_TYPE_VENDOR:
1355                 name = g_strdup(devname);
1356                 break;
1357         }
1358
1359         device = connman_device_create(name, type);
1360         if (!device)
1361                 goto done;
1362
1363         switch (type) {
1364         case CONNMAN_DEVICE_TYPE_UNKNOWN:
1365         case CONNMAN_DEVICE_TYPE_VENDOR:
1366         case CONNMAN_DEVICE_TYPE_GPS:
1367                 break;
1368         case CONNMAN_DEVICE_TYPE_ETHERNET:
1369         case CONNMAN_DEVICE_TYPE_GADGET:
1370                 ident = index2ident(index, NULL);
1371                 break;
1372         case CONNMAN_DEVICE_TYPE_WIFI:
1373                 ident = index2ident(index, NULL);
1374                 break;
1375         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
1376                 break;
1377         case CONNMAN_DEVICE_TYPE_CELLULAR:
1378                 ident = index2ident(index, NULL);
1379                 break;
1380         }
1381
1382         connman_device_set_index(device, index);
1383         connman_device_set_interface(device, devname);
1384
1385         if (ident) {
1386                 connman_device_set_ident(device, ident);
1387                 g_free(ident);
1388         }
1389
1390         connman_device_set_string(device, "Address", addr);
1391
1392 done:
1393         g_free(devname);
1394         g_free(name);
1395         g_free(addr);
1396
1397         return device;
1398 }
1399
1400 bool __connman_device_isfiltered(const char *devname)
1401 {
1402         char **pattern;
1403         char **blacklisted_interfaces;
1404         bool match;
1405
1406         if (!device_filter)
1407                 goto nodevice;
1408
1409         for (pattern = device_filter, match = false; *pattern; pattern++) {
1410                 if (g_pattern_match_simple(*pattern, devname)) {
1411                         match = true;
1412                         break;
1413                 }
1414         }
1415
1416         if (!match) {
1417                 DBG("ignoring device %s (match)", devname);
1418                 return true;
1419         }
1420
1421 nodevice:
1422         if (g_pattern_match_simple("dummy*", devname)) {
1423                 DBG("ignoring dummy networking devices");
1424                 return true;
1425         }
1426
1427         if (!nodevice_filter)
1428                 goto list;
1429
1430         for (pattern = nodevice_filter; *pattern; pattern++) {
1431                 if (g_pattern_match_simple(*pattern, devname)) {
1432                         DBG("ignoring device %s (no match)", devname);
1433                         return true;
1434                 }
1435         }
1436
1437 list:
1438         blacklisted_interfaces =
1439                 connman_setting_get_string_list("NetworkInterfaceBlacklist");
1440         if (!blacklisted_interfaces)
1441                 return false;
1442
1443         for (pattern = blacklisted_interfaces; *pattern; pattern++) {
1444                 if (g_str_has_prefix(devname, *pattern)) {
1445                         DBG("ignoring device %s (blacklist)", devname);
1446                         return true;
1447                 }
1448         }
1449
1450         return false;
1451 }
1452
1453 static void cleanup_devices(void)
1454 {
1455         /*
1456          * Check what interfaces are currently up and if connman is
1457          * suppose to handle the interface, then cleanup the mess
1458          * related to that interface. There might be weird routes etc
1459          * that are related to that interface and that might confuse
1460          * connmand. So in this case we just turn the interface down
1461          * so that kernel removes routes/addresses automatically and
1462          * then proceed the startup.
1463          *
1464          * Note that this cleanup must be done before rtnl/detect code
1465          * has activated interface watches.
1466          */
1467
1468         char **interfaces;
1469         int i;
1470
1471         interfaces = __connman_inet_get_running_interfaces();
1472
1473         if (!interfaces)
1474                 return;
1475
1476         for (i = 0; interfaces[i]; i++) {
1477                 bool filtered;
1478                 int index;
1479                 struct sockaddr_in sin_addr, sin_mask;
1480
1481                 filtered = __connman_device_isfiltered(interfaces[i]);
1482                 if (filtered)
1483                         continue;
1484
1485                 index = connman_inet_ifindex(interfaces[i]);
1486                 if (index < 0)
1487                         continue;
1488
1489                 if (!__connman_inet_get_address_netmask(index, &sin_addr,
1490                                                         &sin_mask)) {
1491                         char *address = g_strdup(inet_ntoa(sin_addr.sin_addr));
1492                         char *netmask = g_strdup(inet_ntoa(sin_mask.sin_addr));
1493
1494                         if (__connman_config_address_provisioned(address,
1495                                                                 netmask)) {
1496                                 DBG("Skip %s which is already provisioned "
1497                                         "with %s/%s", interfaces[i], address,
1498                                         netmask);
1499                                 g_free(address);
1500                                 g_free(netmask);
1501                                 continue;
1502                         }
1503
1504                         g_free(address);
1505                         g_free(netmask);
1506                 }
1507
1508                 DBG("cleaning up %s index %d", interfaces[i], index);
1509
1510 #if defined TIZEN_EXT
1511                 if (strcmp(interfaces[i], "wlan0") != 0)
1512 #endif
1513                 connman_inet_ifdown(index);
1514
1515                 /*
1516                  * ConnMan will turn the interface UP automatically so
1517                  * no need to do it here.
1518                  */
1519         }
1520
1521         g_strfreev(interfaces);
1522 }
1523
1524 int __connman_device_init(const char *device, const char *nodevice)
1525 {
1526         DBG("");
1527
1528         if (device)
1529                 device_filter = g_strsplit(device, ",", -1);
1530
1531         if (nodevice)
1532                 nodevice_filter = g_strsplit(nodevice, ",", -1);
1533
1534         cleanup_devices();
1535
1536         return 0;
1537 }
1538
1539 void __connman_device_cleanup(void)
1540 {
1541         DBG("");
1542
1543         g_strfreev(nodevice_filter);
1544         g_strfreev(device_filter);
1545 }