5 * Copyright (C) 2014 Intel Corporation. All rights reserved.
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.
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.
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
29 #include <gdhcp/gdhcp.h>
30 #include <netinet/if_ether.h>
32 #include <connman/agent.h>
36 static DBusConnection *connection = NULL;
38 static GHashTable *peers_table = NULL;
40 static struct connman_peer_driver *peer_driver;
42 struct _peers_notify {
48 struct _peer_service {
49 enum connman_peer_service_type type;
56 struct connman_device *device;
57 struct connman_device *sub_device;
58 unsigned char *iface_address[ETH_ALEN];
62 enum connman_peer_state state;
63 struct connman_ipconfig *ipconfig;
66 bool connection_master;
67 struct connman_ippool *ip_pool;
68 GDHCPServer *dhcp_server;
73 static void settings_changed(struct connman_peer *peer);
75 static void stop_dhcp_server(struct connman_peer *peer)
79 if (peer->dhcp_server)
80 g_dhcp_server_unref(peer->dhcp_server);
82 peer->dhcp_server = NULL;
85 __connman_ippool_unref(peer->ip_pool);
90 static void dhcp_server_debug(const char *str, void *data)
92 connman_info("%s: %s\n", (const char *) data, str);
95 static void lease_added(unsigned char *mac, uint32_t ip)
99 start = list = g_hash_table_get_values(peers_table);
100 for (; list; list = list->next) {
101 struct connman_peer *temp = list->data;
103 if (!memcmp(temp->iface_address, mac, ETH_ALEN)) {
105 settings_changed(temp);
113 static gboolean dhcp_server_started(gpointer data)
115 struct connman_peer *peer = data;
117 connman_peer_set_state(peer, CONNMAN_PEER_STATE_READY);
118 connman_peer_unref(peer);
123 static int start_dhcp_server(struct connman_peer *peer)
125 const char *start_ip, *end_ip;
126 GDHCPServerError dhcp_error;
127 const char *broadcast;
138 if (peer->sub_device)
139 index = connman_device_get_index(peer->sub_device);
141 index = connman_device_get_index(peer->device);
143 peer->ip_pool = __connman_ippool_create(index, 2, 1, NULL, NULL);
147 gateway = __connman_ippool_get_gateway(peer->ip_pool);
148 subnet = __connman_ippool_get_subnet_mask(peer->ip_pool);
149 broadcast = __connman_ippool_get_broadcast(peer->ip_pool);
150 start_ip = __connman_ippool_get_start_ip(peer->ip_pool);
151 end_ip = __connman_ippool_get_end_ip(peer->ip_pool);
153 prefixlen = connman_ipaddress_calc_netmask_len(subnet);
155 err = __connman_inet_modify_address(RTM_NEWADDR,
156 NLM_F_REPLACE | NLM_F_ACK, index, AF_INET,
157 gateway, NULL, prefixlen, broadcast);
161 peer->dhcp_server = g_dhcp_server_new(G_DHCP_IPV4, index, &dhcp_error);
162 if (!peer->dhcp_server)
165 g_dhcp_server_set_debug(peer->dhcp_server,
166 dhcp_server_debug, "Peer DHCP server");
167 g_dhcp_server_set_lease_time(peer->dhcp_server, 3600);
168 g_dhcp_server_set_option(peer->dhcp_server, G_DHCP_SUBNET, subnet);
169 g_dhcp_server_set_option(peer->dhcp_server, G_DHCP_ROUTER, gateway);
170 g_dhcp_server_set_option(peer->dhcp_server, G_DHCP_DNS_SERVER, NULL);
171 g_dhcp_server_set_ip_range(peer->dhcp_server, start_ip, end_ip);
173 g_dhcp_server_set_lease_added_cb(peer->dhcp_server, lease_added);
175 err = g_dhcp_server_start(peer->dhcp_server);
179 g_timeout_add_seconds(0, dhcp_server_started, connman_peer_ref(peer));
184 stop_dhcp_server(peer);
188 static void reply_pending(struct connman_peer *peer, int error)
193 connman_dbus_reply_pending(peer->pending, error, NULL);
194 peer->pending = NULL;
197 static void peer_free(gpointer data)
199 struct connman_peer *peer = data;
201 reply_pending(peer, ENOENT);
203 connman_peer_unregister(peer);
210 if (peer->ipconfig) {
211 __connman_ipconfig_set_ops(peer->ipconfig, NULL);
212 __connman_ipconfig_set_data(peer->ipconfig, NULL);
213 __connman_ipconfig_unref(peer->ipconfig);
214 peer->ipconfig = NULL;
217 stop_dhcp_server(peer);
220 connman_device_unref(peer->device);
225 connman_peer_reset_services(peer);
227 g_free(peer->identifier);
233 static const char *state2string(enum connman_peer_state state)
236 case CONNMAN_PEER_STATE_UNKNOWN:
238 case CONNMAN_PEER_STATE_IDLE:
240 case CONNMAN_PEER_STATE_ASSOCIATION:
241 return "association";
242 case CONNMAN_PEER_STATE_CONFIGURATION:
243 return "configuration";
244 case CONNMAN_PEER_STATE_READY:
246 case CONNMAN_PEER_STATE_DISCONNECT:
248 case CONNMAN_PEER_STATE_FAILURE:
255 static bool is_connecting(struct connman_peer *peer)
257 if (peer->state == CONNMAN_PEER_STATE_ASSOCIATION ||
258 peer->state == CONNMAN_PEER_STATE_CONFIGURATION ||
265 static bool is_connected(struct connman_peer *peer)
267 if (peer->state == CONNMAN_PEER_STATE_READY)
273 static bool allow_property_changed(struct connman_peer *peer)
275 if (g_hash_table_lookup_extended(peers_notify->add, peer->path,
282 static void append_ipv4(DBusMessageIter *iter, void *user_data)
284 struct connman_peer *peer = user_data;
285 char trans[INET_ADDRSTRLEN+1] = {};
286 const char *local = "";
287 const char *remote = "";
290 if (!is_connected(peer))
293 if (peer->connection_master) {
296 addr.s_addr = peer->lease_ip;
297 inet_ntop(AF_INET, &addr, trans, INET_ADDRSTRLEN);
299 local = __connman_ippool_get_gateway(peer->ip_pool);
301 } else if (peer->ipconfig) {
302 local = __connman_ipconfig_get_local(peer->ipconfig);
304 remote = __connman_ipconfig_get_gateway(peer->ipconfig);
306 remote = dhcp = __connman_dhcp_get_server_address(
313 connman_dbus_dict_append_basic(iter, "Local",
314 DBUS_TYPE_STRING, &local);
315 connman_dbus_dict_append_basic(iter, "Remote",
316 DBUS_TYPE_STRING, &remote);
321 static void append_peer_service(DBusMessageIter *iter,
322 struct _peer_service *service)
324 DBusMessageIter dict;
326 connman_dbus_dict_open(iter, &dict);
328 switch (service->type) {
329 case CONNMAN_PEER_SERVICE_UNKNOWN:
330 /* Should never happen */
332 case CONNMAN_PEER_SERVICE_WIFI_DISPLAY:
333 connman_dbus_dict_append_fixed_array(&dict,
334 "WiFiDisplayIEs", DBUS_TYPE_BYTE,
335 &service->data, service->length);
339 connman_dbus_dict_close(iter, &dict);
342 static void append_peer_services(DBusMessageIter *iter, void *user_data)
344 struct connman_peer *peer = user_data;
345 DBusMessageIter container;
348 dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
351 if (!peer->services) {
352 DBusMessageIter dict;
354 connman_dbus_dict_open(&container, &dict);
355 connman_dbus_dict_close(&container, &dict);
357 for (list = peer->services; list; list = list->next)
358 append_peer_service(&container, list->data);
361 dbus_message_iter_close_container(iter, &container);
364 static void append_properties(DBusMessageIter *iter, struct connman_peer *peer)
366 const char *state = state2string(peer->state);
367 DBusMessageIter dict;
369 connman_dbus_dict_open(iter, &dict);
371 connman_dbus_dict_append_basic(&dict, "State",
372 DBUS_TYPE_STRING, &state);
373 connman_dbus_dict_append_basic(&dict, "Name",
374 DBUS_TYPE_STRING, &peer->name);
375 connman_dbus_dict_append_dict(&dict, "IPv4", append_ipv4, peer);
376 connman_dbus_dict_append_array(&dict, "Services",
377 DBUS_TYPE_DICT_ENTRY,
378 append_peer_services, peer);
379 connman_dbus_dict_close(iter, &dict);
382 static void settings_changed(struct connman_peer *peer)
384 if (!allow_property_changed(peer))
387 connman_dbus_property_changed_dict(peer->path,
388 CONNMAN_PEER_INTERFACE, "IPv4",
392 static DBusMessage *get_peer_properties(DBusConnection *conn,
393 DBusMessage *msg, void *data)
395 struct connman_peer *peer = data;
396 DBusMessageIter dict;
399 reply = dbus_message_new_method_return(msg);
403 dbus_message_iter_init_append(reply, &dict);
404 append_properties(&dict, peer);
409 static void append_peer_struct(gpointer key, gpointer value,
412 DBusMessageIter *array = user_data;
413 struct connman_peer *peer = value;
414 DBusMessageIter entry;
416 dbus_message_iter_open_container(array, DBUS_TYPE_STRUCT,
418 dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
420 append_properties(&entry, peer);
421 dbus_message_iter_close_container(array, &entry);
424 static void state_changed(struct connman_peer *peer)
428 state = state2string(peer->state);
429 if (!state || !allow_property_changed(peer))
432 connman_dbus_property_changed_basic(peer->path,
433 CONNMAN_PEER_INTERFACE, "State",
434 DBUS_TYPE_STRING, &state);
437 static void append_existing_and_new_peers(gpointer key,
438 gpointer value, gpointer user_data)
440 struct connman_peer *peer = value;
441 DBusMessageIter *iter = user_data;
442 DBusMessageIter entry, dict;
444 if (!peer || !peer->registered)
447 if (g_hash_table_lookup(peers_notify->add, peer->path)) {
448 DBG("new %s", peer->path);
450 append_peer_struct(key, peer, iter);
451 g_hash_table_remove(peers_notify->add, peer->path);
452 } else if (!g_hash_table_lookup(peers_notify->remove, peer->path)) {
453 DBG("existing %s", peer->path);
455 dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
457 dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
459 connman_dbus_dict_open(&entry, &dict);
460 connman_dbus_dict_close(&entry, &dict);
462 dbus_message_iter_close_container(iter, &entry);
466 static void peer_append_all(DBusMessageIter *iter, void *user_data)
468 g_hash_table_foreach(peers_table, append_existing_and_new_peers, iter);
471 static void append_removed(gpointer key, gpointer value, gpointer user_data)
473 DBusMessageIter *iter = user_data;
476 DBG("removed %s", objpath);
477 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &objpath);
480 static void peer_append_removed(DBusMessageIter *iter, void *user_data)
482 g_hash_table_foreach(peers_notify->remove, append_removed, iter);
485 static gboolean peer_send_changed(gpointer data)
491 peers_notify->id = 0;
493 signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
494 CONNMAN_MANAGER_INTERFACE, "PeersChanged");
498 __connman_dbus_append_objpath_dict_array(signal,
499 peer_append_all, NULL);
500 __connman_dbus_append_objpath_array(signal,
501 peer_append_removed, NULL);
503 dbus_connection_send(connection, signal, NULL);
504 dbus_message_unref(signal);
506 g_hash_table_remove_all(peers_notify->remove);
507 g_hash_table_remove_all(peers_notify->add);
512 static void peer_schedule_changed(void)
514 if (peers_notify->id != 0)
517 peers_notify->id = g_timeout_add(100, peer_send_changed, NULL);
520 static void peer_added(struct connman_peer *peer)
522 DBG("peer %p", peer);
524 g_hash_table_remove(peers_notify->remove, peer->path);
525 g_hash_table_replace(peers_notify->add, peer->path, peer);
527 peer_schedule_changed();
530 static void peer_removed(struct connman_peer *peer)
532 DBG("peer %p", peer);
534 g_hash_table_remove(peers_notify->add, peer->path);
535 g_hash_table_replace(peers_notify->remove, g_strdup(peer->path), NULL);
537 peer_schedule_changed();
540 static const char *get_dbus_sender(struct connman_peer *peer)
545 return dbus_message_get_sender(peer->pending);
548 static enum connman_peer_wps_method check_wpspin(struct connman_peer *peer,
554 return CONNMAN_PEER_WPS_PBC;
556 len = strlen(wpspin);
558 return CONNMAN_PEER_WPS_PBC;
561 return CONNMAN_PEER_WPS_UNKNOWN;
562 for (i = 0; i < 8; i++) {
563 if (!isdigit((unsigned char) wpspin[i]))
564 return CONNMAN_PEER_WPS_UNKNOWN;
567 return CONNMAN_PEER_WPS_PIN;
570 static void request_authorization_cb(struct connman_peer *peer,
571 bool choice_done, const char *wpspin,
572 const char *error, void *user_data)
574 enum connman_peer_wps_method wps_method;
577 DBG("RequestInput return, %p", peer);
581 "net.connman.Agent.Error.Canceled") == 0 ||
583 "net.connman.Agent.Error.Rejected") == 0) {
589 if (!choice_done || !peer_driver->connect) {
594 wps_method = check_wpspin(peer, wpspin);
596 err = peer_driver->connect(peer, wps_method, wpspin);
597 if (err == -EINPROGRESS)
601 reply_pending(peer, EIO);
602 connman_peer_set_state(peer, CONNMAN_PEER_STATE_IDLE);
605 static int peer_connect(struct connman_peer *peer)
609 if (peer_driver->connect)
610 err = peer_driver->connect(peer,
611 CONNMAN_PEER_WPS_UNKNOWN, NULL);
613 if (err == -ENOKEY) {
614 err = __connman_agent_request_peer_authorization(peer,
615 request_authorization_cb, true,
616 get_dbus_sender(peer), NULL);
622 static int peer_disconnect(struct connman_peer *peer)
626 connman_agent_cancel(peer);
627 reply_pending(peer, ECONNABORTED);
629 connman_peer_set_state(peer, CONNMAN_PEER_STATE_DISCONNECT);
631 if (peer->connection_master)
632 stop_dhcp_server(peer);
634 __connman_dhcp_stop(peer->ipconfig);
636 if (peer_driver->disconnect)
637 err = peer_driver->disconnect(peer);
639 connman_peer_set_state(peer, CONNMAN_PEER_STATE_IDLE);
644 static DBusMessage *connect_peer(DBusConnection *conn,
645 DBusMessage *msg, void *user_data)
647 struct connman_peer *peer = user_data;
651 DBG("peer %p", peer);
654 return __connman_error_in_progress(msg);
656 list = g_hash_table_get_values(peers_table);
658 for (; list; list = list->next) {
659 struct connman_peer *temp = list->data;
661 if (temp == peer || temp->device != peer->device)
664 if (is_connecting(temp) || is_connected(temp)) {
665 if (peer_disconnect(temp) == -EINPROGRESS) {
667 return __connman_error_in_progress(msg);
674 peer->pending = dbus_message_ref(msg);
676 err = peer_connect(peer);
677 if (err == -EINPROGRESS)
681 dbus_message_unref(peer->pending);
682 peer->pending = NULL;
684 return __connman_error_failed(msg, -err);
687 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
690 static DBusMessage *disconnect_peer(DBusConnection *conn,
691 DBusMessage *msg, void *user_data)
693 struct connman_peer *peer = user_data;
696 DBG("peer %p", peer);
698 err = peer_disconnect(peer);
699 if (err < 0 && err != -EINPROGRESS)
700 return __connman_error_failed(msg, -err);
702 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
705 struct connman_peer *connman_peer_create(const char *identifier)
707 struct connman_peer *peer;
709 peer = g_malloc0(sizeof(struct connman_peer));
710 peer->identifier = g_strdup(identifier);
711 peer->state = CONNMAN_PEER_STATE_IDLE;
718 struct connman_peer *connman_peer_ref_debug(struct connman_peer *peer,
719 const char *file, int line, const char *caller)
721 DBG("%p ref %d by %s:%d:%s()", peer, peer->refcount + 1,
724 __sync_fetch_and_add(&peer->refcount, 1);
729 void connman_peer_unref_debug(struct connman_peer *peer,
730 const char *file, int line, const char *caller)
732 DBG("%p ref %d by %s:%d:%s()", peer, peer->refcount - 1,
735 if (__sync_fetch_and_sub(&peer->refcount, 1) != 1)
738 if (!peer->registered && !peer->path)
739 return peer_free(peer);
741 g_hash_table_remove(peers_table, peer->path);
744 const char *connman_peer_get_identifier(struct connman_peer *peer)
749 return peer->identifier;
752 void connman_peer_set_name(struct connman_peer *peer, const char *name)
755 peer->name = g_strdup(name);
758 void connman_peer_set_iface_address(struct connman_peer *peer,
759 const unsigned char *iface_address)
761 memset(peer->iface_address, 0, ETH_ALEN);
762 memcpy(peer->iface_address, iface_address, ETH_ALEN);
765 void connman_peer_set_device(struct connman_peer *peer,
766 struct connman_device *device)
768 if (!peer || !device)
771 peer->device = device;
772 connman_device_ref(device);
775 struct connman_device *connman_peer_get_device(struct connman_peer *peer)
783 void connman_peer_set_sub_device(struct connman_peer *peer,
784 struct connman_device *device)
786 if (!peer || !device || peer->sub_device)
789 peer->sub_device = device;
792 void connman_peer_set_as_master(struct connman_peer *peer, bool master)
794 if (!peer || !is_connecting(peer))
797 peer->connection_master = master;
800 static void dhcp_callback(struct connman_ipconfig *ipconfig,
801 struct connman_network *network,
802 bool success, gpointer data)
804 struct connman_peer *peer = data;
810 DBG("lease acquired for ipconfig %p", ipconfig);
812 err = __connman_ipconfig_address_add(ipconfig);
819 __connman_ipconfig_address_remove(ipconfig);
820 connman_peer_set_state(peer, CONNMAN_PEER_STATE_FAILURE);
823 static int start_dhcp_client(struct connman_peer *peer)
825 if (peer->sub_device)
826 __connman_ipconfig_set_index(peer->ipconfig,
827 connman_device_get_index(peer->sub_device));
829 __connman_ipconfig_enable(peer->ipconfig);
831 return __connman_dhcp_start(peer->ipconfig, NULL, dhcp_callback, peer);
834 static void report_error_cb(void *user_context, bool retry, void *user_data)
836 struct connman_peer *peer = user_context;
840 err = peer_connect(peer);
842 if (err == 0 || err == -EINPROGRESS)
846 reply_pending(peer, ENOTCONN);
848 peer_disconnect(peer);
850 if (!peer->connection_master) {
851 __connman_dhcp_stop(peer->ipconfig);
852 __connman_ipconfig_disable(peer->ipconfig);
854 stop_dhcp_server(peer);
856 peer->connection_master = false;
857 peer->sub_device = NULL;
860 static int manage_peer_error(struct connman_peer *peer)
864 err = __connman_agent_report_peer_error(peer, peer->path,
865 "connect-failed", report_error_cb,
866 get_dbus_sender(peer), NULL);
867 if (err != -EINPROGRESS) {
868 report_error_cb(peer, false, NULL);
875 int connman_peer_set_state(struct connman_peer *peer,
876 enum connman_peer_state new_state)
878 enum connman_peer_state old_state = peer->state;
881 DBG("peer (%s) old state %d new state %d", peer->name,
882 old_state, new_state);
884 if (old_state == new_state)
888 case CONNMAN_PEER_STATE_UNKNOWN:
890 case CONNMAN_PEER_STATE_IDLE:
891 if (is_connecting(peer) || is_connected(peer))
892 return peer_disconnect(peer);
893 peer->sub_device = NULL;
895 case CONNMAN_PEER_STATE_ASSOCIATION:
897 case CONNMAN_PEER_STATE_CONFIGURATION:
898 if (peer->connection_master)
899 err = start_dhcp_server(peer);
901 err = start_dhcp_client(peer);
903 return connman_peer_set_state(peer,
904 CONNMAN_PEER_STATE_FAILURE);
906 case CONNMAN_PEER_STATE_READY:
907 reply_pending(peer, 0);
909 case CONNMAN_PEER_STATE_DISCONNECT:
910 if (peer->connection_master)
911 stop_dhcp_server(peer);
912 peer->connection_master = false;
913 peer->sub_device = NULL;
916 case CONNMAN_PEER_STATE_FAILURE:
917 if (manage_peer_error(peer) == 0)
922 peer->state = new_state;
925 if (peer->state == CONNMAN_PEER_STATE_READY ||
926 peer->state == CONNMAN_PEER_STATE_DISCONNECT)
927 settings_changed(peer);
932 int connman_peer_request_connection(struct connman_peer *peer)
934 return __connman_agent_request_peer_authorization(peer,
935 request_authorization_cb, false,
939 static void peer_service_free(gpointer data)
941 struct _peer_service *service = data;
946 g_free(service->data);
950 void connman_peer_reset_services(struct connman_peer *peer)
955 g_slist_free_full(peer->services, peer_service_free);
956 peer->services = NULL;
959 void connman_peer_services_changed(struct connman_peer *peer)
961 if (!peer || !peer->registered || !allow_property_changed(peer))
964 connman_dbus_property_changed_array(peer->path,
965 CONNMAN_PEER_INTERFACE, "Services",
966 DBUS_TYPE_DICT_ENTRY, append_peer_services, peer);
969 void connman_peer_add_service(struct connman_peer *peer,
970 enum connman_peer_service_type type,
971 const unsigned char *data, int data_length)
973 struct _peer_service *service;
975 if (!peer || !data || type == CONNMAN_PEER_SERVICE_UNKNOWN)
978 service = g_malloc0(sizeof(struct _peer_service));
979 service->type = type;
980 service->data = g_memdup(data, data_length * sizeof(unsigned char));
981 service->length = data_length;
983 peer->services = g_slist_prepend(peer->services, service);
986 static void peer_up(struct connman_ipconfig *ipconfig, const char *ifname)
988 DBG("%s up", ifname);
991 static void peer_down(struct connman_ipconfig *ipconfig, const char *ifname)
993 DBG("%s down", ifname);
996 static void peer_lower_up(struct connman_ipconfig *ipconfig,
999 DBG("%s lower up", ifname);
1002 static void peer_lower_down(struct connman_ipconfig *ipconfig,
1005 struct connman_peer *peer = __connman_ipconfig_get_data(ipconfig);
1007 DBG("%s lower down", ifname);
1009 __connman_ipconfig_disable(ipconfig);
1010 connman_peer_set_state(peer, CONNMAN_PEER_STATE_DISCONNECT);
1013 static void peer_ip_bound(struct connman_ipconfig *ipconfig,
1016 struct connman_peer *peer = __connman_ipconfig_get_data(ipconfig);
1018 DBG("%s ip bound", ifname);
1020 if (peer->state == CONNMAN_PEER_STATE_READY)
1021 settings_changed(peer);
1022 connman_peer_set_state(peer, CONNMAN_PEER_STATE_READY);
1025 static void peer_ip_release(struct connman_ipconfig *ipconfig,
1028 struct connman_peer *peer = __connman_ipconfig_get_data(ipconfig);
1030 DBG("%s ip release", ifname);
1032 if (peer->state == CONNMAN_PEER_STATE_READY)
1033 settings_changed(peer);
1036 static const struct connman_ipconfig_ops peer_ip_ops = {
1039 .lower_up = peer_lower_up,
1040 .lower_down = peer_lower_down,
1041 .ip_bound = peer_ip_bound,
1042 .ip_release = peer_ip_release,
1044 .route_unset = NULL,
1047 static struct connman_ipconfig *create_ipconfig(int index, void *user_data)
1049 struct connman_ipconfig *ipconfig;
1051 ipconfig = __connman_ipconfig_create(index,
1052 CONNMAN_IPCONFIG_TYPE_IPV4);
1056 __connman_ipconfig_set_method(ipconfig, CONNMAN_IPCONFIG_METHOD_DHCP);
1057 __connman_ipconfig_set_data(ipconfig, user_data);
1058 __connman_ipconfig_set_ops(ipconfig, &peer_ip_ops);
1063 static const GDBusMethodTable peer_methods[] = {
1064 { GDBUS_METHOD("GetProperties",
1065 NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
1066 get_peer_properties) },
1067 { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, connect_peer) },
1068 { GDBUS_METHOD("Disconnect", NULL, NULL, disconnect_peer) },
1072 static const GDBusSignalTable peer_signals[] = {
1073 { GDBUS_SIGNAL("PropertyChanged",
1074 GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
1078 static char *get_peer_path(struct connman_device *device,
1079 const char *identifier)
1081 return g_strdup_printf("%s/peer/peer_%s_%s", CONNMAN_PATH,
1082 connman_device_get_ident(device), identifier);
1085 int connman_peer_register(struct connman_peer *peer)
1089 DBG("peer %p", peer);
1091 if (peer->path && peer->registered)
1094 index = connman_device_get_index(peer->device);
1095 peer->ipconfig = create_ipconfig(index, peer);
1096 if (!peer->ipconfig)
1099 peer->path = get_peer_path(peer->device, peer->identifier);
1100 DBG("path %s", peer->path);
1102 g_hash_table_insert(peers_table, peer->path, peer);
1104 g_dbus_register_interface(connection, peer->path,
1105 CONNMAN_PEER_INTERFACE,
1106 peer_methods, peer_signals,
1108 peer->registered = true;
1114 void connman_peer_unregister(struct connman_peer *peer)
1116 DBG("peer %p", peer);
1118 if (!peer->path || !peer->registered)
1121 connman_agent_cancel(peer);
1122 reply_pending(peer, EIO);
1124 g_dbus_unregister_interface(connection, peer->path,
1125 CONNMAN_PEER_INTERFACE);
1126 peer->registered = false;
1130 struct connman_peer *connman_peer_get(struct connman_device *device,
1131 const char *identifier)
1133 char *ident = get_peer_path(device, identifier);
1134 struct connman_peer *peer;
1136 peer = g_hash_table_lookup(peers_table, ident);
1142 int connman_peer_driver_register(struct connman_peer_driver *driver)
1144 if (peer_driver && peer_driver != driver)
1147 peer_driver = driver;
1149 __connman_peer_service_set_driver(driver);
1154 void connman_peer_driver_unregister(struct connman_peer_driver *driver)
1156 if (peer_driver != driver)
1161 __connman_peer_service_set_driver(NULL);
1164 void __connman_peer_list_struct(DBusMessageIter *array)
1166 g_hash_table_foreach(peers_table, append_peer_struct, array);
1169 const char *__connman_peer_get_path(struct connman_peer *peer)
1171 if (!peer || !peer->registered)
1177 int __connman_peer_init(void)
1181 connection = connman_dbus_get_connection();
1183 peers_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1186 peers_notify = g_new0(struct _peers_notify, 1);
1187 peers_notify->add = g_hash_table_new(g_str_hash, g_str_equal);
1188 peers_notify->remove = g_hash_table_new_full(g_str_hash, g_str_equal,
1193 void __connman_peer_cleanup(void)
1197 g_hash_table_destroy(peers_notify->remove);
1198 g_hash_table_destroy(peers_notify->add);
1199 g_free(peers_notify);
1201 g_hash_table_destroy(peers_table);
1203 dbus_connection_unref(connection);