Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/src/jarabe/model/network.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/jarabe/model/network.py')
-rw-r--r--src/jarabe/model/network.py353
1 files changed, 226 insertions, 127 deletions
diff --git a/src/jarabe/model/network.py b/src/jarabe/model/network.py
index 79e4360..f265ae4 100644
--- a/src/jarabe/model/network.py
+++ b/src/jarabe/model/network.py
@@ -34,6 +34,7 @@ from sugar import dispatch
from sugar import env
from sugar.util import unique_id
+
DEVICE_TYPE_802_3_ETHERNET = 1
DEVICE_TYPE_802_11_WIRELESS = 2
DEVICE_TYPE_GSM_MODEM = 3
@@ -129,11 +130,16 @@ NM_802_11_DEVICE_CAP_RSN = 0x00000020
SETTINGS_SERVICE = 'org.freedesktop.NetworkManagerUserSettings'
+NM_SERVICE = 'org.freedesktop.NetworkManager'
+NM_IFACE = 'org.freedesktop.NetworkManager'
+NM_PATH = '/org/freedesktop/NetworkManager'
+NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
NM_SETTINGS_PATH = '/org/freedesktop/NetworkManagerSettings'
NM_SETTINGS_IFACE = 'org.freedesktop.NetworkManagerSettings'
NM_CONNECTION_IFACE = 'org.freedesktop.NetworkManagerSettings.Connection'
NM_SECRETS_IFACE = 'org.freedesktop.NetworkManagerSettings.Connection.Secrets'
NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
+NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
GSM_USERNAME_PATH = '/desktop/sugar/network/gsm/username'
GSM_PASSWORD_PATH = '/desktop/sugar/network/gsm/password'
@@ -147,102 +153,102 @@ _conn_counter = 0
_nm_device_state_reason_description = None
+
def get_error_by_reason(reason):
global _nm_device_state_reason_description
if _nm_device_state_reason_description is None:
_nm_device_state_reason_description = {
- NM_DEVICE_STATE_REASON_UNKNOWN: \
- _("The reason for the device state change \ is unknown."),
- NM_DEVICE_STATE_REASON_NONE: \
- _("The state change is normal."),
- NM_DEVICE_STATE_REASON_NOW_MANAGED: \
- _("The device is now managed."),
- NM_DEVICE_STATE_REASON_NOW_UNMANAGED: \
- _("The device is no longer managed."),
- NM_DEVICE_STATE_REASON_CONFIG_FAILED: \
- _("The device could not be readied for configuration."),
- NM_DEVICE_STATE_REASON_CONFIG_UNAVAILABLE : \
- _("IP configuration could not be reserved " \
- "(no available address, timeout, etc)."),
- NM_DEVICE_STATE_REASON_CONFIG_EXPIRED : \
- _("The IP configuration is no longer valid."),
- NM_DEVICE_STATE_REASON_NO_SECRETS : \
- _("Secrets were required, but not provided."),
- NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT : \
- _("The 802.1X supplicant disconnected from "\
- "the access point or authentication server."),
- NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED : \
- _("Configuration of the 802.1X supplicant failed."),
- NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED : \
- _("The 802.1X supplicant quit or failed unexpectedly."),
- NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT : \
- _("The 802.1X supplicant took too long to authenticate."),
- NM_DEVICE_STATE_REASON_PPP_START_FAILED : \
- _("The PPP service failed to start within the allowed time."),
- NM_DEVICE_STATE_REASON_PPP_DISCONNECT : \
- _("The PPP service disconnected unexpectedly."),
- NM_DEVICE_STATE_REASON_PPP_FAILED : \
- _("The PPP service quit or failed unexpectedly."),
- NM_DEVICE_STATE_REASON_DHCP_START_FAILED : \
- _("The DHCP service failed to start within the allowed time."),
- NM_DEVICE_STATE_REASON_DHCP_ERROR : \
- _("The DHCP service reported an unexpected error."),
- NM_DEVICE_STATE_REASON_DHCP_FAILED : \
- _("The DHCP service quit or failed unexpectedly."),
- NM_DEVICE_STATE_REASON_SHARED_START_FAILED : \
- _("The shared connection service failed to start."),
- NM_DEVICE_STATE_REASON_SHARED_FAILED : \
- _("The shared connection service quit or " \
- "failed unexpectedly."),
- NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED : \
- _("The AutoIP service failed to start."),
- NM_DEVICE_STATE_REASON_AUTOIP_ERROR : \
- _("The AutoIP service reported an unexpected error."),
- NM_DEVICE_STATE_REASON_AUTOIP_FAILED : \
- _("The AutoIP service quit or failed unexpectedly."),
- NM_DEVICE_STATE_REASON_MODEM_BUSY : \
- _("Dialing failed because the line was busy."),
- NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE : \
- _("Dialing failed because there was no dial tone."),
- NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER : \
- _("Dialing failed because there was no carrier."),
- NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT : \
- _("Dialing timed out."),
- NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED : \
- _("Dialing failed."),
- NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED : \
- _("Modem initialization failed."),
- NM_DEVICE_STATE_REASON_GSM_APN_FAILED : \
- _("Failed to select the specified GSM APN."),
- NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING : \
- _("Not searching for networks."),
- NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED : \
- _("Network registration was denied."),
- NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT : \
- _("Network registration timed out."),
- NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED : \
- _("Failed to register with the requested GSM network."),
- NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED : \
- _("PIN check failed."),
- NM_DEVICE_STATE_REASON_FIRMWARE_MISSING : \
- _("Necessary firmware for the device may be missing."),
- NM_DEVICE_STATE_REASON_REMOVED : \
- _("The device was removed."),
- NM_DEVICE_STATE_REASON_SLEEPING : \
- _("NetworkManager went to sleep."),
- NM_DEVICE_STATE_REASON_CONNECTION_REMOVED : \
- _("The device's active connection was removed " \
- "or disappeared."),
- NM_DEVICE_STATE_REASON_USER_REQUESTED : \
- _("A user or client requested the disconnection."),
- NM_DEVICE_STATE_REASON_CARRIER : \
+ NM_DEVICE_STATE_REASON_UNKNOWN:
+ _('The reason for the device state change is unknown.'),
+ NM_DEVICE_STATE_REASON_NONE:
+ _('The state change is normal.'),
+ NM_DEVICE_STATE_REASON_NOW_MANAGED:
+ _('The device is now managed.'),
+ NM_DEVICE_STATE_REASON_NOW_UNMANAGED:
+ _('The device is no longer managed.'),
+ NM_DEVICE_STATE_REASON_CONFIG_FAILED:
+ _('The device could not be readied for configuration.'),
+ NM_DEVICE_STATE_REASON_CONFIG_UNAVAILABLE:
+ _('IP configuration could not be reserved '
+ '(no available address, timeout, etc).'),
+ NM_DEVICE_STATE_REASON_CONFIG_EXPIRED:
+ _('The IP configuration is no longer valid.'),
+ NM_DEVICE_STATE_REASON_NO_SECRETS:
+ _('Secrets were required, but not provided.'),
+ NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT:
+ _('The 802.1X supplicant disconnected from '
+ 'the access point or authentication server.'),
+ NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED:
+ _('Configuration of the 802.1X supplicant failed.'),
+ NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED:
+ _('The 802.1X supplicant quit or failed unexpectedly.'),
+ NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT:
+ _('The 802.1X supplicant took too long to authenticate.'),
+ NM_DEVICE_STATE_REASON_PPP_START_FAILED:
+ _('The PPP service failed to start within the allowed time.'),
+ NM_DEVICE_STATE_REASON_PPP_DISCONNECT:
+ _('The PPP service disconnected unexpectedly.'),
+ NM_DEVICE_STATE_REASON_PPP_FAILED:
+ _('The PPP service quit or failed unexpectedly.'),
+ NM_DEVICE_STATE_REASON_DHCP_START_FAILED:
+ _('The DHCP service failed to start within the allowed time.'),
+ NM_DEVICE_STATE_REASON_DHCP_ERROR:
+ _('The DHCP service reported an unexpected error.'),
+ NM_DEVICE_STATE_REASON_DHCP_FAILED:
+ _('The DHCP service quit or failed unexpectedly.'),
+ NM_DEVICE_STATE_REASON_SHARED_START_FAILED:
+ _('The shared connection service failed to start.'),
+ NM_DEVICE_STATE_REASON_SHARED_FAILED:
+ _('The shared connection service quit or failed'
+ ' unexpectedly.'),
+ NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED:
+ _('The AutoIP service failed to start.'),
+ NM_DEVICE_STATE_REASON_AUTOIP_ERROR:
+ _('The AutoIP service reported an unexpected error.'),
+ NM_DEVICE_STATE_REASON_AUTOIP_FAILED:
+ _('The AutoIP service quit or failed unexpectedly.'),
+ NM_DEVICE_STATE_REASON_MODEM_BUSY:
+ _('Dialing failed because the line was busy.'),
+ NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE:
+ _('Dialing failed because there was no dial tone.'),
+ NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER:
+ _('Dialing failed because there was no carrier.'),
+ NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT:
+ _('Dialing timed out.'),
+ NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED:
+ _('Dialing failed.'),
+ NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED:
+ _('Modem initialization failed.'),
+ NM_DEVICE_STATE_REASON_GSM_APN_FAILED:
+ _('Failed to select the specified GSM APN'),
+ NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING:
+ _('Not searching for networks.'),
+ NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED:
+ _('Network registration was denied.'),
+ NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT:
+ _('Network registration timed out.'),
+ NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED:
+ _('Failed to register with the requested GSM network.'),
+ NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED:
+ _('PIN check failed.'),
+ NM_DEVICE_STATE_REASON_FIRMWARE_MISSING:
+ _('Necessary firmware for the device may be missing.'),
+ NM_DEVICE_STATE_REASON_REMOVED:
+ _('The device was removed.'),
+ NM_DEVICE_STATE_REASON_SLEEPING:
+ _('NetworkManager went to sleep.'),
+ NM_DEVICE_STATE_REASON_CONNECTION_REMOVED:
+ _("The device's active connection was removed "
+ "or disappeared."),
+ NM_DEVICE_STATE_REASON_USER_REQUESTED:
+ _('A user or client requested the disconnection.'),
+ NM_DEVICE_STATE_REASON_CARRIER:
_("The device's carrier/link changed.")}
return _nm_device_state_reason_description[reason]
-
def frequency_to_channel(frequency):
"""Returns the channel matching a given radio channel frequency. If a
frequency is not in the dictionary channel 1 will be returned.
@@ -258,11 +264,12 @@ def frequency_to_channel(frequency):
2452: 9, 2457: 10, 2462: 11, 2467: 12,
2472: 13}
if frequency not in ftoc:
- logging.warning("The frequency %s can not be mapped to a channel, " \
- "defaulting to channel 1.", frequency)
+ logging.warning('The frequency %s can not be mapped to a channel, '
+ 'defaulting to channel 1.', frequency)
return 1
return ftoc[frequency]
+
def is_sugar_adhoc_network(ssid):
"""Checks whether an access point is a sugar Ad-hoc network.
@@ -294,8 +301,9 @@ class WirelessSecurity(object):
wireless_security['group'] = self.group
return wireless_security
+
class Wireless(object):
- nm_name = "802-11-wireless"
+ nm_name = '802-11-wireless'
def __init__(self):
self.ssid = None
@@ -318,7 +326,7 @@ class Wireless(object):
class OlpcMesh(object):
- nm_name = "802-11-olpc-mesh"
+ nm_name = '802-11-olpc-mesh'
def __init__(self, channel, anycast_addr):
self.channel = channel
@@ -326,12 +334,12 @@ class OlpcMesh(object):
def get_dict(self):
ret = {
- "ssid": dbus.ByteArray("olpc-mesh"),
- "channel": self.channel,
+ 'ssid': dbus.ByteArray('olpc-mesh'),
+ 'channel': self.channel,
}
if self.anycast_addr:
- ret["dhcp-anycast-address"] = dbus.ByteArray(self.anycast_addr)
+ ret['dhcp-anycast-address'] = dbus.ByteArray(self.anycast_addr)
return ret
@@ -352,6 +360,7 @@ class Connection(object):
connection['timestamp'] = self.timestamp
return connection
+
class IP4Config(object):
def __init__(self):
self.method = None
@@ -362,6 +371,7 @@ class IP4Config(object):
ip4_config['method'] = self.method
return ip4_config
+
class Serial(object):
def __init__(self):
self.baud = None
@@ -374,6 +384,7 @@ class Serial(object):
return serial
+
class Ppp(object):
def __init__(self):
pass
@@ -382,6 +393,7 @@ class Ppp(object):
ppp = {}
return ppp
+
class Gsm(object):
def __init__(self):
self.apn = None
@@ -400,6 +412,7 @@ class Gsm(object):
return gsm
+
class Settings(object):
def __init__(self, wireless_cfg=None):
self.connection = Connection()
@@ -422,6 +435,7 @@ class Settings(object):
settings['ipv4'] = self.ip4_config.get_dict()
return settings
+
class Secrets(object):
def __init__(self, settings):
self.settings = settings
@@ -447,6 +461,7 @@ class Secrets(object):
return settings
+
class SettingsGsm(object):
def __init__(self):
self.connection = Connection()
@@ -466,22 +481,24 @@ class SettingsGsm(object):
return settings
+
class SecretsGsm(object):
def __init__(self):
self.password = None
self.pin = None
self.puk = None
-
+
def get_dict(self):
secrets = {}
if self.password is not None:
secrets['password'] = self.password
if self.pin is not None:
secrets['pin'] = self.pin
- if self.puk is not None:
+ if self.puk is not None:
secrets['puk'] = self.puk
return {'gsm': secrets}
+
class NMSettings(dbus.service.Object):
def __init__(self):
bus = dbus.SystemBus()
@@ -509,10 +526,19 @@ class NMSettings(dbus.service.Object):
self.secrets_request.send(self, connection=sender,
response=kwargs['response'])
+ def clear_wifi_connections(self):
+ for uuid in self.connections.keys():
+ conn = self.connections[uuid]
+ if conn._settings.connection.type == \
+ NM_CONNECTION_TYPE_802_11_WIRELESS:
+ conn.Removed()
+ self.connections.pop(uuid)
+
+
class SecretsResponse(object):
- ''' Intermediate object to report the secrets from the dialog
+ """Intermediate object to report the secrets from the dialog
back to the connection object and which will inform NM
- '''
+ """
def __init__(self, connection, reply_cb, error_cb):
self._connection = connection
self._reply_cb = reply_cb
@@ -525,6 +551,7 @@ class SecretsResponse(object):
def set_error(self, error):
self._error_cb(error)
+
class NMSettingsConnection(dbus.service.Object):
def __init__(self, path, settings, secrets):
bus = dbus.SystemBus()
@@ -537,15 +564,26 @@ class NMSettingsConnection(dbus.service.Object):
self._settings = settings
self._secrets = secrets
+ @dbus.service.signal(dbus_interface=NM_CONNECTION_IFACE,
+ signature='')
+ def Removed(self):
+ pass
+
+ @dbus.service.signal(dbus_interface=NM_CONNECTION_IFACE,
+ signature='a{sa{sv}}')
+ def Updated(self, settings):
+ pass
+
def set_connected(self):
if self._settings.connection.type == NM_CONNECTION_TYPE_GSM:
self._settings.connection.timestamp = int(time.time())
- else:
- if not self._settings.connection.autoconnect:
- self._settings.connection.autoconnect = True
- self._settings.connection.timestamp = int(time.time())
- if self._settings.connection.type == NM_CONNECTION_TYPE_802_11_WIRELESS:
- self.save()
+ elif not self._settings.connection.autoconnect:
+ self._settings.connection.autoconnect = True
+ self._settings.connection.timestamp = int(time.time())
+ if (self._settings.connection.type ==
+ NM_CONNECTION_TYPE_802_11_WIRELESS):
+ self.Updated(self._settings.get_dict())
+ self.save()
try:
# try to flush resolver cache - SL#1940
@@ -555,19 +593,28 @@ class NMSettingsConnection(dbus.service.Object):
res_init = getattr(libc, '__res_init')
res_init(None)
except:
+ # pylint: disable=W0702
logging.exception('Error calling libc.__res_init')
+ def disable_autoconnect(self):
+ if self._settings.connection.type != NM_CONNECTION_TYPE_GSM and \
+ self._settings.connection.autoconnect:
+ self._settings.connection.autoconnect = False
+ self._settings.connection.timestamp = None
+ self.Updated(self._settings.get_dict())
+ self.save()
+
def set_secrets(self, secrets):
self._secrets = secrets
- if self._settings.connection.type == NM_CONNECTION_TYPE_802_11_WIRELESS:
+ if self._settings.connection.type == \
+ NM_CONNECTION_TYPE_802_11_WIRELESS:
self.save()
def get_settings(self):
return self._settings
def save(self):
- profile_path = env.get_profile_path()
- config_path = os.path.join(profile_path, 'nm', 'connections.cfg')
+ config_path = _get_wifi_connections_path()
config = ConfigParser.ConfigParser()
try:
@@ -635,24 +682,28 @@ class NMSettingsConnection(dbus.service.Object):
self.path, request_new)
if self._settings.connection.type is not NM_CONNECTION_TYPE_GSM:
if request_new or self._secrets is None:
- # request_new is for example the case when the pw on the AP changes
+ # request_new is for example the case when the pw on the AP
+ # changes
response = SecretsResponse(self, reply, error)
try:
self.secrets_request.send(self, response=response)
except Exception:
- logging.exception('Error requesting the secrets via dialog')
+ logging.exception('Error requesting the secrets via'
+ ' dialog')
else:
reply(self._secrets.get_dict())
else:
if not request_new:
reply(self._secrets.get_dict())
else:
- raise Exception('The stored GSM secret has already been supplied ')
+ raise Exception('The stored GSM secret has already been'
+ ' supplied')
+
class AccessPoint(gobject.GObject):
__gsignals__ = {
'props-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
+ ([gobject.TYPE_PYOBJECT])),
}
def __init__(self, device, model):
@@ -672,8 +723,7 @@ class AccessPoint(gobject.GObject):
self.channel = 0
def initialize(self):
- model_props = dbus.Interface(self.model,
- 'org.freedesktop.DBus.Properties')
+ model_props = dbus.Interface(self.model, dbus.PROPERTIES_IFACE)
model_props.GetAll(NM_ACCESSPOINT_IFACE, byte_arrays=True,
reply_handler=self._ap_properties_changed_cb,
error_handler=self._get_all_props_error_cb)
@@ -718,7 +768,7 @@ class AccessPoint(gobject.GObject):
else:
fl |= 1 << 6
- hashstr = str(fl) + "@" + self.name
+ hashstr = str(fl) + '@' + self.name
return hash(hashstr)
def _update_properties(self, properties):
@@ -757,6 +807,7 @@ class AccessPoint(gobject.GObject):
path=self.model.object_path,
dbus_interface=NM_ACCESSPOINT_IFACE)
+
def get_settings():
global _nm_settings
if _nm_settings is None:
@@ -767,17 +818,20 @@ def get_settings():
load_connections()
return _nm_settings
+
def find_connection_by_ssid(ssid):
connections = get_settings().connections
for conn_index in connections:
connection = connections[conn_index]
- if connection._settings.connection.type == NM_CONNECTION_TYPE_802_11_WIRELESS:
- if connection._settings.wireless.ssid == ssid:
- return connection
+ if connection._settings.connection.type == \
+ NM_CONNECTION_TYPE_802_11_WIRELESS and \
+ connection._settings.wireless.ssid == ssid:
+ return connection
return None
+
def add_connection(uuid, settings, secrets=None):
global _conn_counter
@@ -788,19 +842,26 @@ def add_connection(uuid, settings, secrets=None):
_nm_settings.add_connection(uuid, conn)
return conn
-def load_wifi_connections():
+
+def _get_wifi_connections_path():
profile_path = env.get_profile_path()
- config_path = os.path.join(profile_path, 'nm', 'connections.cfg')
+ return os.path.join(profile_path, 'nm', 'connections.cfg')
- config = ConfigParser.ConfigParser()
+
+def _create_wifi_connections(config_path):
+ if not os.path.exists(os.path.dirname(config_path)):
+ os.makedirs(os.path.dirname(config_path), 0755)
+ f = open(config_path, 'w')
+ f.close()
+
+
+def load_wifi_connections():
+ config_path = _get_wifi_connections_path()
if not os.path.exists(config_path):
- if not os.path.exists(os.path.dirname(config_path)):
- os.makedirs(os.path.dirname(config_path), 0755)
- f = open(config_path, 'w')
- config.write(f)
- f.close()
+ _create_wifi_connections(config_path)
+ config = ConfigParser.ConfigParser()
try:
if not config.read(config_path):
logging.error('Error reading the nm config file')
@@ -870,10 +931,10 @@ def load_gsm_connection():
if username and number and apn:
settings = SettingsGsm()
- settings.gsm.username = username
+ settings.gsm.username = username
settings.gsm.number = number
settings.gsm.apn = apn
-
+
secrets = SecretsGsm()
secrets.pin = pin
secrets.puk = puk
@@ -891,12 +952,14 @@ def load_gsm_connection():
except Exception:
logging.exception('Error adding gsm connection to NMSettings.')
else:
- logging.exception("No gsm connection was set in GConf.")
+ logging.warning('No gsm connection was set in GConf.')
+
def load_connections():
load_wifi_connections()
load_gsm_connection()
+
def find_gsm_connection():
connections = get_settings().connections
@@ -906,3 +969,39 @@ def find_gsm_connection():
logging.debug('There is no gsm connection in the NMSettings.')
return None
+
+
+def have_wifi_connections():
+ return bool(get_settings().connections)
+
+
+def clear_wifi_connections():
+ if _nm_settings is not None:
+ _nm_settings.clear_wifi_connections()
+
+ config_path = _get_wifi_connections_path()
+ _create_wifi_connections(config_path)
+
+
+def disconnect_access_points(ap_paths):
+ """
+ Disconnect all devices connected to any of the given access points.
+ """
+ bus = dbus.SystemBus()
+ netmgr_obj = bus.get_object(NM_SERVICE, NM_PATH)
+ netmgr = dbus.Interface(netmgr_obj, NM_IFACE)
+ netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE)
+ active_connection_paths = netmgr_props.Get(NM_IFACE, 'ActiveConnections')
+
+ for conn_path in active_connection_paths:
+ conn_obj = bus.get_object(NM_IFACE, conn_path)
+ conn_props = dbus.Interface(conn_obj, dbus.PROPERTIES_IFACE)
+ ap_path = conn_props.Get(NM_ACTIVE_CONN_IFACE, 'SpecificObject')
+ if ap_path == '/' or ap_path not in ap_paths:
+ continue
+
+ dev_paths = conn_props.Get(NM_ACTIVE_CONN_IFACE, 'Devices')
+ for dev_path in dev_paths:
+ dev_obj = bus.get_object(NM_SERVICE, dev_path)
+ dev = dbus.Interface(dev_obj, NM_DEVICE_IFACE)
+ dev.Disconnect()