device: use g_hash_table_replace instead of insert function
[framework/connectivity/connman.git] / src / device.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  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         connman_uint16_t scan_interval;
51         connman_uint16_t backoff_interval;
52         char *name;
53         char *node;
54         char *address;
55         char *interface;
56         char *ident;
57         char *path;
58         char *devname;
59         int phyindex;
60         int index;
61         guint scan_timeout;
62         guint pending_timeout;
63
64         struct connman_device_driver *driver;
65         void *driver_data;
66
67         char *last_network;
68         struct connman_network *network;
69         GHashTable *networks;
70 };
71
72 #define SCAN_INITIAL_DELAY 10
73
74 static gboolean device_scan_trigger(gpointer user_data)
75 {
76         struct connman_device *device = user_data;
77
78         DBG("device %p", device);
79
80         if (device->driver == NULL) {
81                 device->scan_timeout = 0;
82                 return FALSE;
83         }
84
85         if (device->driver->scan)
86                 device->driver->scan(device);
87
88         return TRUE;
89 }
90
91 static void clear_scan_trigger(struct connman_device *device)
92 {
93         if (device->scan_timeout > 0) {
94                 g_source_remove(device->scan_timeout);
95                 device->scan_timeout = 0;
96         }
97 }
98
99 static void clear_pending_trigger(struct connman_device *device)
100 {
101         if (device->pending_timeout > 0) {
102                 g_source_remove(device->pending_timeout);
103                 device->pending_timeout = 0;
104         }
105 }
106
107 static void reset_scan_trigger(struct connman_device *device)
108 {
109         clear_scan_trigger(device);
110
111         if (device->scan_interval > 0) {
112                 guint interval;
113
114                 if (g_hash_table_size(device->networks) == 0) {
115                         if (device->backoff_interval >= device->scan_interval)
116                                 device->backoff_interval = SCAN_INITIAL_DELAY;
117                         interval = device->backoff_interval;
118                 } else
119                         interval = device->scan_interval;
120
121                 DBG("interval %d", interval);
122
123                 device->scan_timeout = g_timeout_add_seconds(interval,
124                                         device_scan_trigger, device);
125
126                 device->backoff_interval *= 2;
127                 if (device->backoff_interval > device->scan_interval)
128                         device->backoff_interval = device->scan_interval;
129         }
130 }
131
132 static void force_scan_trigger(struct connman_device *device)
133 {
134         clear_scan_trigger(device);
135
136         device->scan_timeout = g_timeout_add_seconds(5,
137                                         device_scan_trigger, device);
138 }
139
140 void connman_device_schedule_scan(struct connman_device *device)
141 {
142         reset_scan_trigger(device);
143 }
144
145 static const char *type2description(enum connman_device_type type)
146 {
147         switch (type) {
148         case CONNMAN_DEVICE_TYPE_UNKNOWN:
149         case CONNMAN_DEVICE_TYPE_VENDOR:
150                 break;
151         case CONNMAN_DEVICE_TYPE_ETHERNET:
152                 return "Ethernet";
153         case CONNMAN_DEVICE_TYPE_WIFI:
154                 return "Wireless";
155         case CONNMAN_DEVICE_TYPE_WIMAX:
156                 return "WiMAX";
157         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
158                 return "Bluetooth";
159         case CONNMAN_DEVICE_TYPE_GPS:
160                 return "GPS";
161         case CONNMAN_DEVICE_TYPE_CELLULAR:
162                 return "Cellular";
163         case CONNMAN_DEVICE_TYPE_GADGET:
164                 return "Gadget";
165
166         }
167
168         return NULL;
169 }
170
171 static const char *type2string(enum connman_device_type type)
172 {
173         switch (type) {
174         case CONNMAN_DEVICE_TYPE_UNKNOWN:
175         case CONNMAN_DEVICE_TYPE_VENDOR:
176                 break;
177         case CONNMAN_DEVICE_TYPE_ETHERNET:
178                 return "ethernet";
179         case CONNMAN_DEVICE_TYPE_WIFI:
180                 return "wifi";
181         case CONNMAN_DEVICE_TYPE_WIMAX:
182                 return "wimax";
183         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
184                 return "bluetooth";
185         case CONNMAN_DEVICE_TYPE_GPS:
186                 return "gps";
187         case CONNMAN_DEVICE_TYPE_CELLULAR:
188                 return "cellular";
189         case CONNMAN_DEVICE_TYPE_GADGET:
190                 return "gadget";
191
192         }
193
194         return NULL;
195 }
196
197 enum connman_service_type __connman_device_get_service_type(struct connman_device *device)
198 {
199         enum connman_device_type type = connman_device_get_type(device);
200
201         switch (type) {
202         case CONNMAN_DEVICE_TYPE_UNKNOWN:
203         case CONNMAN_DEVICE_TYPE_VENDOR:
204         case CONNMAN_DEVICE_TYPE_GPS:
205                 break;
206         case CONNMAN_DEVICE_TYPE_ETHERNET:
207                 return CONNMAN_SERVICE_TYPE_ETHERNET;
208         case CONNMAN_DEVICE_TYPE_WIFI:
209                 return CONNMAN_SERVICE_TYPE_WIFI;
210         case CONNMAN_DEVICE_TYPE_WIMAX:
211                 return CONNMAN_SERVICE_TYPE_WIMAX;
212         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
213                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
214         case CONNMAN_DEVICE_TYPE_CELLULAR:
215                 return CONNMAN_SERVICE_TYPE_CELLULAR;
216         case CONNMAN_DEVICE_TYPE_GADGET:
217                 return CONNMAN_SERVICE_TYPE_GADGET;
218
219         }
220
221         return CONNMAN_SERVICE_TYPE_UNKNOWN;
222 }
223
224 static gboolean device_pending_reset(gpointer user_data)
225 {
226         struct connman_device *device = user_data;
227
228         DBG("device %p", device);
229
230         /* Power request timedout, reset power pending state. */
231         device->pending_timeout = 0;
232         device->powered_pending = PENDING_NONE;
233
234         return FALSE;
235 }
236
237 int __connman_device_enable(struct connman_device *device)
238 {
239         int err;
240
241         DBG("device %p", device);
242
243         if (!device->driver || !device->driver->enable)
244                 return -EOPNOTSUPP;
245
246         /* There is an ongoing power disable request. */
247         if (device->powered_pending == PENDING_DISABLE)
248                 return -EBUSY;
249
250         if (device->powered_pending == PENDING_ENABLE)
251                 return -EALREADY;
252
253         if (device->powered_pending == PENDING_NONE && device->powered == TRUE)
254                 return -EALREADY;
255
256         device->powered_pending = PENDING_ENABLE;
257
258         err = device->driver->enable(device);
259         /*
260          * device gets enabled right away.
261          * Invoke the callback
262          */
263         if (err == 0) {
264                 connman_device_set_powered(device, TRUE);
265                 goto done;
266         }
267
268         if (err == -EALREADY) {
269                 /* If device is already powered, but connman is not updated */
270                 connman_device_set_powered(device, TRUE);
271                 goto done;
272         }
273         /*
274          * if err == -EINPROGRESS, then the DBus call to the respective daemon
275          * was successful. We set a 4 sec timeout so if the daemon never
276          * returns a reply, we would reset the pending request.
277          */
278         if (err == -EINPROGRESS)
279                 device->pending_timeout = g_timeout_add_seconds(4,
280                                         device_pending_reset, device);
281 done:
282         return err;
283 }
284
285 int __connman_device_disable(struct connman_device *device)
286 {
287         int err;
288
289         DBG("device %p", device);
290
291         if (!device->driver || !device->driver->disable)
292                 return -EOPNOTSUPP;
293
294         /* Ongoing power enable request */
295         if (device->powered_pending == PENDING_ENABLE)
296                 return -EBUSY;
297
298         if (device->powered_pending == PENDING_DISABLE)
299                 return -EALREADY;
300
301         if (device->powered_pending == PENDING_NONE && device->powered == FALSE)
302                 return -EALREADY;
303
304         device->powered_pending = PENDING_DISABLE;
305         device->reconnect = FALSE;
306
307         clear_scan_trigger(device);
308
309         if (device->network) {
310                 struct connman_service *service =
311                         __connman_service_lookup_from_network(device->network);
312
313                 if (service != NULL)
314                         __connman_service_disconnect(service);
315                 else
316                         connman_network_set_connected(device->network, FALSE);
317         }
318
319         err = device->driver->disable(device);
320         if (err == 0) {
321                 connman_device_set_powered(device, FALSE);
322                 goto done;
323         }
324
325         if (err == -EALREADY) {
326                 connman_device_set_powered(device, FALSE);
327                 goto done;
328         }
329
330         if (err == -EINPROGRESS)
331                 device->pending_timeout = g_timeout_add_seconds(4,
332                                         device_pending_reset, device);
333 done:
334         return err;
335 }
336
337 static void probe_driver(struct connman_device_driver *driver)
338 {
339         GSList *list;
340
341         DBG("driver %p name %s", driver, driver->name);
342
343         for (list = device_list; list != NULL; list = list->next) {
344                 struct connman_device *device = list->data;
345
346                 if (device->driver != NULL)
347                         continue;
348
349                 if (driver->type != device->type)
350                         continue;
351
352                 if (driver->probe(device) < 0)
353                         continue;
354
355                 device->driver = driver;
356
357                 __connman_technology_add_device(device);
358         }
359 }
360
361 static void remove_device(struct connman_device *device)
362 {
363         DBG("device %p", device);
364
365         __connman_device_disable(device);
366
367         __connman_technology_remove_device(device);
368
369         if (device->driver->remove)
370                 device->driver->remove(device);
371
372         device->driver = NULL;
373 }
374
375 static void remove_driver(struct connman_device_driver *driver)
376 {
377         GSList *list;
378
379         DBG("driver %p name %s", driver, driver->name);
380
381         for (list = device_list; list != NULL; list = list->next) {
382                 struct connman_device *device = list->data;
383
384                 if (device->driver == driver)
385                         remove_device(device);
386         }
387 }
388
389 connman_bool_t __connman_device_has_driver(struct connman_device *device)
390 {
391         if (device == NULL || device->driver == NULL)
392                 return FALSE;
393
394         return TRUE;
395 }
396
397 static GSList *driver_list = NULL;
398
399 static gint compare_priority(gconstpointer a, gconstpointer b)
400 {
401         const struct connman_device_driver *driver1 = a;
402         const struct connman_device_driver *driver2 = b;
403
404         return driver2->priority - driver1->priority;
405 }
406
407 /**
408  * connman_device_driver_register:
409  * @driver: device driver definition
410  *
411  * Register a new device driver
412  *
413  * Returns: %0 on success
414  */
415 int connman_device_driver_register(struct connman_device_driver *driver)
416 {
417         DBG("driver %p name %s", driver, driver->name);
418
419         driver_list = g_slist_insert_sorted(driver_list, driver,
420                                                         compare_priority);
421         probe_driver(driver);
422
423         return 0;
424 }
425
426 /**
427  * connman_device_driver_unregister:
428  * @driver: device driver definition
429  *
430  * Remove a previously registered device driver
431  */
432 void connman_device_driver_unregister(struct connman_device_driver *driver)
433 {
434         DBG("driver %p name %s", driver, driver->name);
435
436         driver_list = g_slist_remove(driver_list, driver);
437
438         remove_driver(driver);
439 }
440
441 static void free_network(gpointer data)
442 {
443         struct connman_network *network = data;
444
445         DBG("network %p", network);
446
447         __connman_network_set_device(network, NULL);
448
449         connman_network_unref(network);
450 }
451
452 static void device_destruct(struct connman_device *device)
453 {
454         DBG("device %p name %s", device, device->name);
455
456         clear_pending_trigger(device);
457         clear_scan_trigger(device);
458
459         g_free(device->ident);
460         g_free(device->node);
461         g_free(device->name);
462         g_free(device->address);
463         g_free(device->interface);
464         g_free(device->path);
465         g_free(device->devname);
466
467         g_free(device->last_network);
468
469         g_hash_table_destroy(device->networks);
470         device->networks = NULL;
471
472         g_free(device);
473 }
474
475 /**
476  * connman_device_create:
477  * @node: device node name (for example an address)
478  * @type: device type
479  *
480  * Allocate a new device of given #type and assign the #node name to it.
481  *
482  * Returns: a newly-allocated #connman_device structure
483  */
484 struct connman_device *connman_device_create(const char *node,
485                                                 enum connman_device_type type)
486 {
487         struct connman_device *device;
488         connman_bool_t bg_scan;
489
490         DBG("node %s type %d", node, type);
491
492         device = g_try_new0(struct connman_device, 1);
493         if (device == NULL)
494                 return NULL;
495
496         DBG("device %p", device);
497
498         device->refcount = 1;
499
500         bg_scan = connman_setting_get_bool("BackgroundScanning");
501
502         device->type = type;
503         device->name = g_strdup(type2description(device->type));
504
505         device->phyindex = -1;
506
507         device->backoff_interval = SCAN_INITIAL_DELAY;
508
509         switch (type) {
510         case CONNMAN_DEVICE_TYPE_UNKNOWN:
511         case CONNMAN_DEVICE_TYPE_ETHERNET:
512         case CONNMAN_DEVICE_TYPE_WIMAX:
513         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
514         case CONNMAN_DEVICE_TYPE_CELLULAR:
515         case CONNMAN_DEVICE_TYPE_GPS:
516         case CONNMAN_DEVICE_TYPE_GADGET:
517         case CONNMAN_DEVICE_TYPE_VENDOR:
518                 device->scan_interval = 0;
519                 break;
520         case CONNMAN_DEVICE_TYPE_WIFI:
521                 if (bg_scan == TRUE)
522                         device->scan_interval = 300;
523                 else
524                         device->scan_interval = 0;
525                 break;
526         }
527
528         device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
529                                                 g_free, free_network);
530
531         device_list = g_slist_append(device_list, device);
532
533         return device;
534 }
535
536 /**
537  * connman_device_ref:
538  * @device: device structure
539  *
540  * Increase reference counter of device
541  */
542 struct connman_device *connman_device_ref_debug(struct connman_device *device,
543                                 const char *file, int line, const char *caller)
544 {
545         DBG("%p ref %d by %s:%d:%s()", device, device->refcount + 1,
546                 file, line, caller);
547
548         __sync_fetch_and_add(&device->refcount, 1);
549
550         return device;
551 }
552
553 /**
554  * connman_device_unref:
555  * @device: device structure
556  *
557  * Decrease reference counter of device
558  */
559 void connman_device_unref_debug(struct connman_device *device,
560                                 const char *file, int line, const char *caller)
561 {
562         DBG("%p ref %d by %s:%d:%s()", device, device->refcount - 1,
563                 file, line, caller);
564
565         if (__sync_fetch_and_sub(&device->refcount, 1) != 1)
566                 return;
567
568         if (device->driver) {
569                 device->driver->remove(device);
570                 device->driver = NULL;
571         }
572
573         device_list = g_slist_remove(device_list, device);
574
575         device_destruct(device);
576 }
577
578 const char *__connman_device_get_type(struct connman_device *device)
579 {
580         return type2string(device->type);
581 }
582
583 /**
584  * connman_device_get_type:
585  * @device: device structure
586  *
587  * Get type of device
588  */
589 enum connman_device_type connman_device_get_type(struct connman_device *device)
590 {
591         return device->type;
592 }
593
594 /**
595  * connman_device_set_index:
596  * @device: device structure
597  * @index: index number
598  *
599  * Set index number of device
600  */
601 void connman_device_set_index(struct connman_device *device, int index)
602 {
603         device->index = index;
604 }
605
606 /**
607  * connman_device_get_index:
608  * @device: device structure
609  *
610  * Get index number of device
611  */
612 int connman_device_get_index(struct connman_device *device)
613 {
614         return device->index;
615 }
616
617 int __connman_device_get_phyindex(struct connman_device *device)
618 {
619         return device->phyindex;
620 }
621
622 void __connman_device_set_phyindex(struct connman_device *device,
623                                                         int phyindex)
624 {
625         device->phyindex = phyindex;
626 }
627
628 /**
629  * connman_device_set_interface:
630  * @device: device structure
631  * @interface: interface name
632  *
633  * Set interface name of device
634  */
635 void connman_device_set_interface(struct connman_device *device,
636                                                 const char *interface)
637 {
638         g_free(device->devname);
639         device->devname = g_strdup(interface);
640
641         g_free(device->interface);
642         device->interface = g_strdup(interface);
643
644         if (device->name == NULL) {
645                 const char *str = type2description(device->type);
646                 if (str != NULL && device->interface != NULL)
647                         device->name = g_strdup_printf("%s (%s)", str,
648                                                         device->interface);
649         }
650 }
651
652 /**
653  * connman_device_set_ident:
654  * @device: device structure
655  * @ident: unique identifier
656  *
657  * Set unique identifier of device
658  */
659 void connman_device_set_ident(struct connman_device *device,
660                                                         const char *ident)
661 {
662         g_free(device->ident);
663         device->ident = g_strdup(ident);
664 }
665
666 const char *connman_device_get_ident(struct connman_device *device)
667 {
668         return device->ident;
669 }
670
671 /**
672  * connman_device_set_powered:
673  * @device: device structure
674  * @powered: powered state
675  *
676  * Change power state of device
677  */
678 int connman_device_set_powered(struct connman_device *device,
679                                                 connman_bool_t powered)
680 {
681         enum connman_service_type type;
682
683         DBG("driver %p powered %d", device, powered);
684
685         if (device->powered == powered)
686                 return -EALREADY;
687
688         clear_pending_trigger(device);
689
690         device->powered_pending = PENDING_NONE;
691
692         device->powered = powered;
693
694         type = __connman_device_get_service_type(device);
695
696         if (device->powered == TRUE)
697                 __connman_technology_enabled(type);
698         else
699                 __connman_technology_disabled(type);
700
701         if (powered == FALSE)
702                 return 0;
703
704         connman_device_set_disconnected(device, FALSE);
705         device->scanning = FALSE;
706
707         reset_scan_trigger(device);
708
709         if (device->driver && device->driver->scan_fast)
710                 device->driver->scan_fast(device);
711         else if (device->driver && device->driver->scan)
712                 device->driver->scan(device);
713
714         return 0;
715 }
716
717 static int device_scan(struct connman_device *device)
718 {
719         if (!device->driver || !device->driver->scan)
720                 return -EOPNOTSUPP;
721
722         if (device->powered == FALSE)
723                 return -ENOLINK;
724
725         reset_scan_trigger(device);
726
727         return device->driver->scan(device);
728 }
729
730 int __connman_device_disconnect(struct connman_device *device)
731 {
732         GHashTableIter iter;
733         gpointer key, value;
734
735         DBG("device %p", device);
736
737         connman_device_set_disconnected(device, TRUE);
738
739         g_hash_table_iter_init(&iter, device->networks);
740
741         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
742                 struct connman_network *network = value;
743
744                 if (connman_network_get_connecting(network) == TRUE) {
745                         /*
746                          * Skip network in the process of connecting.
747                          * This is a workaround for WiFi networks serviced
748                          * by the supplicant plugin that hold a reference
749                          * to the network.  If we disconnect the network
750                          * here then the referenced object will not be
751                          * registered and usage (like launching DHCP client)
752                          * will fail.  There is nothing to be gained by
753                          * removing the network here anyway.
754                          */
755                         connman_warn("Skipping disconnect of %s, network is connecting.",
756                                 connman_network_get_identifier(network));
757                         continue;
758                 }
759
760                 __connman_network_disconnect(network);
761         }
762
763         return 0;
764 }
765
766 static void mark_network_available(gpointer key, gpointer value,
767                                                         gpointer user_data)
768 {
769         struct connman_network *network = value;
770
771         connman_network_set_available(network, TRUE);
772 }
773
774 static void mark_network_unavailable(gpointer key, gpointer value,
775                                                         gpointer user_data)
776 {
777         struct connman_network *network = value;
778
779         if (connman_network_get_connected(network) == TRUE)
780                 return;
781
782         connman_network_set_available(network, FALSE);
783 }
784
785 static gboolean remove_unavailable_network(gpointer key, gpointer value,
786                                                         gpointer user_data)
787 {
788         struct connman_network *network = value;
789
790         if (connman_network_get_connected(network) == TRUE)
791                 return FALSE;
792
793         if (connman_network_get_available(network) == TRUE)
794                 return FALSE;
795
796         return TRUE;
797 }
798
799 void __connman_device_cleanup_networks(struct connman_device *device)
800 {
801         g_hash_table_foreach_remove(device->networks,
802                                         remove_unavailable_network, NULL);
803 }
804
805 connman_bool_t __connman_device_scanning(struct connman_device *device)
806 {
807         return device->scanning;
808 }
809
810 void connman_device_reset_scanning(struct connman_device *device)
811 {
812         device->scanning = FALSE;
813
814         g_hash_table_foreach(device->networks,
815                                 mark_network_available, NULL);
816
817 }
818
819 /**
820  * connman_device_set_scanning:
821  * @device: device structure
822  * @scanning: scanning state
823  *
824  * Change scanning state of device
825  */
826 int connman_device_set_scanning(struct connman_device *device,
827                                                 connman_bool_t scanning)
828 {
829         DBG("device %p scanning %d", device, scanning);
830
831         if (!device->driver || !device->driver->scan)
832                 return -EINVAL;
833
834         if (device->scanning == scanning)
835                 return -EALREADY;
836
837         device->scanning = scanning;
838
839         if (scanning == TRUE) {
840                 __connman_technology_scan_started(device);
841
842                 reset_scan_trigger(device);
843
844                 g_hash_table_foreach(device->networks,
845                                         mark_network_unavailable, NULL);
846
847                 return 0;
848         }
849
850         __connman_device_cleanup_networks(device);
851
852         __connman_technology_scan_stopped(device);
853
854         __connman_service_auto_connect();
855
856         return 0;
857 }
858
859 /**
860  * connman_device_set_disconnected:
861  * @device: device structure
862  * @disconnected: disconnected state
863  *
864  * Change disconnected state of device (only for device with networks)
865  */
866 int connman_device_set_disconnected(struct connman_device *device,
867                                                 connman_bool_t disconnected)
868 {
869         DBG("device %p disconnected %d", device, disconnected);
870
871         if (device->disconnected == disconnected)
872                 return -EALREADY;
873
874         device->disconnected = disconnected;
875
876         if (disconnected == TRUE)
877         {
878                 force_scan_trigger(device);
879                 device->backoff_interval = SCAN_INITIAL_DELAY;
880         }
881
882         return 0;
883 }
884
885 /**
886  * connman_device_get_disconnected:
887  * @device: device structure
888  *
889  * Get device disconnected state
890  */
891 connman_bool_t connman_device_get_disconnected(struct connman_device *device)
892 {
893         return device->disconnected;
894 }
895
896 /**
897  * connman_device_set_string:
898  * @device: device structure
899  * @key: unique identifier
900  * @value: string value
901  *
902  * Set string value for specific key
903  */
904 int connman_device_set_string(struct connman_device *device,
905                                         const char *key, const char *value)
906 {
907         DBG("device %p key %s value %s", device, key, value);
908
909         if (g_str_equal(key, "Address") == TRUE) {
910                 g_free(device->address);
911                 device->address = g_strdup(value);
912         } else if (g_str_equal(key, "Name") == TRUE) {
913                 g_free(device->name);
914                 device->name = g_strdup(value);
915         } else if (g_str_equal(key, "Node") == TRUE) {
916                 g_free(device->node);
917                 device->node = g_strdup(value);
918         } else if (g_str_equal(key, "Path") == TRUE) {
919                 g_free(device->path);
920                 device->path = g_strdup(value);
921         } else {
922                 return -EINVAL;
923         }
924
925         return 0;
926 }
927
928 /**
929  * connman_device_get_string:
930  * @device: device structure
931  * @key: unique identifier
932  *
933  * Get string value for specific key
934  */
935 const char *connman_device_get_string(struct connman_device *device,
936                                                         const char *key)
937 {
938         DBG("device %p key %s", device, key);
939
940         if (g_str_equal(key, "Address") == TRUE)
941                 return device->address;
942         else if (g_str_equal(key, "Name") == TRUE)
943                 return device->name;
944         else if (g_str_equal(key, "Node") == TRUE)
945                 return device->node;
946         else if (g_str_equal(key, "Interface") == TRUE)
947                 return device->interface;
948         else if (g_str_equal(key, "Path") == TRUE)
949                 return device->path;
950
951         return NULL;
952 }
953
954 /**
955  * connman_device_add_network:
956  * @device: device structure
957  * @network: network structure
958  *
959  * Add new network to the device
960  */
961 int connman_device_add_network(struct connman_device *device,
962                                         struct connman_network *network)
963 {
964         const char *identifier = connman_network_get_identifier(network);
965
966         DBG("device %p network %p", device, network);
967
968         if (identifier == NULL)
969                 return -EINVAL;
970
971         connman_network_ref(network);
972
973         __connman_network_set_device(network, device);
974
975         g_hash_table_replace(device->networks, g_strdup(identifier),
976                                                                 network);
977
978         return 0;
979 }
980
981 /**
982  * connman_device_get_network:
983  * @device: device structure
984  * @identifier: network identifier
985  *
986  * Get network for given identifier
987  */
988 struct connman_network *connman_device_get_network(struct connman_device *device,
989                                                         const char *identifier)
990 {
991         DBG("device %p identifier %s", device, identifier);
992
993         return g_hash_table_lookup(device->networks, identifier);
994 }
995
996 /**
997  * connman_device_remove_network:
998  * @device: device structure
999  * @identifier: network identifier
1000  *
1001  * Remove network for given identifier
1002  */
1003 int connman_device_remove_network(struct connman_device *device,
1004                                                 struct connman_network *network)
1005 {
1006         const char *identifier;
1007
1008         DBG("device %p network %p", device, network);
1009
1010         if (network == NULL)
1011                 return 0;
1012
1013         identifier = connman_network_get_identifier(network);
1014         g_hash_table_remove(device->networks, identifier);
1015
1016         return 0;
1017 }
1018
1019 void connman_device_remove_all_networks(struct connman_device *device)
1020 {
1021         g_hash_table_remove_all(device->networks);
1022 }
1023
1024 void __connman_device_set_network(struct connman_device *device,
1025                                         struct connman_network *network)
1026 {
1027         const char *name;
1028
1029         if (device == NULL)
1030                 return;
1031
1032         if (device->network == network)
1033                 return;
1034
1035         if (network != NULL) {
1036                 name = connman_network_get_string(network, "Name");
1037                 g_free(device->last_network);
1038                 device->last_network = g_strdup(name);
1039
1040                 device->network = network;
1041         } else {
1042                 g_free(device->last_network);
1043                 device->last_network = NULL;
1044
1045                 device->network = NULL;
1046         }
1047 }
1048
1049 void __connman_device_set_reconnect(struct connman_device *device,
1050                                                 connman_bool_t reconnect)
1051 {
1052         device->reconnect = reconnect;
1053 }
1054
1055 connman_bool_t  __connman_device_get_reconnect(
1056                                 struct connman_device *device)
1057 {
1058         return device->reconnect;
1059 }
1060
1061 static gboolean match_driver(struct connman_device *device,
1062                                         struct connman_device_driver *driver)
1063 {
1064         if (device->type == driver->type ||
1065                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
1066                 return TRUE;
1067
1068         return FALSE;
1069 }
1070
1071 /**
1072  * connman_device_register:
1073  * @device: device structure
1074  *
1075  * Register device with the system
1076  */
1077 int connman_device_register(struct connman_device *device)
1078 {
1079         GSList *list;
1080
1081         DBG("device %p name %s", device, device->name);
1082
1083         if (device->driver != NULL)
1084                 return -EALREADY;
1085
1086         for (list = driver_list; list; list = list->next) {
1087                 struct connman_device_driver *driver = list->data;
1088
1089                 if (match_driver(device, driver) == FALSE)
1090                         continue;
1091
1092                 DBG("driver %p name %s", driver, driver->name);
1093
1094                 if (driver->probe(device) == 0) {
1095                         device->driver = driver;
1096                         break;
1097                 }
1098         }
1099
1100         if (device->driver == NULL)
1101                 return 0;
1102
1103         return __connman_technology_add_device(device);
1104 }
1105
1106 /**
1107  * connman_device_unregister:
1108  * @device: device structure
1109  *
1110  * Unregister device with the system
1111  */
1112 void connman_device_unregister(struct connman_device *device)
1113 {
1114         DBG("device %p name %s", device, device->name);
1115
1116         if (device->driver == NULL)
1117                 return;
1118
1119         remove_device(device);
1120 }
1121
1122 /**
1123  * connman_device_get_data:
1124  * @device: device structure
1125  *
1126  * Get private device data pointer
1127  */
1128 void *connman_device_get_data(struct connman_device *device)
1129 {
1130         return device->driver_data;
1131 }
1132
1133 /**
1134  * connman_device_set_data:
1135  * @device: device structure
1136  * @data: data pointer
1137  *
1138  * Set private device data pointer
1139  */
1140 void connman_device_set_data(struct connman_device *device, void *data)
1141 {
1142         device->driver_data = data;
1143 }
1144
1145 struct connman_device *__connman_device_find_device(
1146                                 enum connman_service_type type)
1147 {
1148         GSList *list;
1149
1150         for (list = device_list; list != NULL; list = list->next) {
1151                 struct connman_device *device = list->data;
1152                 enum connman_service_type service_type =
1153                         __connman_device_get_service_type(device);
1154
1155                 if (service_type != type)
1156                         continue;
1157
1158                 return device;
1159         }
1160
1161         return NULL;
1162 }
1163
1164 int __connman_device_request_scan(enum connman_service_type type)
1165 {
1166         connman_bool_t success = FALSE;
1167         int last_err = -ENOSYS;
1168         GSList *list;
1169         int err;
1170
1171         switch (type) {
1172         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1173         case CONNMAN_SERVICE_TYPE_SYSTEM:
1174         case CONNMAN_SERVICE_TYPE_ETHERNET:
1175         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1176         case CONNMAN_SERVICE_TYPE_CELLULAR:
1177         case CONNMAN_SERVICE_TYPE_GPS:
1178         case CONNMAN_SERVICE_TYPE_VPN:
1179         case CONNMAN_SERVICE_TYPE_GADGET:
1180                 return -EOPNOTSUPP;
1181         case CONNMAN_SERVICE_TYPE_WIFI:
1182         case CONNMAN_SERVICE_TYPE_WIMAX:
1183                 break;
1184         }
1185
1186         for (list = device_list; list != NULL; list = list->next) {
1187                 struct connman_device *device = list->data;
1188                 enum connman_service_type service_type =
1189                         __connman_device_get_service_type(device);
1190
1191                 if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN &&
1192                                 service_type != type) {
1193                         continue;
1194                 }
1195
1196                 err = device_scan(device);
1197                 if (err == 0 || err == -EALREADY || err == -EINPROGRESS) {
1198                         success = TRUE;
1199                 } else {
1200                         last_err = err;
1201                         DBG("device %p err %d", device, err);
1202                 }
1203         }
1204
1205         if (success == TRUE)
1206                 return 0;
1207
1208         return last_err;
1209 }
1210
1211 int __connman_device_request_hidden_scan(struct connman_device *device,
1212                                 const char *ssid, unsigned int ssid_len,
1213                                 const char *identity, const char *passphrase)
1214 {
1215         DBG("device %p", device);
1216
1217         if (device == NULL || device->driver == NULL ||
1218                         device->driver->scan_hidden == NULL)
1219                 return -EINVAL;
1220
1221         if (device->scanning == TRUE)
1222                 return -EALREADY;
1223
1224         return device->driver->scan_hidden(device, ssid, ssid_len,
1225                                         identity, passphrase);
1226 }
1227
1228 connman_bool_t __connman_device_isfiltered(const char *devname)
1229 {
1230         char **pattern;
1231
1232         if (device_filter == NULL)
1233                 goto nodevice;
1234
1235         for (pattern = device_filter; *pattern; pattern++) {
1236                 if (g_pattern_match_simple(*pattern, devname) == FALSE) {
1237                         DBG("ignoring device %s (match)", devname);
1238                         return TRUE;
1239                 }
1240         }
1241
1242 nodevice:
1243         if (g_pattern_match_simple("dummy*", devname) == TRUE) {
1244                 DBG("ignoring dummy networking devices");
1245                 return TRUE;
1246         }
1247
1248         if (nodevice_filter == NULL)
1249                 return FALSE;
1250
1251         for (pattern = nodevice_filter; *pattern; pattern++) {
1252                 if (g_pattern_match_simple(*pattern, devname) == TRUE) {
1253                         DBG("ignoring device %s (no match)", devname);
1254                         return TRUE;
1255                 }
1256         }
1257
1258         return FALSE;
1259 }
1260
1261 int __connman_device_init(const char *device, const char *nodevice)
1262 {
1263         DBG("");
1264
1265         if (device != NULL)
1266                 device_filter = g_strsplit(device, ",", -1);
1267
1268         if (nodevice != NULL)
1269                 nodevice_filter = g_strsplit(nodevice, ",", -1);
1270
1271         return 0;
1272 }
1273
1274 void __connman_device_cleanup(void)
1275 {
1276         DBG("");
1277
1278         g_strfreev(nodevice_filter);
1279         g_strfreev(device_filter);
1280 }