summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2019-01-27 23:46:28 +0100
committerThomas Haller <thaller@redhat.com>2019-01-27 23:46:28 +0100
commitce3f7bf812c21773251748693cd39d2fb54b9055 (patch)
treec83ce4959ede34eac770b705ecdef32446ea2b42
parentc7d6e55ed7ebbed23f620c76329a773a38511a9d (diff)
parentd8bc41bb580557214f3a894abe33dd44b92159b4 (diff)
downloadNetworkManager-ce3f7bf812c21773251748693cd39d2fb54b9055.tar.gz
wifi-p2p: merge branch 'benzea/p2p-wifi'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/24
-rw-r--r--Makefile.am134
-rw-r--r--clients/cli/connections.c1
-rw-r--r--clients/common/nm-client-utils.c1
-rw-r--r--clients/common/nm-meta-setting-desc.c28
-rw-r--r--clients/common/settings-docs.h.in2
-rw-r--r--docs/api/Makefile.am51
-rw-r--r--docs/api/network-manager-docs.xml7
-rw-r--r--docs/libnm/libnm-docs.xml3
-rw-r--r--introspection/meson.build2
-rw-r--r--introspection/org.freedesktop.NetworkManager.Device.P2PWireless.xml85
-rw-r--r--introspection/org.freedesktop.NetworkManager.P2PPeer.xml78
-rw-r--r--libnm-core/meson.build2
-rw-r--r--libnm-core/nm-core-enum-types.c.template1
-rw-r--r--libnm-core/nm-core-internal.h1
-rw-r--r--libnm-core/nm-core-types.h1
-rw-r--r--libnm-core/nm-dbus-interface.h5
-rw-r--r--libnm-core/nm-setting-p2p-wireless.c281
-rw-r--r--libnm-core/nm-setting-p2p-wireless.h74
-rw-r--r--libnm/NetworkManager.h3
-rw-r--r--libnm/libnm.ver23
-rw-r--r--libnm/meson.build4
-rw-r--r--libnm/nm-autoptr.h1
-rw-r--r--libnm/nm-client.c9
-rw-r--r--libnm/nm-device-p2p-wifi.c537
-rw-r--r--libnm/nm-device-p2p-wifi.h85
-rw-r--r--libnm/nm-p2p-peer.c596
-rw-r--r--libnm/nm-p2p-peer.h104
-rw-r--r--libnm/nm-types.h2
-rw-r--r--po/POTFILES.in2
-rw-r--r--shared/nm-meta-setting.c7
-rw-r--r--shared/nm-meta-setting.h1
-rw-r--r--src/devices/nm-device.c1
-rw-r--r--src/devices/wifi/meson.build8
-rw-r--r--src/devices/wifi/nm-device-p2p-wifi.c1366
-rw-r--r--src/devices/wifi/nm-device-p2p-wifi.h56
-rw-r--r--src/devices/wifi/nm-device-wifi.c86
-rw-r--r--src/devices/wifi/nm-device-wifi.h1
-rw-r--r--src/devices/wifi/nm-wifi-factory.c23
-rw-r--r--src/devices/wifi/nm-wifi-p2p-peer.c808
-rw-r--r--src/devices/wifi/nm-wifi-p2p-peer.h114
-rw-r--r--src/nm-types.h1
-rw-r--r--src/org.freedesktop.NetworkManager.conf4
-rw-r--r--vapi/NM-1.0.metadata1
43 files changed, 4515 insertions, 85 deletions
diff --git a/Makefile.am b/Makefile.am
index c8a5ed0617..7a75a6637f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -389,30 +389,32 @@ introspection_libnmdbus_la_CPPFLAGS = $(GLIB_CFLAGS)
introspection_sources = \
introspection/org.freedesktop.NetworkManager.AccessPoint.c \
introspection/org.freedesktop.NetworkManager.AccessPoint.h \
- introspection/org.freedesktop.NetworkManager.Connection.Active.c \
- introspection/org.freedesktop.NetworkManager.Connection.Active.h \
introspection/org.freedesktop.NetworkManager.AgentManager.c \
introspection/org.freedesktop.NetworkManager.AgentManager.h \
introspection/org.freedesktop.NetworkManager.Checkpoint.c \
introspection/org.freedesktop.NetworkManager.Checkpoint.h \
+ introspection/org.freedesktop.NetworkManager.Connection.Active.c \
+ introspection/org.freedesktop.NetworkManager.Connection.Active.h \
+ introspection/org.freedesktop.NetworkManager.DHCP4Config.c \
+ introspection/org.freedesktop.NetworkManager.DHCP4Config.h \
+ introspection/org.freedesktop.NetworkManager.DHCP6Config.c \
+ introspection/org.freedesktop.NetworkManager.DHCP6Config.h \
introspection/org.freedesktop.NetworkManager.Device.Adsl.c \
introspection/org.freedesktop.NetworkManager.Device.Adsl.h \
+ introspection/org.freedesktop.NetworkManager.Device.Bluetooth.c \
+ introspection/org.freedesktop.NetworkManager.Device.Bluetooth.h \
introspection/org.freedesktop.NetworkManager.Device.Bond.c \
introspection/org.freedesktop.NetworkManager.Device.Bond.h \
introspection/org.freedesktop.NetworkManager.Device.Bridge.c \
introspection/org.freedesktop.NetworkManager.Device.Bridge.h \
- introspection/org.freedesktop.NetworkManager.Device.Bluetooth.c \
- introspection/org.freedesktop.NetworkManager.Device.Bluetooth.h \
introspection/org.freedesktop.NetworkManager.Device.Dummy.c \
introspection/org.freedesktop.NetworkManager.Device.Dummy.h \
- introspection/org.freedesktop.NetworkManager.Device.Wired.c \
- introspection/org.freedesktop.NetworkManager.Device.Wired.h \
introspection/org.freedesktop.NetworkManager.Device.Generic.c \
introspection/org.freedesktop.NetworkManager.Device.Generic.h \
- introspection/org.freedesktop.NetworkManager.Device.Infiniband.c \
- introspection/org.freedesktop.NetworkManager.Device.Infiniband.h \
introspection/org.freedesktop.NetworkManager.Device.IPTunnel.c \
introspection/org.freedesktop.NetworkManager.Device.IPTunnel.h \
+ introspection/org.freedesktop.NetworkManager.Device.Infiniband.c \
+ introspection/org.freedesktop.NetworkManager.Device.Infiniband.h \
introspection/org.freedesktop.NetworkManager.Device.Lowpan.c \
introspection/org.freedesktop.NetworkManager.Device.Lowpan.h \
introspection/org.freedesktop.NetworkManager.Device.Macsec.c \
@@ -423,12 +425,14 @@ introspection_sources = \
introspection/org.freedesktop.NetworkManager.Device.Modem.h \
introspection/org.freedesktop.NetworkManager.Device.OlpcMesh.c \
introspection/org.freedesktop.NetworkManager.Device.OlpcMesh.h \
+ introspection/org.freedesktop.NetworkManager.Device.OvsBridge.c \
+ introspection/org.freedesktop.NetworkManager.Device.OvsBridge.h \
introspection/org.freedesktop.NetworkManager.Device.OvsInterface.c \
introspection/org.freedesktop.NetworkManager.Device.OvsInterface.h \
introspection/org.freedesktop.NetworkManager.Device.OvsPort.c \
introspection/org.freedesktop.NetworkManager.Device.OvsPort.h \
- introspection/org.freedesktop.NetworkManager.Device.OvsBridge.c \
- introspection/org.freedesktop.NetworkManager.Device.OvsBridge.h \
+ introspection/org.freedesktop.NetworkManager.Device.P2PWireless.c \
+ introspection/org.freedesktop.NetworkManager.Device.P2PWireless.h \
introspection/org.freedesktop.NetworkManager.Device.Ppp.c \
introspection/org.freedesktop.NetworkManager.Device.Ppp.h \
introspection/org.freedesktop.NetworkManager.Device.Statistics.c \
@@ -443,28 +447,26 @@ introspection_sources = \
introspection/org.freedesktop.NetworkManager.Device.Vlan.h \
introspection/org.freedesktop.NetworkManager.Device.Vxlan.c \
introspection/org.freedesktop.NetworkManager.Device.Vxlan.h \
+ introspection/org.freedesktop.NetworkManager.Device.WiMax.c \
+ introspection/org.freedesktop.NetworkManager.Device.WiMax.h \
introspection/org.freedesktop.NetworkManager.Device.WireGuard.c \
introspection/org.freedesktop.NetworkManager.Device.WireGuard.h \
+ introspection/org.freedesktop.NetworkManager.Device.Wired.c \
+ introspection/org.freedesktop.NetworkManager.Device.Wired.h \
introspection/org.freedesktop.NetworkManager.Device.Wireless.c \
introspection/org.freedesktop.NetworkManager.Device.Wireless.h \
- introspection/org.freedesktop.NetworkManager.Device.WiMax.c \
- introspection/org.freedesktop.NetworkManager.Device.WiMax.h \
introspection/org.freedesktop.NetworkManager.Device.Wpan.c \
introspection/org.freedesktop.NetworkManager.Device.Wpan.h \
introspection/org.freedesktop.NetworkManager.Device.c \
introspection/org.freedesktop.NetworkManager.Device.h \
- introspection/org.freedesktop.NetworkManager.DHCP4Config.c \
- introspection/org.freedesktop.NetworkManager.DHCP4Config.h \
- introspection/org.freedesktop.NetworkManager.DHCP6Config.c \
- introspection/org.freedesktop.NetworkManager.DHCP6Config.h \
introspection/org.freedesktop.NetworkManager.DnsManager.c \
introspection/org.freedesktop.NetworkManager.DnsManager.h \
introspection/org.freedesktop.NetworkManager.IP4Config.c \
introspection/org.freedesktop.NetworkManager.IP4Config.h \
introspection/org.freedesktop.NetworkManager.IP6Config.c \
introspection/org.freedesktop.NetworkManager.IP6Config.h \
- introspection/org.freedesktop.NetworkManager.c \
- introspection/org.freedesktop.NetworkManager.h \
+ introspection/org.freedesktop.NetworkManager.P2PPeer.c \
+ introspection/org.freedesktop.NetworkManager.P2PPeer.h \
introspection/org.freedesktop.NetworkManager.PPP.c \
introspection/org.freedesktop.NetworkManager.PPP.h \
introspection/org.freedesktop.NetworkManager.SecretAgent.c \
@@ -476,56 +478,62 @@ introspection_sources = \
introspection/org.freedesktop.NetworkManager.VPN.Connection.c \
introspection/org.freedesktop.NetworkManager.VPN.Connection.h \
introspection/org.freedesktop.NetworkManager.VPN.Plugin.c \
- introspection/org.freedesktop.NetworkManager.VPN.Plugin.h
+ introspection/org.freedesktop.NetworkManager.VPN.Plugin.h \
+ introspection/org.freedesktop.NetworkManager.c \
+ introspection/org.freedesktop.NetworkManager.h \
+ $(NULL)
nodist_introspection_libnmdbus_la_SOURCES = $(introspection_sources)
DBUS_INTERFACE_DOCS = \
docs/api/dbus-org.freedesktop.NetworkManager.AccessPoint.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Connection.Active.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.AgentManager.xml \
docs/api/dbus-org.freedesktop.NetworkManager.Checkpoint.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Device.Team.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Connection.Active.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.DHCP4Config.xml \
docs/api/dbus-org.freedesktop.NetworkManager.DHCP6Config.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Device.Wireless.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.VPN.Connection.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.SecretAgent.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Device.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.VPN.Plugin.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.Adsl.xml \
docs/api/dbus-org.freedesktop.NetworkManager.Device.Bluetooth.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Device.Dummy.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Device.Vxlan.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Settings.Connection.xml \
docs/api/dbus-org.freedesktop.NetworkManager.Device.Bond.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.Bridge.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.Dummy.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.Generic.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.IPTunnel.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.Infiniband.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.Lowpan.xml \
docs/api/dbus-org.freedesktop.NetworkManager.Device.Macsec.xml \
docs/api/dbus-org.freedesktop.NetworkManager.Device.Macvlan.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.PPP.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Device.Vlan.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Device.Adsl.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.AgentManager.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Device.WiMax.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Device.Wpan.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Device.IPTunnel.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Device.Tun.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Device.Bridge.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.Modem.xml \
docs/api/dbus-org.freedesktop.NetworkManager.Device.OlpcMesh.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.OvsBridge.xml \
docs/api/dbus-org.freedesktop.NetworkManager.Device.OvsInterface.xml \
docs/api/dbus-org.freedesktop.NetworkManager.Device.OvsPort.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Device.OvsBridge.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.P2PWireless.xml \
docs/api/dbus-org.freedesktop.NetworkManager.Device.Ppp.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.DHCP4Config.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Device.Generic.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Device.Infiniband.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Device.Modem.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.IP6Config.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.Statistics.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.Team.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.Tun.xml \
docs/api/dbus-org.freedesktop.NetworkManager.Device.Veth.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Settings.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Device.Wired.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.Vlan.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.Vxlan.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.WiMax.xml \
docs/api/dbus-org.freedesktop.NetworkManager.Device.WireGuard.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.IP4Config.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Device.Statistics.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.Wired.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.Wireless.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.Wpan.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.xml \
docs/api/dbus-org.freedesktop.NetworkManager.DnsManager.xml \
- docs/api/dbus-org.freedesktop.NetworkManager.Device.Lowpan.xml
+ docs/api/dbus-org.freedesktop.NetworkManager.IP4Config.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.IP6Config.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.P2PPeer.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.PPP.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.SecretAgent.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Settings.Connection.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Settings.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.VPN.Connection.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.VPN.Plugin.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.xml \
+ $(NULL)
introspection/%.c: introspection/%.xml
@$(MKDIR_P) introspection/
@@ -566,6 +574,7 @@ dbusinterfaces_DATA = \
introspection/org.freedesktop.NetworkManager.Device.OvsInterface.xml \
introspection/org.freedesktop.NetworkManager.Device.OvsPort.xml \
introspection/org.freedesktop.NetworkManager.Device.OvsBridge.xml \
+ introspection/org.freedesktop.NetworkManager.Device.P2PWireless.xml \
introspection/org.freedesktop.NetworkManager.Device.Ppp.xml \
introspection/org.freedesktop.NetworkManager.Device.Statistics.xml \
introspection/org.freedesktop.NetworkManager.Device.Team.xml \
@@ -584,6 +593,7 @@ dbusinterfaces_DATA = \
introspection/org.freedesktop.NetworkManager.IP4Config.xml \
introspection/org.freedesktop.NetworkManager.IP6Config.xml \
introspection/org.freedesktop.NetworkManager.xml \
+ introspection/org.freedesktop.NetworkManager.P2PPeer.xml \
introspection/org.freedesktop.NetworkManager.PPP.xml \
introspection/org.freedesktop.NetworkManager.SecretAgent.xml \
introspection/org.freedesktop.NetworkManager.Settings.Connection.xml \
@@ -643,6 +653,7 @@ libnm_core_lib_h_pub_real = \
libnm-core/nm-setting-ovs-interface.h \
libnm-core/nm-setting-ovs-patch.h \
libnm-core/nm-setting-ovs-port.h \
+ libnm-core/nm-setting-p2p-wireless.h \
libnm-core/nm-setting-ppp.h \
libnm-core/nm-setting-pppoe.h \
libnm-core/nm-setting-proxy.h \
@@ -711,6 +722,7 @@ libnm_core_lib_c_settings_real = \
libnm-core/nm-setting-ovs-interface.c \
libnm-core/nm-setting-ovs-patch.c \
libnm-core/nm-setting-ovs-port.c \
+ libnm-core/nm-setting-p2p-wireless.c \
libnm-core/nm-setting-ppp.c \
libnm-core/nm-setting-pppoe.c \
libnm-core/nm-setting-proxy.c \
@@ -1032,6 +1044,7 @@ libnm_lib_h_pub_real = \
libnm/nm-device-ovs-interface.h \
libnm/nm-device-ovs-port.h \
libnm/nm-device-ovs-bridge.h \
+ libnm/nm-device-p2p-wifi.h \
libnm/nm-device-ppp.h \
libnm/nm-device-team.h \
libnm/nm-device-tun.h \
@@ -1045,6 +1058,7 @@ libnm_lib_h_pub_real = \
libnm/nm-dhcp-config.h \
libnm/nm-ip-config.h \
libnm/nm-object.h \
+ libnm/nm-p2p-peer.h \
libnm/nm-remote-connection.h \
libnm/nm-secret-agent-old.h \
libnm/nm-types.h \
@@ -1091,6 +1105,7 @@ libnm_lib_c_real = \
libnm/nm-device-ovs-interface.c \
libnm/nm-device-ovs-port.c \
libnm/nm-device-ovs-bridge.c \
+ libnm/nm-device-p2p-wifi.c \
libnm/nm-device-ppp.c \
libnm/nm-device-team.c \
libnm/nm-device-tun.c \
@@ -1110,6 +1125,7 @@ libnm_lib_c_real = \
libnm/nm-ip6-config.c \
libnm/nm-manager.c \
libnm/nm-object.c \
+ libnm/nm-p2p-peer.c \
libnm/nm-remote-connection.c \
libnm/nm-remote-settings.c \
libnm/nm-secret-agent-old.c \
@@ -3238,24 +3254,30 @@ if WITH_WIFI
core_plugins += src/devices/wifi/libnm-device-plugin-wifi.la
src_devices_wifi_libnm_device_plugin_wifi_la_SOURCES = \
- src/devices/wifi/nm-wifi-factory.c \
+ src/devices/wifi/nm-device-olpc-mesh.c \
+ src/devices/wifi/nm-device-olpc-mesh.h \
+ src/devices/wifi/nm-device-p2p-wifi.c \
+ src/devices/wifi/nm-device-p2p-wifi.h \
src/devices/wifi/nm-device-wifi.c \
src/devices/wifi/nm-device-wifi.h \
src/devices/wifi/nm-wifi-ap.c \
src/devices/wifi/nm-wifi-ap.h \
- src/devices/wifi/nm-wifi-utils.c \
- src/devices/wifi/nm-wifi-utils.h \
src/devices/wifi/nm-wifi-common.c \
src/devices/wifi/nm-wifi-common.h \
- src/devices/wifi/nm-device-olpc-mesh.c \
- src/devices/wifi/nm-device-olpc-mesh.h
+ src/devices/wifi/nm-wifi-factory.c \
+ src/devices/wifi/nm-wifi-p2p-peer.c \
+ src/devices/wifi/nm-wifi-p2p-peer.h \
+ src/devices/wifi/nm-wifi-utils.c \
+ src/devices/wifi/nm-wifi-utils.h \
+ $(NULL)
if WITH_IWD
src_devices_wifi_libnm_device_plugin_wifi_la_SOURCES += \
src/devices/wifi/nm-device-iwd.c \
src/devices/wifi/nm-device-iwd.h \
src/devices/wifi/nm-iwd-manager.c \
- src/devices/wifi/nm-iwd-manager.h
+ src/devices/wifi/nm-iwd-manager.h \
+ $(NULL)
endif
src_devices_wifi_libnm_device_plugin_wifi_la_CPPFLAGS = $(src_cppflags_device_plugin)
diff --git a/clients/cli/connections.c b/clients/cli/connections.c
index 446424ba46..8155bfb960 100644
--- a/clients/cli/connections.c
+++ b/clients/cli/connections.c
@@ -796,6 +796,7 @@ const NmcMetaGenericInfo *const metagen_con_active_vpn[_NMC_GENERIC_INFO_TYPE_CO
NM_SETTING_IP4_CONFIG_SETTING_NAME","\
NM_SETTING_IP6_CONFIG_SETTING_NAME","\
NM_SETTING_SERIAL_SETTING_NAME","\
+ NM_SETTING_P2P_WIRELESS_SETTING_NAME","\
NM_SETTING_PPP_SETTING_NAME","\
NM_SETTING_PPPOE_SETTING_NAME","\
NM_SETTING_ADSL_SETTING_NAME","\
diff --git a/clients/common/nm-client-utils.c b/clients/common/nm-client-utils.c
index 8ba2453ee8..1241131a11 100644
--- a/clients/common/nm-client-utils.c
+++ b/clients/common/nm-client-utils.c
@@ -352,6 +352,7 @@ NM_UTILS_LOOKUP_STR_DEFINE (nmc_device_reason_to_string, NMDeviceStateReason,
NM_UTILS_LOOKUP_ITEM (NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE, N_("A duplicate IP address was detected")),
NM_UTILS_LOOKUP_ITEM (NM_DEVICE_STATE_REASON_IP_METHOD_UNSUPPORTED, N_("The selected IP method is not supported")),
NM_UTILS_LOOKUP_ITEM (NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED, N_("Failed to configure SR-IOV parameters")),
+ NM_UTILS_LOOKUP_ITEM (NM_DEVICE_STATE_REASON_PEER_NOT_FOUND, N_("The Wi-Fi P2P peer could not be found")),
)
NM_UTILS_LOOKUP_STR_DEFINE (nm_active_connection_state_reason_to_string, NMActiveConnectionStateReason,
diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c
index 4befce259a..6b76d80be3 100644
--- a/clients/common/nm-meta-setting-desc.c
+++ b/clients/common/nm-meta-setting-desc.c
@@ -7843,6 +7843,27 @@ static const NMMetaPropertyInfo *const property_infos_6LOWPAN[] = {
NULL
};
+#undef _CURRENT_NM_META_SETTING_TYPE
+#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_P2P_WIRELESS
+static const NMMetaPropertyInfo *const property_infos_P2P_WIRELESS[] = {
+ PROPERTY_INFO_WITH_DESC (NM_SETTING_P2P_WIRELESS_PEER,
+ .is_cli_option = TRUE,
+ .property_alias = "peer",
+ .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD,
+ .prompt = N_("Peer"),
+ .property_type = &_pt_gobject_mac,
+ ),
+ PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_SECURITY_WPS_METHOD,
+ .property_type = &_pt_gobject_enum,
+ .property_typ_data = DEFINE_PROPERTY_TYP_DATA (
+ PROPERTY_TYP_DATA_SUBTYPE (gobject_enum,
+ .get_gtype = nm_setting_wireless_security_wps_method_get_type,
+ ),
+ ),
+ ),
+ NULL
+};
+
/*****************************************************************************/
static void
@@ -8008,6 +8029,7 @@ _setting_init_fcn_wireless (ARGS_SETTING_INIT_FCN)
#define SETTING_PRETTY_NAME_WIRELESS_SECURITY N_("Wi-Fi security settings")
#define SETTING_PRETTY_NAME_WPAN N_("WPAN settings")
#define SETTING_PRETTY_NAME_6LOWPAN N_("6LOWPAN settings")
+#define SETTING_PRETTY_NAME_P2P_WIRELESS N_("P2P Wi-Fi connection")
#define NM_META_SETTING_VALID_PARTS(...) \
((const NMMetaSettingValidPartItem *const[]) { __VA_ARGS__ NULL })
@@ -8282,6 +8304,12 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
NM_META_SETTING_VALID_PART_ITEM (WPAN, TRUE),
),
),
+ SETTING_INFO (P2P_WIRELESS,
+ .valid_parts = NM_META_SETTING_VALID_PARTS (
+ NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE),
+ NM_META_SETTING_VALID_PART_ITEM (P2P_WIRELESS, TRUE),
+ ),
+ ),
};
/*****************************************************************************/
diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in
index ca0150e694..7f1a59d5fa 100644
--- a/clients/common/settings-docs.h.in
+++ b/clients/common/settings-docs.h.in
@@ -263,6 +263,8 @@
#define DESCRIBE_DOC_NM_SETTING_OVS_PORT_LACP N_("LACP mode. One of \"active\", \"off\", or \"passive\".")
#define DESCRIBE_DOC_NM_SETTING_OVS_PORT_TAG N_("The VLAN tag in the range 0-4095.")
#define DESCRIBE_DOC_NM_SETTING_OVS_PORT_VLAN_MODE N_("The VLAN mode. One of \"access\", \"native-tagged\", \"native-untagged\", \"trunk\" or unset.")
+#define DESCRIBE_DOC_NM_SETTING_P2P_WIRELESS_PEER N_("The P2P device that should be connected to. Currently this is the only way to create or join a group.")
+#define DESCRIBE_DOC_NM_SETTING_P2P_WIRELESS_WPS_METHOD N_("Flags indicating which mode of WPS is to be used. There's little point in changing the default setting as NetworkManager will automatically determine the best method to use.")
#define DESCRIBE_DOC_NM_SETTING_PPP_BAUD N_("If non-zero, instruct pppd to set the serial port to the specified baudrate. This value should normally be left as 0 to automatically choose the speed.")
#define DESCRIBE_DOC_NM_SETTING_PPP_CRTSCTS N_("If TRUE, specify that pppd should set the serial port to use hardware flow control with RTS and CTS signals. This value should normally be set to FALSE.")
#define DESCRIBE_DOC_NM_SETTING_PPP_LCP_ECHO_FAILURE N_("If non-zero, instruct pppd to presume the connection to the peer has failed if the specified number of LCP echo-requests go unanswered by the peer. The \"lcp-echo-interval\" property must also be set to a non-zero value if this property is used.")
diff --git a/docs/api/Makefile.am b/docs/api/Makefile.am
index 2baf40562f..7ec77963f2 100644
--- a/docs/api/Makefile.am
+++ b/docs/api/Makefile.am
@@ -42,42 +42,43 @@ MKHTML_OPTIONS=--path="$(abs_srcdir)"
content_files = \
$(GENERATED_FILES) \
dbus-org.freedesktop.NetworkManager.AccessPoint.xml \
+ dbus-org.freedesktop.NetworkManager.AgentManager.xml \
dbus-org.freedesktop.NetworkManager.Connection.Active.xml \
- dbus-org.freedesktop.NetworkManager.Device.Team.xml \
+ dbus-org.freedesktop.NetworkManager.DHCP4Config.xml \
dbus-org.freedesktop.NetworkManager.DHCP6Config.xml \
- dbus-org.freedesktop.NetworkManager.Device.Wireless.xml \
- dbus-org.freedesktop.NetworkManager.xml \
- dbus-org.freedesktop.NetworkManager.VPN.Connection.xml \
- dbus-org.freedesktop.NetworkManager.SecretAgent.xml \
- dbus-org.freedesktop.NetworkManager.Device.xml \
- dbus-org.freedesktop.NetworkManager.VPN.Plugin.xml \
+ dbus-org.freedesktop.NetworkManager.Device.Adsl.xml \
dbus-org.freedesktop.NetworkManager.Device.Bluetooth.xml \
- dbus-org.freedesktop.NetworkManager.Device.Dummy.xml \
- dbus-org.freedesktop.NetworkManager.Device.Vxlan.xml \
- dbus-org.freedesktop.NetworkManager.Settings.Connection.xml \
dbus-org.freedesktop.NetworkManager.Device.Bond.xml \
- dbus-org.freedesktop.NetworkManager.Device.Macvlan.xml \
- dbus-org.freedesktop.NetworkManager.Device.Macsec.xml \
- dbus-org.freedesktop.NetworkManager.PPP.xml \
- dbus-org.freedesktop.NetworkManager.Device.Vlan.xml \
- dbus-org.freedesktop.NetworkManager.Device.Adsl.xml \
- dbus-org.freedesktop.NetworkManager.AgentManager.xml \
- dbus-org.freedesktop.NetworkManager.Device.IPTunnel.xml \
- dbus-org.freedesktop.NetworkManager.Device.Tun.xml \
dbus-org.freedesktop.NetworkManager.Device.Bridge.xml \
- dbus-org.freedesktop.NetworkManager.Device.OlpcMesh.xml \
- dbus-org.freedesktop.NetworkManager.DHCP4Config.xml \
+ dbus-org.freedesktop.NetworkManager.Device.Dummy.xml \
dbus-org.freedesktop.NetworkManager.Device.Generic.xml \
+ dbus-org.freedesktop.NetworkManager.Device.IPTunnel.xml \
dbus-org.freedesktop.NetworkManager.Device.Infiniband.xml \
+ dbus-org.freedesktop.NetworkManager.Device.Macsec.xml \
+ dbus-org.freedesktop.NetworkManager.Device.Macvlan.xml \
dbus-org.freedesktop.NetworkManager.Device.Modem.xml \
- dbus-org.freedesktop.NetworkManager.IP6Config.xml \
+ dbus-org.freedesktop.NetworkManager.Device.OlpcMesh.xml \
+ dbus-org.freedesktop.NetworkManager.Device.Statistics.xml \
+ dbus-org.freedesktop.NetworkManager.Device.Team.xml \
+ dbus-org.freedesktop.NetworkManager.Device.Tun.xml \
dbus-org.freedesktop.NetworkManager.Device.Veth.xml \
- dbus-org.freedesktop.NetworkManager.Settings.xml \
- dbus-org.freedesktop.NetworkManager.Device.Wired.xml \
+ dbus-org.freedesktop.NetworkManager.Device.Vlan.xml \
+ dbus-org.freedesktop.NetworkManager.Device.Vxlan.xml \
dbus-org.freedesktop.NetworkManager.Device.WireGuard.xml \
- dbus-org.freedesktop.NetworkManager.IP4Config.xml \
- dbus-org.freedesktop.NetworkManager.Device.Statistics.xml \
+ dbus-org.freedesktop.NetworkManager.Device.P2PWireless.xml \
+ dbus-org.freedesktop.NetworkManager.Device.Wired.xml \
+ dbus-org.freedesktop.NetworkManager.Device.Wireless.xml \
+ dbus-org.freedesktop.NetworkManager.Device.xml \
dbus-org.freedesktop.NetworkManager.DnsManager.xml \
+ dbus-org.freedesktop.NetworkManager.IP4Config.xml \
+ dbus-org.freedesktop.NetworkManager.IP6Config.xml \
+ dbus-org.freedesktop.NetworkManager.PPP.xml \
+ dbus-org.freedesktop.NetworkManager.SecretAgent.xml \
+ dbus-org.freedesktop.NetworkManager.Settings.Connection.xml \
+ dbus-org.freedesktop.NetworkManager.Settings.xml \
+ dbus-org.freedesktop.NetworkManager.VPN.Connection.xml \
+ dbus-org.freedesktop.NetworkManager.VPN.Plugin.xml \
+ dbus-org.freedesktop.NetworkManager.xml \
$(top_builddir)/libnm-core/nm-dbus-types.xml \
$(top_builddir)/libnm-core/nm-vpn-dbus-types.xml \
$(top_builddir)/man/nmcli.xml \
diff --git a/docs/api/network-manager-docs.xml b/docs/api/network-manager-docs.xml
index 06ac37415d..8b7c8c6bf9 100644
--- a/docs/api/network-manager-docs.xml
+++ b/docs/api/network-manager-docs.xml
@@ -206,6 +206,7 @@
<xi:include href="dbus-org.freedesktop.NetworkManager.Device.Vxlan.xml"/>
<xi:include href="dbus-org.freedesktop.NetworkManager.Device.WireGuard.xml"/>
<xi:include href="dbus-org.freedesktop.NetworkManager.Device.Wireless.xml"/>
+ <xi:include href="dbus-org.freedesktop.NetworkManager.Device.P2PWireless.xml"/>
<xi:include href="dbus-org.freedesktop.NetworkManager.Device.Wpan.xml"/>
<xi:include href="dbus-org.freedesktop.NetworkManager.PPP.xml"/>
</chapter>
@@ -247,6 +248,12 @@
<xi:include href="dbus-org.freedesktop.NetworkManager.AccessPoint.xml"/>
</chapter>
+ <chapter id="ref-dbus-p2p-peers">
+ <title>The <literal>/org/freedesktop/NetworkManager/P2PPeer/*</literal> objects</title>
+ <!-- TODO: Describe the objects here -->
+ <xi:include href="dbus-org.freedesktop.NetworkManager.P2PPeer.xml"/>
+ </chapter>
+
<chapter id="ref-dbus-checkpoint">
<title>The <literal>/org/freedesktop/NetworkManager/Checkpoint/*</literal> objects</title>
<!-- TODO: Describe the objects here -->
diff --git a/docs/libnm/libnm-docs.xml b/docs/libnm/libnm-docs.xml
index eb4f6cf585..03f6835737 100644
--- a/docs/libnm/libnm-docs.xml
+++ b/docs/libnm/libnm-docs.xml
@@ -218,6 +218,7 @@ print ("NetworkManager version " + client.get_version())]]></programlisting></in
<xi:include href="xml/nm-setting-ovs-interface.xml"/>
<xi:include href="xml/nm-setting-ovs-patch.xml"/>
<xi:include href="xml/nm-setting-ovs-port.xml"/>
+ <xi:include href="xml/nm-setting-p2p-wireless.xml"/>
<xi:include href="xml/nm-setting-pppoe.xml"/>
<xi:include href="xml/nm-setting-ppp.xml"/>
<xi:include href="xml/nm-setting-proxy.xml"/>
@@ -260,6 +261,7 @@ print ("NetworkManager version " + client.get_version())]]></programlisting></in
<xi:include href="xml/nm-device-ovs-bridge.xml"/>
<xi:include href="xml/nm-device-ovs-interface.xml"/>
<xi:include href="xml/nm-device-ovs-port.xml"/>
+ <xi:include href="xml/nm-device-p2p-wifi.xml"/>
<xi:include href="xml/nm-device-ppp.xml"/>
<xi:include href="xml/nm-device-team.xml"/>
<xi:include href="xml/nm-device-tun.xml"/>
@@ -273,6 +275,7 @@ print ("NetworkManager version " + client.get_version())]]></programlisting></in
<xi:include href="xml/nm-active-connection.xml"/>
<xi:include href="xml/nm-vpn-connection.xml"/>
<xi:include href="xml/nm-access-point.xml"/>
+ <xi:include href="xml/nm-p2p-peer.xml"/>
<xi:include href="xml/nm-wimax-nsp.xml"/>
<xi:include href="xml/nm-ip-config.xml"/>
<xi:include href="xml/nm-dhcp-config.xml"/>
diff --git a/introspection/meson.build b/introspection/meson.build
index ef2ad9c1af..e5bbe2a284 100644
--- a/introspection/meson.build
+++ b/introspection/meson.build
@@ -23,6 +23,7 @@ ifaces = [
'org.freedesktop.NetworkManager.Device.OvsInterface',
'org.freedesktop.NetworkManager.Device.OvsPort',
'org.freedesktop.NetworkManager.Device.OvsBridge',
+ 'org.freedesktop.NetworkManager.Device.P2PWireless',
'org.freedesktop.NetworkManager.Device.Ppp',
'org.freedesktop.NetworkManager.Device.Statistics',
'org.freedesktop.NetworkManager.Device.Team',
@@ -42,6 +43,7 @@ ifaces = [
'org.freedesktop.NetworkManager.IP4Config',
'org.freedesktop.NetworkManager.IP6Config',
'org.freedesktop.NetworkManager',
+ 'org.freedesktop.NetworkManager.P2PPeer',
'org.freedesktop.NetworkManager.PPP',
'org.freedesktop.NetworkManager.SecretAgent',
'org.freedesktop.NetworkManager.Settings.Connection',
diff --git a/introspection/org.freedesktop.NetworkManager.Device.P2PWireless.xml b/introspection/org.freedesktop.NetworkManager.Device.P2PWireless.xml
new file mode 100644
index 0000000000..6f7bdeaeb6
--- /dev/null
+++ b/introspection/org.freedesktop.NetworkManager.Device.P2PWireless.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<node name="/">
+ <!--
+ org.freedesktop.NetworkManager.Device.P2PWireless:
+ @short_description: P2P Wi-Fi Device
+
+ -->
+ <interface name="org.freedesktop.NetworkManager.Device.P2PWireless">
+ <annotation name="org.gtk.GDBus.C.Name" value="Device_P2P_Wifi"/>
+
+ <!--
+ HwAddress:
+
+ The active hardware address of the device.
+ -->
+ <property name="HwAddress" type="s" access="read"/>
+
+ <!--
+ GroupOwner:
+
+ Whether this device is currently the group owner.
+ -->
+ <property name="GroupOwner" type="b" access="read"/>
+
+ <!--
+ WFDIEs:
+
+ The Wi-Fi Display information elements.
+ -->
+ <property name="WFDIEs" type="ay" access="read">
+ <!-- gdbus-codegen assumes that "ay" means "non-UTF-8 string" and
+ won't deal with '\0' bytes correctly.
+ -->
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="1"/>
+ </property>
+
+ <!--
+ Peers:
+
+ List of object paths of peers visible to this p2p wireless device.
+ -->
+ <property name="Peers" type="ao" access="read"/>
+
+ <!--
+ StartFind:
+ @options: Options of find. Currently 'timeout' option with value of "i"
+ in the range of 1-600 seconds is supported. The default is
+ 30 seconds.
+
+ Start a find operation for P2P peers.
+ -->
+ <method name="StartFind">
+ <arg name="options" type="a{sv}" direction="in"/>
+ </method>
+
+ <!--
+ StopFind:
+
+ Stop an ongoing find operation again.
+ -->
+ <method name="StopFind">
+ </method>
+
+ <!--
+ PeerAdded:
+ @peer: The object path of the newly found access point.
+
+ Emitted when a new P2P peer is found by the device.
+ -->
+ <signal name="PeerAdded">
+ <arg name="peer" type="o"/>
+ </signal>
+
+ <!--
+ PeerRemoved:
+ @peer: The object path of the P2P peer that has disappeared.
+
+ Emitted when a P2P peer disappears from view of the device.
+ -->
+ <signal name="PeerRemoved">
+ <arg name="peer" type="o"/>
+ </signal>
+
+ </interface>
+</node>
diff --git a/introspection/org.freedesktop.NetworkManager.P2PPeer.xml b/introspection/org.freedesktop.NetworkManager.P2PPeer.xml
new file mode 100644
index 0000000000..1a1cf71308
--- /dev/null
+++ b/introspection/org.freedesktop.NetworkManager.P2PPeer.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<node name="/">
+ <!--
+ org.freedesktop.NetworkManager.P2PPeer:
+ @short_description: P2P Wi-Fi Peer
+
+ -->
+ <interface name="org.freedesktop.NetworkManager.P2PPeer">
+ <annotation name="org.gtk.GDBus.C.Name" value="P2P_Peer"/>
+
+ <!--
+ Flags:
+
+ Flags describing the capabilities of the access point.
+
+ Returns: <link linkend="NM80211ApFlags">NM80211ApFlags</link>
+ -->
+ <property name="Flags" type="u" access="read"/>
+
+ <!--
+ Manufacturer:
+
+ The manufacturer of the P2P peer.
+ -->
+ <property name="Manufacturer" type="s" access="read"/>
+
+ <!--
+ Model:
+
+ The model of the P2P peer.
+ -->
+ <property name="Model" type="s" access="read"/>
+
+ <!--
+ ModelNumber:
+
+ The model number of the P2P peer.
+ -->
+ <property name="ModelNumber" type="s" access="read"/>
+
+ <!--
+ Serial:
+
+ The serial number of the P2P peer.
+ -->
+ <property name="Serial" type="s" access="read"/>
+
+ <!--
+ Wfdies:
+
+ The Wi-Fi Display Information Elements of the P2P peer.
+ -->
+ <property name="WfdIEs" type="ay" access="read"/>
+
+ <!--
+ HwAddress:
+
+ The hardware address (BSSID) of the access point.
+ -->
+ <property name="HwAddress" type="s" access="read"/>
+
+ <!--
+ Strength:
+
+ The current signal quality of the access point, in percent.
+ -->
+ <property name="Strength" type="y" access="read"/>
+
+ <!--
+ LastSeen:
+
+ The timestamp (in CLOCK_BOOTTIME seconds) for the last time the access
+ point was found in scan results. A value of -1 means the access point has
+ never been found in scan results.
+ -->
+ <property name="LastSeen" type="i" access="read"/>
+ </interface>
+</node>
diff --git a/libnm-core/meson.build b/libnm-core/meson.build
index 812f12bbcc..e615b3451e 100644
--- a/libnm-core/meson.build
+++ b/libnm-core/meson.build
@@ -32,6 +32,7 @@ libnm_core_headers = files(
'nm-setting-ovs-interface.h',
'nm-setting-ovs-patch.h',
'nm-setting-ovs-port.h',
+ 'nm-setting-p2p-wireless.h',
'nm-setting-ppp.h',
'nm-setting-pppoe.h',
'nm-setting-proxy.h',
@@ -87,6 +88,7 @@ libnm_core_settings_sources = files(
'nm-setting-ovs-interface.c',
'nm-setting-ovs-patch.c',
'nm-setting-ovs-port.c',
+ 'nm-setting-p2p-wireless.c',
'nm-setting-ppp.c',
'nm-setting-pppoe.c',
'nm-setting-proxy.c',
diff --git a/libnm-core/nm-core-enum-types.c.template b/libnm-core/nm-core-enum-types.c.template
index 605fa34ae4..0edb97dcc7 100644
--- a/libnm-core/nm-core-enum-types.c.template
+++ b/libnm-core/nm-core-enum-types.c.template
@@ -33,6 +33,7 @@
#include "nm-setting-ovs-interface.h"
#include "nm-setting-ovs-patch.h"
#include "nm-setting-ovs-port.h"
+#include "nm-setting-p2p-wireless.h"
#include "nm-setting-ppp.h"
#include "nm-setting-pppoe.h"
#include "nm-setting-proxy.h"
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h
index 6af293a013..f73d728b7d 100644
--- a/libnm-core/nm-core-internal.h
+++ b/libnm-core/nm-core-internal.h
@@ -63,6 +63,7 @@
#include "nm-setting-ovs-interface.h"
#include "nm-setting-ovs-patch.h"
#include "nm-setting-ovs-port.h"
+#include "nm-setting-p2p-wireless.h"
#include "nm-setting-ppp.h"
#include "nm-setting-pppoe.h"
#include "nm-setting-serial.h"
diff --git a/libnm-core/nm-core-types.h b/libnm-core/nm-core-types.h
index 89d99579e5..823001324e 100644
--- a/libnm-core/nm-core-types.h
+++ b/libnm-core/nm-core-types.h
@@ -57,6 +57,7 @@ typedef struct _NMSettingOvsBridge NMSettingOvsBridge;
typedef struct _NMSettingOvsInterface NMSettingOvsInterface;
typedef struct _NMSettingOvsPatch NMSettingOvsPatch;
typedef struct _NMSettingOvsPort NMSettingOvsPort;
+typedef struct _NMSettingP2PWireless NMSettingP2PWireless;
typedef struct _NMSettingPpp NMSettingPpp;
typedef struct _NMSettingPppoe NMSettingPppoe;
typedef struct _NMSettingSerial NMSettingSerial;
diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h
index aac4d7eadd..924140edef 100644
--- a/libnm-core/nm-dbus-interface.h
+++ b/libnm-core/nm-dbus-interface.h
@@ -44,6 +44,7 @@
#define NM_DBUS_INTERFACE_DEVICE_WIRED NM_DBUS_INTERFACE_DEVICE ".Wired"
#define NM_DBUS_INTERFACE_DEVICE_ADSL NM_DBUS_INTERFACE_DEVICE ".Adsl"
#define NM_DBUS_INTERFACE_DEVICE_WIRELESS NM_DBUS_INTERFACE_DEVICE ".Wireless"
+#define NM_DBUS_INTERFACE_DEVICE_P2P_WIRELESS NM_DBUS_INTERFACE_DEVICE ".P2PWireless"
#define NM_DBUS_INTERFACE_DEVICE_BLUETOOTH NM_DBUS_INTERFACE_DEVICE ".Bluetooth"
#define NM_DBUS_INTERFACE_DEVICE_OLPC_MESH NM_DBUS_INTERFACE_DEVICE ".OlpcMesh"
#define NM_DBUS_INTERFACE_DEVICE_OVS_INTERFACE NM_DBUS_INTERFACE_DEVICE ".OvsInterface"
@@ -51,6 +52,8 @@
#define NM_DBUS_INTERFACE_DEVICE_OVS_BRIDGE NM_DBUS_INTERFACE_DEVICE ".OvsBridge"
#define NM_DBUS_PATH_ACCESS_POINT NM_DBUS_PATH "/AccessPoint"
#define NM_DBUS_INTERFACE_ACCESS_POINT NM_DBUS_INTERFACE ".AccessPoint"
+#define NM_DBUS_PATH_P2P_PEER NM_DBUS_PATH "/P2PPeer"
+#define NM_DBUS_INTERFACE_P2P_PEER NM_DBUS_INTERFACE ".P2PPeer"
#define NM_DBUS_INTERFACE_DEVICE_MODEM NM_DBUS_INTERFACE_DEVICE ".Modem"
#define NM_DBUS_INTERFACE_DEVICE_WIMAX NM_DBUS_INTERFACE_DEVICE ".WiMax"
#define NM_DBUS_INTERFACE_WIMAX_NSP NM_DBUS_INTERFACE ".WiMax.Nsp"
@@ -563,6 +566,7 @@ typedef enum {
* @NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE: a duplicate IP address was detected
* @NM_DEVICE_STATE_REASON_IP_METHOD_UNSUPPORTED: The selected IP method is not supported
* @NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED: configuration of SR-IOV parameters failed
+ * @NM_DEVICE_STATE_REASON_PEER_NOT_FOUND: The Wi-Fi P2P peer could not be found
*
* Device state change reason codes
*/
@@ -634,6 +638,7 @@ typedef enum {
NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE = 64,
NM_DEVICE_STATE_REASON_IP_METHOD_UNSUPPORTED = 65,
NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED = 66,
+ NM_DEVICE_STATE_REASON_PEER_NOT_FOUND = 67,
} NMDeviceStateReason;
/**
diff --git a/libnm-core/nm-setting-p2p-wireless.c b/libnm-core/nm-setting-p2p-wireless.c
new file mode 100644
index 0000000000..e49ff0d995
--- /dev/null
+++ b/libnm-core/nm-setting-p2p-wireless.c
@@ -0,0 +1,281 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nm-setting-p2p-wireless.h"
+
+#include <string.h>
+#include <net/ethernet.h>
+
+#include "nm-utils.h"
+#include "nm-common-macros.h"
+#include "nm-utils-private.h"
+#include "nm-setting-private.h"
+
+/**
+ * SECTION:nm-setting-p2p-wireless
+ * @short_description: Describes connection properties for 802.11 Wi-Fi P2P networks
+ *
+ * The #NMSettingP2PWireless object is a #NMSetting subclass that describes properties
+ * necessary for connection to 802.11 Wi-Fi P2P networks (aka Wi-Fi Direct).
+ **/
+
+/**
+ * NMSettingP2PWireless:
+ *
+ * P2P Wi-Fi Settings
+ */
+
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+ PROP_PEER,
+ PROP_WPS_METHOD,
+#if 0
+ PROP_WPS_PIN,
+ PROP_WPS_PIN_FLAGS,
+#endif
+);
+
+typedef struct {
+ char *peer_mac_address;
+
+ NMSettingWirelessSecurityWpsMethod wps_method;
+} NMSettingP2PWirelessPrivate;
+
+struct _NMSettingP2PWireless {
+ NMSetting parent;
+ NMSettingP2PWirelessPrivate _priv;
+};
+
+struct _NMSettingP2PWirelessClass {
+ NMSettingClass parent;
+};
+
+G_DEFINE_TYPE (NMSettingP2PWireless, nm_setting_p2p_wireless, NM_TYPE_SETTING)
+
+#define NM_SETTING_P2P_WIRELESS_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMSettingP2PWireless, NM_IS_SETTING_P2P_WIRELESS, NMSetting)
+
+/*****************************************************************************/
+
+/**
+ * nm_setting_p2p_wireless_get_peer:
+ * @setting: the #NMSettingP2PWireless
+ *
+ * Returns: the #NMSettingP2PWireless:peer property of the setting
+ *
+ * Since: 1.16
+ **/
+const char *
+nm_setting_p2p_wireless_get_peer (NMSettingP2PWireless *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_P2P_WIRELESS (setting), NULL);
+
+ return NM_SETTING_P2P_WIRELESS_GET_PRIVATE (setting)->peer_mac_address;
+}
+
+/**
+ * nm_setting_p2p_wireless_get_wps_method:
+ * @setting: the #NMSettingP2PWireless
+ *
+ * Returns: the #NMSettingP2PWireless:wps-method property of the setting
+ *
+ * Since: 1.16
+ **/
+NMSettingWirelessSecurityWpsMethod
+nm_setting_p2p_wireless_get_wps_method (NMSettingP2PWireless *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_P2P_WIRELESS (setting), NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_DEFAULT);
+
+ return NM_SETTING_P2P_WIRELESS_GET_PRIVATE (setting)->wps_method;
+}
+
+static gboolean
+verify (NMSetting *setting, NMConnection *connection, GError **error)
+{
+ NMSettingP2PWirelessPrivate *priv = NM_SETTING_P2P_WIRELESS_GET_PRIVATE (setting);
+
+ if (!priv->peer_mac_address || !nm_utils_hwaddr_valid (priv->peer_mac_address, ETH_ALEN)) {
+ g_set_error_literal (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("property is invalid"));
+ g_prefix_error (error, "%s.%s: ", NM_SETTING_P2P_WIRELESS_SETTING_NAME, NM_SETTING_P2P_WIRELESS_PEER);
+ return FALSE;
+ }
+
+ if (priv->wps_method > NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_PIN) {
+ g_set_error_literal (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("property is invalid"));
+ return FALSE;
+ }
+
+ if (priv->wps_method > NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_DISABLED) {
+ g_set_error_literal (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("P2P connections require WPS"));
+ return FALSE;
+ }
+
+ if (priv->wps_method > NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_DISABLED) {
+ g_set_error_literal (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("P2P connections require WPS"));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+static void
+get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ NMSettingP2PWireless *setting = NM_SETTING_P2P_WIRELESS (object);
+
+ switch (prop_id) {
+ case PROP_PEER:
+ g_value_set_string (value, nm_setting_p2p_wireless_get_peer (setting));
+ break;
+ case PROP_WPS_METHOD:
+ g_value_set_uint (value, nm_setting_p2p_wireless_get_wps_method (setting));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ NMSettingP2PWirelessPrivate *priv = NM_SETTING_P2P_WIRELESS_GET_PRIVATE (object);
+
+ switch (prop_id) {
+ case PROP_PEER:
+ g_free (priv->peer_mac_address);
+ priv->peer_mac_address = _nm_utils_hwaddr_canonical_or_invalid (g_value_get_string (value),
+ ETH_ALEN);
+ break;
+ case PROP_WPS_METHOD:
+ priv->wps_method = g_value_get_uint (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/*****************************************************************************/
+
+static void
+nm_setting_p2p_wireless_init (NMSettingP2PWireless *setting)
+{
+}
+
+/**
+ * nm_setting_p2p_wireless_new:
+ *
+ * Creates a new #NMSettingP2PWireless object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingP2PWireless object
+ *
+ * Since: 1.16
+ **/
+NMSetting *
+nm_setting_p2p_wireless_new (void)
+{
+ return (NMSetting *) g_object_new (NM_TYPE_SETTING_P2P_WIRELESS, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+ NMSettingP2PWirelessPrivate *priv = NM_SETTING_P2P_WIRELESS_GET_PRIVATE (object);
+
+ g_free (priv->peer_mac_address);
+
+ G_OBJECT_CLASS (nm_setting_p2p_wireless_parent_class)->finalize (object);
+}
+
+static void
+nm_setting_p2p_wireless_class_init (NMSettingP2PWirelessClass *setting_p2p_wireless_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (setting_p2p_wireless_class);
+ NMSettingClass *setting_class = NM_SETTING_CLASS (setting_p2p_wireless_class);
+
+ object_class->set_property = set_property;
+ object_class->get_property = get_property;
+ object_class->finalize = finalize;
+
+ setting_class->verify = verify;
+
+ /**
+ * NMSettingP2PWireless:peer:
+ *
+ * The P2P device that should be connected to. Currently this is the only
+ * way to create or join a group.
+ *
+ * Since: 1.16
+ */
+ /* ---keyfile---
+ * property: peer
+ * format: usual hex-digits-and-colons notation
+ * description: MAC address in traditional hex-digits-and-colons notation
+ * (e.g. 00:22:68:12:79:A2), or semicolon separated list of 6 bytes (obsolete)
+ * (e.g. 0;34;104;18;121;162).
+ * ---end---
+ */
+ obj_properties[PROP_PEER] =
+ g_param_spec_string (NM_SETTING_P2P_WIRELESS_PEER, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ /**
+ * NMSettingP2PWireless:wps-method:
+ *
+ * Flags indicating which mode of WPS is to be used.
+ *
+ * There's little point in changing the default setting as NetworkManager will
+ * automatically determine the best method to use.
+ *
+ * Since: 1.16
+ */
+ obj_properties[PROP_WPS_METHOD] =
+ g_param_spec_uint (NM_SETTING_WIRELESS_SECURITY_WPS_METHOD, "", "",
+ 0,
+ G_MAXUINT32,
+ NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_DEFAULT,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_FUZZY_IGNORE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
+ _nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_P2P_WIRELESS);
+}
diff --git a/libnm-core/nm-setting-p2p-wireless.h b/libnm-core/nm-setting-p2p-wireless.h
new file mode 100644
index 0000000000..4880867198
--- /dev/null
+++ b/libnm-core/nm-setting-p2p-wireless.h
@@ -0,0 +1,74 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2019 Red Hat, Inc.
+ */
+
+#ifndef __NM_SETTING_P2P_WIRELESS_H__
+#define __NM_SETTING_P2P_WIRELESS_H__
+
+#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION)
+#error "Only <NetworkManager.h> can be included directly."
+#endif
+
+#include "nm-setting.h"
+#include "nm-setting-wireless-security.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_SETTING_P2P_WIRELESS (nm_setting_p2p_wireless_get_type ())
+#define NM_SETTING_P2P_WIRELESS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_P2P_WIRELESS, NMSettingP2PWireless))
+#define NM_SETTING_P2P_WIRELESS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_P2P_WIRELESS, NMSettingP2PWirelessClass))
+#define NM_IS_SETTING_P2P_WIRELESS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_P2P_WIRELESS))
+#define NM_IS_SETTING_P2P_WIRELESS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTING_P2P_WIRELESS))
+#define NM_SETTING_P2P_WIRELESS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_P2P_WIRELESS, NMSettingP2PWirelessClass))
+
+#define NM_SETTING_P2P_WIRELESS_SETTING_NAME "p2p-wireless"
+
+/**
+ * NM_SETTING_P2P_WIRELESS_PEER:
+ *
+ * The mac address of the peer to connect to.
+ */
+#define NM_SETTING_P2P_WIRELESS_PEER "peer"
+#define NM_SETTING_P2P_WIRELESS_WPS_METHOD "wps-method"
+#if 0
+#define NM_SETTING_P2P_WIRELESS_WPS_PIN "wps-pin"
+#endif
+
+#if 0
+#define NM_SETTING_P2P_WIRELESS_GO_INTENT "go-intent"
+/* Not sure how we could even handle this, i.e. would we need to store more information? */
+#define NM_SETTING_P2P_WIRELESS_PERSISTENT "persistent"
+#endif
+
+typedef struct _NMSettingP2PWirelessClass NMSettingP2PWirelessClass;
+
+NM_AVAILABLE_IN_1_16
+GType nm_setting_p2p_wireless_get_type (void);
+
+NM_AVAILABLE_IN_1_16
+NMSetting *nm_setting_p2p_wireless_new (void);
+
+NM_AVAILABLE_IN_1_16
+const char *nm_setting_p2p_wireless_get_peer (NMSettingP2PWireless *setting);
+
+NM_AVAILABLE_IN_1_16
+NMSettingWirelessSecurityWpsMethod nm_setting_p2p_wireless_get_wps_method (NMSettingP2PWireless *setting);
+
+G_END_DECLS
+
+#endif /* __NM_SETTING_P2P_WIRELESS_H__ */
diff --git a/libnm/NetworkManager.h b/libnm/NetworkManager.h
index 759a413187..1f98e50b11 100644
--- a/libnm/NetworkManager.h
+++ b/libnm/NetworkManager.h
@@ -46,6 +46,7 @@
#include "nm-device-ovs-interface.h"
#include "nm-device-ovs-port.h"
#include "nm-device-ovs-bridge.h"
+#include "nm-device-p2p-wifi.h"
#include "nm-device-ppp.h"
#include "nm-device-team.h"
#include "nm-device-tun.h"
@@ -60,6 +61,7 @@
#include "nm-enum-types.h"
#include "nm-ip-config.h"
#include "nm-object.h"
+#include "nm-p2p-peer.h"
#include "nm-remote-connection.h"
#include "nm-setting-6lowpan.h"
#include "nm-setting-8021x.h"
@@ -88,6 +90,7 @@
#include "nm-setting-ovs-interface.h"
#include "nm-setting-ovs-patch.h"
#include "nm-setting-ovs-port.h"
+#include "nm-setting-p2p-wireless.h"
#include "nm-setting-ppp.h"
#include "nm-setting-pppoe.h"
#include "nm-setting-proxy.h"
diff --git a/libnm/libnm.ver b/libnm/libnm.ver
index 652e01eb68..0267c140a0 100644
--- a/libnm/libnm.ver
+++ b/libnm/libnm.ver
@@ -1450,6 +1450,29 @@ global:
nm_client_add_and_activate_connection2;
nm_client_add_and_activate_connection2_finish;
nm_device_get_connectivity;
+ nm_device_p2p_wifi_get_group_owner;
+ nm_device_p2p_wifi_get_hw_address;
+ nm_device_p2p_wifi_get_peers;
+ nm_device_p2p_wifi_get_type;
+ nm_device_p2p_wifi_start_find;
+ nm_device_p2p_wifi_stop_find;
+ nm_p2p_peer_connection_valid;
+ nm_p2p_peer_filter_connections;
+ nm_p2p_peer_get_flags;
+ nm_p2p_peer_get_hw_address;
+ nm_p2p_peer_get_last_seen;
+ nm_p2p_peer_get_manufacturer;
+ nm_p2p_peer_get_model;
+ nm_p2p_peer_get_model_number;
+ nm_p2p_peer_get_name;
+ nm_p2p_peer_get_serial;
+ nm_p2p_peer_get_strength;
+ nm_p2p_peer_get_type;
+ nm_p2p_peer_get_wfd_ies;
+ nm_setting_p2p_wireless_get_peer;
+ nm_setting_p2p_wireless_get_type;
+ nm_setting_p2p_wireless_get_wps_method;
+ nm_setting_p2p_wireless_new;
nm_team_link_watcher_get_vlanid;
nm_team_link_watcher_new_arp_ping2;
} libnm_1_14_0;
diff --git a/libnm/meson.build b/libnm/meson.build
index 2e44a6a49b..dee4e36bdf 100644
--- a/libnm/meson.build
+++ b/libnm/meson.build
@@ -50,6 +50,7 @@ libnm_headers = files(
'nm-device-ovs-interface.h',
'nm-device-ovs-port.h',
'nm-device-ovs-bridge.h',
+ 'nm-device-p2p-wifi.h',
'nm-device-ppp.h',
'nm-device-team.h',
'nm-device-tun.h',
@@ -62,6 +63,7 @@ libnm_headers = files(
'nm-dhcp-config.h',
'nm-ip-config.h',
'nm-object.h',
+ 'nm-p2p-peer.h',
'nm-remote-connection.h',
'nm-secret-agent-old.h',
'nm-types.h',
@@ -114,6 +116,7 @@ libnm_sources = files(
'nm-device-ovs-interface.c',
'nm-device-ovs-port.c',
'nm-device-ovs-bridge.c',
+ 'nm-device-p2p-wifi.c',
'nm-device-ppp.c',
'nm-device-team.c',
'nm-device-tun.c',
@@ -132,6 +135,7 @@ libnm_sources = files(
'nm-ip6-config.c',
'nm-manager.c',
'nm-object.c',
+ 'nm-p2p-peer.c',
'nm-remote-connection.c',
'nm-remote-settings.c',
'nm-secret-agent-old.c',
diff --git a/libnm/nm-autoptr.h b/libnm/nm-autoptr.h
index e96a03a099..bffacd39cd 100644
--- a/libnm/nm-autoptr.h
+++ b/libnm/nm-autoptr.h
@@ -64,6 +64,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingOvsBridge, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingOvsInterface, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingOvsPatch, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingOvsPort, g_object_unref)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingP2PWireless, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingPpp, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingPppoe, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingProxy, g_object_unref)
diff --git a/libnm/nm-client.c b/libnm/nm-client.c
index e2522229bc..e5902ad051 100644
--- a/libnm/nm-client.c
+++ b/libnm/nm-client.c
@@ -41,6 +41,7 @@
#include "introspection/org.freedesktop.NetworkManager.h"
#include "introspection/org.freedesktop.NetworkManager.Device.Wireless.h"
+#include "introspection/org.freedesktop.NetworkManager.Device.P2PWireless.h"
#include "introspection/org.freedesktop.NetworkManager.Device.h"
#include "introspection/org.freedesktop.NetworkManager.DnsManager.h"
#include "introspection/org.freedesktop.NetworkManager.Settings.h"
@@ -68,6 +69,7 @@
#include "nm-device-ovs-interface.h"
#include "nm-device-ovs-port.h"
#include "nm-device-ovs-bridge.h"
+#include "nm-device-p2p-wifi.h"
#include "nm-device-ppp.h"
#include "nm-device-team.h"
#include "nm-device-tun.h"
@@ -83,6 +85,7 @@
#include "nm-ip4-config.h"
#include "nm-ip6-config.h"
#include "nm-manager.h"
+#include "nm-p2p-peer.h"
#include "nm-remote-connection.h"
#include "nm-remote-settings.h"
#include "nm-vpn-connection.h"
@@ -2611,6 +2614,8 @@ proxy_type (GDBusObjectManagerClient *manager,
return NMDBUS_TYPE_MANAGER_PROXY;
else if (strcmp (interface_name, NM_DBUS_INTERFACE_DEVICE_WIRELESS) == 0)
return NMDBUS_TYPE_DEVICE_WIFI_PROXY;
+ else if (strcmp (interface_name, NM_DBUS_INTERFACE_DEVICE_P2P_WIRELESS) == 0)
+ return NMDBUS_TYPE_DEVICE_P2P_WIFI_PROXY;
else if (strcmp (interface_name, NM_DBUS_INTERFACE_DEVICE) == 0)
return NMDBUS_TYPE_DEVICE_PROXY;
else if (strcmp (interface_name, NM_DBUS_INTERFACE_SETTINGS_CONNECTION) == 0)
@@ -2689,6 +2694,8 @@ obj_nm_for_gdbus_object (NMClient *self, GDBusObject *object, GDBusObjectManager
type = NM_TYPE_DEVICE_OVS_PORT;
else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_OVS_BRIDGE) == 0)
type = NM_TYPE_DEVICE_OVS_BRIDGE;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_P2P_WIRELESS) == 0)
+ type = NM_TYPE_DEVICE_P2P_WIFI;
else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_PPP) == 0)
type = NM_TYPE_DEVICE_PPP;
else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_TEAM) == 0)
@@ -2715,6 +2722,8 @@ obj_nm_for_gdbus_object (NMClient *self, GDBusObject *object, GDBusObjectManager
type = NM_TYPE_IP4_CONFIG;
else if (strcmp (ifname, NM_DBUS_INTERFACE_IP6_CONFIG) == 0)
type = NM_TYPE_IP6_CONFIG;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_P2P_PEER) == 0)
+ type = NM_TYPE_P2P_PEER;
else if (strcmp (ifname, NM_DBUS_INTERFACE_SETTINGS_CONNECTION) == 0)
type = NM_TYPE_REMOTE_CONNECTION;
else if (strcmp (ifname, NM_DBUS_INTERFACE_SETTINGS) == 0)
diff --git a/libnm/nm-device-p2p-wifi.c b/libnm/nm-device-p2p-wifi.c
new file mode 100644
index 0000000000..4d740fafec
--- /dev/null
+++ b/libnm/nm-device-p2p-wifi.c
@@ -0,0 +1,537 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2007 - 2008 Novell, Inc.
+ * Copyright 2007 - 2018 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nm-device-p2p-wifi.h"
+
+#include <string.h>
+
+#include "nm-setting-connection.h"
+#include "nm-setting-p2p-wireless.h"
+#include "nm-utils.h"
+
+#include "nm-p2p-peer.h"
+#include "nm-object-private.h"
+#include "nm-core-internal.h"
+#include "nm-dbus-helpers.h"
+
+#include "introspection/org.freedesktop.NetworkManager.Device.P2PWireless.h"
+
+G_DEFINE_TYPE (NMDeviceP2PWifi, nm_device_p2p_wifi, NM_TYPE_DEVICE)
+
+#define NM_DEVICE_P2P_WIFI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_P2P_WIFI, NMDeviceP2PWifiPrivate))
+
+void _nm_device_p2p_wifi_set_p2p_wireless_enabled (NMDeviceP2PWifi *device, gboolean enabled);
+static void state_changed_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data);
+
+typedef struct {
+ NMDeviceP2PWifi *device;
+ GSimpleAsyncResult *simple;
+} RequestScanInfo;
+
+typedef struct {
+ NMDBusDeviceP2PWifi *proxy;
+
+ char *hw_address;
+
+ gboolean group_owner;
+ GByteArray *wfd_ies;
+ GPtrArray *peers;
+} NMDeviceP2PWifiPrivate;
+
+enum {
+ PROP_0,
+ PROP_HW_ADDRESS,
+ PROP_GROUP_OWNER,
+ PROP_WFDIES,
+ PROP_PEERS,
+
+ LAST_PROP
+};
+
+enum {
+ PEER_ADDED,
+ PEER_REMOVED,
+
+ LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/**
+ * nm_device_p2p_wifi_get_hw_address:
+ * @device: a #NMDeviceP2PWifi
+ *
+ * Gets the actual hardware (MAC) address of the #NMDeviceP2PWifi
+ *
+ * Returns: the actual hardware address. This is the internal string used by the
+ * device, and must not be modified.
+ *
+ * Since: 1.16
+ **/
+const char *
+nm_device_p2p_wifi_get_hw_address (NMDeviceP2PWifi *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_P2P_WIFI (device), NULL);
+
+ return nm_str_not_empty (NM_DEVICE_P2P_WIFI_GET_PRIVATE (device)->hw_address);
+}
+
+/**
+ * nm_device_p2p_wifi_get_group_owner:
+ * @device: a #NMDeviceP2PWifi
+ *
+ * Gets whether the device is currently the P2P group owner. This is only
+ * valid when a connection is established.
+ *
+ * Returns: Whether the device is the P2P group owner.
+ *
+ * Since: 1.16
+ **/
+gboolean
+nm_device_p2p_wifi_get_group_owner (NMDeviceP2PWifi *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_P2P_WIFI (device), FALSE);
+
+ return NM_DEVICE_P2P_WIFI_GET_PRIVATE (device)->group_owner;
+}
+
+/**
+ * nm_device_p2p_wifi_get_peers:
+ * @device: a #NMDeviceP2PWifi
+ *
+ * Gets all the found peers of the #NMDeviceP2PWifi.
+ *
+ * Returns: (element-type NMP2PPeer): a #GPtrArray containing all the
+ * found #NMP2PPeers.
+ * The returned array is owned by the client and should not be modified.
+ *
+ * Since: 1.16
+ **/
+const GPtrArray *
+nm_device_p2p_wifi_get_peers (NMDeviceP2PWifi *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_P2P_WIFI (device), NULL);
+
+ return NM_DEVICE_P2P_WIFI_GET_PRIVATE (device)->peers;
+}
+
+/**
+ * nm_device_p2p_wifi_get_peer_by_path:
+ * @device: a #NMDeviceP2PWifi
+ * @path: the object path of the peer
+ *
+ * Gets a #NMP2PPeer by path.
+ *
+ * Returns: (transfer none): the peer or %NULL if none is found.
+ *
+ * Since: 1.16
+ **/
+NMP2PPeer *
+nm_device_p2p_wifi_get_peer_by_path (NMDeviceP2PWifi *device,
+ const char *path)
+{
+ const GPtrArray *peers;
+ int i;
+ NMP2PPeer *peer = NULL;
+
+ g_return_val_if_fail (NM_IS_DEVICE_P2P_WIFI (device), NULL);
+ g_return_val_if_fail (path != NULL, NULL);
+
+ peers = nm_device_p2p_wifi_get_peers (device);
+ if (!peers)
+ return NULL;
+
+ for (i = 0; i < peers->len; i++) {
+ NMP2PPeer *candidate = g_ptr_array_index (peers, i);
+ if (!strcmp (nm_object_get_path (NM_OBJECT (candidate)), path)) {
+ peer = candidate;
+ break;
+ }
+ }
+
+ return peer;
+}
+
+static void
+clean_up_peers (NMDeviceP2PWifi *self, gboolean in_dispose)
+{
+ NMDeviceP2PWifiPrivate *priv;
+ GPtrArray *peers;
+ int i;
+
+ g_return_if_fail (NM_IS_DEVICE_P2P_WIFI (self));
+
+ priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+
+ peers = priv->peers;
+
+ if (in_dispose)
+ priv->peers = NULL;
+ else {
+ priv->peers = g_ptr_array_new ();
+
+ for (i = 0; i < peers->len; i++) {
+ NMP2PPeer *peer = NM_P2P_PEER (g_ptr_array_index (peers, i));
+
+ g_signal_emit (self, signals[PEER_REMOVED], 0, peer);
+ }
+ }
+
+ g_ptr_array_unref (peers);
+}
+
+static gboolean
+connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
+{
+ if (!NM_DEVICE_CLASS (nm_device_p2p_wifi_parent_class)->connection_compatible (device, connection, error))
+ return FALSE;
+
+ if (!nm_connection_is_type (connection, NM_SETTING_P2P_WIRELESS_SETTING_NAME)) {
+ g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
+ _("The connection was not a P2P Wi-Fi connection."));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static GType
+get_setting_type (NMDevice *device)
+{
+ return NM_TYPE_SETTING_WIRELESS;
+}
+
+static const char *
+get_hw_address (NMDevice *device)
+{
+ return nm_device_p2p_wifi_get_hw_address (NM_DEVICE_P2P_WIFI (device));
+}
+
+static GVariant *
+nm_device_p2p_wifi_get_wfdies_as_variant (const NMDeviceP2PWifi *self)
+{
+ const NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+
+ if (priv->wfd_ies) {
+ return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
+ priv->wfd_ies->data, priv->wfd_ies->len, 1);
+ } else
+ return g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0);
+}
+
+/**
+ * nm_device_p2p_wifi_start_find:
+ * @device: a #NMDeviceP2PWifi
+ * @cancellable: a #GCancellable, or %NULL
+ * @error: location for a #GError, or %NULL
+ *
+ * Request NM to search for P2P peers on @device. Note that the function
+ * returns immediately after requesting the find, and it may take some time
+ * after that for peers to be found.
+ *
+ * The find operation will run for 30s by default. You can stop it earlier
+ * using nm_device_p2p_wifi_stop_find().
+ *
+ * Returns: %TRUE on success, %FALSE on error, in which case @error will be
+ * set.
+ *
+ * Since: 1.16
+ **/
+gboolean
+nm_device_p2p_wifi_start_find (NMDeviceP2PWifi *device,
+ GCancellable *cancellable,
+ GError **error)
+{
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (device);
+ GVariant *options = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0);
+ gboolean ret;
+
+ g_return_val_if_fail (NM_IS_DEVICE_P2P_WIFI (device), FALSE);
+
+ ret = nmdbus_device_p2p_wifi_call_start_find_sync (priv->proxy,
+ options,
+ cancellable, error);
+
+ if (error && *error)
+ g_dbus_error_strip_remote_error (*error);
+
+ return ret;
+}
+
+/**
+ * nm_device_p2p_wifi_stop_find:
+ * @device: a #NMDeviceP2PWifi
+ * @cancellable: a #GCancellable, or %NULL
+ * @error: location for a #GError, or %NULL
+ *
+ * Request NM to stop searching for P2P peers on @device.
+ *
+ * Returns: %TRUE on success, %FALSE on error, in which case @error will be
+ * set.
+ *
+ * Since: 1.16
+ **/
+gboolean
+nm_device_p2p_wifi_stop_find (NMDeviceP2PWifi *device,
+ GCancellable *cancellable,
+ GError **error)
+{
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (device);
+ gboolean ret;
+
+ g_return_val_if_fail (NM_IS_DEVICE_P2P_WIFI (device), FALSE);
+
+ ret = nmdbus_device_p2p_wifi_call_stop_find_sync (priv->proxy,
+ cancellable, error);
+ if (error && *error)
+ g_dbus_error_strip_remote_error (*error);
+
+ return ret;
+}
+
+/*****************************************************************************/
+
+static void
+get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (object);
+
+ switch (prop_id) {
+ case PROP_HW_ADDRESS:
+ g_value_set_string (value, nm_device_p2p_wifi_get_hw_address (self));
+ break;
+ case PROP_GROUP_OWNER:
+ g_value_set_enum (value, nm_device_p2p_wifi_get_group_owner (self));
+ break;
+ case PROP_WFDIES:
+ g_value_take_variant (value, nm_device_p2p_wifi_get_wfdies_as_variant (self));
+ break;
+ case PROP_PEERS:
+ g_value_take_boxed (value, _nm_utils_copy_object_array (nm_device_p2p_wifi_get_peers (self)));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+nm_device_p2p_wifi_init (NMDeviceP2PWifi *device)
+{
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (device);
+
+ g_signal_connect (device,
+ "notify::" NM_DEVICE_STATE,
+ G_CALLBACK (state_changed_cb),
+ NULL);
+
+ priv->peers = g_ptr_array_new ();
+}
+
+static void
+state_changed_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data)
+{
+#if 0
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (device);
+
+ switch (nm_device_get_state (device)) {
+ case NM_DEVICE_STATE_UNKNOWN:
+ case NM_DEVICE_STATE_UNMANAGED:
+ case NM_DEVICE_STATE_UNAVAILABLE:
+ case NM_DEVICE_STATE_DISCONNECTED:
+ case NM_DEVICE_STATE_FAILED:
+ /* TODO: Do something? */
+ break;
+ default:
+ break;
+ }
+#endif
+}
+
+static void
+init_dbus (NMObject *object)
+{
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (object);
+ const NMPropertiesInfo property_info[] = {
+ { NM_DEVICE_P2P_WIFI_HW_ADDRESS, &priv->hw_address },
+ { NM_DEVICE_P2P_WIFI_GROUP_OWNER, &priv->group_owner },
+ { NM_DEVICE_P2P_WIFI_WFDIES, &priv->wfd_ies },
+ { NM_DEVICE_P2P_WIFI_PEERS, &priv->peers, NULL, NM_TYPE_P2P_PEER, "peer" },
+ { NULL },
+ };
+
+ NM_OBJECT_CLASS (nm_device_p2p_wifi_parent_class)->init_dbus (object);
+
+ priv->proxy = NMDBUS_DEVICE_P2P_WIFI (_nm_object_get_proxy (object, NM_DBUS_INTERFACE_DEVICE_P2P_WIRELESS));
+ _nm_object_register_properties (object,
+ NM_DBUS_INTERFACE_DEVICE_P2P_WIRELESS,
+ property_info);
+}
+
+static void
+dispose (GObject *object)
+{
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (object);
+
+ if (priv->peers)
+ clean_up_peers (NM_DEVICE_P2P_WIFI (object), TRUE);
+
+ g_clear_object (&priv->proxy);
+ if (priv->wfd_ies)
+ g_byte_array_unref (priv->wfd_ies);
+ priv->wfd_ies = NULL;
+
+ G_OBJECT_CLASS (nm_device_p2p_wifi_parent_class)->dispose (object);
+}
+
+static void
+finalize (GObject *object)
+{
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (object);
+
+ g_free (priv->hw_address);
+
+ G_OBJECT_CLASS (nm_device_p2p_wifi_parent_class)->finalize (object);
+}
+
+static void
+nm_device_p2p_wifi_class_init (NMDeviceP2PWifiClass *wifi_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (wifi_class);
+ NMObjectClass *nm_object_class = NM_OBJECT_CLASS (wifi_class);
+ NMDeviceClass *device_class = NM_DEVICE_CLASS (wifi_class);
+
+ g_type_class_add_private (wifi_class, sizeof (NMDeviceP2PWifiPrivate));
+
+ /* virtual methods */
+ object_class->get_property = get_property;
+ object_class->dispose = dispose;
+ object_class->finalize = finalize;
+
+ nm_object_class->init_dbus = init_dbus;
+
+ device_class->connection_compatible = connection_compatible;
+ device_class->get_setting_type = get_setting_type;
+ device_class->get_hw_address = get_hw_address;
+
+ /* properties */
+
+ /**
+ * NMDeviceP2PWifi:hw-address:
+ *
+ * The hardware (MAC) address of the device.
+ *
+ * Since: 1.16
+ **/
+ g_object_class_install_property
+ (object_class, PROP_HW_ADDRESS,
+ g_param_spec_string (NM_DEVICE_P2P_WIFI_HW_ADDRESS, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+
+ /**
+ * NMDeviceP2PWifi:group-owner:
+ *
+ * Whether the device is currently the group owner.
+ *
+ * Since: 1.16
+ **/
+ g_object_class_install_property
+ (object_class, PROP_GROUP_OWNER,
+ g_param_spec_boolean (NM_DEVICE_P2P_WIFI_GROUP_OWNER, "", "",
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMDeviceP2PWifi:wfd-ies:
+ *
+ * Whether the device is currently the group owner.
+ *
+ * Since: 1.16
+ **/
+ g_object_class_install_property
+ (object_class, PROP_WFDIES,
+ g_param_spec_variant (NM_DEVICE_P2P_WIFI_WFDIES, "", "",
+ G_VARIANT_TYPE ("ay"),
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMDeviceP2PWifi:peers: (type GPtrArray(NMP2PPeer))
+ *
+ * List of all P2P Wi-Fi peers the device can see.
+ *
+ * Since: 1.16
+ **/
+ g_object_class_install_property
+ (object_class, PROP_PEERS,
+ g_param_spec_boxed (NM_DEVICE_P2P_WIFI_PEERS, "", "",
+ G_TYPE_PTR_ARRAY,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /* signals */
+
+ /**
+ * NMDeviceP2PWifi::peer-added:
+ * @device: the P2P Wi-Fi device that received the signal
+ * @peer: the new access point
+ *
+ * Notifies that a #NMP2PPeer is added to the P2P Wi-Fi device.
+ *
+ * Since: 1.16
+ **/
+ signals[PEER_ADDED] =
+ g_signal_new ("peer-added",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (NMDeviceP2PWifiClass, peer_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ G_TYPE_OBJECT);
+
+ /**
+ * NMDeviceP2PWifi::peer-removed:
+ * @device: the P2P Wi-Fi device that received the signal
+ * @peer: the removed access point
+ *
+ * Notifies that a #NMP2PPeer is removed from the P2P Wi-Fi device.
+ *
+ * Since: 1.16
+ **/
+ signals[PEER_REMOVED] =
+ g_signal_new ("peer-removed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (NMDeviceP2PWifiClass, peer_removed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ G_TYPE_OBJECT);
+}
diff --git a/libnm/nm-device-p2p-wifi.h b/libnm/nm-device-p2p-wifi.h
new file mode 100644
index 0000000000..90a7242489
--- /dev/null
+++ b/libnm/nm-device-p2p-wifi.h
@@ -0,0 +1,85 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2007 - 2008 Novell, Inc.
+ * Copyright 2007 - 2018 Red Hat, Inc.
+ */
+
+#ifndef __NM_DEVICE_P2P_WIFI_H__
+#define __NM_DEVICE_P2P_WIFI_H__
+
+#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION)
+#error "Only <NetworkManager.h> can be included directly."
+#endif
+
+#include "nm-device.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_DEVICE_P2P_WIFI (nm_device_p2p_wifi_get_type ())
+#define NM_DEVICE_P2P_WIFI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_P2P_WIFI, NMDeviceP2PWifi))
+#define NM_DEVICE_P2P_WIFI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_P2P_WIFI, NMDeviceP2PWifiClass))
+#define NM_IS_DEVICE_P2P_WIFI(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_P2P_WIFI))
+#define NM_IS_DEVICE_P2P_WIFI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_P2P_WIFI))
+#define NM_DEVICE_P2P_WIFI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_P2P_WIFI, NMDeviceP2PWifiClass))
+
+#define NM_DEVICE_P2P_WIFI_HW_ADDRESS "hw-address"
+#define NM_DEVICE_P2P_WIFI_GROUP_OWNER "group-owner"
+#define NM_DEVICE_P2P_WIFI_PEERS "peers"
+#define NM_DEVICE_P2P_WIFI_WFDIES "wfdies"
+
+/**
+ * NMDeviceP2PWifi:
+ */
+struct _NMDeviceP2PWifi {
+ NMDevice parent;
+};
+
+typedef struct {
+ NMDeviceClass parent;
+
+ /* Signals */
+ void (*peer_added) (NMDeviceP2PWifi *device, NMP2PPeer *peer);
+ void (*peer_removed) (NMDeviceP2PWifi *device, NMP2PPeer *peer);
+
+ /*< private >*/
+ gpointer padding[4];
+} NMDeviceP2PWifiClass;
+
+GType nm_device_p2p_wifi_get_type (void);
+
+const char * nm_device_p2p_wifi_get_hw_address (NMDeviceP2PWifi *device);
+gboolean nm_device_p2p_wifi_get_group_owner (NMDeviceP2PWifi *device);
+
+#if 0
+gboolean nm_device_p2p_wifi_get_wfdies (NMDeviceP2PWifi *device);
+#endif
+
+NMP2PPeer * nm_device_p2p_wifi_get_peer_by_path (NMDeviceP2PWifi *device,
+ const char *path);
+
+const GPtrArray * nm_device_p2p_wifi_get_peers (NMDeviceP2PWifi *device);
+
+gboolean nm_device_p2p_wifi_start_find (NMDeviceP2PWifi *device,
+ GCancellable *cancellable,
+ GError **error);
+gboolean nm_device_p2p_wifi_stop_find (NMDeviceP2PWifi *device,
+ GCancellable *cancellable,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __NM_DEVICE_P2P_WIFI_H__ */
diff --git a/libnm/nm-p2p-peer.c b/libnm/nm-p2p-peer.c
new file mode 100644
index 0000000000..7919424210
--- /dev/null
+++ b/libnm/nm-p2p-peer.c
@@ -0,0 +1,596 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2007 - 2008 Novell, Inc.
+ * Copyright 2007 - 2018 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nm-p2p-peer.h"
+
+#include <string.h>
+
+#include "nm-connection.h"
+#include "nm-setting-connection.h"
+#include "nm-setting-p2p-wireless.h"
+#include "nm-utils.h"
+
+#include "nm-dbus-interface.h"
+#include "nm-object-private.h"
+
+G_DEFINE_TYPE (NMP2PPeer, nm_p2p_peer, NM_TYPE_OBJECT)
+
+#define NM_P2P_PEER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_P2P_PEER, NMP2PPeerPrivate))
+
+typedef struct {
+ NM80211ApFlags flags;
+
+ char *name;
+ char *manufacturer;
+ char *model;
+ char *model_number;
+ char *serial;
+
+ GBytes *wfd_ies;
+
+ char *hw_address;
+
+ guint8 strength;
+ int last_seen;
+} NMP2PPeerPrivate;
+
+enum {
+ PROP_0,
+ PROP_FLAGS,
+ PROP_NAME,
+ PROP_MANUFACTURER,
+ PROP_MODEL,
+ PROP_MODEL_NUMBER,
+ PROP_SERIAL,
+ PROP_WFD_IES,
+ PROP_HW_ADDRESS,
+ PROP_STRENGTH,
+ PROP_LAST_SEEN,
+
+ LAST_PROP
+};
+
+/**
+ * nm_p2p_peer_get_flags:
+ * @peer: a #NMP2PPeer
+ *
+ * Gets the flags of the P2P peer.
+ *
+ * Returns: the flags
+ *
+ * Since: 1.16
+ **/
+NM80211ApFlags
+nm_p2p_peer_get_flags (NMP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_P2P_PEER (peer), NM_802_11_AP_FLAGS_NONE);
+
+ return NM_P2P_PEER_GET_PRIVATE (peer)->flags;
+}
+
+/**
+ * nm_p2p_peer_get_name:
+ * @peer: a #NMP2PPeer
+ *
+ * Gets the name of the P2P peer.
+ *
+ * Returns: the name
+ *
+ * Since: 1.16
+ **/
+const char *
+nm_p2p_peer_get_name (NMP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_P2P_PEER (peer), NULL);
+
+ return NM_P2P_PEER_GET_PRIVATE (peer)->name;
+}
+
+/**
+ * nm_p2p_peer_get_manufacturer:
+ * @peer: a #NMP2PPeer
+ *
+ * Gets the manufacturer of the P2P peer.
+ *
+ * Returns: the manufacturer
+ *
+ * Since: 1.16
+ **/
+const char *
+nm_p2p_peer_get_manufacturer (NMP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_P2P_PEER (peer), NULL);
+
+ return NM_P2P_PEER_GET_PRIVATE (peer)->manufacturer;
+}
+
+/**
+ * nm_p2p_peer_get_model:
+ * @peer: a #NMP2PPeer
+ *
+ * Gets the model of the P2P peer.
+ *
+ * Returns: the model
+ *
+ * Since: 1.16
+ **/
+const char *
+nm_p2p_peer_get_model (NMP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_P2P_PEER (peer), NULL);
+
+ return NM_P2P_PEER_GET_PRIVATE (peer)->model;
+}
+
+/**
+ * nm_p2p_peer_get_model_number:
+ * @peer: a #NMP2PPeer
+ *
+ * Gets the model number of the P2P peer.
+ *
+ * Returns: the model number
+ *
+ * Since: 1.16
+ **/
+const char *
+nm_p2p_peer_get_model_number (NMP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_P2P_PEER (peer), NULL);
+
+ return NM_P2P_PEER_GET_PRIVATE (peer)->model_number;
+}
+
+/**
+ * nm_p2p_peer_get_serial:
+ * @peer: a #NMP2PPeer
+ *
+ * Gets the serial number of the P2P peer.
+ *
+ * Returns: the serial number
+ *
+ * Since: 1.16
+ **/
+const char *
+nm_p2p_peer_get_serial (NMP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_P2P_PEER (peer), NULL);
+
+ return NM_P2P_PEER_GET_PRIVATE (peer)->serial;
+}
+
+/**
+ * nm_p2p_peer_get_wfd_ies:
+ * @peer: a #NMP2PPeer
+ *
+ * Gets the WFD information elements of the P2P peer.
+ *
+ * Returns: (transfer none): the #GBytes containing the WFD IEs, or %NULL.
+ *
+ * Since: 1.16
+ **/
+GBytes *
+nm_p2p_peer_get_wfd_ies (NMP2PPeer *peer)
+{
+ NMP2PPeerPrivate *priv;
+
+ g_return_val_if_fail (NM_IS_P2P_PEER (peer), NULL);
+
+ priv = NM_P2P_PEER_GET_PRIVATE (peer);
+ if (!priv->wfd_ies || g_bytes_get_size (priv->wfd_ies) == 0)
+ return NULL;
+
+ return priv->wfd_ies;
+}
+
+/**
+ * nm_p2p_peer_get_hw_address:
+ * @peer: a #NMP2PPeer
+ *
+ * Gets the hardware address of the P2P peer.
+ *
+ * Returns: the hardware adress
+ *
+ * Since: 1.16
+ **/
+const char *
+nm_p2p_peer_get_hw_address (NMP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_P2P_PEER (peer), NULL);
+
+ return NM_P2P_PEER_GET_PRIVATE (peer)->hw_address;
+}
+
+/**
+ * nm_p2p_peer_get_strength:
+ * @peer: a #NMP2PPeer
+ *
+ * Gets the current signal strength of the P2P peer as a percentage.
+ *
+ * Returns: the signal strength (0 to 100)
+ *
+ * Since: 1.16
+ **/
+guint8
+nm_p2p_peer_get_strength (NMP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_P2P_PEER (peer), 0);
+
+ return NM_P2P_PEER_GET_PRIVATE (peer)->strength;
+}
+
+/**
+ * nm_p2p_peer_get_last_seen:
+ * @peer: a #NMP2PPeer
+ *
+ * Returns the timestamp (in CLOCK_BOOTTIME seconds) for the last time the
+ * P2P peer was seen. A value of -1 means the P2P peer has never been seen.
+ *
+ * Returns: the last seen time in seconds
+ *
+ * Since: 1.16
+ **/
+int
+nm_p2p_peer_get_last_seen (NMP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_P2P_PEER (peer), -1);
+
+ return NM_P2P_PEER_GET_PRIVATE (peer)->last_seen;
+}
+
+/**
+ * nm_p2p_peer_connection_valid:
+ * @peer: an #NMP2PPeer to validate @connection against
+ * @connection: an #NMConnection to validate against @peer
+ *
+ * Validates a given connection against a given Wi-Fi P2P peer to ensure that
+ * the connection may be activated with that peer. The connection must match the
+ * @peer's address and in the future possibly other attributes.
+ *
+ * Returns: %TRUE if the connection may be activated with this Wi-Fi P2P Peer,
+ * %FALSE if it cannot be.
+ *
+ * Since: 1.16
+ **/
+gboolean
+nm_p2p_peer_connection_valid (NMP2PPeer *peer, NMConnection *connection)
+{
+ NMSettingConnection *s_con;
+ NMSettingP2PWireless *s_p2p_wifi;
+ const char *ctype;
+ const char *hw_address;
+ const char *setting_peer;
+
+ s_con = nm_connection_get_setting_connection (connection);
+ if (!s_con)
+ return FALSE;
+
+ ctype = nm_setting_connection_get_connection_type (s_con);
+ if (!ctype || !nm_streq (ctype, NM_SETTING_P2P_WIRELESS_SETTING_NAME))
+ return FALSE;
+
+ s_p2p_wifi = (NMSettingP2PWireless*) nm_connection_get_setting (connection, NM_TYPE_SETTING_P2P_WIRELESS);
+ if (!s_p2p_wifi)
+ return FALSE;
+
+ /* HW Address check */
+ hw_address = nm_p2p_peer_get_hw_address (peer);
+ if (!hw_address)
+ return FALSE;
+ setting_peer = nm_setting_p2p_wireless_get_peer (s_p2p_wifi);
+ if ( !setting_peer
+ || g_strcmp0 (hw_address, setting_peer))
+ return FALSE;
+
+ return TRUE;
+}
+
+/**
+ * nm_p2p_peer_filter_connections:
+ * @peer: an #NMP2PPeer to filter connections for
+ * @connections: (element-type NMConnection): an array of #NMConnections to
+ * filter
+ *
+ * Filters a given array of connections for a given #NMP2PPeer object and
+ * returns connections which may be activated with the P2P peer. Any
+ * returned connections will match the @peers's HW address and in the future
+ * possibly other attributes.
+ *
+ * To obtain the list of connections that are compatible with this P2P peer,
+ * use nm_client_get_connections() and then filter the returned list for a given
+ * #NMDevice using nm_device_filter_connections() and finally filter that list
+ * with this function.
+ *
+ * Returns: (transfer container) (element-type NMConnection): an array of
+ * #NMConnections that could be activated with the given @peer. The array should
+ * be freed with g_ptr_array_unref() when it is no longer required.
+ *
+ * Since: 1.16
+ **/
+GPtrArray *
+nm_p2p_peer_filter_connections (NMP2PPeer *peer, const GPtrArray *connections)
+{
+ GPtrArray *filtered;
+ int i;
+
+ filtered = g_ptr_array_new_with_free_func (g_object_unref);
+ for (i = 0; i < connections->len; i++) {
+ NMConnection *candidate = connections->pdata[i];
+
+ if (nm_p2p_peer_connection_valid (peer, candidate))
+ g_ptr_array_add (filtered, g_object_ref (candidate));
+ }
+
+ return filtered;
+}
+
+/*****************************************************************************/
+
+static void
+get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ NMP2PPeer *peer = NM_P2P_PEER (object);
+
+ switch (prop_id) {
+ case PROP_FLAGS:
+ g_value_set_flags (value, nm_p2p_peer_get_flags (peer));
+ break;
+ case PROP_NAME:
+ g_value_set_string (value, nm_p2p_peer_get_name (peer));
+ break;
+ case PROP_MANUFACTURER:
+ g_value_set_string (value, nm_p2p_peer_get_manufacturer (peer));
+ break;
+ case PROP_MODEL:
+ g_value_set_string (value, nm_p2p_peer_get_model (peer));
+ break;
+ case PROP_MODEL_NUMBER:
+ g_value_set_string (value, nm_p2p_peer_get_model_number (peer));
+ break;
+ case PROP_SERIAL:
+ g_value_set_string (value, nm_p2p_peer_get_serial (peer));
+ break;
+ case PROP_WFD_IES:
+ g_value_set_boxed (value, nm_p2p_peer_get_wfd_ies (peer));
+ break;
+ case PROP_HW_ADDRESS:
+ g_value_set_string (value, nm_p2p_peer_get_hw_address (peer));
+ break;
+ case PROP_STRENGTH:
+ g_value_set_uchar (value, nm_p2p_peer_get_strength (peer));
+ break;
+ case PROP_LAST_SEEN:
+ g_value_set_int (value, nm_p2p_peer_get_last_seen (peer));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+nm_p2p_peer_init (NMP2PPeer *peer)
+{
+ NM_P2P_PEER_GET_PRIVATE (peer)->last_seen = -1;
+}
+
+static void
+finalize (GObject *object)
+{
+ NMP2PPeerPrivate *priv = NM_P2P_PEER_GET_PRIVATE (object);
+
+ g_free (priv->name);
+ g_free (priv->manufacturer);
+ g_free (priv->model);
+ g_free (priv->model_number);
+ g_free (priv->serial);
+
+ if (priv->wfd_ies)
+ g_bytes_unref (priv->wfd_ies);
+
+ G_OBJECT_CLASS (nm_p2p_peer_parent_class)->finalize (object);
+}
+
+static void
+init_dbus (NMObject *object)
+{
+ NMP2PPeerPrivate *priv = NM_P2P_PEER_GET_PRIVATE (object);
+ const NMPropertiesInfo property_info[] = {
+ { NM_P2P_PEER_FLAGS, &priv->flags },
+ { NM_P2P_PEER_NAME, &priv->name },
+ { NM_P2P_PEER_MANUFACTURER, &priv->manufacturer },
+ { NM_P2P_PEER_MODEL, &priv->model },
+ { NM_P2P_PEER_MODEL_NUMBER, &priv->model_number },
+ { NM_P2P_PEER_SERIAL, &priv->serial },
+ { NM_P2P_PEER_WFD_IES, &priv->wfd_ies },
+ { NM_P2P_PEER_HW_ADDRESS, &priv->hw_address },
+ { NM_P2P_PEER_STRENGTH, &priv->strength },
+ { NM_P2P_PEER_LAST_SEEN, &priv->last_seen },
+ { NULL },
+ };
+
+ NM_OBJECT_CLASS (nm_p2p_peer_parent_class)->init_dbus (object);
+
+ _nm_object_register_properties (object,
+ NM_DBUS_INTERFACE_P2P_PEER,
+ property_info);
+}
+
+static void
+nm_p2p_peer_class_init (NMP2PPeerClass *peer_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (peer_class);
+ NMObjectClass *nm_object_class = NM_OBJECT_CLASS (peer_class);
+
+ g_type_class_add_private (peer_class, sizeof (NMP2PPeerPrivate));
+
+ /* virtual methods */
+ object_class->get_property = get_property;
+ object_class->finalize = finalize;
+
+ nm_object_class->init_dbus = init_dbus;
+
+ /* properties */
+
+ /**
+ * NMP2PPeer:flags:
+ *
+ * The flags of the P2P peer.
+ *
+ * Since: 1.16
+ **/
+ g_object_class_install_property
+ (object_class, PROP_FLAGS,
+ g_param_spec_flags (NM_P2P_PEER_FLAGS, "", "",
+ NM_TYPE_802_11_AP_FLAGS,
+ NM_802_11_AP_FLAGS_NONE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMP2PPeer:name:
+ *
+ * The name of the P2P peer.
+ *
+ * Since: 1.16
+ **/
+ g_object_class_install_property
+ (object_class, PROP_NAME,
+ g_param_spec_string (NM_P2P_PEER_NAME, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMP2PPeer:manufacturer:
+ *
+ * The manufacturer of the P2P peer.
+ *
+ * Since: 1.16
+ **/
+ g_object_class_install_property
+ (object_class, PROP_MANUFACTURER,
+ g_param_spec_string (NM_P2P_PEER_MANUFACTURER, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMP2PPeer:model:
+ *
+ * The model of the P2P peer.
+ *
+ * Since: 1.16
+ **/
+ g_object_class_install_property
+ (object_class, PROP_MODEL,
+ g_param_spec_string (NM_P2P_PEER_MODEL, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMP2PPeer:model-number:
+ *
+ * The hardware address of the P2P peer.
+ *
+ * Since: 1.16
+ **/
+ g_object_class_install_property
+ (object_class, PROP_MODEL_NUMBER,
+ g_param_spec_string (NM_P2P_PEER_MODEL_NUMBER, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMP2PPeer:serial:
+ *
+ * The serial number of the P2P peer.
+ *
+ * Since: 1.16
+ **/
+ g_object_class_install_property
+ (object_class, PROP_SERIAL,
+ g_param_spec_string (NM_P2P_PEER_SERIAL, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMP2PPeer:wfd-ies:
+ *
+ * The WFD information elements of the P2P peer.
+ *
+ * Since: 1.16
+ **/
+ g_object_class_install_property
+ (object_class, PROP_WFD_IES,
+ g_param_spec_boxed (NM_P2P_PEER_WFD_IES, "", "",
+ G_TYPE_BYTES,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+ /**
+ * NMP2PPeer:hw-address:
+ *
+ * The hardware address of the P2P peer.
+ *
+ * Since: 1.16
+ **/
+ g_object_class_install_property
+ (object_class, PROP_HW_ADDRESS,
+ g_param_spec_string (NM_P2P_PEER_HW_ADDRESS, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMP2PPeer:strength:
+ *
+ * The current signal strength of the P2P peer.
+ *
+ * Since: 1.16
+ **/
+ g_object_class_install_property
+ (object_class, PROP_STRENGTH,
+ g_param_spec_uchar (NM_P2P_PEER_STRENGTH, "", "",
+ 0, G_MAXUINT8, 0,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMP2PPeer:last-seen:
+ *
+ * The timestamp (in CLOCK_BOOTTIME seconds) for the last time the
+ * P2P peer was found. A value of -1 means the peer has never been seen.
+ *
+ * Since: 1.16
+ **/
+ g_object_class_install_property
+ (object_class, PROP_LAST_SEEN,
+ g_param_spec_int (NM_P2P_PEER_LAST_SEEN, "", "",
+ -1, G_MAXINT, -1,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+}
diff --git a/libnm/nm-p2p-peer.h b/libnm/nm-p2p-peer.h
new file mode 100644
index 0000000000..bb96df4312
--- /dev/null
+++ b/libnm/nm-p2p-peer.h
@@ -0,0 +1,104 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2007 - 2008 Novell, Inc.
+ * Copyright 2007 - 2011 Red Hat, Inc.
+ */
+
+#ifndef __NM_P2P_PEER_H__
+#define __NM_P2P_PEER_H__
+
+#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION)
+#error "Only <NetworkManager.h> can be included directly."
+#endif
+
+#include "nm-object.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_P2P_PEER (nm_p2p_peer_get_type ())
+#define NM_P2P_PEER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_P2P_PEER, NMP2PPeer))
+#define NM_P2P_PEER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_P2P_PEER, NMP2PPeerClass))
+#define NM_IS_P2P_PEER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_P2P_PEER))
+#define NM_IS_P2P_PEER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_P2P_PEER))
+#define NM_P2P_PEER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_P2P_PEER, NMP2PPeerClass))
+
+#define NM_P2P_PEER_FLAGS "flags"
+#define NM_P2P_PEER_NAME "name"
+#define NM_P2P_PEER_MANUFACTURER "manufacturer"
+#define NM_P2P_PEER_MODEL "model"
+#define NM_P2P_PEER_MODEL_NUMBER "model-number"
+#define NM_P2P_PEER_SERIAL "serial"
+#define NM_P2P_PEER_WFD_IES "wfd-ies"
+#define NM_P2P_PEER_HW_ADDRESS "hw-address"
+#define NM_P2P_PEER_STRENGTH "strength"
+#define NM_P2P_PEER_LAST_SEEN "last-seen"
+
+/**
+ * NMP2PPeer:
+ */
+NM_AVAILABLE_IN_1_16
+struct _NMP2PPeer {
+ NMObject parent;
+};
+
+NM_AVAILABLE_IN_1_16
+typedef struct {
+ NMObjectClass parent;
+
+ /*< private >*/
+ gpointer padding[4];
+} NMP2PPeerClass;
+
+NM_AVAILABLE_IN_1_16
+GType nm_p2p_peer_get_type (void);
+
+NM_AVAILABLE_IN_1_16
+NM80211ApFlags nm_p2p_peer_get_flags (NMP2PPeer *peer);
+
+NM_AVAILABLE_IN_1_16
+const char * nm_p2p_peer_get_name (NMP2PPeer *peer);
+NM_AVAILABLE_IN_1_16
+const char * nm_p2p_peer_get_manufacturer (NMP2PPeer *peer);
+NM_AVAILABLE_IN_1_16
+const char * nm_p2p_peer_get_model (NMP2PPeer *peer);
+NM_AVAILABLE_IN_1_16
+const char * nm_p2p_peer_get_model_number (NMP2PPeer *peer);
+NM_AVAILABLE_IN_1_16
+const char * nm_p2p_peer_get_serial (NMP2PPeer *peer);
+
+NM_AVAILABLE_IN_1_16
+GBytes * nm_p2p_peer_get_wfd_ies (NMP2PPeer *peer);
+
+NM_AVAILABLE_IN_1_16
+const char * nm_p2p_peer_get_hw_address (NMP2PPeer *peer);
+
+NM_AVAILABLE_IN_1_16
+guint8 nm_p2p_peer_get_strength (NMP2PPeer *peer);
+NM_AVAILABLE_IN_1_16
+int nm_p2p_peer_get_last_seen (NMP2PPeer *peer);
+
+NM_AVAILABLE_IN_1_16
+GPtrArray * nm_p2p_peer_filter_connections (NMP2PPeer *peer,
+ const GPtrArray *connections);
+
+NM_AVAILABLE_IN_1_16
+gboolean nm_p2p_peer_connection_valid (NMP2PPeer *peer,
+ NMConnection *connection);
+
+G_END_DECLS
+
+#endif /* __NM_P2P_PEER_H__ */
diff --git a/libnm/nm-types.h b/libnm/nm-types.h
index bb77e642df..0cf8186f5c 100644
--- a/libnm/nm-types.h
+++ b/libnm/nm-types.h
@@ -54,11 +54,13 @@ typedef struct _NMDeviceTun NMDeviceTun;
typedef struct _NMDeviceVlan NMDeviceVlan;
typedef struct _NMDeviceVxlan NMDeviceVxlan;
typedef struct _NMDeviceWifi NMDeviceWifi;
+typedef struct _NMDeviceP2PWifi NMDeviceP2PWifi;
typedef struct _NMDeviceWimax NMDeviceWimax;
typedef struct _NMDeviceWireGuard NMDeviceWireGuard;
typedef struct _NMDeviceWpan NMDeviceWpan;
typedef struct _NMDhcpConfig NMDhcpConfig;
typedef struct _NMIPConfig NMIPConfig;
+typedef struct _NMP2PPeer NMP2PPeer;
typedef struct _NMObject NMObject;
typedef struct _NMRemoteConnection NMRemoteConnection;
typedef struct _NMVpnConnection NMVpnConnection;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 33192b1dd0..31a614fc8a 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -82,6 +82,7 @@ libnm-core/nm-setting-ovs-interface.c
libnm-core/nm-setting-ovs-patch.c
libnm-core/nm-setting-ovs-port.c
libnm-core/nm-setting-ovs-bridge.c
+libnm-core/nm-setting-p2p-wireless.c
libnm-core/nm-setting-ppp.c
libnm-core/nm-setting-pppoe.c
libnm-core/nm-setting-proxy.c
@@ -151,6 +152,7 @@ libnm/nm-device-olpc-mesh.c
libnm/nm-device-ovs-bridge.c
libnm/nm-device-ovs-interface.c
libnm/nm-device-ovs-port.c
+libnm/nm-device-p2p-wifi.c
libnm/nm-device-team.c
libnm/nm-device-vlan.c
libnm/nm-device-vxlan.c
diff --git a/shared/nm-meta-setting.c b/shared/nm-meta-setting.c
index 3e79747fba..6256b06c00 100644
--- a/shared/nm-meta-setting.c
+++ b/shared/nm-meta-setting.c
@@ -50,6 +50,7 @@
#include "nm-setting-ovs-interface.h"
#include "nm-setting-ovs-patch.h"
#include "nm-setting-ovs-port.h"
+#include "nm-setting-p2p-wireless.h"
#include "nm-setting-ppp.h"
#include "nm-setting-pppoe.h"
#include "nm-setting-proxy.h"
@@ -305,6 +306,12 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = {
.setting_name = NM_SETTING_OVS_PORT_SETTING_NAME,
.get_setting_gtype = nm_setting_ovs_port_get_type,
},
+ [NM_META_SETTING_TYPE_P2P_WIRELESS] = {
+ .meta_type = NM_META_SETTING_TYPE_P2P_WIRELESS,
+ .setting_priority = NM_SETTING_PRIORITY_HW_BASE,
+ .setting_name = NM_SETTING_P2P_WIRELESS_SETTING_NAME,
+ .get_setting_gtype = nm_setting_p2p_wireless_get_type,
+ },
[NM_META_SETTING_TYPE_PPPOE] = {
.meta_type = NM_META_SETTING_TYPE_PPPOE,
.setting_priority = NM_SETTING_PRIORITY_AUX,
diff --git a/shared/nm-meta-setting.h b/shared/nm-meta-setting.h
index 26c29beaa7..089acc8e9c 100644
--- a/shared/nm-meta-setting.h
+++ b/shared/nm-meta-setting.h
@@ -132,6 +132,7 @@ typedef enum {
NM_META_SETTING_TYPE_OVS_INTERFACE,
NM_META_SETTING_TYPE_OVS_PATCH,
NM_META_SETTING_TYPE_OVS_PORT,
+ NM_META_SETTING_TYPE_P2P_WIRELESS,
NM_META_SETTING_TYPE_PPP,
NM_META_SETTING_TYPE_PPPOE,
NM_META_SETTING_TYPE_PROXY,
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 17cc454603..c2396d77c8 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -742,6 +742,7 @@ NM_UTILS_LOOKUP_STR_DEFINE (nm_device_state_reason_to_str, NMDeviceStateReason,
NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE, "ip-address-duplicate"),
NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_IP_METHOD_UNSUPPORTED, "ip-method-unsupported"),
NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED, "sriov-configuration-failed"),
+ NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_PEER_NOT_FOUND, "peer-not-found"),
);
#define reason_to_string_a(reason) NM_UTILS_LOOKUP_STR_A (nm_device_state_reason_to_str, reason)
diff --git a/src/devices/wifi/meson.build b/src/devices/wifi/meson.build
index dd2be5406b..d2b807fc95 100644
--- a/src/devices/wifi/meson.build
+++ b/src/devices/wifi/meson.build
@@ -1,13 +1,15 @@
common_sources = files(
'nm-wifi-ap.c',
+ 'nm-wifi-p2p-peer.c',
'nm-wifi-utils.c',
)
sources = common_sources + files(
- 'nm-wifi-factory.c',
- 'nm-wifi-common.c',
- 'nm-device-wifi.c',
'nm-device-olpc-mesh.c',
+ 'nm-device-p2p-wifi.c',
+ 'nm-device-wifi.c',
+ 'nm-wifi-common.c',
+ 'nm-wifi-factory.c',
)
if enable_iwd
diff --git a/src/devices/wifi/nm-device-p2p-wifi.c b/src/devices/wifi/nm-device-p2p-wifi.c
new file mode 100644
index 0000000000..80fda59c47
--- /dev/null
+++ b/src/devices/wifi/nm-device-p2p-wifi.c
@@ -0,0 +1,1366 @@
+/* NetworkManager -- P2P Wi-Fi Device
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2018 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nm-device-p2p-wifi.h"
+
+#include <sys/socket.h>
+
+#include "supplicant/nm-supplicant-manager.h"
+#include "supplicant/nm-supplicant-interface.h"
+
+#include "nm-manager.h"
+#include "nm-utils.h"
+#include "nm-wifi-p2p-peer.h"
+#include "NetworkManagerUtils.h"
+#include "devices/nm-device-private.h"
+#include "settings/nm-settings.h"
+#include "nm-setting-p2p-wireless.h"
+#include "nm-act-request.h"
+#include "nm-ip4-config.h"
+#include "platform/nm-platform.h"
+#include "nm-manager.h"
+#include "nm-core-internal.h"
+#include "platform/nmp-object.h"
+
+#include "devices/nm-device-logging.h"
+_LOG_DECLARE_SELF(NMDeviceP2PWifi);
+
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceP2PWifi,
+ PROP_GROUP_OWNER,
+ //PROP_SSID,
+ //PROP_BSSID,
+ PROP_PEERS,
+ PROP_WFDIES, /* TODO: Make this a property of the setting and Find feature
+ * making the device stateless.
+ */
+
+ PROP_MGMT_IFACE,
+);
+
+enum {
+ SCANNING_PROHIBITED,
+
+ LAST_SIGNAL
+};
+
+//static guint signals[LAST_SIGNAL] = { 0 };
+
+typedef struct {
+ NMSupplicantManager *sup_mgr;
+
+ /* NOTE: In theory management and group ifaces could be identical. However,
+ * in practice, this cannot happen currently as NMDeviceP2PWifi is only
+ * created for existing non-P2P interfaces.
+ * (i.e. a single standalone P2P interface is not supported at this point)
+ */
+ NMSupplicantInterface *mgmt_iface;
+ NMSupplicantInterface *group_iface;
+
+ CList peers_lst_head;
+ GBytes *wfd_ies;
+
+ guint sup_timeout_id;
+ guint peer_dump_id;
+ guint peer_missing_id;
+
+ gboolean group_owner;
+} NMDeviceP2PWifiPrivate;
+
+struct _NMDeviceP2PWifi {
+ NMDevice parent;
+ NMDeviceP2PWifiPrivate _priv;
+};
+
+struct _NMDeviceP2PWifiClass {
+ NMDeviceClass parent;
+};
+
+G_DEFINE_TYPE (NMDeviceP2PWifi, nm_device_p2p_wifi, NM_TYPE_DEVICE)
+
+#define NM_DEVICE_P2P_WIFI_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceP2PWifi, NM_IS_DEVICE_P2P_WIFI, NMDevice)
+
+/*****************************************************************************/
+
+static const NMDBusInterfaceInfoExtended interface_info_device_p2p_wifi;
+static const GDBusSignalInfo nm_signal_info_p2p_wireless_peer_added;
+static const GDBusSignalInfo nm_signal_info_p2p_wireless_peer_removed;
+
+static void supplicant_group_interface_release (NMDeviceP2PWifi *self);
+static void supplicant_interfaces_release (NMDeviceP2PWifi *self);
+
+/*****************************************************************************/
+
+static void
+_peer_dump (NMDeviceP2PWifi *self,
+ NMLogLevel log_level,
+ const NMWifiP2PPeer *peer,
+ const char *prefix,
+ gint32 now_s)
+{
+ char buf[1024];
+
+ _NMLOG (log_level, LOGD_WIFI_SCAN, "wifi-peer: %-7s %s",
+ prefix,
+ nm_wifi_p2p_peer_to_string (peer, buf, sizeof (buf), now_s));
+}
+
+static gboolean
+peer_list_dump (gpointer user_data)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (user_data);
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+
+ priv->peer_dump_id = 0;
+
+ if (_LOGD_ENABLED (LOGD_WIFI_SCAN)) {
+ NMWifiP2PPeer *peer;
+ gint32 now_s = nm_utils_get_monotonic_timestamp_s ();
+
+ _LOGD (LOGD_WIFI_SCAN, "P2P Peers: [now:%u]", now_s);
+ c_list_for_each_entry (peer, &priv->peers_lst_head, peers_lst)
+ _peer_dump (self, LOGL_DEBUG, peer, "dump", now_s);
+ }
+ return G_SOURCE_REMOVE;
+}
+
+static void
+schedule_peer_list_dump (NMDeviceP2PWifi *self)
+{
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+
+ if ( !priv->peer_dump_id
+ && _LOGD_ENABLED (LOGD_WIFI_SCAN))
+ priv->peer_dump_id = g_timeout_add_seconds (1, peer_list_dump, self);
+}
+
+/*****************************************************************************/
+
+static gboolean
+check_connection_peer_joined (NMDeviceP2PWifi *device)
+{
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (device);
+ NMConnection *conn = nm_device_get_applied_connection (NM_DEVICE (device));
+ NMWifiP2PPeer *peer;
+ const char* group;
+ const char * const * groups;
+
+ if (!conn || !priv->group_iface)
+ return FALSE;
+
+ /* Comparing the object path found on the group_iface with the peers
+ * found on the mgmt_iface is legal. */
+ group = nm_supplicant_interface_get_p2p_group_path (priv->group_iface);
+ if (!group)
+ return FALSE;
+
+ /* NOTE: We currently only support connections to a specific peer */
+ peer = nm_wifi_p2p_peers_find_first_compatible (&priv->peers_lst_head, conn);
+ if (!peer)
+ return FALSE;
+
+ groups = nm_wifi_p2p_peer_get_groups (peer);
+ if ( !groups
+ || !g_strv_contains (groups, group))
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+disconnect_on_connection_peer_missing_cb (gpointer user_data)
+{
+ NMDevice *device = NM_DEVICE (user_data);
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (device);
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+
+ _LOGW (LOGD_WIFI, "Peer requested in connection is missing for too long, failing connection.");
+
+ priv->peer_missing_id = 0;
+
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_FAILED,
+ NM_DEVICE_STATE_REASON_PEER_NOT_FOUND);
+ return FALSE;
+}
+
+static void
+update_disconnect_on_connection_peer_missing (NMDeviceP2PWifi *self)
+{
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+ NMDeviceState state;
+
+ state = nm_device_get_state (NM_DEVICE (self));
+ if ( state < NM_DEVICE_STATE_IP_CONFIG
+ || state > NM_DEVICE_STATE_ACTIVATED) {
+ nm_clear_g_source (&priv->peer_missing_id);
+ return;
+ }
+
+ if (check_connection_peer_joined (self)) {
+ if (nm_clear_g_source (&priv->peer_missing_id))
+ _LOGD (LOGD_WIFI, "Peer requested in connection is joined, removing timeout");
+ return;
+ }
+
+ if (priv->peer_missing_id == 0) {
+ _LOGD (LOGD_WIFI, "Peer requested in connection is missing, adding timeout");
+ priv->peer_missing_id = g_timeout_add_seconds (5, disconnect_on_connection_peer_missing_cb, self);
+ }
+}
+
+static gboolean
+is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (device);
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+ NMSupplicantInterfaceState supplicant_state;
+
+ if (!priv->mgmt_iface)
+ return FALSE;
+
+ supplicant_state = nm_supplicant_interface_get_state (priv->mgmt_iface);
+ if ( supplicant_state < NM_SUPPLICANT_INTERFACE_STATE_READY
+ || supplicant_state > NM_SUPPLICANT_INTERFACE_STATE_COMPLETED)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
+{
+ if (!NM_DEVICE_CLASS (nm_device_p2p_wifi_parent_class)->check_connection_compatible (device, connection, error))
+ return FALSE;
+
+ /* TODO: Allow limitting the interface using the HW-address? */
+
+ /* We don't need to check anything else here. The P2P device will only
+ * exists if we are able to establish a P2P connection, and there should
+ * be no further restrictions necessary.
+ */
+
+ return TRUE;
+}
+
+static gboolean
+complete_connection (NMDevice *device,
+ NMConnection *connection,
+ const char *specific_object,
+ NMConnection *const*existing_connections,
+ GError **error)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (device);
+ gs_free char *setting_name = NULL;
+ NMSettingP2PWireless *s_p2p_wireless;
+ NMWifiP2PPeer *peer;
+ const char *setting_peer;
+
+ s_p2p_wireless = NM_SETTING_P2P_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_P2P_WIRELESS));
+
+ if (!specific_object) {
+ /* If not given a specific object, we need at minimum a peer address */
+ if (!s_p2p_wireless) {
+ g_set_error_literal (error,
+ NM_DEVICE_ERROR,
+ NM_DEVICE_ERROR_INVALID_CONNECTION,
+ "A 'p2p-wireless' setting is required if no Peer path was given.");
+ return FALSE;
+ }
+
+ setting_peer = nm_setting_p2p_wireless_get_peer (s_p2p_wireless);
+ if (!setting_peer) {
+ g_set_error_literal (error,
+ NM_DEVICE_ERROR,
+ NM_DEVICE_ERROR_INVALID_CONNECTION,
+ "A 'p2p-wireless' setting with a valid Peer is required if no Peer path was given.");
+ return FALSE;
+ }
+
+ } else {
+ peer = nm_wifi_p2p_peer_lookup_for_device (NM_DEVICE (self), specific_object);
+ if (!peer) {
+ g_set_error (error,
+ NM_DEVICE_ERROR,
+ NM_DEVICE_ERROR_SPECIFIC_OBJECT_NOT_FOUND,
+ "The P2P peer %s is unknown.",
+ specific_object);
+ return FALSE;
+ }
+
+ setting_peer = nm_wifi_p2p_peer_get_address (peer);
+ g_assert (setting_peer);
+ }
+
+ /* Add a P2P wifi setting if one doesn't exist yet */
+ if (!s_p2p_wireless) {
+ s_p2p_wireless = NM_SETTING_P2P_WIRELESS (nm_setting_p2p_wireless_new ());
+ nm_connection_add_setting (connection, NM_SETTING (s_p2p_wireless));
+ }
+
+ g_object_set (G_OBJECT (s_p2p_wireless), NM_SETTING_P2P_WIRELESS_PEER, setting_peer, NULL);
+
+ setting_name = g_strdup_printf ("P2P Peer %s", setting_peer);
+ nm_utils_complete_generic (nm_device_get_platform (device),
+ connection,
+ NM_SETTING_P2P_WIRELESS_SETTING_NAME,
+ existing_connections,
+ setting_name,
+ setting_name,
+ NULL,
+ TRUE);
+
+ return TRUE;
+}
+
+/*
+ * supplicant_find_timeout_cb
+ *
+ * Called when the supplicant has been unable to find the peer we want to connect to.
+ */
+static gboolean
+supplicant_find_timeout_cb (gpointer user_data)
+{
+ NMDevice *device = NM_DEVICE (user_data);
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (user_data);
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+
+ priv->sup_timeout_id = 0;
+
+ nm_supplicant_interface_p2p_cancel_connect (priv->mgmt_iface);
+
+ if (nm_device_is_activating (device)) {
+ _LOGW (LOGD_DEVICE | LOGD_WIFI,
+ "Activation: (p2p-wifi) could not find peer, failing activation");
+ nm_device_state_changed (device, NM_DEVICE_STATE_FAILED,
+ NM_DEVICE_STATE_REASON_PEER_NOT_FOUND);
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static NMActStageReturn
+act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (device);
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+ NMActStageReturn ret;
+ NMActRequest *req;
+ NMConnection *connection;
+ NMSettingP2PWireless *s_p2p_wireless;
+ NMWifiP2PPeer *peer;
+
+ nm_clear_g_source (&priv->sup_timeout_id);
+
+ ret = NM_DEVICE_CLASS (nm_device_p2p_wifi_parent_class)->act_stage1_prepare (device, out_failure_reason);
+ if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
+ return ret;
+
+ if (!priv->mgmt_iface) {
+ NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+ return NM_ACT_STAGE_RETURN_FAILURE;
+ }
+
+ req = nm_device_get_act_request (NM_DEVICE (self));
+ g_return_val_if_fail (req, NM_ACT_STAGE_RETURN_FAILURE);
+
+ connection = nm_act_request_get_applied_connection (req);
+ g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE);
+
+ s_p2p_wireless = NM_SETTING_P2P_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_P2P_WIRELESS));
+ g_return_val_if_fail (s_p2p_wireless, NM_ACT_STAGE_RETURN_FAILURE);
+
+ peer = nm_wifi_p2p_peers_find_first_compatible (&priv->peers_lst_head, connection);
+ if (!peer) {
+ /* Set up a timeout on the find attempt and run a find for the same period of time */
+ priv->sup_timeout_id = g_timeout_add_seconds (10,
+ supplicant_find_timeout_cb,
+ self);
+
+ nm_supplicant_interface_p2p_start_find (priv->mgmt_iface, 10);
+
+ return NM_ACT_STAGE_RETURN_POSTPONE;
+ }
+
+ /* TODO: Set WFD IEs on supplicant manager here! */
+
+ return NM_ACT_STAGE_RETURN_SUCCESS;
+}
+
+static void
+cleanup_p2p_connect_attempt (NMDeviceP2PWifi *self, gboolean disconnect)
+{
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+
+ nm_clear_g_source (&priv->sup_timeout_id);
+ nm_clear_g_source (&priv->peer_missing_id);
+
+ if (priv->mgmt_iface)
+ nm_supplicant_interface_p2p_cancel_connect (priv->mgmt_iface);
+
+ if (disconnect && priv->group_iface)
+ nm_supplicant_interface_p2p_disconnect (priv->group_iface);
+}
+
+/*
+ * supplicant_connection_timeout_cb
+ *
+ * Called when the supplicant has been unable to connect to a peer
+ * within a specified period of time.
+ */
+static gboolean
+supplicant_connection_timeout_cb (gpointer user_data)
+{
+ NMDevice *device = NM_DEVICE (user_data);
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (user_data);
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+
+ priv->sup_timeout_id = 0;
+
+ nm_supplicant_interface_p2p_cancel_connect (priv->mgmt_iface);
+
+ if (nm_device_is_activating (device)) {
+ _LOGW (LOGD_DEVICE | LOGD_WIFI,
+ "Activation: (p2p-wifi) connecting took too long, failing activation");
+ nm_device_state_changed (device, NM_DEVICE_STATE_FAILED,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT);
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static NMActStageReturn
+act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (device);
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+ NMConnection *connection;
+ NMWifiP2PPeer *peer;
+
+ nm_clear_g_source (&priv->sup_timeout_id);
+
+ connection = nm_device_get_applied_connection (device);
+ g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE);
+
+ nm_assert (NM_IS_SETTING_P2P_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_P2P_WIRELESS)));
+
+ /* The prepare stage ensures that the peer has been found */
+ peer = nm_wifi_p2p_peers_find_first_compatible (&priv->peers_lst_head, connection);
+ if (!peer) {
+ NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_PEER_NOT_FOUND);
+ return NM_ACT_STAGE_RETURN_FAILURE;
+ }
+
+ /* TODO: Grab secrets if we don't have them yet! */
+
+ /* TODO: Fix "pbc" being hardcoded here! */
+ nm_supplicant_interface_p2p_connect (priv->mgmt_iface,
+ nm_wifi_p2p_peer_get_supplicant_path (peer),
+ "pbc", NULL);
+
+ /* Set up a timeout on the connect attempt */
+ priv->sup_timeout_id = g_timeout_add_seconds (45,
+ supplicant_connection_timeout_cb,
+ self);
+
+ /* We'll get stage3 started when the P2P group has been started */
+ return NM_ACT_STAGE_RETURN_POSTPONE;
+}
+
+/*****************************************************************************/
+
+static void
+emit_signal_p2p_peer_add_remove (NMDeviceP2PWifi *device,
+ NMWifiP2PPeer *peer,
+ gboolean is_added /* or else is_removed */)
+{
+ nm_dbus_object_emit_signal (NM_DBUS_OBJECT (device),
+ &interface_info_device_p2p_wifi,
+ is_added
+ ? &nm_signal_info_p2p_wireless_peer_added
+ : &nm_signal_info_p2p_wireless_peer_removed,
+ "(o)",
+ nm_dbus_object_get_path (NM_DBUS_OBJECT (peer)));
+}
+
+static void
+peer_add_remove (NMDeviceP2PWifi *self,
+ gboolean is_adding, /* or else removing */
+ NMWifiP2PPeer *peer,
+ gboolean recheck_available_connections)
+{
+ NMDevice *device = NM_DEVICE (self);
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+
+ if (is_adding) {
+ g_object_ref (peer);
+ peer->wifi_device = device;
+ c_list_link_tail (&priv->peers_lst_head, &peer->peers_lst);
+ nm_dbus_object_export (NM_DBUS_OBJECT (peer));
+ _peer_dump (self, LOGL_DEBUG, peer, "added", 0);
+
+ emit_signal_p2p_peer_add_remove (self, peer, TRUE);
+ } else {
+ peer->wifi_device = NULL;
+ c_list_unlink (&peer->peers_lst);
+ _peer_dump (self, LOGL_DEBUG, peer, "removed", 0);
+ }
+
+ _notify (self, PROP_PEERS);
+
+ if (!is_adding) {
+ emit_signal_p2p_peer_add_remove (self, peer, FALSE);
+ nm_dbus_object_clear_and_unexport (&peer);
+ }
+
+ if (is_adding) {
+ /* If we are in prepare state, then we are currently runnign a find
+ * to search for the requested peer. */
+ if (nm_device_get_state (device) == NM_DEVICE_STATE_PREPARE) {
+ NMConnection *connection;
+
+ connection = nm_device_get_applied_connection (device);
+ g_assert (connection);
+
+ peer = nm_wifi_p2p_peers_find_first_compatible (&priv->peers_lst_head, connection);
+ if (peer) {
+ /* A peer for the connection was found, cancel the timeout and go to configure state. */
+ nm_clear_g_source (&priv->sup_timeout_id);
+ nm_device_activate_schedule_stage2_device_config (device);
+ }
+ }
+
+ /* TODO: We may want to re-check auto-activation here, otherwise it will never work. */
+ }
+
+ update_disconnect_on_connection_peer_missing (self);
+
+#if 0
+ nm_device_emit_recheck_auto_activate (NM_DEVICE (self));
+ if (recheck_available_connections)
+ nm_device_recheck_available_connections (NM_DEVICE (self));
+#endif
+}
+
+static void
+remove_all_peers (NMDeviceP2PWifi *self)
+{
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+ NMWifiP2PPeer *peer;
+
+ if (c_list_is_empty (&priv->peers_lst_head))
+ return;
+
+ while ((peer = c_list_first_entry (&priv->peers_lst_head, NMWifiP2PPeer, peers_lst)))
+ peer_add_remove (self, FALSE, peer, FALSE);
+
+ nm_device_recheck_available_connections (NM_DEVICE (self));
+}
+
+/*****************************************************************************/
+
+
+static NMActStageReturn
+act_stage3_ip4_config_start (NMDevice *device,
+ NMIP4Config **out_config,
+ NMDeviceStateReason *out_failure_reason)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (device);
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+ NMConnection *connection;
+ NMSettingIPConfig *s_ip4;
+ const char *method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
+
+ connection = nm_device_get_applied_connection (device);
+ g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE);
+
+ s_ip4 = nm_connection_get_setting_ip4_config (connection);
+ if (s_ip4)
+ method = nm_setting_ip_config_get_method (s_ip4);
+
+ /* Indicate that a critical protocol is about to start */
+ if ( !priv->group_owner
+ && nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO))
+ nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), nm_device_get_ip_ifindex (device), TRUE);
+
+ return NM_DEVICE_CLASS (nm_device_p2p_wifi_parent_class)->act_stage3_ip4_config_start (device, out_config, out_failure_reason);
+}
+
+static NMActStageReturn
+act_stage3_ip6_config_start (NMDevice *device,
+ NMIP6Config **out_config,
+ NMDeviceStateReason *out_failure_reason)
+{
+ NMConnection *connection;
+ NMSettingIPConfig *s_ip6;
+ const char *method = NM_SETTING_IP6_CONFIG_METHOD_AUTO;
+
+ connection = nm_device_get_applied_connection (device);
+ g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE);
+
+ s_ip6 = nm_connection_get_setting_ip6_config (connection);
+ if (s_ip6)
+ method = nm_setting_ip_config_get_method (s_ip6);
+
+ /* Indicate that a critical protocol is about to start */
+ if (NM_IN_STRSET (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO
+ NM_SETTING_IP6_CONFIG_METHOD_DHCP))
+ nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), nm_device_get_ip_ifindex (device), TRUE);
+
+ return NM_DEVICE_CLASS (nm_device_p2p_wifi_parent_class)->act_stage3_ip6_config_start (device, out_config, out_failure_reason);
+}
+
+static void
+deactivate (NMDevice *device)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (device);
+ int ifindex = nm_device_get_ip_ifindex (device);
+
+ cleanup_p2p_connect_attempt (self, TRUE);
+
+ /* Clear any critical protocol notification in the Wi-Fi stack */
+ if (ifindex > 0)
+ nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), ifindex, FALSE);
+}
+
+static guint32
+get_configured_mtu (NMDevice *device, NMDeviceMtuSource *out_source)
+{
+ *out_source = NM_DEVICE_MTU_SOURCE_NONE;
+ return 0;
+}
+
+static const char *
+get_auto_ip_config_method (NMDevice *device, int addr_family)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (device);
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+
+ /* Override the AUTO method to mean shared if we are group owner. */
+ if ( priv->group_iface
+ && nm_supplicant_interface_get_p2p_group_owner (priv->group_iface)) {
+ if (addr_family == AF_INET)
+ return NM_SETTING_IP4_CONFIG_METHOD_SHARED;
+
+ if (addr_family == AF_INET6)
+ return NM_SETTING_IP6_CONFIG_METHOD_SHARED;
+ }
+
+ return NULL;
+}
+
+static gboolean
+unmanaged_on_quit (NMDevice *self)
+{
+ return TRUE;
+}
+
+static void
+supplicant_iface_state_cb (NMSupplicantInterface *iface,
+ int new_state_i,
+ int old_state_i,
+ int disconnect_reason,
+ gpointer user_data)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (user_data);
+ NMDevice *device = NM_DEVICE (self);
+ NMSupplicantInterfaceState new_state = new_state_i;
+ NMSupplicantInterfaceState old_state = old_state_i;
+
+ if (new_state == old_state)
+ return;
+
+ _LOGI (LOGD_DEVICE | LOGD_WIFI,
+ "supplicant management interface state: %s -> %s",
+ nm_supplicant_interface_state_to_string (old_state),
+ nm_supplicant_interface_state_to_string (new_state));
+
+ switch (new_state) {
+ case NM_SUPPLICANT_INTERFACE_STATE_READY:
+ _LOGD (LOGD_WIFI, "supplicant ready");
+ nm_device_queue_recheck_available (device,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+
+ if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY)
+ nm_device_remove_pending_action (device, NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE);
+ break;
+ case NM_SUPPLICANT_INTERFACE_STATE_DOWN:
+ nm_device_queue_recheck_available (device,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+
+ supplicant_interfaces_release (self);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+supplicant_iface_peer_updated_cb (NMSupplicantInterface *iface,
+ const char *object_path,
+ GVariant *properties,
+ NMDeviceP2PWifi *self)
+{
+ NMDeviceP2PWifiPrivate *priv;
+ NMWifiP2PPeer *found_peer;
+
+ g_return_if_fail (self != NULL);
+ g_return_if_fail (object_path != NULL);
+
+ priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+
+ found_peer = nm_wifi_p2p_peers_find_by_supplicant_path (&priv->peers_lst_head, object_path);
+ if (found_peer) {
+ if (!nm_wifi_p2p_peer_update_from_properties (found_peer, object_path, properties))
+ return;
+
+ update_disconnect_on_connection_peer_missing (self);
+ _peer_dump (self, LOGL_DEBUG, found_peer, "updated", 0);
+ } else {
+ gs_unref_object NMWifiP2PPeer *peer = NULL;
+
+ peer = nm_wifi_p2p_peer_new_from_properties (object_path, properties);
+ if (!peer) {
+ _LOGD (LOGD_WIFI, "invalid P2P peer properties received for %s", object_path);
+ return;
+ }
+
+ peer_add_remove (self, TRUE, peer, TRUE);
+ }
+
+ schedule_peer_list_dump (self);
+}
+
+static void
+supplicant_iface_peer_removed_cb (NMSupplicantInterface *iface,
+ const char *object_path,
+ NMDeviceP2PWifi *self)
+{
+ NMDeviceP2PWifiPrivate *priv;
+ NMWifiP2PPeer *peer;
+
+ g_return_if_fail (self != NULL);
+ g_return_if_fail (object_path != NULL);
+
+ priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+ peer = nm_wifi_p2p_peers_find_by_supplicant_path (&priv->peers_lst_head, object_path);
+ if (!peer)
+ return;
+
+ peer_add_remove (self, FALSE, peer, TRUE);
+ schedule_peer_list_dump (self);
+}
+
+static void
+check_group_iface_ready (NMDeviceP2PWifi *self)
+{
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);;
+
+ if (!priv->group_iface)
+ return;
+
+ if (nm_supplicant_interface_get_state (priv->group_iface) < NM_SUPPLICANT_INTERFACE_STATE_READY)
+ return;
+
+ if (!nm_supplicant_interface_get_p2p_group_joined (priv->group_iface))
+ return;
+
+ nm_clear_g_source (&priv->sup_timeout_id);
+ update_disconnect_on_connection_peer_missing (self);
+
+ nm_device_activate_schedule_stage3_ip_config_start (NM_DEVICE (self));
+}
+
+static void
+supplicant_group_iface_state_cb (NMSupplicantInterface *iface,
+ int new_state_i,
+ int old_state_i,
+ int disconnect_reason,
+ gpointer user_data)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (user_data);
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+ NMDevice *device = NM_DEVICE (self);
+ NMSupplicantInterfaceState new_state = new_state_i;
+ NMSupplicantInterfaceState old_state = old_state_i;
+
+ if (new_state == old_state)
+ return;
+
+ _LOGI (LOGD_DEVICE | LOGD_WIFI,
+ "P2P Group supplicant interface state: %s -> %s",
+ nm_supplicant_interface_state_to_string (old_state),
+ nm_supplicant_interface_state_to_string (new_state));
+
+ switch (new_state) {
+ case NM_SUPPLICANT_INTERFACE_STATE_READY:
+ _LOGD (LOGD_WIFI, "P2P Group supplicant ready");
+
+ if (!nm_device_set_ip_iface (device, nm_supplicant_interface_get_ifname (priv->group_iface))) {
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_FAILED,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+ break;
+ }
+
+ if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY)
+ nm_device_remove_pending_action (device, NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE);
+
+ check_group_iface_ready (self);
+ break;
+ case NM_SUPPLICANT_INTERFACE_STATE_DOWN:
+ supplicant_group_interface_release (self);
+
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_DISCONNECTED,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+supplicant_group_iface_group_finished_cb (NMSupplicantInterface *iface,
+ void *user_data)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (user_data);
+
+ supplicant_group_interface_release (self);
+
+ nm_device_state_changed (NM_DEVICE (self),
+ NM_DEVICE_STATE_DISCONNECTED,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
+}
+
+static void
+supplicant_iface_group_joined_updated_cb (NMSupplicantInterface *iface,
+ GParamSpec *pspec,
+ void *user_data)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (user_data);
+
+ check_group_iface_ready (self);
+}
+
+static void
+supplicant_iface_group_started_cb (NMSupplicantInterface *iface,
+ NMSupplicantInterface *group_iface,
+ NMDeviceP2PWifi *self)
+{
+ NMDeviceP2PWifiPrivate *priv;
+
+ g_return_if_fail (self != NULL);
+
+ if (!nm_device_is_activating (NM_DEVICE (self))) {
+ _LOGW (LOGD_DEVICE | LOGD_WIFI, "P2P: WPA supplicant notified a group start but we are not trying to connect! Ignoring the event.");
+ return;
+ }
+
+ priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+
+ supplicant_group_interface_release (self);
+ priv->group_iface = g_object_ref (group_iface);
+
+ /* We need to wait for the interface to be ready and the group
+ * information to be resolved. */
+ g_signal_connect (priv->group_iface,
+ "notify::" NM_SUPPLICANT_INTERFACE_P2P_GROUP_JOINED,
+ G_CALLBACK (supplicant_iface_group_joined_updated_cb),
+ self);
+
+ g_signal_connect (priv->group_iface,
+ NM_SUPPLICANT_INTERFACE_STATE,
+ G_CALLBACK (supplicant_group_iface_state_cb),
+ self);
+
+ g_signal_connect (priv->group_iface, NM_SUPPLICANT_INTERFACE_GROUP_FINISHED,
+ G_CALLBACK (supplicant_group_iface_group_finished_cb),
+ self);
+
+ if (nm_supplicant_interface_get_state (priv->group_iface) < NM_SUPPLICANT_INTERFACE_STATE_READY)
+ nm_device_add_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, FALSE);
+
+ check_group_iface_ready (self);
+}
+
+static void
+supplicant_group_interface_release (NMDeviceP2PWifi *self)
+{
+ NMDeviceP2PWifiPrivate *priv;
+
+ g_return_if_fail (self != NULL);
+
+ priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+
+ if (priv->group_iface) {
+ /* Tell the supplicant to disconnect from the current Group/Peer */
+ nm_supplicant_interface_p2p_disconnect (priv->group_iface);
+
+ /* Clear supplicant interface signal handlers */
+ g_signal_handlers_disconnect_by_data (priv->group_iface, self);
+
+ g_clear_object (&priv->group_iface);
+ }
+}
+
+static void
+supplicant_interfaces_release (NMDeviceP2PWifi *self)
+{
+ NMDeviceP2PWifiPrivate *priv;
+
+ g_return_if_fail (self != NULL);
+
+ priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+
+ _LOGD (LOGD_DEVICE | LOGD_WIFI, "P2P: Releasing WPA supplicant interfaces.");
+
+ nm_clear_g_source (&priv->peer_dump_id);
+ remove_all_peers (self);
+
+ if (priv->mgmt_iface) {
+ /* Clear supplicant interface signal handlers */
+ g_signal_handlers_disconnect_by_data (priv->mgmt_iface, self);
+
+ g_clear_object (&priv->mgmt_iface);
+
+ nm_device_add_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, FALSE);
+ }
+
+ supplicant_group_interface_release (self);
+}
+
+static void
+device_state_changed (NMDevice *device,
+ NMDeviceState new_state,
+ NMDeviceState old_state,
+ NMDeviceStateReason reason)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (device);
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+
+#if 0
+ if (new_state > NM_DEVICE_STATE_ACTIVATED)
+ wifi_secrets_cancel (self);
+#endif
+
+ update_disconnect_on_connection_peer_missing (self);
+
+ if (new_state <= NM_DEVICE_STATE_UNAVAILABLE) {
+ /* Clean up the supplicant interface because in these states the
+ * device cannot be used.
+ * Do not clean up for the UNMANAGED to UNAVAILABLE transition which
+ * will happen during initialization.
+ */
+ if (priv->mgmt_iface && old_state > new_state)
+ supplicant_interfaces_release (self);
+
+ /* TODO: More cleanup needed? */
+ } else
+ nm_assert (priv->mgmt_iface != NULL);
+
+ switch (new_state) {
+ case NM_DEVICE_STATE_UNMANAGED:
+ break;
+ case NM_DEVICE_STATE_UNAVAILABLE:
+ if (!priv->mgmt_iface || nm_supplicant_interface_get_state (priv->mgmt_iface) < NM_SUPPLICANT_INTERFACE_STATE_READY)
+ nm_device_add_pending_action (device, NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, FALSE);
+
+ break;
+ case NM_DEVICE_STATE_NEED_AUTH:
+ /* Disconnect? */
+ break;
+ case NM_DEVICE_STATE_IP_CHECK:
+ /* Clear any critical protocol notification in the wifi stack */
+ nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), nm_device_get_ip_ifindex (device), FALSE);
+ break;
+ case NM_DEVICE_STATE_ACTIVATED:
+ //activation_success_handler (device);
+ break;
+ case NM_DEVICE_STATE_FAILED:
+ /* Clear any critical protocol notification in the wifi stack.
+ * At this point the IP device may have been removed already. */
+ if (nm_device_get_ip_ifindex (device) > 0)
+ nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), nm_device_get_ip_ifindex (device), FALSE);
+ break;
+ case NM_DEVICE_STATE_DISCONNECTED:
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+impl_device_p2p_wifi_start_find (NMDBusObject *obj,
+ const NMDBusInterfaceInfoExtended *interface_info,
+ const NMDBusMethodInfoExtended *method_info,
+ GDBusConnection *connection,
+ const char *sender,
+ GDBusMethodInvocation *invocation,
+ GVariant *parameters)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (obj);
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+ gs_unref_variant GVariant *options = NULL;
+ int timeout;
+
+ g_variant_get (parameters, "(@a{sv})", &options);
+
+ if (!g_variant_lookup (options, "Timeout", "^ai", &timeout)) {
+ /* Default to running a find for 30s. */
+ timeout = 30;
+ }
+
+ /* Reject unreasonable timeout values. */
+ if (timeout <= 0 || timeout > 600) {
+ g_dbus_method_invocation_return_error_literal (invocation,
+ NM_DEVICE_ERROR,
+ NM_DEVICE_ERROR_NOT_ALLOWED,
+ "The timeout for a find operation needs to be in the range of 1-600s.");
+
+ return;
+ }
+
+ if (!priv->mgmt_iface) {
+ g_dbus_method_invocation_return_error_literal (invocation,
+ NM_DEVICE_ERROR,
+ NM_DEVICE_ERROR_NOT_ACTIVE,
+ "WPA Supplicant management interface is currently unavailable.");
+
+ return;
+ }
+
+ nm_supplicant_interface_p2p_start_find (priv->mgmt_iface, timeout);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+}
+
+static void
+impl_device_p2p_wifi_stop_find (NMDBusObject *obj,
+ const NMDBusInterfaceInfoExtended *interface_info,
+ const NMDBusMethodInfoExtended *method_info,
+ GDBusConnection *connection,
+ const char *sender,
+ GDBusMethodInvocation *invocation,
+ GVariant *parameters)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (obj);
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+
+ nm_supplicant_interface_p2p_stop_find (priv->mgmt_iface);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+}
+
+/*****************************************************************************/
+
+NMSupplicantInterface *
+nm_device_p2p_wifi_get_mgmt_iface (NMDeviceP2PWifi *self)
+{
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+
+ return priv->mgmt_iface;
+}
+
+void
+nm_device_p2p_wifi_set_mgmt_iface (NMDeviceP2PWifi *self,
+ NMSupplicantInterface *iface)
+{
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+
+ /* Don't do anything if nothing changed. */
+ if (priv->mgmt_iface == iface)
+ return;
+
+ supplicant_interfaces_release (self);
+
+ if (iface == NULL) {
+ _LOGD (LOGD_DEVICE | LOGD_WIFI, "P2P: WPA supplicant management interface cleared.");
+ return;
+ }
+
+ _LOGD (LOGD_DEVICE | LOGD_WIFI, "P2P: WPA supplicant management interface changed to %s.", nm_supplicant_interface_get_object_path (iface));
+
+ priv->mgmt_iface = g_object_ref (iface);
+
+ /* We are not waiting on the supplicant anymore if the state is ready. */
+ if (nm_supplicant_interface_get_state (priv->mgmt_iface) >= NM_SUPPLICANT_INTERFACE_STATE_READY)
+ nm_device_remove_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE);
+
+ g_signal_connect_object (priv->mgmt_iface, NM_SUPPLICANT_INTERFACE_STATE,
+ G_CALLBACK (supplicant_iface_state_cb),
+ self,
+ 0);
+ g_signal_connect_object (priv->mgmt_iface, NM_SUPPLICANT_INTERFACE_PEER_UPDATED,
+ G_CALLBACK (supplicant_iface_peer_updated_cb),
+ self,
+ 0);
+ g_signal_connect_object (priv->mgmt_iface, NM_SUPPLICANT_INTERFACE_PEER_REMOVED,
+ G_CALLBACK (supplicant_iface_peer_removed_cb),
+ self,
+ 0);
+ g_signal_connect_object (priv->mgmt_iface, NM_SUPPLICANT_INTERFACE_GROUP_STARTED,
+ G_CALLBACK (supplicant_iface_group_started_cb),
+ self,
+ 0);
+}
+
+void
+nm_device_p2p_wifi_remove (NMDeviceP2PWifi* self)
+{
+ g_signal_emit_by_name (self, NM_DEVICE_REMOVED);
+}
+
+/*****************************************************************************/
+
+static const GDBusSignalInfo nm_signal_info_p2p_wireless_peer_added = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT (
+ "PeerAdded",
+ .args = NM_DEFINE_GDBUS_ARG_INFOS (
+ NM_DEFINE_GDBUS_ARG_INFO ("peer", "o"),
+ ),
+);
+
+static const GDBusSignalInfo nm_signal_info_p2p_wireless_peer_removed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT (
+ "PeerRemoved",
+ .args = NM_DEFINE_GDBUS_ARG_INFOS (
+ NM_DEFINE_GDBUS_ARG_INFO ("peer", "o"),
+ ),
+);
+
+static const NMDBusInterfaceInfoExtended interface_info_device_p2p_wifi = {
+ .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT (
+ NM_DBUS_INTERFACE_DEVICE_P2P_WIRELESS,
+ .methods = NM_DEFINE_GDBUS_METHOD_INFOS (
+ NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
+ NM_DEFINE_GDBUS_METHOD_INFO_INIT (
+ "StartFind",
+ .in_args = NM_DEFINE_GDBUS_ARG_INFOS (
+ NM_DEFINE_GDBUS_ARG_INFO ("options", "a{sv}"),
+ ),
+ ),
+ .handle = impl_device_p2p_wifi_start_find,
+ ),
+ NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
+ NM_DEFINE_GDBUS_METHOD_INFO_INIT (
+ "StopFind",
+ ),
+ .handle = impl_device_p2p_wifi_stop_find,
+ ),
+ ),
+ .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS (
+ &nm_signal_info_p2p_wireless_peer_added,
+ &nm_signal_info_p2p_wireless_peer_removed,
+ ),
+ .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS (
+ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("HwAddress", "s", NM_DEVICE_HW_ADDRESS),
+ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("GroupOwner", "b", NM_DEVICE_P2P_WIFI_GROUP_OWNER),
+ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Peers", "ao", NM_DEVICE_P2P_WIFI_PEERS),
+ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("WFDIEs", "ay", NM_DEVICE_P2P_WIFI_WFDIES),
+ ),
+ ),
+ .legacy_property_changed = FALSE,
+};
+
+/*****************************************************************************/
+
+static void
+get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (object);
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+ const char **list;
+
+ switch (prop_id) {
+ case PROP_MGMT_IFACE:
+ g_value_set_object (value, priv->mgmt_iface);
+ break;
+ case PROP_GROUP_OWNER:
+ g_value_set_boolean (value, priv->group_owner);
+ break;
+ case PROP_PEERS:
+ list = nm_wifi_p2p_peers_get_paths (&priv->peers_lst_head);
+ g_value_take_boxed (value, nm_utils_strv_make_deep_copied (list));
+ break;
+ case PROP_WFDIES:
+ g_value_take_variant (value, nm_utils_gbytes_to_variant_ay (priv->wfd_ies));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (object);
+
+ switch (prop_id) {
+ case PROP_MGMT_IFACE:
+ /* construct-only */
+ nm_device_p2p_wifi_set_mgmt_iface (self, g_value_get_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/*****************************************************************************/
+
+static void
+nm_device_p2p_wifi_init (NMDeviceP2PWifi * self)
+{
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+ c_list_init (&priv->peers_lst_head);
+}
+
+static void
+constructed (GObject *object)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (object);
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (self);
+
+ G_OBJECT_CLASS (nm_device_p2p_wifi_parent_class)->constructed (object);
+
+ /* Connect to the supplicant manager */
+ priv->sup_mgr = g_object_ref (nm_supplicant_manager_get ());
+
+ nm_device_add_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, FALSE);
+}
+
+NMDevice*
+nm_device_p2p_wifi_new (NMSupplicantInterface *mgmt_iface, const char *iface)
+{
+ return g_object_new (NM_TYPE_DEVICE_P2P_WIFI,
+ NM_DEVICE_IFACE, iface,
+ NM_DEVICE_TYPE_DESC, "802.11 P2P WiFi",
+ NM_DEVICE_DEVICE_TYPE, NM_TYPE_DEVICE_P2P_WIFI,
+ NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_WIFI,
+ NM_DEVICE_RFKILL_TYPE, RFKILL_TYPE_WLAN,
+ NM_DEVICE_P2P_WIFI_MGMT_IFACE, mgmt_iface,
+ NULL);
+}
+
+static void
+dispose (GObject *object)
+{
+ NMDeviceP2PWifi *self = NM_DEVICE_P2P_WIFI (object);
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (object);
+
+ g_clear_object (&priv->sup_mgr);
+
+ supplicant_interfaces_release (self);
+
+ G_OBJECT_CLASS (nm_device_p2p_wifi_parent_class)->dispose (object);
+}
+
+static void
+finalize (GObject *object)
+{
+ NMDeviceP2PWifi *peer = NM_DEVICE_P2P_WIFI (object);
+ NMDeviceP2PWifiPrivate *priv = NM_DEVICE_P2P_WIFI_GET_PRIVATE (peer);
+
+ nm_assert (c_list_is_empty (&priv->peers_lst_head));
+
+ g_bytes_unref (priv->wfd_ies);
+
+ G_OBJECT_CLASS (nm_device_p2p_wifi_parent_class)->finalize (object);
+}
+
+static void
+nm_device_p2p_wifi_class_init (NMDeviceP2PWifiClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass);
+ NMDeviceClass *device_class = NM_DEVICE_CLASS (klass);
+
+ object_class->constructed = constructed;
+ object_class->get_property = get_property;
+ object_class->set_property = set_property;
+ object_class->dispose = dispose;
+ object_class->finalize = finalize;
+
+ dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_p2p_wifi);
+
+ device_class->connection_type_supported = NM_SETTING_P2P_WIRELESS_SETTING_NAME;
+ device_class->connection_type_check_compatible = NM_SETTING_P2P_WIRELESS_SETTING_NAME;
+ device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_P2P_WIFI);
+
+ /* Do we need compatibility checking or is the default good enough? */
+ device_class->is_available = is_available;
+ device_class->check_connection_compatible = check_connection_compatible;
+ device_class->complete_connection = complete_connection;
+
+ device_class->act_stage1_prepare = act_stage1_prepare;
+ device_class->act_stage2_config = act_stage2_config;
+ device_class->get_configured_mtu = get_configured_mtu;
+ device_class->get_auto_ip_config_method = get_auto_ip_config_method;
+ device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start;
+ device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start;
+
+ device_class->deactivate = deactivate;
+ device_class->unmanaged_on_quit = unmanaged_on_quit;
+
+ device_class->state_changed = device_state_changed;
+
+ /*klass->scanning_prohibited = scanning_prohibited;*/
+
+ obj_properties[PROP_GROUP_OWNER] =
+ g_param_spec_boolean (NM_DEVICE_P2P_WIFI_GROUP_OWNER, "", "",
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ obj_properties[PROP_PEERS] =
+ g_param_spec_boxed (NM_DEVICE_P2P_WIFI_PEERS, "", "",
+ G_TYPE_STRV,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ obj_properties[PROP_WFDIES] =
+ g_param_spec_variant (NM_DEVICE_P2P_WIFI_WFDIES, "", "",
+ G_VARIANT_TYPE ("ay"),
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ obj_properties[PROP_MGMT_IFACE] =
+ g_param_spec_object (NM_DEVICE_P2P_WIFI_MGMT_IFACE, "", "",
+ NM_TYPE_SUPPLICANT_INTERFACE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ /* obj_properties[PROP_SCANNING] = */
+ /* g_param_spec_boolean (NM_DEVICE_WIFI_SCANNING, "", "", */
+ /* FALSE, */
+ /* G_PARAM_READABLE | */
+ /* G_PARAM_STATIC_STRINGS); */
+
+ g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+}
diff --git a/src/devices/wifi/nm-device-p2p-wifi.h b/src/devices/wifi/nm-device-p2p-wifi.h
new file mode 100644
index 0000000000..128914e055
--- /dev/null
+++ b/src/devices/wifi/nm-device-p2p-wifi.h
@@ -0,0 +1,56 @@
+/* NetworkManager -- P2P Wi-Fi Device
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2018 Red Hat, Inc.
+ */
+
+#ifndef __NM_DEVICE_P2P_WIFI_H__
+#define __NM_DEVICE_P2P_WIFI_H__
+
+#include "devices/nm-device.h"
+#include "supplicant/nm-supplicant-interface.h"
+
+#define NM_TYPE_DEVICE_P2P_WIFI (nm_device_p2p_wifi_get_type ())
+#define NM_DEVICE_P2P_WIFI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_P2P_WIFI, NMDeviceP2PWifi))
+#define NM_DEVICE_P2P_WIFI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_P2P_WIFI, NMDeviceP2PWifiClass))
+#define NM_IS_DEVICE_P2P_WIFI(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_P2P_WIFI))
+#define NM_IS_DEVICE_P2P_WIFI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_P2P_WIFI))
+#define NM_DEVICE_P2P_WIFI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_P2P_WIFI, NMDeviceP2PWifiClass))
+
+#define NM_DEVICE_P2P_WIFI_GROUP_OWNER "group-owner"
+#define NM_DEVICE_P2P_WIFI_PEERS "peers"
+#define NM_DEVICE_P2P_WIFI_GROUPS "groups"
+#define NM_DEVICE_P2P_WIFI_WFDIES "WFDIEs"
+
+#define NM_DEVICE_P2P_WIFI_MGMT_IFACE "mgmt-iface"
+
+
+typedef struct _NMDeviceP2PWifi NMDeviceP2PWifi;
+typedef struct _NMDeviceP2PWifiClass NMDeviceP2PWifiClass;
+
+GType nm_device_p2p_wifi_get_type (void);
+
+NMDevice* nm_device_p2p_wifi_new (NMSupplicantInterface *mgmt_iface,
+ const char* iface);
+
+NMSupplicantInterface * nm_device_p2p_wifi_get_mgmt_iface (NMDeviceP2PWifi *self);
+void nm_device_p2p_wifi_set_mgmt_iface (NMDeviceP2PWifi *self,
+ NMSupplicantInterface *iface);
+
+void nm_device_p2p_wifi_remove (NMDeviceP2PWifi *self);
+
+#endif /* __NM_DEVICE_P2P_WIFI_H__ */
diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
index e0be38c3f7..4ba14ac336 100644
--- a/src/devices/wifi/nm-device-wifi.c
+++ b/src/devices/wifi/nm-device-wifi.c
@@ -22,6 +22,7 @@
#include "nm-default.h"
#include "nm-device-wifi.h"
+#include "nm-device-p2p-wifi.h"
#include <netinet/in.h>
#include <string.h>
@@ -79,6 +80,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceWifi,
enum {
SCANNING_PROHIBITED,
+ P2P_DEVICE_CREATED,
LAST_SIGNAL
};
@@ -124,6 +126,8 @@ typedef struct {
guint wps_timeout_id;
NMSettingWirelessWakeOnWLan wowlan_restore;
+
+ NMDeviceP2PWifi *p2p_device;
} NMDeviceWifiPrivate;
struct _NMDeviceWifi
@@ -186,6 +190,10 @@ static void supplicant_iface_notify_current_bss (NMSupplicantInterface *iface,
GParamSpec *pspec,
NMDeviceWifi *self);
+static void supplicant_iface_notify_p2p_available (NMSupplicantInterface *iface,
+ GParamSpec *pspec,
+ NMDeviceWifi *self);
+
static void request_wireless_scan (NMDeviceWifi *self,
gboolean periodic,
gboolean force_if_scanning,
@@ -198,6 +206,8 @@ static void ap_add_remove (NMDeviceWifi *self,
static void _hw_addr_set_scanning (NMDeviceWifi *self, gboolean do_reset);
+static void recheck_p2p_availability (NMDeviceWifi *self);
+
/*****************************************************************************/
static void
@@ -291,6 +301,10 @@ supplicant_interface_acquire (NMDeviceWifi *self)
"notify::" NM_SUPPLICANT_INTERFACE_CURRENT_BSS,
G_CALLBACK (supplicant_iface_notify_current_bss),
self);
+ g_signal_connect (priv->sup_iface,
+ "notify::" NM_SUPPLICANT_INTERFACE_P2P_AVAILABLE,
+ G_CALLBACK (supplicant_iface_notify_p2p_available),
+ self);
_notify_scanning (self);
@@ -347,6 +361,11 @@ supplicant_interface_release (NMDeviceWifi *self)
g_clear_object (&priv->sup_iface);
}
+ if (priv->p2p_device) {
+ /* Signal to P2P device to also release its reference */
+ nm_device_p2p_wifi_set_mgmt_iface (priv->p2p_device, NULL);
+ }
+
_notify_scanning (self);
}
@@ -2028,6 +2047,10 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
&& new_state <= NM_SUPPLICANT_INTERFACE_STATE_COMPLETED)
priv->ssid_found = TRUE;
+ if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY &&
+ new_state >= NM_SUPPLICANT_INTERFACE_STATE_READY)
+ recheck_p2p_availability (self);
+
switch (new_state) {
case NM_SUPPLICANT_INTERFACE_STATE_READY:
_LOGD (LOGD_WIFI, "supplicant ready");
@@ -2204,6 +2227,61 @@ supplicant_iface_notify_current_bss (NMSupplicantInterface *iface,
}
}
+/* We bind the existance of the P2P device to a wifi device that is being
+ * managed by NetworkManager and is capable of P2P operation.
+ * Note that some care must be taken here, because we don't want to re-create
+ * the device every time the supplicant interface is destroyed (e.g. due to
+ * a suspend/resume cycle).
+ * Therefore, this function will be called when a change in the P2P capability
+ * is detected and the supplicant interface has been initialised.
+ */
+static void
+recheck_p2p_availability (NMDeviceWifi *self)
+{
+ NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+ NMDeviceP2PWifi *p2p_device;
+ gboolean p2p_available;
+
+ g_object_get (priv->sup_iface,
+ NM_SUPPLICANT_INTERFACE_P2P_AVAILABLE, &p2p_available,
+ NULL);
+
+ if (p2p_available && !priv->p2p_device) {
+ g_autofree char *iface_name = NULL;
+ /* Create a P2P device. "p2p-dev-" is the same prefix as chosen by
+ * wpa_supplicant internally.
+ */
+ iface_name = g_strconcat ("p2p-dev-", nm_device_get_iface (NM_DEVICE (self)), NULL);
+ p2p_device = NM_DEVICE_P2P_WIFI (nm_device_p2p_wifi_new (priv->sup_iface, iface_name));
+ priv->p2p_device = p2p_device;
+
+ g_signal_emit (self, signals[P2P_DEVICE_CREATED], 0, priv->p2p_device);
+ g_object_add_weak_pointer (G_OBJECT (p2p_device), (gpointer*) &priv->p2p_device);
+ g_object_unref (p2p_device);
+
+ } else if (p2p_available && priv->p2p_device) {
+ nm_device_p2p_wifi_set_mgmt_iface (priv->p2p_device, priv->sup_iface);
+
+ } else if (!p2p_available && priv->p2p_device) {
+ /* Destroy the P2P device. */
+ g_object_remove_weak_pointer (G_OBJECT (priv->p2p_device), (gpointer*) &priv->p2p_device);
+ nm_device_p2p_wifi_remove (priv->p2p_device);
+ priv->p2p_device = NULL;
+ }
+}
+
+static void
+supplicant_iface_notify_p2p_available (NMSupplicantInterface *iface,
+ GParamSpec *pspec,
+ NMDeviceWifi *self)
+{
+ /* Do not update when the interface is still initializing. */
+ if (nm_supplicant_interface_get_state (iface) < NM_SUPPLICANT_INTERFACE_STATE_READY)
+ return;
+
+ recheck_p2p_availability (self);
+}
+
static gboolean
handle_auth_or_fail (NMDeviceWifi *self,
NMActRequest *req,
@@ -3426,4 +3504,12 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass)
G_STRUCT_OFFSET (NMDeviceWifiClass, scanning_prohibited),
NULL, NULL, NULL,
G_TYPE_BOOLEAN, 1, G_TYPE_BOOLEAN);
+
+ signals[P2P_DEVICE_CREATED] =
+ g_signal_new (NM_DEVICE_WIFI_P2P_DEVICE_CREATED,
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, NM_TYPE_DEVICE);
}
diff --git a/src/devices/wifi/nm-device-wifi.h b/src/devices/wifi/nm-device-wifi.h
index 1c555f5fe1..116ad11e48 100644
--- a/src/devices/wifi/nm-device-wifi.h
+++ b/src/devices/wifi/nm-device-wifi.h
@@ -40,6 +40,7 @@
#define NM_DEVICE_WIFI_LAST_SCAN "last-scan"
#define NM_DEVICE_WIFI_SCANNING_PROHIBITED "scanning-prohibited"
+#define NM_DEVICE_WIFI_P2P_DEVICE_CREATED "p2p-device-created"
typedef struct _NMDeviceWifi NMDeviceWifi;
typedef struct _NMDeviceWifiClass NMDeviceWifiClass;
diff --git a/src/devices/wifi/nm-wifi-factory.c b/src/devices/wifi/nm-wifi-factory.c
index 4e9d1ecb20..e220c3a4cb 100644
--- a/src/devices/wifi/nm-wifi-factory.c
+++ b/src/devices/wifi/nm-wifi-factory.c
@@ -26,6 +26,7 @@
#include "nm-setting-wireless.h"
#include "nm-setting-olpc-mesh.h"
#include "nm-device-wifi.h"
+#include "nm-device-p2p-wifi.h"
#include "nm-device-olpc-mesh.h"
#include "nm-device-iwd.h"
#include "settings/nm-settings-connection.h"
@@ -68,6 +69,18 @@ nm_device_factory_create (GError **error)
/*****************************************************************************/
+static void
+p2p_device_created (NMDeviceWifi *device,
+ NMDeviceP2PWifi *p2p_device,
+ NMDeviceFactory *self)
+{
+ nm_log_info (LOGD_PLATFORM | LOGD_WIFI,
+ "P2P Wifi device controlled by wifi interface %s created",
+ nm_device_get_iface (NM_DEVICE (device)));
+
+ g_signal_emit_by_name (self, NM_DEVICE_FACTORY_DEVICE_ADDED, p2p_device);
+}
+
static NMDevice *
create_device (NMDeviceFactory *factory,
const char *iface,
@@ -98,6 +111,7 @@ create_device (NMDeviceFactory *factory,
NM_PRINT_FMT_QUOTE_STRING (backend),
WITH_IWD ? " (iwd support enabled)" : "");
if (!backend || !strcasecmp (backend, "wpa_supplicant")) {
+ NMDevice *device;
NMDeviceWifiCapabilities capabilities;
NM80211Mode mode;
@@ -120,7 +134,14 @@ create_device (NMDeviceFactory *factory,
return NULL;
}
- return nm_device_wifi_new (iface, capabilities);
+ device = nm_device_wifi_new (iface, capabilities);
+
+ g_signal_connect_object (device, NM_DEVICE_WIFI_P2P_DEVICE_CREATED,
+ G_CALLBACK (p2p_device_created),
+ factory,
+ 0);
+
+ return device;
}
#if WITH_IWD
else if (!strcasecmp (backend, "iwd"))
diff --git a/src/devices/wifi/nm-wifi-p2p-peer.c b/src/devices/wifi/nm-wifi-p2p-peer.c
new file mode 100644
index 0000000000..417365907c
--- /dev/null
+++ b/src/devices/wifi/nm-wifi-p2p-peer.c
@@ -0,0 +1,808 @@
+/* NetworkManager -- P2P Wi-Fi Peer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2018 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nm-wifi-p2p-peer.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "nm-setting-wireless.h"
+
+#include "nm-wifi-utils.h"
+#include "NetworkManagerUtils.h"
+#include "nm-utils.h"
+#include "nm-core-internal.h"
+#include "platform/nm-platform.h"
+#include "devices/nm-device.h"
+#include "nm-dbus-manager.h"
+
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE (NMWifiP2PPeer,
+ PROP_NAME,
+ PROP_MANUFACTURER,
+ PROP_MODEL,
+ PROP_MODEL_NUMBER,
+ PROP_SERIAL,
+ //PROP_PRIMARY_DEVICE_TYPE, { "PrimaryDeviceType", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
+ // "devicecapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y",
+ // "groupcapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y",
+ // "SecondaryDeviceTypes", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
+ // "VendorExtension", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
+ PROP_WFD_IES,
+ PROP_GROUPS,
+
+ PROP_HW_ADDRESS,
+ //PROP_MODE,
+ PROP_STRENGTH,
+ PROP_LAST_SEEN,
+
+ //PROP_MAX_BITRATE,
+ // One of the following (FLAGS would simply mirror/use the same as AP flags)
+ PROP_FLAGS,
+ //PROP_CONFIG_METHOD,
+);
+
+struct _NMWifiP2PPeerPrivate {
+ char *supplicant_path; /* D-Bus object path of this Peer from wpa_supplicant */
+
+ /* Scanned or cached values */
+ char * name;
+ char * manufacturer;
+ char * model;
+ char * model_number;
+ char * serial;
+
+ char * address;
+
+ GBytes * wfd_ies;
+ char ** groups;
+
+ guint8 strength;
+
+ NM80211ApFlags flags; /* General flags */
+
+ /* Non-scanned attributes */
+ gint32 last_seen; /* Timestamp when the Peer was seen lastly (obtained via nm_utils_get_monotonic_timestamp_s()) */
+};
+
+typedef struct _NMWifiP2PPeerPrivate NMWifiP2PPeerPrivate;
+
+struct _NMWifiP2PPeerClass {
+ NMDBusObjectClass parent;
+};
+
+G_DEFINE_TYPE (NMWifiP2PPeer, nm_wifi_p2p_peer, NM_TYPE_DBUS_OBJECT)
+
+#define NM_WIFI_P2P_PEER_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMWifiP2PPeer, NM_IS_WIFI_P2P_PEER)
+
+/*****************************************************************************/
+
+const char *
+nm_wifi_p2p_peer_get_supplicant_path (NMWifiP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL);
+
+ return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->supplicant_path;
+}
+
+const char *
+nm_wifi_p2p_peer_get_name (const NMWifiP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL);
+
+ return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->name;
+}
+
+gboolean
+nm_wifi_p2p_peer_set_name (NMWifiP2PPeer *peer, const char *name)
+{
+ NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer);
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE);
+
+ if (g_strcmp0 (name, priv->name) == 0)
+ return FALSE;
+
+ g_clear_pointer (&priv->name, g_free);
+ if (name)
+ priv->name = g_strdup (name);
+
+ _notify (peer, PROP_NAME);
+ return TRUE;
+}
+
+const char *
+nm_wifi_p2p_peer_get_manufacturer (const NMWifiP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL);
+
+ return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->manufacturer;
+}
+
+gboolean
+nm_wifi_p2p_peer_set_manufacturer (NMWifiP2PPeer *peer, const char *manufacturer)
+{
+ NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer);
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE);
+
+ if (g_strcmp0 (manufacturer, priv->manufacturer) == 0)
+ return FALSE;
+
+ g_clear_pointer (&priv->manufacturer, g_free);
+ if (manufacturer)
+ priv->manufacturer = g_strdup (manufacturer);
+
+ _notify (peer, PROP_MANUFACTURER);
+ return TRUE;
+}
+
+const char *
+nm_wifi_p2p_peer_get_model (const NMWifiP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL);
+
+ return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->model;
+}
+
+gboolean
+nm_wifi_p2p_peer_set_model (NMWifiP2PPeer *peer, const char *model)
+{
+ NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer);
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE);
+
+ if (g_strcmp0 (model, priv->model) == 0)
+ return FALSE;
+
+ g_clear_pointer (&priv->model, g_free);
+ if (model)
+ priv->model = g_strdup (model);
+
+ _notify (peer, PROP_MODEL);
+ return TRUE;
+}
+
+const char *
+nm_wifi_p2p_peer_get_model_number (const NMWifiP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL);
+
+ return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->model_number;
+}
+
+gboolean
+nm_wifi_p2p_peer_set_model_number (NMWifiP2PPeer *peer, const char *model_number)
+{
+ NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer);
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE);
+
+ if (g_strcmp0 (model_number, priv->model_number) == 0)
+ return FALSE;
+
+ g_clear_pointer (&priv->model_number, g_free);
+ if (model_number)
+ priv->model_number = g_strdup (model_number);
+
+ _notify (peer, PROP_MODEL_NUMBER);
+ return TRUE;
+}
+
+const char *
+nm_wifi_p2p_peer_get_serial (const NMWifiP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL);
+
+ return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->serial;
+}
+
+gboolean
+nm_wifi_p2p_peer_set_serial (NMWifiP2PPeer *peer, const char *serial)
+{
+ NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer);
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE);
+
+ if (g_strcmp0 (serial, priv->serial) == 0)
+ return FALSE;
+
+ g_clear_pointer (&priv->serial, g_free);
+ if (serial)
+ priv->serial = g_strdup (serial);
+
+ _notify (peer, PROP_SERIAL);
+ return TRUE;
+}
+
+GBytes *
+nm_wifi_p2p_peer_get_wfd_ies (const NMWifiP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL);
+
+ return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->wfd_ies;
+}
+
+gboolean
+nm_wifi_p2p_peer_set_wfd_ies (NMWifiP2PPeer *peer, GBytes *wfd_ies)
+{
+ NMWifiP2PPeerPrivate *priv;
+
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE);
+
+ priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer);
+
+ if (nm_gbytes_equal0 (priv->wfd_ies, wfd_ies))
+ return FALSE;
+
+ g_bytes_unref (priv->wfd_ies);
+ priv->wfd_ies = wfd_ies ? g_bytes_ref (wfd_ies) : NULL;
+
+ _notify (peer, PROP_WFD_IES);
+ return TRUE;
+}
+
+const char *const*
+nm_wifi_p2p_peer_get_groups (const NMWifiP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL);
+
+ return (const char * const*) NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->groups;
+}
+
+static gboolean
+nm_wifi_p2p_peer_set_groups (NMWifiP2PPeer *peer, const char** groups)
+{
+ NMWifiP2PPeerPrivate *priv;
+
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE);
+ g_return_val_if_fail (groups != NULL, FALSE);
+
+ priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer);
+
+ if (_nm_utils_strv_equal (priv->groups, (char **) groups))
+ return FALSE;
+
+ g_strfreev (priv->groups);
+ priv->groups = g_strdupv ((char**) groups);
+
+ _notify (peer, PROP_GROUPS);
+ return TRUE;
+}
+
+const char *
+nm_wifi_p2p_peer_get_address (const NMWifiP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL);
+
+ return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->address;
+}
+
+static gboolean
+nm_wifi_p2p_peer_set_address_bin (NMWifiP2PPeer *peer, const guint8 addr[static ETH_ALEN])
+{
+ NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer);
+
+ if ( priv->address
+ && nm_utils_hwaddr_matches (addr, ETH_ALEN, priv->address, -1))
+ return FALSE;
+
+ g_free (priv->address);
+ priv->address = nm_utils_hwaddr_ntoa (addr, ETH_ALEN);
+ _notify (peer, PROP_HW_ADDRESS);
+ return TRUE;
+}
+
+gboolean
+nm_wifi_p2p_peer_set_address (NMWifiP2PPeer *peer, const char *addr)
+{
+ guint8 addr_buf[ETH_ALEN];
+
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE);
+
+ if ( !addr
+ || !nm_utils_hwaddr_aton (addr, addr_buf, sizeof (addr_buf)))
+ g_return_val_if_reached (FALSE);
+
+ return nm_wifi_p2p_peer_set_address_bin (peer, addr_buf);
+}
+
+gint8
+nm_wifi_p2p_peer_get_strength (NMWifiP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), 0);
+
+ return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->strength;
+}
+
+gboolean
+nm_wifi_p2p_peer_set_strength (NMWifiP2PPeer *peer, const gint8 strength)
+{
+ NMWifiP2PPeerPrivate *priv;
+
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE);
+
+ priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer);
+
+ if (priv->strength != strength) {
+ priv->strength = strength;
+ _notify (peer, PROP_STRENGTH);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+NM80211ApFlags
+nm_wifi_p2p_peer_get_flags (const NMWifiP2PPeer *peer)
+{
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NM_802_11_AP_FLAGS_NONE);
+
+ return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->flags;
+}
+
+static gboolean
+nm_wifi_p2p_peer_set_last_seen (NMWifiP2PPeer *peer, gint32 last_seen)
+{
+ NMWifiP2PPeerPrivate *priv;
+
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE);
+
+ priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer);
+
+ if (priv->last_seen != last_seen) {
+ priv->last_seen = last_seen;
+ _notify (peer, PROP_LAST_SEEN);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*****************************************************************************/
+
+gboolean
+nm_wifi_p2p_peer_update_from_properties (NMWifiP2PPeer *peer,
+ const char *supplicant_path,
+ GVariant *properties)
+{
+ NMWifiP2PPeerPrivate *priv;
+ const guint8 *bytes;
+ GVariant *v;
+ gsize len;
+ const char *s;
+ const char **sv;
+ gint32 i32;
+ gboolean changed = FALSE;
+
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE);
+ g_return_val_if_fail (properties, FALSE);
+
+ priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer);
+
+ g_object_freeze_notify (G_OBJECT (peer));
+
+ if (g_variant_lookup (properties, "level", "i", &i32))
+ changed |= nm_wifi_p2p_peer_set_strength (peer, nm_wifi_utils_level_to_quality (i32));
+
+ if (g_variant_lookup (properties, "DeviceName", "&s", &s))
+ changed |= nm_wifi_p2p_peer_set_name (peer, s);
+
+ if (g_variant_lookup (properties, "Manufacturer", "&s", &s))
+ changed |= nm_wifi_p2p_peer_set_manufacturer (peer, s);
+
+ if (g_variant_lookup (properties, "Model", "&s", &s))
+ changed |= nm_wifi_p2p_peer_set_model (peer, s);
+
+ if (g_variant_lookup (properties, "ModelNumber", "&s", &s))
+ changed |= nm_wifi_p2p_peer_set_model_number (peer, s);
+
+ if (g_variant_lookup (properties, "Serial", "&s", &s))
+ changed |= nm_wifi_p2p_peer_set_serial (peer, s);
+
+ v = g_variant_lookup_value (properties, "DeviceAddress", G_VARIANT_TYPE_BYTESTRING);
+ if (v) {
+ bytes = g_variant_get_fixed_array (v, &len, 1);
+ if ( len == ETH_ALEN
+ && memcmp (bytes, nm_ip_addr_zero.addr_eth, ETH_ALEN) != 0
+ && memcmp (bytes, (char[ETH_ALEN]) { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, ETH_ALEN) != 0)
+ changed |= nm_wifi_p2p_peer_set_address_bin (peer, bytes);
+ g_variant_unref (v);
+ }
+
+ /* The IEs property contains the WFD R1 subelements */
+ v = g_variant_lookup_value (properties, "IEs", G_VARIANT_TYPE_BYTESTRING);
+ if (v) {
+ gs_unref_bytes GBytes *b = NULL;
+
+ bytes = g_variant_get_fixed_array (v, &len, 1);
+ b = g_bytes_new (bytes, len);
+ changed |= nm_wifi_p2p_peer_set_wfd_ies (peer, b);
+ g_variant_unref (v);
+ }
+
+ v = g_variant_lookup_value (properties, "Groups", G_VARIANT_TYPE_OBJECT_PATH_ARRAY);
+ if (v) {
+ sv = g_variant_get_objv (v, NULL);
+ changed |= nm_wifi_p2p_peer_set_groups (peer, sv);
+ g_free (sv);
+ }
+
+ /*if (max_rate)
+ changed |= nm_wifi_p2p_peer_set_max_bitrate (peer, max_rate / 1000);*/
+
+ if (!priv->supplicant_path) {
+ priv->supplicant_path = g_strdup (supplicant_path);
+ changed = TRUE;
+ }
+
+ changed |= nm_wifi_p2p_peer_set_last_seen (peer, nm_utils_get_monotonic_timestamp_s ());
+
+ g_object_thaw_notify (G_OBJECT (peer));
+
+ return changed;
+}
+
+const char *
+nm_wifi_p2p_peer_to_string (const NMWifiP2PPeer *self,
+ char *str_buf,
+ gsize buf_len,
+ gint32 now_s)
+{
+ const NMWifiP2PPeerPrivate *priv;
+ const char *supplicant_id = "-";
+ const char* export_path;
+
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (self), NULL);
+
+ priv = NM_WIFI_P2P_PEER_GET_PRIVATE (self);
+
+ if (priv->supplicant_path)
+ supplicant_id = strrchr (priv->supplicant_path, '/') ?: supplicant_id;
+
+ export_path = nm_dbus_object_get_path (NM_DBUS_OBJECT (self));
+ if (export_path)
+ export_path = strrchr (export_path, '/') ?: export_path;
+ else
+ export_path = "/";
+
+ g_snprintf (str_buf, buf_len,
+ "%17s [n:%s, m:%s, mod:%s, mod_num:%s, ser:%s] %3us sup:%s [nm:%s]",
+ priv->address ?: "(none)",
+ priv->name,
+ priv->manufacturer,
+ priv->model,
+ priv->model_number,
+ priv->serial,
+ priv->last_seen > 0 ? ((now_s > 0 ? now_s : nm_utils_get_monotonic_timestamp_s ()) - priv->last_seen) : -1,
+ supplicant_id,
+ export_path);
+
+ return str_buf;
+}
+
+gboolean
+nm_wifi_p2p_peer_check_compatible (NMWifiP2PPeer *self,
+ NMConnection *connection)
+{
+ NMWifiP2PPeerPrivate *priv;
+ NMSettingP2PWireless *s_p2p_wireless;
+ const char *hwaddr;
+
+ g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (self), FALSE);
+ g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
+
+ priv = NM_WIFI_P2P_PEER_GET_PRIVATE (self);
+
+ s_p2p_wireless = NM_SETTING_P2P_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_P2P_WIRELESS));
+ if (s_p2p_wireless == NULL)
+ return FALSE;
+
+ hwaddr = nm_setting_p2p_wireless_get_peer (s_p2p_wireless);
+ if ( hwaddr
+ && ( !priv->address
+ || !nm_utils_hwaddr_matches (hwaddr, -1, priv->address, -1)))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+static void
+get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ NMWifiP2PPeer *self = NM_WIFI_P2P_PEER (object);
+ NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (self);
+
+ switch (prop_id) {
+ case PROP_FLAGS:
+ g_value_set_uint (value, priv->flags);
+ break;
+ case PROP_NAME:
+ g_value_set_string (value, priv->name);
+ break;
+ case PROP_MANUFACTURER:
+ g_value_set_string (value, priv->manufacturer);
+ break;
+ case PROP_MODEL:
+ g_value_set_string (value, priv->model);
+ break;
+ case PROP_MODEL_NUMBER:
+ g_value_set_string (value, priv->model_number);
+ break;
+ case PROP_SERIAL:
+ g_value_set_string (value, priv->serial);
+ break;
+ case PROP_WFD_IES:
+ g_value_take_variant (value, nm_utils_gbytes_to_variant_ay (priv->wfd_ies));
+ break;
+ case PROP_GROUPS:
+ g_value_set_variant (value,
+ g_variant_new_strv ( (const char*const*) priv->groups
+ ?: NM_PTRARRAY_EMPTY (const char *),
+ -1));
+ break;
+ case PROP_HW_ADDRESS:
+ g_value_set_string (value, priv->address);
+ break;
+ case PROP_STRENGTH:
+ g_value_set_uchar (value, priv->strength);
+ break;
+ case PROP_LAST_SEEN:
+ g_value_set_int (value,
+ priv->last_seen > 0
+ ? (int) nm_utils_monotonic_timestamp_as_boottime (priv->last_seen, NM_UTILS_NS_PER_SECOND)
+ : -1);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/*****************************************************************************/
+
+static void
+nm_wifi_p2p_peer_init (NMWifiP2PPeer *self)
+{
+ NMWifiP2PPeerPrivate *priv;
+
+ priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_WIFI_P2P_PEER, NMWifiP2PPeerPrivate);
+
+ self->_priv = priv;
+
+ c_list_init (&self->peers_lst);
+
+ priv->flags = NM_802_11_AP_FLAGS_NONE;
+ priv->last_seen = -1;
+}
+
+NMWifiP2PPeer *
+nm_wifi_p2p_peer_new_from_properties (const char *supplicant_path, GVariant *properties)
+{
+ NMWifiP2PPeer *peer;
+
+ g_return_val_if_fail (supplicant_path != NULL, NULL);
+ g_return_val_if_fail (properties != NULL, NULL);
+
+ peer = (NMWifiP2PPeer *) g_object_new (NM_TYPE_WIFI_P2P_PEER, NULL);
+ nm_wifi_p2p_peer_update_from_properties (peer, supplicant_path, properties);
+
+ /* ignore peers with invalid or missing address */
+ if (!nm_wifi_p2p_peer_get_address (peer)) {
+ g_object_unref (peer);
+ return NULL;
+ }
+
+ return peer;
+}
+
+static void
+finalize (GObject *object)
+{
+ NMWifiP2PPeer *self = NM_WIFI_P2P_PEER (object);
+ NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (self);
+
+ nm_assert (!self->wifi_device);
+ nm_assert (c_list_is_empty (&self->peers_lst));
+
+ g_free (priv->supplicant_path);
+ g_free (priv->name);
+ g_free (priv->manufacturer);
+ g_free (priv->model);
+ g_free (priv->model_number);
+ g_free (priv->serial);
+ g_free (priv->address);
+ g_bytes_unref (priv->wfd_ies);
+ g_strfreev (priv->groups);
+
+ G_OBJECT_CLASS (nm_wifi_p2p_peer_parent_class)->finalize (object);
+}
+
+static const NMDBusInterfaceInfoExtended interface_info_p2p_peer = {
+ .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT (
+ NM_DBUS_INTERFACE_P2P_PEER,
+ .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS (
+ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Flags", "u", NM_WIFI_P2P_PEER_FLAGS),
+ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Name", "s", NM_WIFI_P2P_PEER_NAME),
+ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Manufacturer", "s", NM_WIFI_P2P_PEER_MANUFACTURER),
+ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Model", "s", NM_WIFI_P2P_PEER_MODEL),
+ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("ModelNumber", "s", NM_WIFI_P2P_PEER_MODEL_NUMBER),
+ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Serial", "s", NM_WIFI_P2P_PEER_SERIAL),
+ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("WfdIEs", "ay", NM_WIFI_P2P_PEER_WFD_IES),
+ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Groups", "as", NM_WIFI_P2P_PEER_GROUPS),
+ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("HwAddress", "s", NM_WIFI_P2P_PEER_HW_ADDRESS),
+ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Strength", "y", NM_WIFI_P2P_PEER_STRENGTH),
+ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("LastSeen", "i", NM_WIFI_P2P_PEER_LAST_SEEN),
+ ),
+ ),
+ .legacy_property_changed = FALSE,
+};
+
+static void
+nm_wifi_p2p_peer_class_init (NMWifiP2PPeerClass *p2p_peer_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (p2p_peer_class);
+ NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (p2p_peer_class);
+
+ g_type_class_add_private (object_class, sizeof (NMWifiP2PPeerPrivate));
+
+ dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED (NM_DBUS_PATH_P2P_PEER);
+ dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_p2p_peer);
+
+ object_class->get_property = get_property;
+ object_class->finalize = finalize;
+
+ obj_properties[PROP_FLAGS] =
+ g_param_spec_uint (NM_WIFI_P2P_PEER_FLAGS, "", "",
+ NM_802_11_AP_FLAGS_NONE,
+ NM_802_11_AP_FLAGS_PRIVACY,
+ NM_802_11_AP_FLAGS_NONE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ obj_properties[PROP_NAME] =
+ g_param_spec_string (NM_WIFI_P2P_PEER_NAME, "", "",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ obj_properties[PROP_MANUFACTURER] =
+ g_param_spec_string (NM_WIFI_P2P_PEER_MANUFACTURER, "", "",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ obj_properties[PROP_MODEL] =
+ g_param_spec_string (NM_WIFI_P2P_PEER_MODEL, "", "",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ obj_properties[PROP_MODEL_NUMBER] =
+ g_param_spec_string (NM_WIFI_P2P_PEER_MODEL_NUMBER, "", "",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ obj_properties[PROP_SERIAL] =
+ g_param_spec_string (NM_WIFI_P2P_PEER_SERIAL, "", "",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ obj_properties[PROP_WFD_IES] =
+ g_param_spec_variant (NM_WIFI_P2P_PEER_WFD_IES, "", "",
+ G_VARIANT_TYPE ("ay"),
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ obj_properties[PROP_GROUPS] =
+ g_param_spec_variant (NM_WIFI_P2P_PEER_GROUPS, "", "",
+ G_VARIANT_TYPE ("as"),
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ obj_properties[PROP_HW_ADDRESS] =
+ g_param_spec_string (NM_WIFI_P2P_PEER_HW_ADDRESS, "", "",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ obj_properties[PROP_STRENGTH] =
+ g_param_spec_uchar (NM_WIFI_P2P_PEER_STRENGTH, "", "",
+ 0, G_MAXINT8, 0,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ obj_properties[PROP_LAST_SEEN] =
+ g_param_spec_int (NM_WIFI_P2P_PEER_LAST_SEEN, "", "",
+ -1, G_MAXINT, -1,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+}
+
+/*****************************************************************************/
+
+const char **
+nm_wifi_p2p_peers_get_paths (const CList *peers_lst_head)
+{
+ NMWifiP2PPeer *peer;
+ const char **list;
+ const char *path;
+ gsize i, n;
+
+ n = c_list_length (peers_lst_head);
+ list = g_new (const char *, n + 1);
+
+ i = 0;
+ if (n > 0) {
+ c_list_for_each_entry (peer, peers_lst_head, peers_lst) {
+ nm_assert (i < n);
+ path = nm_dbus_object_get_path (NM_DBUS_OBJECT (peer));
+ nm_assert (path);
+
+ list[i++] = path;
+ }
+ nm_assert (i <= n);
+ }
+ list[i] = NULL;
+ return list;
+}
+
+NMWifiP2PPeer *
+nm_wifi_p2p_peers_find_first_compatible (const CList *peers_lst_head,
+ NMConnection *connection)
+{
+ NMWifiP2PPeer *peer;
+
+ g_return_val_if_fail (connection, NULL);
+
+ c_list_for_each_entry (peer, peers_lst_head, peers_lst) {
+ if (nm_wifi_p2p_peer_check_compatible (peer, connection))
+ return peer;
+ }
+ return NULL;
+}
+
+NMWifiP2PPeer *
+nm_wifi_p2p_peers_find_by_supplicant_path (const CList *peers_lst_head, const char *path)
+{
+ NMWifiP2PPeer *peer;
+
+ g_return_val_if_fail (path != NULL, NULL);
+
+ c_list_for_each_entry (peer, peers_lst_head, peers_lst) {
+ if (nm_streq0 (path, nm_wifi_p2p_peer_get_supplicant_path (peer)))
+ return peer;
+ }
+ return NULL;
+}
+
+/*****************************************************************************/
+
+NMWifiP2PPeer *
+nm_wifi_p2p_peer_lookup_for_device (NMDevice *device, const char *exported_path)
+{
+ NMWifiP2PPeer *peer;
+
+ g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
+
+ peer = (NMWifiP2PPeer *) nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (device)),
+ exported_path);
+ if ( !peer
+ || !NM_IS_WIFI_P2P_PEER (peer)
+ || peer->wifi_device != device)
+ return NULL;
+
+ return peer;
+}
diff --git a/src/devices/wifi/nm-wifi-p2p-peer.h b/src/devices/wifi/nm-wifi-p2p-peer.h
new file mode 100644
index 0000000000..13c4add6cd
--- /dev/null
+++ b/src/devices/wifi/nm-wifi-p2p-peer.h
@@ -0,0 +1,114 @@
+/* NetworkManager -- P2P Wi-Fi Peer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2018 Red Hat, Inc.
+ */
+
+#ifndef __NM_WIFI_P2P_PEER_H__
+#define __NM_WIFI_P2P_PEER_H__
+
+#include "nm-dbus-object.h"
+#include "nm-dbus-interface.h"
+#include "nm-connection.h"
+
+#define NM_TYPE_WIFI_P2P_PEER (nm_wifi_p2p_peer_get_type ())
+#define NM_WIFI_P2P_PEER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_WIFI_P2P_PEER, NMWifiP2PPeer))
+#define NM_WIFI_P2P_PEER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_WIFI_P2P_PEER, NMWifiP2PPeerClass))
+#define NM_IS_WIFI_P2P_PEER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_WIFI_P2P_PEER))
+#define NM_IS_WIFI_P2P_PEER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_WIFI_P2P_PEER))
+#define NM_WIFI_P2P_PEER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_WIFI_P2P_PEER, NMWifiP2PPeerClass))
+
+#define NM_WIFI_P2P_PEER_FLAGS "flags"
+#define NM_WIFI_P2P_PEER_NAME "name"
+#define NM_WIFI_P2P_PEER_MANUFACTURER "manufacturer"
+#define NM_WIFI_P2P_PEER_MODEL "model"
+#define NM_WIFI_P2P_PEER_MODEL_NUMBER "model-number"
+#define NM_WIFI_P2P_PEER_SERIAL "serial"
+#define NM_WIFI_P2P_PEER_WFD_IES "wfd-ies"
+#define NM_WIFI_P2P_PEER_GROUPS "groups"
+#define NM_WIFI_P2P_PEER_HW_ADDRESS "hw-address"
+#define NM_WIFI_P2P_PEER_STRENGTH "strength"
+#define NM_WIFI_P2P_PEER_LAST_SEEN "last-seen"
+
+typedef struct {
+ NMDBusObject parent;
+ NMDevice *wifi_device;
+ CList peers_lst;
+ struct _NMWifiP2PPeerPrivate *_priv;
+} NMWifiP2PPeer;
+
+typedef struct _NMWifiP2PPeerClass NMWifiP2PPeerClass;
+
+GType nm_wifi_p2p_peer_get_type (void);
+
+NMWifiP2PPeer * nm_wifi_p2p_peer_new_from_properties (const char *supplicant_path,
+ GVariant *properties);
+
+gboolean nm_wifi_p2p_peer_update_from_properties (NMWifiP2PPeer *peer,
+ const char *supplicant_path,
+ GVariant *properties);
+
+gboolean nm_wifi_p2p_peer_check_compatible (NMWifiP2PPeer *self,
+ NMConnection *connection);
+
+const char * nm_wifi_p2p_peer_get_supplicant_path (NMWifiP2PPeer *peer);
+
+const char * nm_wifi_p2p_peer_get_name (const NMWifiP2PPeer *peer);
+gboolean nm_wifi_p2p_peer_set_name (NMWifiP2PPeer *peer,
+ const char *name);
+const char * nm_wifi_p2p_peer_get_manufacturer (const NMWifiP2PPeer *peer);
+gboolean nm_wifi_p2p_peer_set_manufacturer (NMWifiP2PPeer *peer,
+ const char *manufacturer);
+const char * nm_wifi_p2p_peer_get_model (const NMWifiP2PPeer *peer);
+gboolean nm_wifi_p2p_peer_set_model (NMWifiP2PPeer *peer,
+ const char *model);
+const char * nm_wifi_p2p_peer_get_model_number (const NMWifiP2PPeer *peer);
+gboolean nm_wifi_p2p_peer_set_model_number (NMWifiP2PPeer *peer,
+ const char *number);
+const char * nm_wifi_p2p_peer_get_serial (const NMWifiP2PPeer *peer);
+gboolean nm_wifi_p2p_peer_set_serial (NMWifiP2PPeer *peer,
+ const char *serial);
+
+GBytes * nm_wifi_p2p_peer_get_wfd_ies (const NMWifiP2PPeer *peer);
+gboolean nm_wifi_p2p_peer_set_wfd_ies (NMWifiP2PPeer *peer,
+ GBytes *bytes);
+
+const char *const*nm_wifi_p2p_peer_get_groups (const NMWifiP2PPeer *peer);
+
+const char * nm_wifi_p2p_peer_get_address (const NMWifiP2PPeer *peer);
+gboolean nm_wifi_p2p_peer_set_address (NMWifiP2PPeer *peer,
+ const char *addr);
+gint8 nm_wifi_p2p_peer_get_strength (NMWifiP2PPeer *peer);
+gboolean nm_wifi_p2p_peer_set_strength (NMWifiP2PPeer *peer,
+ gint8 strength);
+NM80211ApFlags nm_wifi_p2p_peer_get_flags (const NMWifiP2PPeer *self);
+
+const char *nm_wifi_p2p_peer_to_string (const NMWifiP2PPeer *self,
+ char *str_buf,
+ gsize buf_len,
+ gint32 now_s);
+
+const char **nm_wifi_p2p_peers_get_paths (const CList *peers_lst_head);
+
+NMWifiP2PPeer *nm_wifi_p2p_peers_find_first_compatible (const CList *peers_lst_head,
+ NMConnection *connection);
+
+NMWifiP2PPeer *nm_wifi_p2p_peers_find_by_supplicant_path (const CList *peers_lst_head, const char *path);
+
+NMWifiP2PPeer *nm_wifi_p2p_peer_lookup_for_device (NMDevice *device, const char *exported_path);
+
+#endif /* __NM_WIFI_P2P_PEER_H__ */
diff --git a/src/nm-types.h b/src/nm-types.h
index 277e0f6ccf..9a384e5800 100644
--- a/src/nm-types.h
+++ b/src/nm-types.h
@@ -152,6 +152,7 @@ typedef enum {
NM_LINK_TYPE_WIMAX,
NM_LINK_TYPE_WPAN,
NM_LINK_TYPE_6LOWPAN,
+ NM_LINK_TYPE_P2P_WIFI,
/* Software types */
NM_LINK_TYPE_BNEP = 0x10000, /* Bluetooth Ethernet emulation */
diff --git a/src/org.freedesktop.NetworkManager.conf b/src/org.freedesktop.NetworkManager.conf
index fa74b280de..2bc7b4de94 100644
--- a/src/org.freedesktop.NetworkManager.conf
+++ b/src/org.freedesktop.NetworkManager.conf
@@ -84,6 +84,8 @@
send_interface="org.freedesktop.NetworkManager.WiMax.Nsp"/>
<allow send_destination="org.freedesktop.NetworkManager"
send_interface="org.freedesktop.NetworkManager.AccessPoint"/>
+ <allow send_destination="org.freedesktop.NetworkManager"
+ send_interface="org.freedesktop.NetworkManager.P2PPeer"/>
<!-- Devices (read-only, no security required) -->
<allow send_destination="org.freedesktop.NetworkManager"
@@ -93,6 +95,8 @@
<allow send_destination="org.freedesktop.NetworkManager"
send_interface="org.freedesktop.NetworkManager.Device.Wireless"/>
<allow send_destination="org.freedesktop.NetworkManager"
+ send_interface="org.freedesktop.NetworkManager.Device.P2PWireless"/>
+ <allow send_destination="org.freedesktop.NetworkManager"
send_interface="org.freedesktop.NetworkManager.Device"/>
<!-- Core stuff (read-only properties, no methods) -->
diff --git a/vapi/NM-1.0.metadata b/vapi/NM-1.0.metadata
index ab43f3e174..98fd071e2d 100644
--- a/vapi/NM-1.0.metadata
+++ b/vapi/NM-1.0.metadata
@@ -28,6 +28,7 @@ SETTING_IP6_CONFIG_* parent="NM.SettingIP6Config" name="SETTIN
SETTING_IP_TUNNEL_* parent="NM.SettingIPTunnel" name="SETTING_IP_TUNNEL_(.+)"
SETTING_MACVLAN_* parent="NM.SettingMacvlan" name="SETTING_MACVLAN_(.+)"
SETTING_OLPC_MESH_* parent="NM.SettingOlpcMesh" name="SETTING_OLPC_MESH_(.+)"
+SETTING_P2P_WIRELESS_* parent="NM.SettingP2PWireless" name="SETTING_P2P_WIRELESS_(.+)"
SETTING_PPP_* parent="NM.SettingPpp" name="SETTING_PPP_(.+)"
SETTING_PPPOE_* parent="NM.SettingPppoe" name="SETTING_PPPOE_(.+)"
SETTING_PROXY_* parent="NM.SettingProxy" name="SETTING_PROXY_(.+)"