device: Remove unused phyindex
[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
29 #include "connman.h"
30
31 static GSList *device_list = NULL;
32 static gchar **device_filter = NULL;
33 static gchar **nodevice_filter = NULL;
34
35 enum connman_pending_type {
36         PENDING_NONE    = 0,
37         PENDING_ENABLE  = 1,
38         PENDING_DISABLE = 2,
39 };
40
41 struct connman_device {
42         int refcount;
43         enum connman_device_type type;
44         enum connman_pending_type powered_pending;      /* Indicates a pending
45                                                         enable/disable request */
46         connman_bool_t powered;
47         connman_bool_t scanning;
48         connman_bool_t disconnected;
49         connman_bool_t reconnect;
50         char *name;
51         char *node;
52         char *address;
53         char *interface;
54         char *ident;
55         char *path;
56         char *devname;
57         int index;
58         guint pending_timeout;
59
60         struct connman_device_driver *driver;
61         void *driver_data;
62
63         char *last_network;
64         struct connman_network *network;
65         GHashTable *networks;
66 };
67
68 static void clear_pending_trigger(struct connman_device *device)
69 {
70         if (device->pending_timeout > 0) {
71                 g_source_remove(device->pending_timeout);
72                 device->pending_timeout = 0;
73         }
74 }
75
76 static const char *type2description(enum connman_device_type type)
77 {
78         switch (type) {
79         case CONNMAN_DEVICE_TYPE_UNKNOWN:
80         case CONNMAN_DEVICE_TYPE_VENDOR:
81                 break;
82         case CONNMAN_DEVICE_TYPE_ETHERNET:
83                 return "Ethernet";
84         case CONNMAN_DEVICE_TYPE_WIFI:
85                 return "Wireless";
86         case CONNMAN_DEVICE_TYPE_WIMAX:
87                 return "WiMAX";
88         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
89                 return "Bluetooth";
90         case CONNMAN_DEVICE_TYPE_GPS:
91                 return "GPS";
92         case CONNMAN_DEVICE_TYPE_CELLULAR:
93                 return "Cellular";
94         case CONNMAN_DEVICE_TYPE_GADGET:
95                 return "Gadget";
96
97         }
98
99         return NULL;
100 }
101
102 static const char *type2string(enum connman_device_type type)
103 {
104         switch (type) {
105         case CONNMAN_DEVICE_TYPE_UNKNOWN:
106         case CONNMAN_DEVICE_TYPE_VENDOR:
107                 break;
108         case CONNMAN_DEVICE_TYPE_ETHERNET:
109                 return "ethernet";
110         case CONNMAN_DEVICE_TYPE_WIFI:
111                 return "wifi";
112         case CONNMAN_DEVICE_TYPE_WIMAX:
113                 return "wimax";
114         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
115                 return "bluetooth";
116         case CONNMAN_DEVICE_TYPE_GPS:
117                 return "gps";
118         case CONNMAN_DEVICE_TYPE_CELLULAR:
119                 return "cellular";
120         case CONNMAN_DEVICE_TYPE_GADGET:
121                 return "gadget";
122
123         }
124
125         return NULL;
126 }
127
128 enum connman_service_type __connman_device_get_service_type(struct connman_device *device)
129 {
130         enum connman_device_type type = connman_device_get_type(device);
131
132         switch (type) {
133         case CONNMAN_DEVICE_TYPE_UNKNOWN:
134         case CONNMAN_DEVICE_TYPE_VENDOR:
135         case CONNMAN_DEVICE_TYPE_GPS:
136                 break;
137         case CONNMAN_DEVICE_TYPE_ETHERNET:
138                 return CONNMAN_SERVICE_TYPE_ETHERNET;
139         case CONNMAN_DEVICE_TYPE_WIFI:
140                 return CONNMAN_SERVICE_TYPE_WIFI;
141         case CONNMAN_DEVICE_TYPE_WIMAX:
142                 return CONNMAN_SERVICE_TYPE_WIMAX;
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_append(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_fast)
593                 device->driver->scan_fast(device);
594         else if (device->driver && device->driver->scan)
595                 device->driver->scan(device);
596
597         return 0;
598 }
599
600 static int device_scan(struct connman_device *device)
601 {
602         if (!device->driver || !device->driver->scan)
603                 return -EOPNOTSUPP;
604
605         if (device->powered == FALSE)
606                 return -ENOLINK;
607
608         return device->driver->scan(device);
609 }
610
611 int __connman_device_disconnect(struct connman_device *device)
612 {
613         GHashTableIter iter;
614         gpointer key, value;
615
616         DBG("device %p", device);
617
618         connman_device_set_disconnected(device, TRUE);
619
620         g_hash_table_iter_init(&iter, device->networks);
621
622         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
623                 struct connman_network *network = value;
624
625                 if (connman_network_get_connecting(network) == TRUE) {
626                         /*
627                          * Skip network in the process of connecting.
628                          * This is a workaround for WiFi networks serviced
629                          * by the supplicant plugin that hold a reference
630                          * to the network.  If we disconnect the network
631                          * here then the referenced object will not be
632                          * registered and usage (like launching DHCP client)
633                          * will fail.  There is nothing to be gained by
634                          * removing the network here anyway.
635                          */
636                         connman_warn("Skipping disconnect of %s, network is connecting.",
637                                 connman_network_get_identifier(network));
638                         continue;
639                 }
640
641                 __connman_network_disconnect(network);
642         }
643
644         return 0;
645 }
646
647 static void mark_network_available(gpointer key, gpointer value,
648                                                         gpointer user_data)
649 {
650         struct connman_network *network = value;
651
652         connman_network_set_available(network, TRUE);
653 }
654
655 static void mark_network_unavailable(gpointer key, gpointer value,
656                                                         gpointer user_data)
657 {
658         struct connman_network *network = value;
659
660         if (connman_network_get_connected(network) == TRUE)
661                 return;
662
663         connman_network_set_available(network, FALSE);
664 }
665
666 static gboolean remove_unavailable_network(gpointer key, gpointer value,
667                                                         gpointer user_data)
668 {
669         struct connman_network *network = value;
670
671         if (connman_network_get_connected(network) == TRUE)
672                 return FALSE;
673
674         if (connman_network_get_available(network) == TRUE)
675                 return FALSE;
676
677         return TRUE;
678 }
679
680 void __connman_device_cleanup_networks(struct connman_device *device)
681 {
682         g_hash_table_foreach_remove(device->networks,
683                                         remove_unavailable_network, NULL);
684 }
685
686 connman_bool_t connman_device_get_scanning(struct connman_device *device)
687 {
688         return device->scanning;
689 }
690
691 void connman_device_reset_scanning(struct connman_device *device)
692 {
693         g_hash_table_foreach(device->networks,
694                                 mark_network_available, NULL);
695 }
696
697 /**
698  * connman_device_set_scanning:
699  * @device: device structure
700  * @scanning: scanning state
701  *
702  * Change scanning state of device
703  */
704 int connman_device_set_scanning(struct connman_device *device,
705                                                 connman_bool_t scanning)
706 {
707         DBG("device %p scanning %d", device, scanning);
708
709         if (!device->driver || !device->driver->scan)
710                 return -EINVAL;
711
712         if (device->scanning == scanning)
713                 return -EALREADY;
714
715         device->scanning = scanning;
716
717         if (scanning == TRUE) {
718                 __connman_technology_scan_started(device);
719
720                 g_hash_table_foreach(device->networks,
721                                         mark_network_unavailable, NULL);
722
723                 return 0;
724         }
725
726         __connman_device_cleanup_networks(device);
727
728         __connman_technology_scan_stopped(device);
729
730         __connman_service_auto_connect();
731
732         return 0;
733 }
734
735 /**
736  * connman_device_set_disconnected:
737  * @device: device structure
738  * @disconnected: disconnected state
739  *
740  * Change disconnected state of device (only for device with networks)
741  */
742 int connman_device_set_disconnected(struct connman_device *device,
743                                                 connman_bool_t disconnected)
744 {
745         DBG("device %p disconnected %d", device, disconnected);
746
747         if (device->disconnected == disconnected)
748                 return -EALREADY;
749
750         device->disconnected = disconnected;
751
752         return 0;
753 }
754
755 /**
756  * connman_device_get_disconnected:
757  * @device: device structure
758  *
759  * Get device disconnected state
760  */
761 connman_bool_t connman_device_get_disconnected(struct connman_device *device)
762 {
763         return device->disconnected;
764 }
765
766 /**
767  * connman_device_set_string:
768  * @device: device structure
769  * @key: unique identifier
770  * @value: string value
771  *
772  * Set string value for specific key
773  */
774 int connman_device_set_string(struct connman_device *device,
775                                         const char *key, const char *value)
776 {
777         DBG("device %p key %s value %s", device, key, value);
778
779         if (g_str_equal(key, "Address") == TRUE) {
780                 g_free(device->address);
781                 device->address = g_strdup(value);
782         } else if (g_str_equal(key, "Name") == TRUE) {
783                 g_free(device->name);
784                 device->name = g_strdup(value);
785         } else if (g_str_equal(key, "Node") == TRUE) {
786                 g_free(device->node);
787                 device->node = g_strdup(value);
788         } else if (g_str_equal(key, "Path") == TRUE) {
789                 g_free(device->path);
790                 device->path = g_strdup(value);
791         } else {
792                 return -EINVAL;
793         }
794
795         return 0;
796 }
797
798 /**
799  * connman_device_get_string:
800  * @device: device structure
801  * @key: unique identifier
802  *
803  * Get string value for specific key
804  */
805 const char *connman_device_get_string(struct connman_device *device,
806                                                         const char *key)
807 {
808         DBG("device %p key %s", device, key);
809
810         if (g_str_equal(key, "Address") == TRUE)
811                 return device->address;
812         else if (g_str_equal(key, "Name") == TRUE)
813                 return device->name;
814         else if (g_str_equal(key, "Node") == TRUE)
815                 return device->node;
816         else if (g_str_equal(key, "Interface") == TRUE)
817                 return device->interface;
818         else if (g_str_equal(key, "Path") == TRUE)
819                 return device->path;
820
821         return NULL;
822 }
823
824 /**
825  * connman_device_add_network:
826  * @device: device structure
827  * @network: network structure
828  *
829  * Add new network to the device
830  */
831 int connman_device_add_network(struct connman_device *device,
832                                         struct connman_network *network)
833 {
834         const char *identifier = connman_network_get_identifier(network);
835
836         DBG("device %p network %p", device, network);
837
838         if (identifier == NULL)
839                 return -EINVAL;
840
841         connman_network_ref(network);
842
843         __connman_network_set_device(network, device);
844
845         g_hash_table_replace(device->networks, g_strdup(identifier),
846                                                                 network);
847
848         return 0;
849 }
850
851 /**
852  * connman_device_get_network:
853  * @device: device structure
854  * @identifier: network identifier
855  *
856  * Get network for given identifier
857  */
858 struct connman_network *connman_device_get_network(struct connman_device *device,
859                                                         const char *identifier)
860 {
861         DBG("device %p identifier %s", device, identifier);
862
863         return g_hash_table_lookup(device->networks, identifier);
864 }
865
866 /**
867  * connman_device_remove_network:
868  * @device: device structure
869  * @identifier: network identifier
870  *
871  * Remove network for given identifier
872  */
873 int connman_device_remove_network(struct connman_device *device,
874                                                 struct connman_network *network)
875 {
876         const char *identifier;
877
878         DBG("device %p network %p", device, network);
879
880         if (network == NULL)
881                 return 0;
882
883         identifier = connman_network_get_identifier(network);
884         g_hash_table_remove(device->networks, identifier);
885
886         return 0;
887 }
888
889 void connman_device_remove_all_networks(struct connman_device *device)
890 {
891         g_hash_table_remove_all(device->networks);
892 }
893
894 void __connman_device_set_network(struct connman_device *device,
895                                         struct connman_network *network)
896 {
897         const char *name;
898
899         if (device == NULL)
900                 return;
901
902         if (device->network == network)
903                 return;
904
905         if (network != NULL) {
906                 name = connman_network_get_string(network, "Name");
907                 g_free(device->last_network);
908                 device->last_network = g_strdup(name);
909
910                 device->network = network;
911         } else {
912                 g_free(device->last_network);
913                 device->last_network = NULL;
914
915                 device->network = NULL;
916         }
917 }
918
919 void __connman_device_set_reconnect(struct connman_device *device,
920                                                 connman_bool_t reconnect)
921 {
922         device->reconnect = reconnect;
923 }
924
925 connman_bool_t  __connman_device_get_reconnect(
926                                 struct connman_device *device)
927 {
928         return device->reconnect;
929 }
930
931 static gboolean match_driver(struct connman_device *device,
932                                         struct connman_device_driver *driver)
933 {
934         if (device->type == driver->type ||
935                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
936                 return TRUE;
937
938         return FALSE;
939 }
940
941 /**
942  * connman_device_register:
943  * @device: device structure
944  *
945  * Register device with the system
946  */
947 int connman_device_register(struct connman_device *device)
948 {
949         GSList *list;
950
951         DBG("device %p name %s", device, device->name);
952
953         if (device->driver != NULL)
954                 return -EALREADY;
955
956         for (list = driver_list; list; list = list->next) {
957                 struct connman_device_driver *driver = list->data;
958
959                 if (match_driver(device, driver) == FALSE)
960                         continue;
961
962                 DBG("driver %p name %s", driver, driver->name);
963
964                 if (driver->probe(device) == 0) {
965                         device->driver = driver;
966                         break;
967                 }
968         }
969
970         if (device->driver == NULL)
971                 return 0;
972
973         return __connman_technology_add_device(device);
974 }
975
976 /**
977  * connman_device_unregister:
978  * @device: device structure
979  *
980  * Unregister device with the system
981  */
982 void connman_device_unregister(struct connman_device *device)
983 {
984         DBG("device %p name %s", device, device->name);
985
986         if (device->driver == NULL)
987                 return;
988
989         remove_device(device);
990 }
991
992 /**
993  * connman_device_get_data:
994  * @device: device structure
995  *
996  * Get private device data pointer
997  */
998 void *connman_device_get_data(struct connman_device *device)
999 {
1000         return device->driver_data;
1001 }
1002
1003 /**
1004  * connman_device_set_data:
1005  * @device: device structure
1006  * @data: data pointer
1007  *
1008  * Set private device data pointer
1009  */
1010 void connman_device_set_data(struct connman_device *device, void *data)
1011 {
1012         device->driver_data = data;
1013 }
1014
1015 struct connman_device *__connman_device_find_device(
1016                                 enum connman_service_type type)
1017 {
1018         GSList *list;
1019
1020         for (list = device_list; list != NULL; list = list->next) {
1021                 struct connman_device *device = list->data;
1022                 enum connman_service_type service_type =
1023                         __connman_device_get_service_type(device);
1024
1025                 if (service_type != type)
1026                         continue;
1027
1028                 return device;
1029         }
1030
1031         return NULL;
1032 }
1033
1034 /**
1035  * connman_device_set_regdom
1036  * @device: device structure
1037  * @alpha2: string representing regulatory domain
1038  *
1039  * Set regulatory domain on device basis
1040  */
1041 int connman_device_set_regdom(struct connman_device *device,
1042                                                 const char *alpha2)
1043 {
1044         if (device->driver == NULL || device->driver->set_regdom == NULL)
1045                 return -ENOTSUP;
1046
1047         if (device->powered == FALSE)
1048                 return -EINVAL;
1049
1050         return device->driver->set_regdom(device, alpha2);
1051 }
1052
1053 /**
1054  * connman_device_regdom_notify
1055  * @device: device structure
1056  * @alpha2: string representing regulatory domain
1057  *
1058  * Notify on setting regulatory domain on device basis
1059  */
1060 void connman_device_regdom_notify(struct connman_device *device,
1061                                         int result, const char *alpha2)
1062 {
1063         __connman_technology_notify_regdom_by_device(device, result, alpha2);
1064 }
1065
1066 int __connman_device_request_scan(enum connman_service_type type)
1067 {
1068         connman_bool_t success = FALSE;
1069         int last_err = -ENOSYS;
1070         GSList *list;
1071         int err;
1072
1073         switch (type) {
1074         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1075         case CONNMAN_SERVICE_TYPE_SYSTEM:
1076         case CONNMAN_SERVICE_TYPE_ETHERNET:
1077         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1078         case CONNMAN_SERVICE_TYPE_CELLULAR:
1079         case CONNMAN_SERVICE_TYPE_GPS:
1080         case CONNMAN_SERVICE_TYPE_VPN:
1081         case CONNMAN_SERVICE_TYPE_GADGET:
1082                 return -EOPNOTSUPP;
1083         case CONNMAN_SERVICE_TYPE_WIFI:
1084         case CONNMAN_SERVICE_TYPE_WIMAX:
1085                 break;
1086         }
1087
1088         for (list = device_list; list != NULL; list = list->next) {
1089                 struct connman_device *device = list->data;
1090                 enum connman_service_type service_type =
1091                         __connman_device_get_service_type(device);
1092
1093                 if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN &&
1094                                 service_type != type) {
1095                         continue;
1096                 }
1097
1098                 err = device_scan(device);
1099                 if (err == 0 || err == -EALREADY || err == -EINPROGRESS) {
1100                         success = TRUE;
1101                 } else {
1102                         last_err = err;
1103                         DBG("device %p err %d", device, err);
1104                 }
1105         }
1106
1107         if (success == TRUE)
1108                 return 0;
1109
1110         return last_err;
1111 }
1112
1113 int __connman_device_request_hidden_scan(struct connman_device *device,
1114                                 const char *ssid, unsigned int ssid_len,
1115                                 const char *identity, const char *passphrase,
1116                                 void *user_data)
1117 {
1118         DBG("device %p", device);
1119
1120         if (device == NULL || device->driver == NULL ||
1121                         device->driver->scan_hidden == NULL)
1122                 return -EINVAL;
1123
1124         if (device->scanning == TRUE)
1125                 return -EALREADY;
1126
1127         return device->driver->scan_hidden(device, ssid, ssid_len,
1128                                         identity, passphrase, user_data);
1129 }
1130
1131 connman_bool_t __connman_device_isfiltered(const char *devname)
1132 {
1133         char **pattern;
1134         char **blacklisted_interfaces;
1135
1136         if (device_filter == NULL)
1137                 goto nodevice;
1138
1139         for (pattern = device_filter; *pattern; pattern++) {
1140                 if (g_pattern_match_simple(*pattern, devname) == FALSE) {
1141                         DBG("ignoring device %s (match)", devname);
1142                         return TRUE;
1143                 }
1144         }
1145
1146 nodevice:
1147         if (g_pattern_match_simple("dummy*", devname) == TRUE) {
1148                 DBG("ignoring dummy networking devices");
1149                 return TRUE;
1150         }
1151
1152         if (nodevice_filter == NULL)
1153                 goto list;
1154
1155         for (pattern = nodevice_filter; *pattern; pattern++) {
1156                 if (g_pattern_match_simple(*pattern, devname) == TRUE) {
1157                         DBG("ignoring device %s (no match)", devname);
1158                         return TRUE;
1159                 }
1160         }
1161
1162 list:
1163         blacklisted_interfaces =
1164                 connman_setting_get_string_list("NetworkInterfaceBlacklist");
1165         if (blacklisted_interfaces == NULL)
1166                 return FALSE;
1167
1168         for (pattern = blacklisted_interfaces; *pattern; pattern++) {
1169                 if (g_str_has_prefix(devname, *pattern) == TRUE) {
1170                         DBG("ignoring device %s (blacklist)", devname);
1171                         return TRUE;
1172                 }
1173         }
1174
1175         return FALSE;
1176 }
1177
1178 static void cleanup_devices(void)
1179 {
1180         /*
1181          * Check what interfaces are currently up and if connman is
1182          * suppose to handle the interface, then cleanup the mess
1183          * related to that interface. There might be weird routes etc
1184          * that are related to that interface and that might confuse
1185          * connmand. So in this case we just turn the interface down
1186          * so that kernel removes routes/addresses automatically and
1187          * then proceed the startup.
1188          *
1189          * Note that this cleanup must be done before rtnl/detect code
1190          * has activated interface watches.
1191          */
1192
1193         char **interfaces;
1194         int i;
1195
1196         interfaces = __connman_inet_get_running_interfaces();
1197
1198         if (interfaces == NULL)
1199                 return;
1200
1201         for (i = 0; interfaces[i] != NULL; i++) {
1202                 connman_bool_t filtered;
1203                 int index;
1204
1205                 filtered = __connman_device_isfiltered(interfaces[i]);
1206                 if (filtered == TRUE)
1207                         continue;
1208
1209                 index = connman_inet_ifindex(interfaces[i]);
1210                 if (index < 0)
1211                         continue;
1212
1213                 DBG("cleaning up %s index %d", interfaces[i], index);
1214
1215                 connman_inet_ifdown(index);
1216
1217                 /*
1218                  * ConnMan will turn the interface UP automatically so
1219                  * no need to do it here.
1220                  */
1221         }
1222
1223         g_strfreev(interfaces);
1224 }
1225
1226 int __connman_device_init(const char *device, const char *nodevice)
1227 {
1228         DBG("");
1229
1230         if (device != NULL)
1231                 device_filter = g_strsplit(device, ",", -1);
1232
1233         if (nodevice != NULL)
1234                 nodevice_filter = g_strsplit(nodevice, ",", -1);
1235
1236         cleanup_devices();
1237
1238         return 0;
1239 }
1240
1241 void __connman_device_cleanup(void)
1242 {
1243         DBG("");
1244
1245         g_strfreev(nodevice_filter);
1246         g_strfreev(device_filter);
1247 }