diff --git a/supervisor/const.py b/supervisor/const.py index 0bd334c2d..c52f836b6 100644 --- a/supervisor/const.py +++ b/supervisor/const.py @@ -240,6 +240,7 @@ ATTR_SNAPSHOT_EXCLUDE = "snapshot_exclude" ATTR_SNAPSHOTS = "snapshots" ATTR_SOURCE = "source" ATTR_SQUASH = "squash" +ATTR_SSID = "ssid" ATTR_SSL = "ssl" ATTR_STAGE = "stage" ATTR_STARTUP = "startup" diff --git a/supervisor/dbus/const.py b/supervisor/dbus/const.py index 4d3754215..881034f49 100644 --- a/supervisor/dbus/const.py +++ b/supervisor/dbus/const.py @@ -19,6 +19,8 @@ DBUS_OBJECT_HOSTNAME = "/org/freedesktop/hostname1" DBUS_OBJECT_NM = "/org/freedesktop/NetworkManager" DBUS_OBJECT_SYSTEMD = "/org/freedesktop/systemd1" +DBUS_ATTR_802_WIRELESS = "802-11-wireless" +DBUS_ATTR_802_WIRELESS_SECURITY = "802-11-wireless-security" DBUS_ATTR_ACTIVE_CONNECTIONS = "ActiveConnections" DBUS_ATTR_ADDRESS_DATA = "AddressData" DBUS_ATTR_BOOT_SLOT = "BootSlot" diff --git a/supervisor/dbus/network/configuration.py b/supervisor/dbus/network/configuration.py index 15f72be9b..5aafc391b 100644 --- a/supervisor/dbus/network/configuration.py +++ b/supervisor/dbus/network/configuration.py @@ -60,3 +60,11 @@ class NetworkDevice: ip4_address: int = attr.ib() device_type: int = attr.ib() real: bool = attr.ib() + + +@attr.s +class WirelessProperties: + """WirelessProperties object for Network Manager.""" + + properties: dict = attr.ib() + security: dict = attr.ib() diff --git a/supervisor/dbus/network/connection.py b/supervisor/dbus/network/connection.py index 7a67d420f..71aa78f21 100644 --- a/supervisor/dbus/network/connection.py +++ b/supervisor/dbus/network/connection.py @@ -4,6 +4,8 @@ from typing import Optional from ...const import ATTR_ADDRESS, ATTR_IPV4, ATTR_METHOD, ATTR_PREFIX from ...utils.gdbus import DBus from ..const import ( + DBUS_ATTR_802_WIRELESS, + DBUS_ATTR_802_WIRELESS_SECURITY, DBUS_ATTR_ADDRESS_DATA, DBUS_ATTR_CONNECTION, DBUS_ATTR_DEFAULT, @@ -23,6 +25,7 @@ from ..const import ( DBUS_NAME_IP4CONFIG, DBUS_NAME_NM, DBUS_OBJECT_BASE, + ConnectionType, ) from .configuration import ( AddressData, @@ -30,6 +33,7 @@ from .configuration import ( NetworkAttributes, NetworkDevice, NetworkSettings, + WirelessProperties, ) @@ -44,6 +48,7 @@ class NetworkConnection(NetworkAttributes): self._settings: Optional[NetworkSettings] = None self._ip4_config: Optional[IpConfiguration] = None self._device: Optional[NetworkDevice] + self._wireless: Optional[WirelessProperties] = None self.primary: bool = False @property @@ -81,6 +86,13 @@ class NetworkConnection(NetworkAttributes): """Return the uuid of the connection.""" return self._properties[DBUS_ATTR_UUID] + @property + def wireless(self) -> str: + """Return wireless properties if any.""" + if self.type != ConnectionType.WIRELESS: + return None + return self._wireless + @property def state(self) -> int: """ @@ -119,6 +131,11 @@ class NetworkConnection(NetworkAttributes): ), ) + self._wireless = WirelessProperties( + data.get(DBUS_ATTR_802_WIRELESS, {}), + data.get(DBUS_ATTR_802_WIRELESS_SECURITY, {}), + ) + self._device = NetworkDevice( device, device_data.get(DBUS_ATTR_DEVICE_INTERFACE), diff --git a/supervisor/dbus/network/interface.py b/supervisor/dbus/network/interface.py index 502720dcd..5803df246 100644 --- a/supervisor/dbus/network/interface.py +++ b/supervisor/dbus/network/interface.py @@ -4,6 +4,7 @@ from ..const import ( DBUS_NAME_CONNECTION_ACTIVE, DBUS_NAME_NM, DBUS_OBJECT_BASE, + ConnectionType, InterfaceMethod, ) from ..payloads.generate import interface_update_payload @@ -49,7 +50,7 @@ class NetworkInterface: return self.connection.ip4_config.address_data.prefix @property - def type(self) -> str: + def type(self) -> ConnectionType: """Return the interface type.""" return self.connection.type diff --git a/supervisor/dbus/payloads/generate.py b/supervisor/dbus/payloads/generate.py index f36a53851..523c1e95b 100644 --- a/supervisor/dbus/payloads/generate.py +++ b/supervisor/dbus/payloads/generate.py @@ -3,8 +3,8 @@ from pathlib import Path import jinja2 -from ...const import ATTR_ADDRESS, ATTR_DNS, ATTR_METHOD, ATTR_PREFIX -from ..const import InterfaceMethod +from ...const import ATTR_ADDRESS, ATTR_DNS, ATTR_METHOD, ATTR_PREFIX, ATTR_SSID +from ..const import ConnectionType, InterfaceMethod from ..network.utils import ip2int INTERFACE_UPDATE_TEMPLATE: Path = ( @@ -31,4 +31,15 @@ def interface_update_payload(interface, **kwargs) -> str: kwargs[ATTR_ADDRESS] = kwargs[ATTR_ADDRESS].split("/")[0] kwargs[ATTR_METHOD] = InterfaceMethod.MANUAL + if interface.type == ConnectionType.WIRELESS: + kwargs[ATTR_SSID] = ", ".join( + [ + f"0x{x}" + for x in interface.connection.wireless.properties[ATTR_SSID] + .encode() + .hex(",") + .split(",") + ] + ) + return template.render(interface=interface, options=kwargs) diff --git a/supervisor/dbus/payloads/interface_update.tmpl b/supervisor/dbus/payloads/interface_update.tmpl index a03b51256..927b893d0 100644 --- a/supervisor/dbus/payloads/interface_update.tmpl +++ b/supervisor/dbus/payloads/interface_update.tmpl @@ -23,4 +23,18 @@ 'gateway': <'{{ options.get("gateway", interface.gateway) }}'> } {% endif %} +{% if interface.type == "802-11-wireless" %} + , + '802-11-wireless': + { + 'security': <'802-11-wireless-security'>, + 'ssid': <[byte {{ options.ssid }}]> + + }, + '802-11-wireless-security': + { + 'auth-alg': <'{{ interface.connection.wireless.security['auth-alg'] }}'>, + 'key-mgmt': <'{{ interface.connection.wireless.security['key-mgmt'] }}'> + } +{% endif %} } \ No newline at end of file diff --git a/tests/dbus/payloads/test_interface_update_payload.py b/tests/dbus/payloads/test_interface_update_payload.py index f6b496c8f..536064235 100644 --- a/tests/dbus/payloads/test_interface_update_payload.py +++ b/tests/dbus/payloads/test_interface_update_payload.py @@ -1,12 +1,13 @@ """Test interface update payload.""" import pytest +from supervisor.dbus.const import ConnectionType from supervisor.dbus.payloads.generate import interface_update_payload from supervisor.utils.gdbus import DBus @pytest.mark.asyncio -async def test_interface_update_payload(network_interface): +async def test_interface_update_payload_ethernet(network_interface): """Test interface update payload.""" data = interface_update_payload(network_interface, **{"method": "auto"}) assert DBus.parse_gvariant(data)["ipv4"]["method"] == "auto" @@ -17,3 +18,18 @@ async def test_interface_update_payload(network_interface): assert DBus.parse_gvariant(data)["ipv4"]["method"] == "manual" assert DBus.parse_gvariant(data)["ipv4"]["address-data"][0]["address"] == "1.1.1.1" assert DBus.parse_gvariant(data)["ipv4"]["dns"] == [16843009, 16777217] + + +@pytest.mark.asyncio +async def test_interface_update_payload_wireless(network_interface): + """Test interface update payload.""" + network_interface.connection._properties["Type"] = ConnectionType.WIRELESS + data = interface_update_payload(network_interface, **{"method": "auto"}) + assert DBus.parse_gvariant(data)["ipv4"]["method"] == "auto" + + data = interface_update_payload( + network_interface, **{"address": "1.1.1.1", "dns": ["1.1.1.1", "1.0.0.1"]} + ) + assert DBus.parse_gvariant(data)["ipv4"]["method"] == "manual" + assert DBus.parse_gvariant(data)["ipv4"]["address-data"][0]["address"] == "1.1.1.1" + assert DBus.parse_gvariant(data)["802-11-wireless"]["ssid"] == "NETT" diff --git a/tests/fixtures/org_freedesktop_NetworkManager.fixture b/tests/fixtures/org_freedesktop_NetworkManager.fixture index 9cb8ee938..233343596 100644 --- a/tests/fixtures/org_freedesktop_NetworkManager.fixture +++ b/tests/fixtures/org_freedesktop_NetworkManager.fixture @@ -1 +1 @@ -({'connection': {'id': <'Wired connection 1'>, 'permissions': <@as []>, 'timestamp': , 'type': <'802-3-ethernet'>, 'uuid': <'0c23631e-2118-355c-bbb0-8943229cb0d6'>}, 'ipv4': {'address-data': <[{'address': <'192.168.2.148'>, 'prefix': }]>, 'addresses': <[[uint32 2483202240, 24, 16951488]]>, 'dns': <[uint32 16951488]>, 'dns-search': <@as []>, 'gateway': <'192.168.2.1'>, 'method': <'auto'>, 'route-data': <@aa{sv} []>, 'routes': <@aau []>}, 'ipv6': {'address-data': <@aa{sv} []>, 'addresses': <@a(ayuay) []>, 'dns': <@aay []>, 'dns-search': <@as []>, 'method': <'auto'>, 'route-data': <@aa{sv} []>, 'routes': <@a(ayuayu) []>}, 'proxy': {}, '802-3-ethernet': {'auto-negotiate': , 'mac-address-blacklist': <@as []>, 's390-options': <@a{ss} {}>}},) \ No newline at end of file +({'connection': {'id': <'Wired connection 1'>, 'permissions': <@as []>, 'timestamp': , 'type': <'802-3-ethernet'>, 'uuid': <'0c23631e-2118-355c-bbb0-8943229cb0d6'>}, 'ipv4': {'address-data': <[{'address': <'192.168.2.148'>, 'prefix': }]>, 'addresses': <[[uint32 2483202240, 24, 16951488]]>, 'dns': <[uint32 16951488]>, 'dns-search': <@as []>, 'gateway': <'192.168.2.1'>, 'method': <'auto'>, 'route-data': <@aa{sv} []>, 'routes': <@aau []>}, 'ipv6': {'address-data': <@aa{sv} []>, 'addresses': <@a(ayuay) []>, 'dns': <@aay []>, 'dns-search': <@as []>, 'method': <'auto'>, 'route-data': <@aa{sv} []>, 'routes': <@a(ayuayu) []>}, 'proxy': {}, '802-3-ethernet': {'auto-negotiate': , 'mac-address-blacklist': <@as []>, 's390-options': <@a{ss} {}>}, '802-11-wireless': {'ssid': <[byte 0x4e, 0x45, 0x54, 0x54]>}},) \ No newline at end of file diff --git a/tests/fixtures/org_freedesktop_NetworkManager_Settings_1.fixture b/tests/fixtures/org_freedesktop_NetworkManager_Settings_1.fixture index 9cb8ee938..233343596 100644 --- a/tests/fixtures/org_freedesktop_NetworkManager_Settings_1.fixture +++ b/tests/fixtures/org_freedesktop_NetworkManager_Settings_1.fixture @@ -1 +1 @@ -({'connection': {'id': <'Wired connection 1'>, 'permissions': <@as []>, 'timestamp': , 'type': <'802-3-ethernet'>, 'uuid': <'0c23631e-2118-355c-bbb0-8943229cb0d6'>}, 'ipv4': {'address-data': <[{'address': <'192.168.2.148'>, 'prefix': }]>, 'addresses': <[[uint32 2483202240, 24, 16951488]]>, 'dns': <[uint32 16951488]>, 'dns-search': <@as []>, 'gateway': <'192.168.2.1'>, 'method': <'auto'>, 'route-data': <@aa{sv} []>, 'routes': <@aau []>}, 'ipv6': {'address-data': <@aa{sv} []>, 'addresses': <@a(ayuay) []>, 'dns': <@aay []>, 'dns-search': <@as []>, 'method': <'auto'>, 'route-data': <@aa{sv} []>, 'routes': <@a(ayuayu) []>}, 'proxy': {}, '802-3-ethernet': {'auto-negotiate': , 'mac-address-blacklist': <@as []>, 's390-options': <@a{ss} {}>}},) \ No newline at end of file +({'connection': {'id': <'Wired connection 1'>, 'permissions': <@as []>, 'timestamp': , 'type': <'802-3-ethernet'>, 'uuid': <'0c23631e-2118-355c-bbb0-8943229cb0d6'>}, 'ipv4': {'address-data': <[{'address': <'192.168.2.148'>, 'prefix': }]>, 'addresses': <[[uint32 2483202240, 24, 16951488]]>, 'dns': <[uint32 16951488]>, 'dns-search': <@as []>, 'gateway': <'192.168.2.1'>, 'method': <'auto'>, 'route-data': <@aa{sv} []>, 'routes': <@aau []>}, 'ipv6': {'address-data': <@aa{sv} []>, 'addresses': <@a(ayuay) []>, 'dns': <@aay []>, 'dns-search': <@as []>, 'method': <'auto'>, 'route-data': <@aa{sv} []>, 'routes': <@a(ayuayu) []>}, 'proxy': {}, '802-3-ethernet': {'auto-negotiate': , 'mac-address-blacklist': <@as []>, 's390-options': <@a{ss} {}>}, '802-11-wireless': {'ssid': <[byte 0x4e, 0x45, 0x54, 0x54]>}},) \ No newline at end of file