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.py1096
1 files changed, 1096 insertions, 0 deletions
diff --git a/src/jarabe/model/network.py b/src/jarabe/model/network.py
new file mode 100644
index 0000000..cc02b58
--- /dev/null
+++ b/src/jarabe/model/network.py
@@ -0,0 +1,1096 @@
+# Copyright (C) 2008 Red Hat, Inc.
+# Copyright (C) 2009 Tomeu Vizoso, Simon Schampijer
+# Copyright (C) 2009-2010 One Laptop per Child
+# Copyright (C) 2009 Paraguay Educa, Martin Abente
+# Copyright (C) 2010 Plan Ceibal, Daniel Castelo
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+import logging
+import os
+
+import dbus
+import dbus.service
+import gobject
+import ConfigParser
+import gconf
+import ctypes
+
+from sugar import dispatch
+from sugar import env
+from sugar.util import unique_id
+
+NM_STATE_UNKNOWN = 0
+NM_STATE_ASLEEP = 10
+NM_STATE_DISCONNECTED = 20
+NM_STATE_DISCONNECTING = 30
+NM_STATE_CONNECTING = 40
+NM_STATE_CONNECTED_LOCAL = 50
+NM_STATE_CONNECTED_SITE = 60
+NM_STATE_CONNECTED_GLOBAL = 70
+
+NM_DEVICE_TYPE_UNKNOWN = 0
+NM_DEVICE_TYPE_ETHERNET = 1
+NM_DEVICE_TYPE_WIFI = 2
+NM_DEVICE_TYPE_UNUSED1 = 3
+NM_DEVICE_TYPE_UNUSED2 = 4
+NM_DEVICE_TYPE_BT = 5
+NM_DEVICE_TYPE_OLPC_MESH = 6
+NM_DEVICE_TYPE_WIMAX = 7
+NM_DEVICE_TYPE_MODEM = 8
+
+NM_DEVICE_STATE_UNKNOWN = 0
+NM_DEVICE_STATE_UNMANAGED = 10
+NM_DEVICE_STATE_UNAVAILABLE = 20
+NM_DEVICE_STATE_DISCONNECTED = 30
+NM_DEVICE_STATE_PREPARE = 40
+NM_DEVICE_STATE_CONFIG = 50
+NM_DEVICE_STATE_NEED_AUTH = 60
+NM_DEVICE_STATE_IP_CONFIG = 70
+NM_DEVICE_STATE_IP_CHECK = 80
+NM_DEVICE_STATE_SECONDARIES = 90
+NM_DEVICE_STATE_ACTIVATED = 100
+NM_DEVICE_STATE_DEACTIVATING = 110
+NM_DEVICE_STATE_FAILED = 120
+
+NM_CONNECTION_TYPE_802_11_WIRELESS = '802-11-wireless'
+NM_CONNECTION_TYPE_GSM = 'gsm'
+
+NM_ACTIVE_CONNECTION_STATE_UNKNOWN = 0
+NM_ACTIVE_CONNECTION_STATE_ACTIVATING = 1
+NM_ACTIVE_CONNECTION_STATE_ACTIVATED = 2
+NM_ACTIVE_CONNECTION_STATE_DEACTIVATING = 3
+
+NM_DEVICE_STATE_REASON_UNKNOWN = 0
+NM_DEVICE_STATE_REASON_NONE = 1
+NM_DEVICE_STATE_REASON_NOW_MANAGED = 2
+NM_DEVICE_STATE_REASON_NOW_UNMANAGED = 3
+NM_DEVICE_STATE_REASON_CONFIG_FAILED = 4
+NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE = 5
+NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED = 6
+NM_DEVICE_STATE_REASON_NO_SECRETS = 7
+NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT = 8
+NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED = 9
+NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED = 10
+NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT = 11
+NM_DEVICE_STATE_REASON_PPP_START_FAILED = 12
+NM_DEVICE_STATE_REASON_PPP_DISCONNECT = 13
+NM_DEVICE_STATE_REASON_PPP_FAILED = 14
+NM_DEVICE_STATE_REASON_DHCP_START_FAILED = 15
+NM_DEVICE_STATE_REASON_DHCP_ERROR = 16
+NM_DEVICE_STATE_REASON_DHCP_FAILED = 17
+NM_DEVICE_STATE_REASON_SHARED_START_FAILED = 18
+NM_DEVICE_STATE_REASON_SHARED_FAILED = 19
+NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED = 20
+NM_DEVICE_STATE_REASON_AUTOIP_ERROR = 21
+NM_DEVICE_STATE_REASON_AUTOIP_FAILED = 22
+NM_DEVICE_STATE_REASON_MODEM_BUSY = 23
+NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE = 24
+NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER = 25
+NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT = 26
+NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED = 27
+NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED = 28
+NM_DEVICE_STATE_REASON_GSM_APN_FAILED = 29
+NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING = 30
+NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED = 31
+NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT = 32
+NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED = 33
+NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED = 34
+NM_DEVICE_STATE_REASON_FIRMWARE_MISSING = 35
+NM_DEVICE_STATE_REASON_REMOVED = 36
+NM_DEVICE_STATE_REASON_SLEEPING = 37
+NM_DEVICE_STATE_REASON_CONNECTION_REMOVED = 38
+NM_DEVICE_STATE_REASON_USER_REQUESTED = 39
+NM_DEVICE_STATE_REASON_CARRIER = 40
+NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED = 41
+NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE = 42
+NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND = 43
+NM_DEVICE_STATE_REASON_BT_FAILED = 44
+NM_DEVICE_STATE_REASON_LAST = 0xFFFF
+
+NM_802_11_AP_FLAGS_NONE = 0x00000000
+NM_802_11_AP_FLAGS_PRIVACY = 0x00000001
+
+NM_802_11_AP_SEC_NONE = 0x0
+NM_802_11_AP_SEC_PAIR_WEP40 = 0x1
+NM_802_11_AP_SEC_PAIR_WEP104 = 0x2
+NM_802_11_AP_SEC_PAIR_TKIP = 0x4
+NM_802_11_AP_SEC_PAIR_CCMP = 0x8
+NM_802_11_AP_SEC_GROUP_WEP40 = 0x10
+NM_802_11_AP_SEC_GROUP_WEP104 = 0x20
+NM_802_11_AP_SEC_GROUP_TKIP = 0x40
+NM_802_11_AP_SEC_GROUP_CCMP = 0x80
+NM_802_11_AP_SEC_KEY_MGMT_PSK = 0x100
+NM_802_11_AP_SEC_KEY_MGMT_802_1X = 0x200
+
+NM_802_11_MODE_UNKNOWN = 0
+NM_802_11_MODE_ADHOC = 1
+NM_802_11_MODE_INFRA = 2
+
+NM_WIFI_DEVICE_CAP_NONE = 0x00000000
+NM_WIFI_DEVICE_CAP_CIPHER_WEP40 = 0x00000001
+NM_WIFI_DEVICE_CAP_CIPHER_WEP104 = 0x00000002
+NM_WIFI_DEVICE_CAP_CIPHER_TKIP = 0x00000004
+NM_WIFI_DEVICE_CAP_CIPHER_CCMP = 0x00000008
+NM_WIFI_DEVICE_CAP_WPA = 0x00000010
+NM_WIFI_DEVICE_CAP_RSN = 0x00000020
+
+NM_BT_CAPABILITY_NONE = 0x00000000
+NM_BT_CAPABILITY_DUN = 0x00000001
+NM_BT_CAPABILITY_NAP = 0x00000002
+
+NM_DEVICE_MODEM_CAPABILITY_NONE = 0x00000000
+NM_DEVICE_MODEM_CAPABILITY_POTS = 0x00000001
+NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO = 0x00000002
+NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS = 0x00000004
+NM_DEVICE_MODEM_CAPABILITY_LTE = 0x00000008
+
+SETTINGS_SERVICE = 'org.freedesktop.NetworkManager'
+
+NM_SERVICE = 'org.freedesktop.NetworkManager'
+NM_IFACE = 'org.freedesktop.NetworkManager'
+NM_PATH = '/org/freedesktop/NetworkManager'
+NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
+NM_WIRED_IFACE = 'org.freedesktop.NetworkManager.Device.Wired'
+NM_WIRELESS_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless'
+NM_MODEM_IFACE = 'org.freedesktop.NetworkManager.Device.Modem'
+NM_OLPC_MESH_IFACE = 'org.freedesktop.NetworkManager.Device.OlpcMesh'
+NM_SETTINGS_PATH = '/org/freedesktop/NetworkManager/Settings'
+NM_SETTINGS_IFACE = 'org.freedesktop.NetworkManager.Settings'
+NM_CONNECTION_IFACE = 'org.freedesktop.NetworkManager.Settings.Connection'
+NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
+NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
+
+NM_SECRET_AGENT_IFACE = 'org.freedesktop.NetworkManager.SecretAgent'
+NM_SECRET_AGENT_PATH = '/org/freedesktop/NetworkManager/SecretAgent'
+NM_AGENT_MANAGER_IFACE = 'org.freedesktop.NetworkManager.AgentManager'
+NM_AGENT_MANAGER_PATH = '/org/freedesktop/NetworkManager/AgentManager'
+
+NM_AGENT_MANAGER_ERR_NO_SECRETS = 'org.freedesktop.NetworkManager.AgentManager.NoSecrets'
+
+GSM_CONNECTION_ID = 'Sugar Modem Connection'
+GSM_BAUD_RATE = 115200
+GSM_USERNAME_PATH = '/desktop/sugar/network/gsm/username'
+GSM_PASSWORD_PATH = '/desktop/sugar/network/gsm/password'
+GSM_NUMBER_PATH = '/desktop/sugar/network/gsm/number'
+GSM_APN_PATH = '/desktop/sugar/network/gsm/apn'
+GSM_PIN_PATH = '/desktop/sugar/network/gsm/pin'
+GSM_PUK_PATH = '/desktop/sugar/network/gsm/puk'
+
+ADHOC_CONNECTION_ID_PREFIX = 'Sugar Ad-hoc Network '
+MESH_CONNECTION_ID_PREFIX = 'OLPC Mesh Network '
+XS_MESH_CONNECTION_ID_PREFIX = 'OLPC XS Mesh Network '
+
+_network_manager = None
+_nm_settings = None
+_secret_agent = None
+_connections = None
+
+_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_IP_CONFIG_UNAVAILABLE:
+ _('IP configuration could not be reserved '
+ '(no available address, timeout, etc).'),
+ NM_DEVICE_STATE_REASON_IP_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."),
+ NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED:
+ _("The device's existing connection was assumed."),
+ NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE:
+ _("The supplicant is now available."),
+ NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND:
+ _("The modem could not be found."),
+ NM_DEVICE_STATE_REASON_BT_FAILED:
+ _("The Bluetooth connection failed or timed out."),
+ NM_DEVICE_STATE_REASON_LAST:
+ _("Unused."),
+ }
+
+ 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.
+
+ Keyword arguments:
+ frequency -- The radio channel frequency in MHz.
+
+ Return: Channel
+
+ """
+ ftoc = {2412: 1, 2417: 2, 2422: 3, 2427: 4,
+ 2432: 5, 2437: 6, 2442: 7, 2447: 8,
+ 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)
+ return 1
+ return ftoc[frequency]
+
+
+def is_sugar_adhoc_network(ssid):
+ """Checks whether an access point is a sugar Ad-hoc network.
+
+ Keyword arguments:
+ ssid -- Ssid of the access point.
+
+ Return: Boolean
+
+ """
+ return ssid.startswith('Ad-hoc Network')
+
+
+class WirelessSecurity(object):
+ def __init__(self):
+ self.key_mgmt = None
+ self.proto = None
+ self.group = None
+ self.pairwise = None
+ self.wep_key = None
+ self.psk = None
+ self.auth_alg = None
+
+ def get_dict(self):
+ wireless_security = {}
+ if self.key_mgmt is not None:
+ wireless_security['key-mgmt'] = self.key_mgmt
+ if self.proto is not None:
+ wireless_security['proto'] = self.proto
+ if self.pairwise is not None:
+ wireless_security['pairwise'] = self.pairwise
+ if self.group is not None:
+ wireless_security['group'] = self.group
+ if self.wep_key is not None:
+ wireless_security['wep-key0'] = self.wep_key
+ if self.psk is not None:
+ wireless_security['psk'] = self.psk
+ if self.auth_alg is not None:
+ wireless_security['auth-alg'] = self.auth_alg
+ return wireless_security
+
+
+class Wireless(object):
+ nm_name = '802-11-wireless'
+
+ def __init__(self):
+ self.ssid = None
+ self.security = None
+ self.mode = None
+ self.band = None
+ self.channel = None
+
+ def get_dict(self):
+ wireless = {'ssid': self.ssid}
+ if self.security:
+ wireless['security'] = self.security
+ if self.mode:
+ wireless['mode'] = self.mode
+ if self.band:
+ wireless['band'] = self.band
+ if self.channel:
+ wireless['channel'] = self.channel
+ return wireless
+
+
+class OlpcMesh(object):
+ nm_name = '802-11-olpc-mesh'
+
+ def __init__(self, channel, anycast_addr):
+ self.channel = channel
+ self.anycast_addr = anycast_addr
+
+ def get_dict(self):
+ ret = {
+ 'ssid': dbus.ByteArray('olpc-mesh'),
+ 'channel': self.channel,
+ }
+
+ if self.anycast_addr:
+ ret['dhcp-anycast-address'] = dbus.ByteArray(self.anycast_addr)
+ return ret
+
+
+class ConnectionSettings(object):
+ def __init__(self):
+ self.id = None
+ self.uuid = None
+ self.type = None
+ self.autoconnect = False
+ self.timestamp = None
+
+ def get_dict(self):
+ connection = {'id': self.id,
+ 'uuid': self.uuid,
+ 'type': self.type,
+ 'autoconnect': self.autoconnect}
+ if self.timestamp:
+ connection['timestamp'] = self.timestamp
+ return connection
+
+
+class IP4Config(object):
+ def __init__(self):
+ self.method = None
+
+ def get_dict(self):
+ ip4_config = {}
+ if self.method is not None:
+ ip4_config['method'] = self.method
+ return ip4_config
+
+
+class Serial(object):
+ def __init__(self):
+ self.baud = None
+
+ def get_dict(self):
+ serial = {}
+
+ if self.baud is not None:
+ serial['baud'] = self.baud
+
+ return serial
+
+
+class Ppp(object):
+ def __init__(self):
+ pass
+
+ def get_dict(self):
+ ppp = {}
+ return ppp
+
+
+class Gsm(object):
+ def __init__(self):
+ self.apn = None
+ self.number = None
+ self.username = None
+ self.pin = None
+ self.password = None
+
+ def get_dict(self):
+ gsm = {}
+
+ if self.apn:
+ gsm['apn'] = self.apn
+ if self.number:
+ gsm['number'] = self.number
+ if self.username:
+ gsm['username'] = self.username
+ if self.password:
+ gsm['password'] = self.password
+ if self.pin:
+ gsm['pin'] = self.pin
+
+ return gsm
+
+
+class Settings(object):
+ def __init__(self, wireless_cfg=None):
+ self.connection = ConnectionSettings()
+ self.ip4_config = None
+ self.wireless_security = None
+
+ if wireless_cfg is not None:
+ self.wireless = wireless_cfg
+ else:
+ self.wireless = Wireless()
+
+ def get_dict(self):
+ settings = {}
+ settings['connection'] = self.connection.get_dict()
+ settings[self.wireless.nm_name] = self.wireless.get_dict()
+ if self.wireless_security is not None:
+ settings['802-11-wireless-security'] = \
+ self.wireless_security.get_dict()
+ if self.ip4_config is not None:
+ settings['ipv4'] = self.ip4_config.get_dict()
+ return settings
+
+
+class SettingsGsm(object):
+ def __init__(self):
+ self.connection = ConnectionSettings()
+ self.ip4_config = IP4Config()
+ self.serial = Serial()
+ self.ppp = Ppp()
+ self.gsm = Gsm()
+
+ def get_dict(self):
+ settings = {}
+
+ settings['connection'] = self.connection.get_dict()
+ settings['serial'] = self.serial.get_dict()
+ settings['ppp'] = self.ppp.get_dict()
+ settings['gsm'] = self.gsm.get_dict()
+ settings['ipv4'] = self.ip4_config.get_dict()
+
+ return settings
+
+
+class SecretsResponse(object):
+ """Intermediate object to report the secrets from the dialog
+ back to the connection object and which will inform NM
+ """
+ def __init__(self, reply_cb, error_cb):
+ self._reply_cb = reply_cb
+ self._error_cb = error_cb
+
+ def set_secrets(self, secrets):
+ self._reply_cb(secrets)
+
+ def set_error(self, error):
+ self._error_cb(error)
+
+
+def set_connected():
+ try:
+ # try to flush resolver cache - SL#1940
+ # ctypes' syntactic sugar does not work
+ # so we must get the func ptr explicitly
+ libc = ctypes.CDLL('libc.so.6')
+ res_init = getattr(libc, '__res_init')
+ res_init(None)
+ except:
+ # pylint: disable=W0702
+ logging.exception('Error calling libc.__res_init')
+
+
+class SecretAgent(dbus.service.Object):
+ def __init__(self):
+ self._bus = dbus.SystemBus()
+ dbus.service.Object.__init__(self, self._bus, NM_SECRET_AGENT_PATH)
+ self.secrets_request = dispatch.Signal()
+ proxy = self._bus.get_object(NM_IFACE, NM_AGENT_MANAGER_PATH)
+ proxy.Register("org.sugarlabs.sugar",
+ dbus_interface=NM_AGENT_MANAGER_IFACE,
+ reply_handler=self._register_reply_cb,
+ error_handler=self._register_error_cb)
+
+ def _register_reply_cb(self):
+ logging.debug("SecretAgent registered")
+
+ def _register_error_cb(self, error):
+ logging.error("Failed to register SecretAgent: %s", error)
+
+ @dbus.service.method(NM_SECRET_AGENT_IFACE,
+ async_callbacks=('reply', 'error'),
+ in_signature='a{sa{sv}}osasb',
+ out_signature='a{sa{sv}}',
+ sender_keyword='sender',
+ byte_arrays=True)
+ def GetSecrets(self, settings, connection_path, setting_name, hints,
+ request_new, reply, error, sender=None):
+ if setting_name != '802-11-wireless-security':
+ raise ValueError("Unsupported setting type %s" % (setting_name,))
+ if not sender:
+ raise Exception("Internal error: couldn't get sender")
+ uid = self._bus.get_unix_user(sender)
+ if uid != 0:
+ raise Exception("UID %d not authorized" % (uid,))
+
+ response = SecretsResponse(reply, error)
+ self.secrets_request.send(self, settings=settings, response=response)
+
+
+class AccessPoint(gobject.GObject):
+ __gsignals__ = {
+ 'props-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ }
+
+ def __init__(self, device, model):
+ self.__gobject_init__()
+ self.device = device
+ self.model = model
+
+ self._initialized = False
+ self._bus = dbus.SystemBus()
+
+ self.ssid = ''
+ self.strength = 0
+ self.flags = 0
+ self.wpa_flags = 0
+ self.rsn_flags = 0
+ self.mode = 0
+ self.channel = 0
+
+ def initialize(self):
+ 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)
+
+ self._bus.add_signal_receiver(self._ap_properties_changed_cb,
+ signal_name='PropertiesChanged',
+ path=self.model.object_path,
+ dbus_interface=NM_ACCESSPOINT_IFACE,
+ byte_arrays=True)
+
+ def network_hash(self):
+ """
+ This is a hash which uniquely identifies the network that this AP
+ is a bridge to. i.e. its expected for 2 APs with identical SSID and
+ other settings to have the same network hash, because we assume that
+ they are a part of the same underlying network.
+ """
+
+ # based on logic from nm-applet
+ fl = 0
+
+ if self.mode == NM_802_11_MODE_INFRA:
+ fl |= 1 << 0
+ elif self.mode == NM_802_11_MODE_ADHOC:
+ fl |= 1 << 1
+ else:
+ fl |= 1 << 2
+
+ # Separate out no encryption, WEP-only, and WPA-capable */
+ if (not (self.flags & NM_802_11_AP_FLAGS_PRIVACY)) \
+ and self.wpa_flags == NM_802_11_AP_SEC_NONE \
+ and self.rsn_flags == NM_802_11_AP_SEC_NONE:
+ fl |= 1 << 3
+ elif (self.flags & NM_802_11_AP_FLAGS_PRIVACY) \
+ and self.wpa_flags == NM_802_11_AP_SEC_NONE \
+ and self.rsn_flags == NM_802_11_AP_SEC_NONE:
+ fl |= 1 << 4
+ elif (not (self.flags & NM_802_11_AP_FLAGS_PRIVACY)) \
+ and self.wpa_flags != NM_802_11_AP_SEC_NONE \
+ and self.rsn_flags != NM_802_11_AP_SEC_NONE:
+ fl |= 1 << 5
+ else:
+ fl |= 1 << 6
+
+ hashstr = str(fl) + '@' + self.ssid
+ return hash(hashstr)
+
+ def _update_properties(self, properties):
+ if self._initialized:
+ old_hash = self.network_hash()
+ else:
+ old_hash = None
+
+ if 'Ssid' in properties:
+ self.ssid = properties['Ssid']
+ if 'Strength' in properties:
+ self.strength = properties['Strength']
+ if 'Flags' in properties:
+ self.flags = properties['Flags']
+ if 'WpaFlags' in properties:
+ self.wpa_flags = properties['WpaFlags']
+ if 'RsnFlags' in properties:
+ self.rsn_flags = properties['RsnFlags']
+ if 'Mode' in properties:
+ self.mode = properties['Mode']
+ if 'Frequency' in properties:
+ self.channel = frequency_to_channel(properties['Frequency'])
+
+ self._initialized = True
+ self.emit('props-changed', old_hash)
+
+ def _get_all_props_error_cb(self, err):
+ logging.error('Error getting the access point properties: %s', err)
+
+ def _ap_properties_changed_cb(self, properties):
+ self._update_properties(properties)
+
+ def disconnect(self):
+ self._bus.remove_signal_receiver(self._ap_properties_changed_cb,
+ signal_name='PropertiesChanged',
+ path=self.model.object_path,
+ dbus_interface=NM_ACCESSPOINT_IFACE)
+
+
+def get_manager():
+ global _network_manager
+ if _network_manager is None:
+ obj = dbus.SystemBus().get_object(NM_SERVICE, NM_PATH)
+ _network_manager = dbus.Interface(obj, NM_IFACE)
+ return _network_manager
+
+
+def _get_settings():
+ global _nm_settings
+ if _nm_settings is None:
+ obj = dbus.SystemBus().get_object(NM_SERVICE, NM_SETTINGS_PATH)
+ _nm_settings = dbus.Interface(obj, NM_SETTINGS_IFACE)
+ _migrate_old_wifi_connections()
+ _migrate_old_gsm_connection()
+ return _nm_settings
+
+
+def get_secret_agent():
+ global _secret_agent
+ if _secret_agent is None:
+ _secret_agent = SecretAgent()
+ return _secret_agent
+
+
+def _activate_reply_cb(connection_path):
+ logging.debug('Activated connection: %s', connection_path)
+
+
+def _activate_error_cb(err):
+ logging.error('Failed to activate connection: %s', err)
+
+
+def _add_and_activate_reply_cb(settings_path, connection_path):
+ logging.debug('Added and activated connection: %s', connection_path)
+
+
+def _add_and_activate_error_cb(err):
+ logging.error('Failed to add and activate connection: %s', err)
+
+
+class Connection(gobject.GObject):
+ __gsignals__ = {
+ 'removed': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
+ }
+
+ def __init__(self, bus, path):
+ gobject.GObject.__init__(self)
+ obj = bus.get_object(NM_SERVICE, path)
+ self._connection = dbus.Interface(obj, NM_CONNECTION_IFACE)
+ self._removed_handle = self._connection.connect_to_signal(
+ 'Removed', self._removed_cb)
+ self._updated_handle = self._connection.connect_to_signal(
+ 'Updated', self._updated_cb)
+ self._settings = self._connection.GetSettings(byte_arrays=True)
+
+ def _updated_cb(self):
+ self._settings = self._connection.GetSettings(byte_arrays=True)
+
+ def _removed_cb(self):
+ self._updated_handle.remove()
+ self._removed_handle.remove()
+ self.emit('removed')
+
+ def get_settings(self, stype=None):
+ if not stype:
+ return self._settings
+ elif stype in self._settings:
+ return self._settings[stype]
+ else:
+ return None
+
+ def get_secrets(self, stype, reply_handler, error_handler):
+ return self._connection.GetSecrets(stype, byte_arrays=True,
+ reply_handler=reply_handler,
+ error_handler=error_handler)
+
+ def update_settings(self, settings):
+ self._connection.Update(settings)
+
+ def activate(self, device_o, reply_handler=_activate_reply_cb,
+ error_handler=_activate_error_cb):
+ activate_connection_by_path(self.get_path(), device_o,
+ reply_handler=reply_handler,
+ error_handler=error_handler)
+
+ def delete(self):
+ self._connection.Delete()
+
+ def get_ssid(self):
+ wifi_settings = self.get_settings('802-11-wireless')
+ if wifi_settings and 'ssid' in wifi_settings:
+ return wifi_settings['ssid']
+ else:
+ return None
+
+ def get_id(self):
+ return self.get_settings('connection')['id']
+
+ def get_path(self):
+ return self._connection.object_path
+
+ def is_sugar_internal_connection(self):
+ """Returns True if this connection is a 'special' Sugar connection,
+ i.e. one that has been created by Sugar internals and should not be
+ visible to the user or deleted by connection-clearing code."""
+ connection_id = self.get_id()
+ return connection_id == GSM_CONNECTION_ID \
+ or connection_id.startswith(ADHOC_CONNECTION_ID_PREFIX) \
+ or connection_id.startswith(MESH_CONNECTION_ID_PREFIX) \
+ or connection_id.startswith(XS_MESH_CONNECTION_ID_PREFIX)
+
+
+class Connections(object):
+ def __init__(self):
+ self._bus = dbus.SystemBus()
+ self._connections = []
+
+ settings = _get_settings()
+ settings.connect_to_signal('NewConnection', self._new_connection_cb)
+
+ for connection_o in settings.ListConnections():
+ self._monitor_connection(connection_o)
+
+ def get_list(self):
+ return self._connections
+
+ def _monitor_connection(self, connection_o):
+ connection = Connection(self._bus, connection_o)
+ connection.connect('removed', self._connection_removed_cb)
+ self._connections.append(connection)
+
+ def _new_connection_cb(self, connection_o):
+ self._monitor_connection(connection_o)
+
+ def _connection_removed_cb(self, connection):
+ connection.disconnect_by_func(self._connection_removed_cb)
+ self._connections.remove(connection)
+
+ def clear(self):
+ """Remove all connections except Sugar-internal ones."""
+
+ # copy the list, to avoid problems with removing elements of a list
+ # while looping over it
+ connections = list(self._connections)
+ for connection in connections:
+ if connection.is_sugar_internal_connection():
+ continue
+ try:
+ connection.delete()
+ except dbus.DBusException:
+ logging.debug("Could not remove connection %s",
+ connection.get_id())
+
+
+def get_connections():
+ global _connections
+ if _connections is None:
+ _connections = Connections()
+ return _connections
+
+
+def find_connection_by_ssid(ssid):
+ # FIXME: this check should be more extensive.
+ # it should look at mode (infra/adhoc), band, security, and really
+ # anything that is stored in the settings.
+ for connection in get_connections().get_list():
+ if connection.get_ssid() == ssid:
+ return connection
+ return None
+
+
+def find_connection_by_id(connection_id):
+ for connection in get_connections().get_list():
+ if connection.get_id() == connection_id:
+ return connection
+ return None
+
+
+def _add_connection_reply_cb(connection):
+ logging.debug('Added connection: %s', connection)
+
+
+def _add_connection_error_cb(err):
+ logging.error('Failed to add connection: %s', err)
+
+
+def add_connection(settings, reply_handler=_add_connection_reply_cb,
+ error_handler=_add_connection_error_cb):
+ _get_settings().AddConnection(settings.get_dict(),
+ reply_handler=reply_handler,
+ error_handler=error_handler)
+
+
+def activate_connection_by_path(connection, device_o,
+ reply_handler=_activate_reply_cb,
+ error_handler=_activate_error_cb):
+ get_manager().ActivateConnection(connection,
+ device_o,
+ '/',
+ reply_handler=reply_handler,
+ error_handler=error_handler)
+
+
+def add_and_activate_connection(device_o, settings, specific_object):
+ manager = get_manager()
+ manager.AddAndActivateConnection(settings.get_dict(), device_o,
+ specific_object,
+ reply_handler=_add_and_activate_reply_cb,
+ error_handler=_add_and_activate_error_cb)
+
+
+def _migrate_old_wifi_connections():
+ """Migrate connections.cfg from Sugar-0.94 and previous to NetworkManager
+ system-wide connections
+ """
+
+ profile_path = env.get_profile_path()
+ config_path = os.path.join(profile_path, 'nm', 'connections.cfg')
+ if not os.path.exists(config_path):
+ return
+
+ config = ConfigParser.ConfigParser()
+ try:
+ if not config.read(config_path):
+ logging.error('Error reading the nm config file')
+ return
+ except ConfigParser.ParsingError:
+ logging.exception('Error reading the nm config file')
+ return
+
+ for section in config.sections():
+ try:
+ settings = Settings()
+ settings.connection.id = section
+ ssid = config.get(section, 'ssid')
+ settings.wireless.ssid = dbus.ByteArray(ssid)
+ uuid = config.get(section, 'uuid')
+ settings.connection.uuid = uuid
+ nmtype = config.get(section, 'type')
+ settings.connection.type = nmtype
+ autoconnect = bool(config.get(section, 'autoconnect'))
+ settings.connection.autoconnect = autoconnect
+
+ if config.has_option(section, 'timestamp'):
+ timestamp = int(config.get(section, 'timestamp'))
+ settings.connection.timestamp = timestamp
+
+ if config.has_option(section, 'key-mgmt'):
+ settings.wireless_security = WirelessSecurity()
+ mgmt = config.get(section, 'key-mgmt')
+ settings.wireless_security.key_mgmt = mgmt
+ security = config.get(section, 'security')
+ settings.wireless.security = security
+ key = config.get(section, 'key')
+ if mgmt == 'none':
+ settings.wireless_security.wep_key = key
+ auth_alg = config.get(section, 'auth-alg')
+ settings.wireless_security.auth_alg = auth_alg
+ elif mgmt == 'wpa-psk':
+ settings.wireless_security.psk = key
+ if config.has_option(section, 'proto'):
+ value = config.get(section, 'proto')
+ settings.wireless_security.proto = value
+ if config.has_option(section, 'group'):
+ value = config.get(section, 'group')
+ settings.wireless_security.group = value
+ if config.has_option(section, 'pairwise'):
+ value = config.get(section, 'pairwise')
+ settings.wireless_security.pairwise = value
+ except ConfigParser.Error:
+ logging.exception('Error reading section')
+ else:
+ add_connection(settings)
+
+ os.unlink(config_path)
+
+
+def create_gsm_connection(username, password, number, apn, pin):
+ settings = SettingsGsm()
+ settings.gsm.username = username
+ settings.gsm.number = number
+ settings.gsm.apn = apn
+ settings.gsm.pin = pin
+ settings.gsm.password = password
+
+ settings.connection.id = GSM_CONNECTION_ID
+ settings.connection.type = NM_CONNECTION_TYPE_GSM
+ settings.connection.uuid = unique_id()
+ settings.connection.autoconnect = False
+ settings.ip4_config.method = 'auto'
+ settings.serial.baud = GSM_BAUD_RATE
+
+ add_connection(settings)
+
+
+def _migrate_old_gsm_connection():
+ if find_gsm_connection():
+ # don't attempt migration if a NM-level connection already exists
+ return
+
+ client = gconf.client_get_default()
+
+ username = client.get_string(GSM_USERNAME_PATH) or ''
+ password = client.get_string(GSM_PASSWORD_PATH) or ''
+ number = client.get_string(GSM_NUMBER_PATH) or ''
+ apn = client.get_string(GSM_APN_PATH) or ''
+ pin = client.get_string(GSM_PIN_PATH) or ''
+
+ if apn or number:
+ logging.info("Migrating old GSM connection details")
+ try:
+ create_gsm_connection(username, password, number, apn, pin)
+ # remove old connection
+ for setting in (GSM_USERNAME_PATH, GSM_PASSWORD_PATH,
+ GSM_NUMBER_PATH, GSM_APN_PATH, GSM_PIN_PATH,
+ GSM_PUK_PATH):
+ client.set_string(setting, '')
+ except Exception:
+ logging.exception('Error adding gsm connection to NMSettings.')
+
+
+def find_gsm_connection():
+ return find_connection_by_id(GSM_CONNECTION_ID)
+
+
+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()
+
+
+def _is_non_printable(char):
+ """
+ Return True if char is a non-printable unicode character, False otherwise
+ """
+ return (char < u' ') or (u'~' < char < u'\xA0') or (char == u'\xAD')
+
+
+def ssid_to_display_name(ssid):
+ """Convert an SSID into a unicode string for recognising Access Points
+
+ Return a unicode string that's useful for recognising and
+ distinguishing between Access Points (APs).
+
+ IEEE 802.11 defines SSIDs as arbitrary byte sequences. As random
+ bytes are not very user-friendly, most APs use some human-readable
+ character string as SSID. However, because there's no standard
+ specifying what encoding to use, AP vendors chose various
+ different encodings. Since there's also no indication of what
+ encoding was used for a particular SSID, the best we can do for
+ turning an SSID into a displayable string is to try a couple of
+ encodings based on some heuristic.
+
+ We're currently using the following heuristic:
+
+ 1. If the SSID is a valid character string consisting only of
+ printable characters in one of the following encodings (tried in
+ the given order), decode it accordingly:
+ UTF-8, ISO-8859-1, Windows-1251.
+ 2. Return a hex dump of the SSID.
+ """
+ for encoding in ['utf-8', 'iso-8859-1', 'windows-1251']:
+ try:
+ display_name = unicode(ssid, encoding)
+ except UnicodeDecodeError:
+ continue
+
+ if not [True for char in display_name if _is_non_printable(char)]:
+ # Only printable characters
+ return display_name
+
+ return ':'.join(['%02x' % (ord(byte), ) for byte in ssid])