diff --git a/Makefile.am b/Makefile.am
index f7f189b56c..1b7289c011 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.WireGuard.c \
- introspection/org.freedesktop.NetworkManager.Device.WireGuard.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.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.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.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.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.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.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.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 \
@@ -3240,24 +3250,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/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/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.Connection.Active.xml \
- dbus-org.freedesktop.NetworkManager.Device.Team.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.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.Connection.Active.xml \
dbus-org.freedesktop.NetworkManager.DHCP4Config.xml \
+ dbus-org.freedesktop.NetworkManager.DHCP6Config.xml \
+ dbus-org.freedesktop.NetworkManager.Device.Adsl.xml \
+ dbus-org.freedesktop.NetworkManager.Device.Bluetooth.xml \
+ dbus-org.freedesktop.NetworkManager.Device.Bond.xml \
+ dbus-org.freedesktop.NetworkManager.Device.Bridge.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.Veth.xml \
- dbus-org.freedesktop.NetworkManager.Settings.xml \
- dbus-org.freedesktop.NetworkManager.Device.Wired.xml \
- dbus-org.freedesktop.NetworkManager.Device.WireGuard.xml \
- dbus-org.freedesktop.NetworkManager.IP4Config.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.Device.Vlan.xml \
+ dbus-org.freedesktop.NetworkManager.Device.Vxlan.xml \
+ dbus-org.freedesktop.NetworkManager.Device.WireGuard.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 @@
+
@@ -247,6 +248,12 @@
+
+ The /org/freedesktop/NetworkManager/P2PPeer/* objects
+
+
+
+
The /org/freedesktop/NetworkManager/Checkpoint/* objects
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..fa85b83f9d
--- /dev/null
+++ b/introspection/org.freedesktop.NetworkManager.Device.P2PWireless.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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/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..a57b2be089
--- /dev/null
+++ b/src/devices/wifi/nm-device-p2p-wifi.c
@@ -0,0 +1,1287 @@
+/* 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
+
+#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;
+ }
+}
+
+/*****************************************************************************/
+
+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,
+ .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-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
+#include
+
+#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"/>
+
+