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