Add function to get index value from DHCP structure
[framework/connectivity/connman.git] / src / network.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  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 <gdbus.h>
30
31 #include "connman.h"
32
33 static unsigned int hidden_counter = 0;
34
35 struct connman_network {
36         struct connman_element element;
37         enum connman_network_type type;
38         enum connman_network_protocol protocol;
39         connman_bool_t secondary;
40         connman_bool_t available;
41         connman_bool_t connected;
42         connman_bool_t roaming;
43         connman_bool_t hidden;
44         connman_uint8_t strength;
45         connman_uint16_t frequency;
46         char *identifier;
47         char *address;
48         char *name;
49         char *node;
50         char *group;
51         struct connman_ipconfig *ipconfig;
52
53         struct connman_network_driver *driver;
54         void *driver_data;
55
56         connman_bool_t registered;
57         connman_bool_t connecting;
58         connman_bool_t associating;
59
60         struct connman_device *device;
61
62         struct {
63                 void *ssid;
64                 int ssid_len;
65                 char *mode;
66                 unsigned short channel;
67                 char *security;
68                 char *passphrase;
69         } wifi;
70 };
71
72 static const char *type2string(enum connman_network_type type)
73 {
74         switch (type) {
75         case CONNMAN_NETWORK_TYPE_UNKNOWN:
76         case CONNMAN_NETWORK_TYPE_VENDOR:
77                 break;
78         case CONNMAN_NETWORK_TYPE_ETHERNET:
79                 return "ethernet";
80         case CONNMAN_NETWORK_TYPE_WIFI:
81                 return "wifi";
82         case CONNMAN_NETWORK_TYPE_WIMAX:
83                 return "wimax";
84         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
85         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
86                 return "bluetooth";
87         case CONNMAN_NETWORK_TYPE_CELLULAR:
88         case CONNMAN_NETWORK_TYPE_MBM:
89         case CONNMAN_NETWORK_TYPE_HSO:
90                 return "cellular";
91         }
92
93         return NULL;
94 }
95
96 static DBusMessage *get_properties(DBusConnection *conn,
97                                         DBusMessage *msg, void *data)
98 {
99         struct connman_network *network = data;
100         DBusMessage *reply;
101         DBusMessageIter array, dict;
102
103         DBG("conn %p", conn);
104
105         if (__connman_security_check_privilege(msg,
106                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
107                 return __connman_error_permission_denied(msg);
108
109         reply = dbus_message_new_method_return(msg);
110         if (reply == NULL)
111                 return NULL;
112
113         dbus_message_iter_init_append(reply, &array);
114
115         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
116                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
117                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
118                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
119
120         if (network->device) {
121                 const char *path = connman_device_get_path(network->device);
122                 if (path != NULL)
123                         connman_dbus_dict_append_variant(&dict, "Device",
124                                                 DBUS_TYPE_OBJECT_PATH, &path);
125         }
126
127         if (network->address != NULL)
128                 connman_dbus_dict_append_variant(&dict, "Address",
129                                         DBUS_TYPE_STRING, &network->address);
130
131         if (network->name != NULL)
132                 connman_dbus_dict_append_variant(&dict, "Name",
133                                         DBUS_TYPE_STRING, &network->name);
134
135         connman_dbus_dict_append_variant(&dict, "Connected",
136                                 DBUS_TYPE_BOOLEAN, &network->connected);
137
138         if (network->strength > 0)
139                 connman_dbus_dict_append_variant(&dict, "Strength",
140                                         DBUS_TYPE_BYTE, &network->strength);
141
142         if (network->frequency > 0)
143                 connman_dbus_dict_append_variant(&dict, "Frequency",
144                                         DBUS_TYPE_UINT16, &network->frequency);
145
146         if (network->wifi.ssid != NULL && network->wifi.ssid_len > 0)
147                 connman_dbus_dict_append_array(&dict, "WiFi.SSID",
148                                 DBUS_TYPE_BYTE, &network->wifi.ssid,
149                                                 network->wifi.ssid_len);
150
151         if (network->wifi.mode != NULL)
152                 connman_dbus_dict_append_variant(&dict, "WiFi.Mode",
153                                 DBUS_TYPE_STRING, &network->wifi.mode);
154
155         if (network->wifi.channel > 0)
156                 connman_dbus_dict_append_variant(&dict, "WiFi.Channel",
157                                 DBUS_TYPE_UINT16, &network->wifi.channel);
158
159         if (network->wifi.security != NULL)
160                 connman_dbus_dict_append_variant(&dict, "WiFi.Security",
161                                 DBUS_TYPE_STRING, &network->wifi.security);
162
163         if (network->wifi.passphrase != NULL &&
164                         __connman_security_check_privilege(msg,
165                                 CONNMAN_SECURITY_PRIVILEGE_SECRET) == 0)
166                 connman_dbus_dict_append_variant(&dict, "WiFi.Passphrase",
167                                 DBUS_TYPE_STRING, &network->wifi.passphrase);
168
169         dbus_message_iter_close_container(&array, &dict);
170
171         return reply;
172 }
173
174 static GDBusMethodTable network_methods[] = {
175         { "GetProperties", "",   "a{sv}", get_properties },
176         { },
177 };
178
179 static GDBusSignalTable network_signals[] = {
180         { "PropertyChanged", "sv" },
181         { },
182 };
183
184 static DBusConnection *connection;
185
186 static void append_networks(struct connman_device *device,
187                                                 DBusMessageIter *entry)
188 {
189         DBusMessageIter value, iter;
190         const char *key = "Networks";
191
192         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
193
194         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
195                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
196                                                                 &value);
197
198         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
199                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
200         __connman_element_list((struct connman_element *) device,
201                                         CONNMAN_ELEMENT_TYPE_NETWORK, &iter);
202         dbus_message_iter_close_container(&value, &iter);
203
204         dbus_message_iter_close_container(entry, &value);
205 }
206
207 static void emit_networks_signal(struct connman_device *device)
208 {
209         const char *path = connman_device_get_path(device);
210         DBusMessage *signal;
211         DBusMessageIter entry;
212
213         signal = dbus_message_new_signal(path,
214                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
215         if (signal == NULL)
216                 return;
217
218         dbus_message_iter_init_append(signal, &entry);
219
220         append_networks(device, &entry);
221
222         g_dbus_send_message(connection, signal);
223 }
224
225 static int register_interface(struct connman_element *element)
226 {
227         struct connman_network *network = element->network;
228
229         DBG("element %p name %s", element, element->name);
230
231         if (g_dbus_register_interface(connection, element->path,
232                                         CONNMAN_NETWORK_INTERFACE,
233                                         network_methods, network_signals,
234                                         NULL, network, NULL) == FALSE) {
235                 connman_error("Failed to register %s network", element->path);
236                 return -EIO;
237         }
238
239         network->registered = TRUE;
240
241         emit_networks_signal(network->device);
242
243         return 0;
244 }
245
246 static void unregister_interface(struct connman_element *element)
247 {
248         struct connman_network * network = element->network;
249
250         DBG("element %p name %s", element, element->name);
251
252         network->registered = FALSE;
253
254         emit_networks_signal(network->device);
255
256         g_dbus_unregister_interface(connection, element->path,
257                                                 CONNMAN_NETWORK_INTERFACE);
258 }
259
260 connman_bool_t __connman_network_has_driver(struct connman_network *network)
261 {
262         if (network == NULL || network->driver == NULL)
263                 return FALSE;
264
265         return network->registered;
266 }
267
268 static GSList *driver_list = NULL;
269
270 static gint compare_priority(gconstpointer a, gconstpointer b)
271 {
272         const struct connman_network_driver *driver1 = a;
273         const struct connman_network_driver *driver2 = b;
274
275         return driver2->priority - driver1->priority;
276 }
277
278 /**
279  * connman_network_driver_register:
280  * @driver: network driver definition
281  *
282  * Register a new network driver
283  *
284  * Returns: %0 on success
285  */
286 int connman_network_driver_register(struct connman_network_driver *driver)
287 {
288         DBG("driver %p name %s", driver, driver->name);
289
290         driver_list = g_slist_insert_sorted(driver_list, driver,
291                                                         compare_priority);
292
293         return 0;
294 }
295
296 /**
297  * connman_network_driver_unregister:
298  * @driver: network driver definition
299  *
300  * Remove a previously registered network driver
301  */
302 void connman_network_driver_unregister(struct connman_network_driver *driver)
303 {
304         DBG("driver %p name %s", driver, driver->name);
305
306         driver_list = g_slist_remove(driver_list, driver);
307 }
308
309 static void network_destruct(struct connman_element *element)
310 {
311         struct connman_network *network = element->network;
312
313         DBG("element %p name %s", element, element->name);
314
315         g_free(network->wifi.ssid);
316         g_free(network->wifi.mode);
317         g_free(network->wifi.security);
318         g_free(network->wifi.passphrase);
319
320         g_free(network->group);
321         g_free(network->node);
322         g_free(network->name);
323         g_free(network->address);
324         g_free(network->identifier);
325
326         if (network->ipconfig) {
327                 connman_ipconfig_unref(network->ipconfig);
328                 network->ipconfig = NULL;
329         }
330 }
331
332 /**
333  * connman_network_create:
334  * @identifier: network identifier (for example an unqiue name)
335  *
336  * Allocate a new network and assign the #identifier to it.
337  *
338  * Returns: a newly-allocated #connman_network structure
339  */
340 struct connman_network *connman_network_create(const char *identifier,
341                                                 enum connman_network_type type)
342 {
343         struct connman_network *network;
344         connman_uint8_t strength = 0;
345         const char *str;
346         char *temp;
347
348         DBG("identifier %s type %d", identifier, type);
349
350         network = g_try_new0(struct connman_network, 1);
351         if (network == NULL)
352                 return NULL;
353
354         DBG("network %p", network);
355
356         __connman_element_initialize(&network->element);
357
358         //temp = connman_dbus_encode_string(identifier);
359         if (identifier == NULL) {
360                 temp = g_strdup_printf("hidden_%d", hidden_counter++);
361                 network->hidden = TRUE;
362         } else
363                 temp = g_strdup(identifier);
364
365         if (temp == NULL) {
366                 g_free(network);
367                 return NULL;
368         }
369
370         network->element.name = temp;
371         network->element.type = CONNMAN_ELEMENT_TYPE_NETWORK;
372
373         network->element.network = network;
374         network->element.destruct = network_destruct;
375
376         str = type2string(type);
377         if (str != NULL)
378                 connman_element_set_string(&network->element, "Type", str);
379
380         connman_element_set_uint8(&network->element, "Strength", strength);
381
382         network->type       = type;
383         network->secondary  = FALSE;
384         network->identifier = g_strdup(temp);
385
386         return network;
387 }
388
389 /**
390  * connman_network_ref:
391  * @network: network structure
392  *
393  * Increase reference counter of  network
394  */
395 struct connman_network *connman_network_ref(struct connman_network *network)
396 {
397         if (connman_element_ref(&network->element) == NULL)
398                 return NULL;
399
400         return network;
401 }
402
403 /**
404  * connman_network_unref:
405  * @network: network structure
406  *
407  * Decrease reference counter of network
408  */
409 void connman_network_unref(struct connman_network *network)
410 {
411         connman_element_unref(&network->element);
412 }
413
414 const char *__connman_network_get_type(struct connman_network *network)
415 {
416         return type2string(network->type);
417 }
418
419 /**
420  * connman_network_get_type:
421  * @network: network structure
422  *
423  * Get type of network
424  */
425 enum connman_network_type connman_network_get_type(struct connman_network *network)
426 {
427         return network->type;
428 }
429
430 /**
431  * connman_network_get_identifier:
432  * @network: network structure
433  *
434  * Get identifier of network
435  */
436 const char *connman_network_get_identifier(struct connman_network *network)
437 {
438         return network->identifier;
439 }
440
441 /**
442  * connman_network_get_path:
443  * @network: network structure
444  *
445  * Get path name of network
446  */
447 const char *connman_network_get_path(struct connman_network *network)
448 {
449         return network->element.path;
450 }
451
452 /**
453  * connman_network_set_index:
454  * @network: network structure
455  * @index: index number
456  *
457  * Set index number of network
458  */
459 void connman_network_set_index(struct connman_network *network, int index)
460 {
461         network->element.index = index;
462 }
463
464 /**
465  * connman_network_get_index:
466  * @network: network structure
467  *
468  * Get index number of network
469  */
470 int connman_network_get_index(struct connman_network *network)
471 {
472         return network->element.index;
473 }
474
475 /**
476  * connman_network_set_protocol:
477  * @network: network structure
478  * @protocol: network protocol
479  *
480  * Change protocol of network
481  */
482 void connman_network_set_protocol(struct connman_network *network,
483                                         enum connman_network_protocol protocol)
484 {
485         network->protocol = protocol;
486 }
487
488 /**
489  * connman_network_set_group:
490  * @network: network structure
491  * @group: group name
492  *
493  * Set group name for automatic clustering
494  */
495 void connman_network_set_group(struct connman_network *network,
496                                                         const char *group)
497 {
498         if (network->secondary == TRUE)
499                 return;
500
501         switch (network->type) {
502         case CONNMAN_NETWORK_TYPE_UNKNOWN:
503         case CONNMAN_NETWORK_TYPE_VENDOR:
504                 return;
505         case CONNMAN_NETWORK_TYPE_ETHERNET:
506         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
507         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
508         case CONNMAN_NETWORK_TYPE_CELLULAR:
509         case CONNMAN_NETWORK_TYPE_MBM:
510         case CONNMAN_NETWORK_TYPE_HSO:
511         case CONNMAN_NETWORK_TYPE_WIFI:
512         case CONNMAN_NETWORK_TYPE_WIMAX:
513                 break;
514         }
515
516         if (g_strcmp0(network->group, group) == 0) {
517                 if (group != NULL)
518                         __connman_profile_update_network(network);
519                 return;
520         }
521
522         if (network->group != NULL) {
523                 __connman_profile_remove_network(network);
524
525                 g_free(network->group);
526         }
527
528         network->group = g_strdup(group);
529
530         if (network->group != NULL)
531                 __connman_profile_add_network(network);
532 }
533
534 /**
535  * connman_network_get_group:
536  * @network: network structure
537  *
538  * Get group name for automatic clustering
539  */
540 const char *connman_network_get_group(struct connman_network *network)
541 {
542         return network->group;
543 }
544
545 const char *__connman_network_get_ident(struct connman_network *network)
546 {
547         if (network->device == NULL)
548                 return NULL;
549
550         return __connman_device_get_ident(network->device);
551 }
552
553 connman_bool_t __connman_network_get_weakness(struct connman_network *network)
554 {
555         if (network->secondary == TRUE)
556                 return FALSE;
557
558         switch (network->type) {
559         case CONNMAN_NETWORK_TYPE_UNKNOWN:
560         case CONNMAN_NETWORK_TYPE_VENDOR:
561         case CONNMAN_NETWORK_TYPE_ETHERNET:
562         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
563         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
564         case CONNMAN_NETWORK_TYPE_CELLULAR:
565         case CONNMAN_NETWORK_TYPE_MBM:
566         case CONNMAN_NETWORK_TYPE_HSO:
567         case CONNMAN_NETWORK_TYPE_WIMAX:
568                 break;
569         case CONNMAN_NETWORK_TYPE_WIFI:
570                 if (network->strength > 0 && network->strength < 20)
571                         return TRUE;
572                 break;
573         }
574
575         return FALSE;
576 }
577
578 connman_bool_t __connman_network_get_connecting(struct connman_network *network)
579 {
580         return network->connecting;
581 }
582
583 /**
584  * connman_network_set_available:
585  * @network: network structure
586  * @available: availability state
587  *
588  * Change availability state of network (in range)
589  */
590 int connman_network_set_available(struct connman_network *network,
591                                                 connman_bool_t available)
592 {
593         DBG("network %p available %d", network, available);
594
595         if (network->available == available)
596                 return -EALREADY;
597
598         network->available = available;
599
600         return 0;
601 }
602
603 /**
604  * connman_network_get_available:
605  * @network: network structure
606  *
607  * Get network available setting
608  */
609 connman_bool_t connman_network_get_available(struct connman_network *network)
610 {
611         if (network->hidden == TRUE)
612                 return TRUE;
613
614         return network->available;
615 }
616
617 /**
618  * connman_network_set_associating:
619  * @network: network structure
620  * @associating: associating state
621  *
622  * Change associating state of network
623  */
624 int connman_network_set_associating(struct connman_network *network,
625                                                 connman_bool_t associating)
626 {
627         DBG("network %p associating %d", network, associating);
628
629         if (network->associating == associating)
630                 return -EALREADY;
631
632         network->associating = associating;
633
634         if (associating == TRUE) {
635                 struct connman_service *service;
636
637                 service = __connman_service_lookup_from_network(network);
638                 __connman_service_indicate_state(service,
639                                         CONNMAN_SERVICE_STATE_ASSOCIATION);
640         }
641
642         return 0;
643 }
644
645 static void set_associate_error(struct connman_network *network)
646 {
647         struct connman_service *service;
648
649         if (network->associating == FALSE)
650                 return ;
651
652         network->associating = FALSE;
653
654         service = __connman_service_lookup_from_network(network);
655
656         __connman_service_indicate_state(service,
657                                         CONNMAN_SERVICE_STATE_FAILURE);
658 }
659
660 void connman_network_set_error(struct connman_network *network,
661                                         enum connman_network_error error)
662 {
663         DBG("nework %p, error %d", network, error);
664
665         switch (error) {
666         case CONNMAN_NETWORK_ERROR_UNKNOWN:
667                 return;
668         case CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL:
669                 set_associate_error(network);
670                 break;
671         }
672 }
673
674 static gboolean set_connected(gpointer user_data)
675 {
676         struct connman_network *network = user_data;
677         struct connman_service *service;
678
679         service = __connman_service_lookup_from_network(network);
680
681         if (network->connected == TRUE) {
682                 struct connman_element *element;
683                 enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
684
685                 switch (network->protocol) {
686                 case CONNMAN_NETWORK_PROTOCOL_UNKNOWN:
687                         return 0;
688                 case CONNMAN_NETWORK_PROTOCOL_IP:
689                         type = CONNMAN_ELEMENT_TYPE_DHCP;
690                         break;
691                 }
692
693                 __connman_device_increase_connections(network->device);
694
695                 __connman_device_set_network(network->device, network);
696
697                 connman_device_set_disconnected(network->device, FALSE);
698
699                 element = connman_element_create(NULL);
700                 if (element != NULL) {
701                         element->type  = type;
702                         element->index = network->element.index;
703
704                         if (connman_element_register(element,
705                                                 &network->element) < 0)
706                                 connman_element_unref(element);
707
708                         __connman_service_indicate_state(service,
709                                         CONNMAN_SERVICE_STATE_CONFIGURATION);
710                 }
711         } else {
712                 connman_element_unregister_children(&network->element);
713
714                 __connman_device_set_network(network->device, NULL);
715                 network->hidden = FALSE;
716
717                 __connman_device_decrease_connections(network->device);
718
719                 __connman_service_indicate_state(service,
720                                                 CONNMAN_SERVICE_STATE_IDLE);
721         }
722
723         network->connecting = FALSE;
724
725         connman_network_set_associating(network, FALSE);
726
727         return FALSE;
728 }
729
730 /**
731  * connman_network_set_connected:
732  * @network: network structure
733  * @connected: connected state
734  *
735  * Change connected state of network
736  */
737 int connman_network_set_connected(struct connman_network *network,
738                                                 connman_bool_t connected)
739 {
740         DBusMessage *signal;
741         DBusMessageIter entry, value;
742         const char *key = "Connected";
743
744         DBG("network %p connected %d", network, connected);
745
746         if ((network->connecting == TRUE || network->associating == TRUE) &&
747                                                         connected == FALSE) {
748                 connman_element_set_error(&network->element,
749                                         CONNMAN_ELEMENT_ERROR_CONNECT_FAILED);
750                 __connman_network_disconnect(network);
751         }
752
753         if (network->connected == connected)
754                 return -EALREADY;
755
756         network->connected = connected;
757
758         if (network->registered == FALSE) {
759                 g_idle_add(set_connected, network);
760                 return 0;
761         }
762
763         signal = dbus_message_new_signal(network->element.path,
764                                 CONNMAN_NETWORK_INTERFACE, "PropertyChanged");
765         if (signal == NULL)
766                 return 0;
767
768         dbus_message_iter_init_append(signal, &entry);
769
770         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
771
772         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
773                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
774         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &connected);
775         dbus_message_iter_close_container(&entry, &value);
776
777         g_dbus_send_message(connection, signal);
778
779         set_connected(network);
780
781         return 0;
782 }
783
784 /**
785  * connman_network_get_connected:
786  * @network: network structure
787  *
788  * Get network connection status
789  */
790 connman_bool_t connman_network_get_connected(struct connman_network *network)
791 {
792         return network->connected;
793 }
794
795 /**
796  * connman_network_get_associating:
797  * @network: network structure
798  *
799  * Get network associating status
800  */
801 connman_bool_t connman_network_get_associating(struct connman_network *network)
802 {
803         return network->associating;
804 }
805
806 /**
807  * __connman_network_connect:
808  * @network: network structure
809  *
810  * Connect network
811  */
812 int __connman_network_connect(struct connman_network *network)
813 {
814         int err;
815
816         DBG("network %p", network);
817
818         if (network->connected == TRUE)
819                 return -EISCONN;
820
821         if (network->connecting == TRUE || network->associating == TRUE)
822                 return -EALREADY;
823
824         if (network->driver == NULL)
825                 return -EUNATCH;
826
827         if (network->driver->connect == NULL)
828                 return -ENOSYS;
829
830         __connman_device_disconnect(network->device);
831
832         network->connecting = TRUE;
833
834         err = network->driver->connect(network);
835         if (err < 0) {
836                 if (err == -EINPROGRESS)
837                         connman_network_set_associating(network, TRUE);
838                 else
839                         network->hidden = FALSE;
840
841                 return err;
842         }
843
844         network->connected = TRUE;
845         set_connected(network);
846
847         return err;
848 }
849
850 /**
851  * __connman_network_disconnect:
852  * @network: network structure
853  *
854  * Disconnect network
855  */
856 int __connman_network_disconnect(struct connman_network *network)
857 {
858         int err;
859
860         DBG("network %p", network);
861
862         if (network->connected == FALSE && network->connecting == FALSE &&
863                                                 network->associating == FALSE)
864                 return -ENOTCONN;
865
866         if (network->driver == NULL)
867                 return -EUNATCH;
868
869         if (network->driver->disconnect == NULL)
870                 return -ENOSYS;
871
872         network->connecting = FALSE;
873
874         err = network->driver->disconnect(network);
875         if (err == 0) {
876                 network->connected = FALSE;
877                 set_connected(network);
878         }
879
880         return err;
881 }
882
883 /**
884  * connman_network_set_address:
885  * @network: network structure
886  * @address: binary address value
887  * @size: binary address length
888  *
889  * Set unique address value for network
890  */
891 int connman_network_set_address(struct connman_network *network,
892                                 const void *address, unsigned int size)
893 {
894         const unsigned char *addr_octet = address;
895         char *str;
896
897         DBG("network %p size %d", network, size);
898
899         if (size != 6)
900                 return -EINVAL;
901
902         str = g_strdup_printf("%02X:%02X:%02X:%02X:%02X:%02X",
903                                 addr_octet[0], addr_octet[1], addr_octet[2],
904                                 addr_octet[3], addr_octet[4], addr_octet[5]);
905         if (str == NULL)
906                 return -ENOMEM;
907
908         g_free(network->address);
909         network->address = str;
910
911         return connman_element_set_string(&network->element,
912                                                 "Address", network->address);
913 }
914
915 /**
916  * connman_network_set_name:
917  * @network: network structure
918  * @name: name value
919  *
920  * Set display name value for network
921  */
922 int connman_network_set_name(struct connman_network *network,
923                                                         const char *name)
924 {
925         DBG("network %p name %s", network, name);
926
927         g_free(network->name);
928         network->name = g_strdup(name);
929
930         return connman_element_set_string(&network->element, "Name", name);
931 }
932
933 /**
934  * connman_network_set_strength:
935  * @network: network structure
936  * @strength: strength value
937  *
938  * Set signal strength value for network
939  */
940 int connman_network_set_strength(struct connman_network *network,
941                                                 connman_uint8_t strength)
942 {
943         DBG("network %p strengh %d", network, strength);
944
945         network->strength = strength;
946
947         return connman_element_set_uint8(&network->element,
948                                                 "Strength", strength);
949 }
950
951 /**
952  * connman_network_set_roaming:
953  * @network: network structure
954  * @roaming: roaming state
955  *
956  * Set roaming state for network
957  */
958 int connman_network_set_roaming(struct connman_network *network,
959                                                 connman_bool_t roaming)
960 {
961         DBG("network %p roaming %d", network, roaming);
962
963         network->roaming = roaming;
964
965         return connman_element_set_bool(&network->element,
966                                                 "Roaming", roaming);
967 }
968
969 /**
970  * connman_network_set_string:
971  * @network: network structure
972  * @key: unique identifier
973  * @value: string value
974  *
975  * Set string value for specific key
976  */
977 int connman_network_set_string(struct connman_network *network,
978                                         const char *key, const char *value)
979 {
980         DBG("network %p key %s value %s", network, key, value);
981
982         if (g_strcmp0(key, "Name") == 0)
983                 return connman_network_set_name(network, value);
984
985         if (g_str_equal(key, "Address") == TRUE) {
986                 g_free(network->address);
987                 network->address = g_strdup(value);
988         } else if (g_str_equal(key, "Node") == TRUE) {
989                 g_free(network->node);
990                 network->node = g_strdup(value);
991         } else if (g_str_equal(key, "WiFi.Mode") == TRUE) {
992                 g_free(network->wifi.mode);
993                 network->wifi.mode = g_strdup(value);
994         } else if (g_str_equal(key, "WiFi.Security") == TRUE) {
995                 g_free(network->wifi.security);
996                 network->wifi.security = g_strdup(value);
997         } else if (g_str_equal(key, "WiFi.Passphrase") == TRUE) {
998                 g_free(network->wifi.passphrase);
999                 network->wifi.passphrase = g_strdup(value);
1000         }
1001
1002         return connman_element_set_string(&network->element, key, value);
1003 }
1004
1005 /**
1006  * connman_network_get_string:
1007  * @network: network structure
1008  * @key: unique identifier
1009  *
1010  * Get string value for specific key
1011  */
1012 const char *connman_network_get_string(struct connman_network *network,
1013                                                         const char *key)
1014 {
1015         DBG("network %p key %s", network, key);
1016
1017         if (g_str_equal(key, "Address") == TRUE)
1018                 return network->address;
1019         else if (g_str_equal(key, "Name") == TRUE)
1020                 return network->name;
1021         else if (g_str_equal(key, "Node") == TRUE)
1022                 return network->node;
1023         else if (g_str_equal(key, "WiFi.Mode") == TRUE)
1024                 return network->wifi.mode;
1025         else if (g_str_equal(key, "WiFi.Security") == TRUE)
1026                 return network->wifi.security;
1027         else if (g_str_equal(key, "WiFi.Passphrase") == TRUE)
1028                 return network->wifi.passphrase;
1029
1030         return connman_element_get_string(&network->element, key);
1031 }
1032
1033 /**
1034  * connman_network_set_bool:
1035  * @network: network structure
1036  * @key: unique identifier
1037  * @value: boolean value
1038  *
1039  * Set boolean value for specific key
1040  */
1041 int connman_network_set_bool(struct connman_network *network,
1042                                         const char *key, connman_bool_t value)
1043 {
1044         DBG("network %p key %s value %d", network, key, value);
1045
1046         if (g_strcmp0(key, "Roaming") == 0)
1047                 return connman_network_set_roaming(network, value);
1048
1049         return connman_element_set_bool(&network->element, key, value);
1050 }
1051
1052 /**
1053  * connman_network_get_bool:
1054  * @network: network structure
1055  * @key: unique identifier
1056  *
1057  * Get boolean value for specific key
1058  */
1059 connman_bool_t connman_network_get_bool(struct connman_network *network,
1060                                                         const char *key)
1061 {
1062         DBG("network %p key %s", network, key);
1063
1064         if (g_str_equal(key, "Roaming") == TRUE)
1065                 return network->roaming;
1066
1067         return connman_element_get_bool(&network->element, key);
1068 }
1069
1070 /**
1071  * connman_network_set_uint8:
1072  * @network: network structure
1073  * @key: unique identifier
1074  * @value: integer value
1075  *
1076  * Set integer value for specific key
1077  */
1078 int connman_network_set_uint8(struct connman_network *network,
1079                                         const char *key, connman_uint8_t value)
1080 {
1081         DBG("network %p key %s value %d", network, key, value);
1082
1083         if (g_strcmp0(key, "Strength") == 0)
1084                 return connman_network_set_strength(network, value);
1085
1086         return connman_element_set_uint8(&network->element, key, value);
1087 }
1088
1089 /**
1090  * connman_network_get_uint8:
1091  * @network: network structure
1092  * @key: unique identifier
1093  *
1094  * Get integer value for specific key
1095  */
1096 connman_uint8_t connman_network_get_uint8(struct connman_network *network,
1097                                                         const char *key)
1098 {
1099         DBG("network %p key %s", network, key);
1100
1101         if (g_str_equal(key, "Strength") == TRUE)
1102                 return network->strength;
1103
1104         return connman_element_get_uint8(&network->element, key);
1105 }
1106
1107 /**
1108  * connman_network_set_uint16:
1109  * @network: network structure
1110  * @key: unique identifier
1111  * @value: integer value
1112  *
1113  * Set integer value for specific key
1114  */
1115 int connman_network_set_uint16(struct connman_network *network,
1116                                 const char *key, connman_uint16_t value)
1117 {
1118         DBG("network %p key %s value %d", network, key, value);
1119
1120         if (g_str_equal(key, "Frequency") == TRUE)
1121                 network->frequency = value;
1122         else if (g_str_equal(key, "WiFi.Channel") == TRUE)
1123                 network->wifi.channel = value;
1124
1125         return -EINVAL;
1126 }
1127
1128 /**
1129  * connman_network_get_uint16:
1130  * @network: network structure
1131  * @key: unique identifier
1132  *
1133  * Get integer value for specific key
1134  */
1135 connman_uint16_t connman_network_get_uint16(struct connman_network *network,
1136                                                         const char *key)
1137 {
1138         DBG("network %p key %s", network, key);
1139
1140         if (g_str_equal(key, "Frequency") == TRUE)
1141                 return network->frequency;
1142         else if (g_str_equal(key, "WiFi.Channel") == TRUE)
1143                 return network->wifi.channel;
1144
1145         return 0;
1146 }
1147
1148 /**
1149  * connman_network_set_blob:
1150  * @network: network structure
1151  * @key: unique identifier
1152  * @data: blob data
1153  * @size: blob size
1154  *
1155  * Set binary blob value for specific key
1156  */
1157 int connman_network_set_blob(struct connman_network *network,
1158                         const char *key, const void *data, unsigned int size)
1159 {
1160         DBG("network %p key %s size %d", network, key, size);
1161
1162         if (g_strcmp0(key, "Address") == 0)
1163                 return connman_network_set_address(network, data, size);
1164
1165         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
1166                 g_free(network->wifi.ssid);
1167                 network->wifi.ssid = g_try_malloc(size);
1168                 if (network->wifi.ssid != NULL) {
1169                         memcpy(network->wifi.ssid, data, size);
1170                         network->wifi.ssid_len = size;
1171                 } else
1172                         network->wifi.ssid_len = 0;
1173         }
1174
1175         return connman_element_set_blob(&network->element, key, data, size);
1176 }
1177
1178 /**
1179  * connman_network_get_blob:
1180  * @network: network structure
1181  * @key: unique identifier
1182  * @size: pointer to blob size
1183  *
1184  * Get binary blob value for specific key
1185  */
1186 const void *connman_network_get_blob(struct connman_network *network,
1187                                         const char *key, unsigned int *size)
1188 {
1189         DBG("network %p key %s", network, key);
1190
1191         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
1192                 if (size != NULL)
1193                         *size = network->wifi.ssid_len;
1194                 return network->wifi.ssid;
1195         }
1196
1197         return connman_element_get_blob(&network->element, key, size);
1198 }
1199
1200 void __connman_network_set_device(struct connman_network *network,
1201                                         struct connman_device *device)
1202 {
1203         network->device = device;
1204 }
1205
1206 /**
1207  * connman_network_get_device:
1208  * @network: network structure
1209  *
1210  * Get parent device of network
1211  */
1212 struct connman_device *connman_network_get_device(struct connman_network *network)
1213 {
1214         return network->device;
1215 }
1216
1217 /**
1218  * connman_network_get_data:
1219  * @network: network structure
1220  *
1221  * Get private network data pointer
1222  */
1223 void *connman_network_get_data(struct connman_network *network)
1224 {
1225         return network->driver_data;
1226 }
1227
1228 /**
1229  * connman_network_set_data:
1230  * @network: network structure
1231  * @data: data pointer
1232  *
1233  * Set private network data pointer
1234  */
1235 void connman_network_set_data(struct connman_network *network, void *data)
1236 {
1237         network->driver_data = data;
1238 }
1239
1240 static gboolean match_driver(struct connman_network *network,
1241                                         struct connman_network_driver *driver)
1242 {
1243         if (network->type == driver->type ||
1244                         driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN)
1245                 return TRUE;
1246
1247         return FALSE;
1248 }
1249
1250 static int network_probe(struct connman_element *element)
1251 {
1252         struct connman_network *network = element->network;
1253         GSList *list;
1254         int err;
1255
1256         DBG("element %p name %s", element, element->name);
1257
1258         if (network == NULL)
1259                 return -ENODEV;
1260
1261         for (list = driver_list; list; list = list->next) {
1262                 struct connman_network_driver *driver = list->data;
1263
1264                 if (match_driver(network, driver) == FALSE)
1265                         continue;
1266
1267                 DBG("driver %p name %s", driver, driver->name);
1268
1269                 if (driver->probe(network) == 0) {
1270                         network->driver = driver;
1271                         break;
1272                 }
1273         }
1274
1275         if (network->driver == NULL)
1276                 return -ENODEV;
1277
1278         err = register_interface(element);
1279         if (err < 0) {
1280                 if (network->driver->remove)
1281                         network->driver->remove(network);
1282                 return err;
1283         }
1284
1285         network->secondary = connman_device_get_secondary(network->device);
1286
1287         switch (network->type) {
1288         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1289         case CONNMAN_NETWORK_TYPE_VENDOR:
1290                 break;
1291         case CONNMAN_NETWORK_TYPE_ETHERNET:
1292         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1293         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1294         case CONNMAN_NETWORK_TYPE_CELLULAR:
1295         case CONNMAN_NETWORK_TYPE_MBM:
1296         case CONNMAN_NETWORK_TYPE_HSO:
1297         case CONNMAN_NETWORK_TYPE_WIFI:
1298         case CONNMAN_NETWORK_TYPE_WIMAX:
1299                 if (network->group != NULL && network->secondary == FALSE)
1300                         __connman_profile_add_network(network);
1301                 break;
1302         }
1303
1304         return 0;
1305 }
1306
1307 static void network_remove(struct connman_element *element)
1308 {
1309         struct connman_network *network = element->network;
1310
1311         DBG("element %p name %s", element, element->name);
1312
1313         if (network == NULL)
1314                 return;
1315
1316         if (network->driver == NULL)
1317                 return;
1318
1319         switch (network->type) {
1320         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1321         case CONNMAN_NETWORK_TYPE_VENDOR:
1322                 break;
1323         case CONNMAN_NETWORK_TYPE_ETHERNET:
1324         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1325         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1326         case CONNMAN_NETWORK_TYPE_CELLULAR:
1327         case CONNMAN_NETWORK_TYPE_MBM:
1328         case CONNMAN_NETWORK_TYPE_HSO:
1329         case CONNMAN_NETWORK_TYPE_WIFI:
1330         case CONNMAN_NETWORK_TYPE_WIMAX:
1331                 if (network->group != NULL && network->secondary == FALSE) {
1332                         __connman_profile_remove_network(network);
1333
1334                         g_free(network->group);
1335                         network->group = NULL;
1336                 }
1337                 break;
1338         }
1339
1340         unregister_interface(element);
1341
1342         if (network->driver->remove)
1343                 network->driver->remove(network);
1344 }
1345
1346 static void network_change(struct connman_element *element)
1347 {
1348         struct connman_network *network = element->network;
1349
1350         DBG("element %p name %s", element, element->name);
1351
1352         if (element->state != CONNMAN_ELEMENT_STATE_ERROR)
1353                 return;
1354
1355         if (element->error != CONNMAN_ELEMENT_ERROR_DHCP_FAILED)
1356                 return;
1357
1358         if (network->connected == FALSE)
1359                 return;
1360
1361         connman_element_unregister_children(element);
1362
1363         connman_device_set_disconnected(network->device, TRUE);
1364
1365         if (network->driver && network->driver->disconnect) {
1366                 network->driver->disconnect(network);
1367                 return;
1368         }
1369
1370         network->connected = FALSE;
1371 }
1372
1373 static struct connman_driver network_driver = {
1374         .name           = "network",
1375         .type           = CONNMAN_ELEMENT_TYPE_NETWORK,
1376         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1377         .probe          = network_probe,
1378         .remove         = network_remove,
1379         .change         = network_change,
1380 };
1381
1382 int __connman_network_init(void)
1383 {
1384         DBG("");
1385
1386         connection = connman_dbus_get_connection();
1387
1388         return connman_driver_register(&network_driver);
1389 }
1390
1391 void __connman_network_cleanup(void)
1392 {
1393         DBG("");
1394
1395         connman_driver_unregister(&network_driver);
1396
1397         dbus_connection_unref(connection);
1398 }