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