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_free(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_idle_add(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 (is_connected(peer))
612 if (peer_driver->connect)
613 err = peer_driver->connect(peer,
614 CONNMAN_PEER_WPS_UNKNOWN, NULL);
616 if (err == -ENOKEY) {
617 err = __connman_agent_request_peer_authorization(peer,
618 request_authorization_cb, true,
619 get_dbus_sender(peer), NULL);
625 static int peer_disconnect(struct connman_peer *peer)
629 connman_agent_cancel(peer);
630 reply_pending(peer, ECONNABORTED);
632 connman_peer_set_state(peer, CONNMAN_PEER_STATE_DISCONNECT);
634 if (peer->connection_master)
635 stop_dhcp_server(peer);
637 __connman_dhcp_stop(peer->ipconfig);
639 if (peer_driver->disconnect)
640 err = peer_driver->disconnect(peer);
642 connman_peer_set_state(peer, CONNMAN_PEER_STATE_IDLE);
647 static DBusMessage *connect_peer(DBusConnection *conn,
648 DBusMessage *msg, void *user_data)
650 struct connman_peer *peer = user_data;
654 DBG("peer %p", peer);
657 return __connman_error_in_progress(msg);
659 list = g_hash_table_get_values(peers_table);
661 for (; list; list = list->next) {
662 struct connman_peer *temp = list->data;
664 if (temp == peer || temp->device != peer->device)
667 if (is_connecting(temp) || is_connected(temp)) {
668 if (peer_disconnect(temp) == -EINPROGRESS) {
670 return __connman_error_in_progress(msg);
677 peer->pending = dbus_message_ref(msg);
679 err = peer_connect(peer);
680 if (err == -EINPROGRESS)
684 dbus_message_unref(peer->pending);
685 peer->pending = NULL;
687 return __connman_error_failed(msg, -err);
690 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
693 static DBusMessage *disconnect_peer(DBusConnection *conn,
694 DBusMessage *msg, void *user_data)
696 struct connman_peer *peer = user_data;
699 DBG("peer %p", peer);
701 err = peer_disconnect(peer);
702 if (err < 0 && err != -EINPROGRESS)
703 return __connman_error_failed(msg, -err);
705 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
708 struct connman_peer *connman_peer_create(const char *identifier)
710 struct connman_peer *peer;
712 peer = g_malloc0(sizeof(struct connman_peer));
713 peer->identifier = g_strdup(identifier);
714 peer->state = CONNMAN_PEER_STATE_IDLE;
721 struct connman_peer *connman_peer_ref_debug(struct connman_peer *peer,
722 const char *file, int line, const char *caller)
724 DBG("%p ref %d by %s:%d:%s()", peer, peer->refcount + 1,
727 __sync_fetch_and_add(&peer->refcount, 1);
732 void connman_peer_unref_debug(struct connman_peer *peer,
733 const char *file, int line, const char *caller)
735 DBG("%p ref %d by %s:%d:%s()", peer, peer->refcount - 1,
738 if (__sync_fetch_and_sub(&peer->refcount, 1) != 1)
741 if (!peer->registered && !peer->path)
742 return peer_free(peer);
744 g_hash_table_remove(peers_table, peer->path);
747 const char *connman_peer_get_identifier(struct connman_peer *peer)
752 return peer->identifier;
755 void connman_peer_set_name(struct connman_peer *peer, const char *name)
758 peer->name = g_strdup(name);
761 void connman_peer_set_iface_address(struct connman_peer *peer,
762 const unsigned char *iface_address)
764 memset(peer->iface_address, 0, sizeof(peer->iface_address));
765 memcpy(peer->iface_address, iface_address, ETH_ALEN);
768 void connman_peer_set_device(struct connman_peer *peer,
769 struct connman_device *device)
771 if (!peer || !device)
774 peer->device = device;
775 connman_device_ref(device);
778 struct connman_device *connman_peer_get_device(struct connman_peer *peer)
786 void connman_peer_set_sub_device(struct connman_peer *peer,
787 struct connman_device *device)
789 if (!peer || !device || peer->sub_device)
792 peer->sub_device = device;
795 void connman_peer_set_as_master(struct connman_peer *peer, bool master)
797 if (!peer || !is_connecting(peer))
800 peer->connection_master = master;
803 static void dhcp_callback(struct connman_ipconfig *ipconfig,
804 struct connman_network *network,
805 bool success, gpointer data)
807 struct connman_peer *peer = data;
813 DBG("lease acquired for ipconfig %p", ipconfig);
815 err = __connman_ipconfig_address_add(ipconfig);
822 __connman_ipconfig_address_remove(ipconfig);
823 connman_peer_set_state(peer, CONNMAN_PEER_STATE_FAILURE);
826 static int start_dhcp_client(struct connman_peer *peer)
828 if (peer->sub_device)
829 __connman_ipconfig_set_index(peer->ipconfig,
830 connman_device_get_index(peer->sub_device));
832 __connman_ipconfig_enable(peer->ipconfig);
834 return __connman_dhcp_start(peer->ipconfig, NULL, dhcp_callback, peer);
837 static void report_error_cb(void *user_context, bool retry, void *user_data)
839 struct connman_peer *peer = user_context;
843 err = peer_connect(peer);
845 if (err == 0 || err == -EINPROGRESS)
849 reply_pending(peer, ENOTCONN);
851 peer_disconnect(peer);
853 if (!peer->connection_master) {
854 __connman_dhcp_stop(peer->ipconfig);
855 __connman_ipconfig_disable(peer->ipconfig);
857 stop_dhcp_server(peer);
859 peer->connection_master = false;
860 peer->sub_device = NULL;
863 static int manage_peer_error(struct connman_peer *peer)
867 err = __connman_agent_report_peer_error(peer, peer->path,
868 "connect-failed", report_error_cb,
869 get_dbus_sender(peer), NULL);
870 if (err != -EINPROGRESS) {
871 report_error_cb(peer, false, NULL);
878 int connman_peer_set_state(struct connman_peer *peer,
879 enum connman_peer_state new_state)
881 enum connman_peer_state old_state = peer->state;
884 DBG("peer (%s) old state %d new state %d", peer->name,
885 old_state, new_state);
887 if (old_state == new_state)
891 case CONNMAN_PEER_STATE_UNKNOWN:
893 case CONNMAN_PEER_STATE_IDLE:
894 if (is_connecting(peer) || is_connected(peer))
895 return peer_disconnect(peer);
896 peer->sub_device = NULL;
898 case CONNMAN_PEER_STATE_ASSOCIATION:
900 case CONNMAN_PEER_STATE_CONFIGURATION:
901 if (peer->connection_master)
902 err = start_dhcp_server(peer);
904 err = start_dhcp_client(peer);
906 return connman_peer_set_state(peer,
907 CONNMAN_PEER_STATE_FAILURE);
909 case CONNMAN_PEER_STATE_READY:
910 reply_pending(peer, 0);
911 __connman_technology_set_connected(CONNMAN_SERVICE_TYPE_P2P, true);
913 case CONNMAN_PEER_STATE_DISCONNECT:
914 if (peer->connection_master)
915 stop_dhcp_server(peer);
917 __connman_dhcp_stop(peer->ipconfig);
918 peer->connection_master = false;
919 peer->sub_device = NULL;
920 __connman_technology_set_connected(CONNMAN_SERVICE_TYPE_P2P, false);
922 case CONNMAN_PEER_STATE_FAILURE:
923 if (manage_peer_error(peer) == 0)
928 peer->state = new_state;
931 if (peer->state == CONNMAN_PEER_STATE_READY ||
932 peer->state == CONNMAN_PEER_STATE_DISCONNECT)
933 settings_changed(peer);
938 int connman_peer_request_connection(struct connman_peer *peer)
940 return __connman_agent_request_peer_authorization(peer,
941 request_authorization_cb, false,
945 static void peer_service_free(gpointer data)
947 struct _peer_service *service = data;
952 g_free(service->data);
956 void connman_peer_reset_services(struct connman_peer *peer)
961 g_slist_free_full(peer->services, peer_service_free);
962 peer->services = NULL;
965 void connman_peer_services_changed(struct connman_peer *peer)
967 if (!peer || !peer->registered || !allow_property_changed(peer))
970 connman_dbus_property_changed_array(peer->path,
971 CONNMAN_PEER_INTERFACE, "Services",
972 DBUS_TYPE_DICT_ENTRY, append_peer_services, peer);
975 void connman_peer_add_service(struct connman_peer *peer,
976 enum connman_peer_service_type type,
977 const unsigned char *data, int data_length)
979 struct _peer_service *service;
981 if (!peer || !data || type == CONNMAN_PEER_SERVICE_UNKNOWN)
984 service = g_malloc0(sizeof(struct _peer_service));
985 service->type = type;
986 service->data = g_memdup(data, data_length * sizeof(unsigned char));
987 service->length = data_length;
989 peer->services = g_slist_prepend(peer->services, service);
992 static void peer_up(struct connman_ipconfig *ipconfig, const char *ifname)
994 DBG("%s up", ifname);
997 static void peer_down(struct connman_ipconfig *ipconfig, const char *ifname)
999 DBG("%s down", ifname);
1002 static void peer_lower_up(struct connman_ipconfig *ipconfig,
1005 DBG("%s lower up", ifname);
1008 static void peer_lower_down(struct connman_ipconfig *ipconfig,
1011 struct connman_peer *peer = __connman_ipconfig_get_data(ipconfig);
1013 DBG("%s lower down", ifname);
1015 __connman_ipconfig_disable(ipconfig);
1016 connman_peer_set_state(peer, CONNMAN_PEER_STATE_DISCONNECT);
1019 static void peer_ip_bound(struct connman_ipconfig *ipconfig,
1022 struct connman_peer *peer = __connman_ipconfig_get_data(ipconfig);
1024 DBG("%s ip bound", ifname);
1026 if (peer->state == CONNMAN_PEER_STATE_READY)
1027 settings_changed(peer);
1028 connman_peer_set_state(peer, CONNMAN_PEER_STATE_READY);
1031 static void peer_ip_release(struct connman_ipconfig *ipconfig,
1034 struct connman_peer *peer = __connman_ipconfig_get_data(ipconfig);
1036 DBG("%s ip release", ifname);
1038 if (peer->state == CONNMAN_PEER_STATE_READY)
1039 settings_changed(peer);
1042 static const struct connman_ipconfig_ops peer_ip_ops = {
1045 .lower_up = peer_lower_up,
1046 .lower_down = peer_lower_down,
1047 .ip_bound = peer_ip_bound,
1048 .ip_release = peer_ip_release,
1050 .route_unset = NULL,
1053 static struct connman_ipconfig *create_ipconfig(int index, void *user_data)
1055 struct connman_ipconfig *ipconfig;
1057 ipconfig = __connman_ipconfig_create(index,
1058 CONNMAN_IPCONFIG_TYPE_IPV4);
1062 __connman_ipconfig_set_method(ipconfig, CONNMAN_IPCONFIG_METHOD_DHCP);
1063 __connman_ipconfig_set_data(ipconfig, user_data);
1064 __connman_ipconfig_set_ops(ipconfig, &peer_ip_ops);
1069 static const GDBusMethodTable peer_methods[] = {
1070 { GDBUS_METHOD("GetProperties",
1071 NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
1072 get_peer_properties) },
1073 { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, connect_peer) },
1074 { GDBUS_METHOD("Disconnect", NULL, NULL, disconnect_peer) },
1078 static const GDBusSignalTable peer_signals[] = {
1079 { GDBUS_SIGNAL("PropertyChanged",
1080 GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
1084 static char *get_peer_path(struct connman_device *device,
1085 const char *identifier)
1087 return g_strdup_printf("%s/peer/peer_%s_%s", CONNMAN_PATH,
1088 connman_device_get_ident(device), identifier);
1091 int connman_peer_register(struct connman_peer *peer)
1095 DBG("peer %p", peer);
1097 if (peer->path && peer->registered)
1100 index = connman_device_get_index(peer->device);
1101 peer->ipconfig = create_ipconfig(index, peer);
1102 if (!peer->ipconfig)
1105 peer->path = get_peer_path(peer->device, peer->identifier);
1106 DBG("path %s", peer->path);
1108 g_hash_table_insert(peers_table, peer->path, peer);
1110 g_dbus_register_interface(connection, peer->path,
1111 CONNMAN_PEER_INTERFACE,
1112 peer_methods, peer_signals,
1114 peer->registered = true;
1120 void connman_peer_unregister(struct connman_peer *peer)
1122 DBG("peer %p", peer);
1124 if (!peer->path || !peer->registered)
1127 connman_agent_cancel(peer);
1128 reply_pending(peer, EIO);
1130 g_dbus_unregister_interface(connection, peer->path,
1131 CONNMAN_PEER_INTERFACE);
1132 peer->registered = false;
1136 struct connman_peer *connman_peer_get(struct connman_device *device,
1137 const char *identifier)
1139 char *ident = get_peer_path(device, identifier);
1140 struct connman_peer *peer;
1142 peer = g_hash_table_lookup(peers_table, ident);
1148 int connman_peer_driver_register(struct connman_peer_driver *driver)
1150 if (peer_driver && peer_driver != driver)
1153 peer_driver = driver;
1155 __connman_peer_service_set_driver(driver);
1160 void connman_peer_driver_unregister(struct connman_peer_driver *driver)
1162 if (peer_driver != driver)
1167 __connman_peer_service_set_driver(NULL);
1170 void __connman_peer_list_struct(DBusMessageIter *array)
1172 g_hash_table_foreach(peers_table, append_peer_struct, array);
1175 const char *__connman_peer_get_path(struct connman_peer *peer)
1177 if (!peer || !peer->registered)
1183 static void disconnect_peer_hash_table(gpointer key,
1184 gpointer value, gpointer user_data)
1186 struct connman_peer *peer = value;
1187 peer_disconnect(peer);
1190 void __connman_peer_disconnect_all(void)
1192 g_hash_table_foreach(peers_table, disconnect_peer_hash_table, NULL);
1195 int __connman_peer_init(void)
1199 connection = connman_dbus_get_connection();
1201 peers_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1204 peers_notify = g_new0(struct _peers_notify, 1);
1205 peers_notify->add = g_hash_table_new(g_str_hash, g_str_equal);
1206 peers_notify->remove = g_hash_table_new_full(g_str_hash, g_str_equal,
1211 void __connman_peer_cleanup(void)
1215 g_hash_table_destroy(peers_notify->remove);
1216 g_hash_table_destroy(peers_notify->add);
1217 g_free(peers_notify);
1219 g_hash_table_destroy(peers_table);
1221 dbus_connection_unref(connection);