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