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