2014-01-09 21:19:07 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
|
|
|
|
|
|
from __future__ import print_function
|
|
|
|
|
|
|
|
import sys
|
2018-05-06 06:51:26 +00:00
|
|
|
|
|
|
|
import gi
|
|
|
|
from gi.repository import GLib
|
|
|
|
|
|
|
|
try:
|
|
|
|
gi.require_version('NM', '1.0')
|
|
|
|
from gi.repository import NM
|
|
|
|
except Exception as e:
|
|
|
|
print("Cannot load gi.NM: %s" % (str(e)))
|
|
|
|
sys.exit(77)
|
|
|
|
|
clients/tests: seed generated numbers for test-networkmanager-service.py
At several places, "test-networkmanager-service.py" uses generated numbers
with a defined seed. For example, generated connection's UUID is
generated in a predictable, but randomized way (if you forgive the
inprecise use of the word "random" in context of using a deterministic
seed).
Aside the connection's UUID, this becomes more interesting in the next commit
where the stub server generates a list of IP and DHCP settings in a predictable
randomized way.
For "clients/tests" we spawn the test service multiple times, but also
create similar environments by calling init_001(). This is done for
convenience, where out of lazyness all the tests share one setup. But it's
still a good idea that these tests generate slightly different setups,
wherever applicable. this increases the possible setups which get tested.
For example, the number of static IPv4 addresses (the following commit) is
interested to explicitly test for zero or a non-zero number of
addresses. If all tests happen to use the same seed, the tests are expected
to also generate the same number of addresses, and we miss an opportunity to
hit interesting test cases.
There is still no guarantee that all interesting cases are hit, the chances are just
better. The approach of generating the setup randomly, does not preclude that
the stub-server allows to explicitly configure the setup. However, due to the
sheer number of combinations that might be interesting to test, it's much simpler
to rely on some randomization and have the justifid hope we catch interesting cases.
Also in terms of runtime of the test, the cli unit tests should complete within
few seconds. Testing every combination would result in huge tests and long runtimes.
Also, the patch refactors generating random numbers in
"test-networkmanager-service.py". For example, it introduces
Util.RandomSeed(), which can be used to generate a sequence of different
random numbers. It works by having an internal state and a counter which is
combined to chain the seed and generate different numbers on each call.
2018-06-07 15:42:31 +00:00
|
|
|
import os
|
2014-01-09 21:19:07 +00:00
|
|
|
import dbus
|
|
|
|
import dbus.service
|
|
|
|
import dbus.mainloop.glib
|
|
|
|
import random
|
2015-12-23 12:50:19 +00:00
|
|
|
import uuid
|
2018-05-04 07:02:53 +00:00
|
|
|
import hashlib
|
2018-06-06 18:28:17 +00:00
|
|
|
import socket
|
2018-06-04 18:33:35 +00:00
|
|
|
import collections
|
2018-05-04 07:02:53 +00:00
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
###############################################################################
|
|
|
|
|
2018-05-09 10:46:34 +00:00
|
|
|
_DEFAULT_ARG = object()
|
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
class Global:
|
|
|
|
pass
|
|
|
|
|
2018-05-15 08:16:14 +00:00
|
|
|
gl = None
|
2018-05-14 12:22:09 +00:00
|
|
|
|
|
|
|
###############################################################################
|
2018-05-04 07:02:53 +00:00
|
|
|
|
|
|
|
class TestError(AssertionError):
|
|
|
|
def __init__(self, message = 'Unspecified error', errors = None):
|
|
|
|
AssertionError.__init__(self, message)
|
|
|
|
self.errors = errors
|
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
###############################################################################
|
2018-05-04 07:02:53 +00:00
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
class Util:
|
|
|
|
|
2018-06-06 18:28:17 +00:00
|
|
|
PY3 = (sys.version_info[0] == 3)
|
|
|
|
|
2018-06-16 11:38:45 +00:00
|
|
|
@staticmethod
|
|
|
|
def g_source_remove(source_id):
|
|
|
|
if source_id is not None:
|
|
|
|
GLib.source_remove(source_id)
|
|
|
|
|
2018-06-06 18:28:17 +00:00
|
|
|
@staticmethod
|
|
|
|
def addr_family_check(family, allow_af_unspec = False):
|
|
|
|
if family == socket.AF_INET:
|
|
|
|
return
|
|
|
|
if family == socket.AF_INET6:
|
|
|
|
return
|
|
|
|
if allow_af_unspec and family == socket.AF_UNSPEC:
|
|
|
|
return
|
|
|
|
raise TestError('invalid address family %s' % (family))
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def ip_addr_pton(addr, family=None):
|
|
|
|
if addr is None:
|
|
|
|
return (None, None)
|
|
|
|
if family is not None and family is not socket.AF_UNSPEC:
|
|
|
|
Util.addr_family_check(family)
|
|
|
|
a = socket.inet_pton(family, addr)
|
|
|
|
else:
|
|
|
|
a = None
|
|
|
|
family = None
|
|
|
|
try:
|
|
|
|
a = socket.inet_pton(socket.AF_INET, addr)
|
|
|
|
family = socket.AF_INET
|
|
|
|
except:
|
|
|
|
a = socket.inet_pton(socket.AF_INET6, addr)
|
|
|
|
family = socket.AF_INET6
|
|
|
|
if Util.PY3:
|
|
|
|
a = tuple([int(c) for c in a])
|
|
|
|
else:
|
|
|
|
a = tuple([ord(c) for c in a])
|
|
|
|
return (a, family)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def ip_addr_ntop(addr, family = None):
|
|
|
|
if Util.PY3:
|
|
|
|
a = bytes(addr)
|
|
|
|
else:
|
|
|
|
a = ''.join([chr(c) for c in addr])
|
|
|
|
if len(a) == 4:
|
|
|
|
f = socket.AF_INET
|
|
|
|
elif len(a) == 16:
|
|
|
|
f = socket.AF_INET6
|
|
|
|
else:
|
|
|
|
raise TestError("Invalid binary IP address '%s'" % (repr(addr)))
|
|
|
|
if family is not None and f != family:
|
|
|
|
raise TestError("Unexpected address family. Expected %s but ip address was %s" % (family, repr(addr)))
|
|
|
|
return socket.inet_ntop(f, a)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def ip_addr_norm(addr, family = None):
|
|
|
|
a, family = Util.ip_addr_pton(addr, family)
|
|
|
|
return (Util.ip_addr_ntop(a, family), family)
|
|
|
|
|
|
|
|
@staticmethod
|
2018-07-11 15:53:30 +00:00
|
|
|
def ip4_addr_be32(addr):
|
|
|
|
# return the IPv4 address as 32 bit integer in network byte order
|
|
|
|
# (big endian).
|
2018-06-06 18:28:17 +00:00
|
|
|
a, family = Util.ip_addr_pton(addr, socket.AF_INET)
|
|
|
|
n = 0
|
|
|
|
for i in range(4):
|
|
|
|
n = (n << 8) + a[i]
|
|
|
|
return socket.htonl(n)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def ip6_addr_ay(addr):
|
|
|
|
return Util.ip_addr_pton(addr, socket.AF_INET6)[0]
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def ip_net_parse(net, family = None):
|
|
|
|
parts = net.split('/')
|
|
|
|
if len(parts) != 2:
|
|
|
|
raise TestError("Invalid IP network '%s' has not '/' for the prefix length" % (net))
|
|
|
|
prefix = int(parts[1])
|
|
|
|
addr, family = Util.ip_addr_norm(parts[0], family)
|
|
|
|
if family == socket.AF_INET:
|
|
|
|
if prefix < 0 or prefix > 32:
|
|
|
|
raise TestError("Invalid prefix length for IPv4 address '%s'" % (net))
|
|
|
|
else:
|
|
|
|
if prefix < 0 or prefix > 128:
|
|
|
|
raise TestError("Invalid prefix length for IPv4 address '%s'" % (net))
|
|
|
|
return (addr, prefix, family)
|
|
|
|
|
clients/tests: seed generated numbers for test-networkmanager-service.py
At several places, "test-networkmanager-service.py" uses generated numbers
with a defined seed. For example, generated connection's UUID is
generated in a predictable, but randomized way (if you forgive the
inprecise use of the word "random" in context of using a deterministic
seed).
Aside the connection's UUID, this becomes more interesting in the next commit
where the stub server generates a list of IP and DHCP settings in a predictable
randomized way.
For "clients/tests" we spawn the test service multiple times, but also
create similar environments by calling init_001(). This is done for
convenience, where out of lazyness all the tests share one setup. But it's
still a good idea that these tests generate slightly different setups,
wherever applicable. this increases the possible setups which get tested.
For example, the number of static IPv4 addresses (the following commit) is
interested to explicitly test for zero or a non-zero number of
addresses. If all tests happen to use the same seed, the tests are expected
to also generate the same number of addresses, and we miss an opportunity to
hit interesting test cases.
There is still no guarantee that all interesting cases are hit, the chances are just
better. The approach of generating the setup randomly, does not preclude that
the stub-server allows to explicitly configure the setup. However, due to the
sheer number of combinations that might be interesting to test, it's much simpler
to rely on some randomization and have the justifid hope we catch interesting cases.
Also in terms of runtime of the test, the cli unit tests should complete within
few seconds. Testing every combination would result in huge tests and long runtimes.
Also, the patch refactors generating random numbers in
"test-networkmanager-service.py". For example, it introduces
Util.RandomSeed(), which can be used to generate a sequence of different
random numbers. It works by having an internal state and a counter which is
combined to chain the seed and generate different numbers on each call.
2018-06-07 15:42:31 +00:00
|
|
|
class RandomSeed():
|
|
|
|
def __init__(self, seed):
|
|
|
|
self.cnt = 0
|
|
|
|
self.seed = str(seed)
|
|
|
|
def _next(self):
|
|
|
|
c = self.cnt
|
|
|
|
self.cnt += 1
|
|
|
|
return self.seed + '-' + str(c)
|
|
|
|
@staticmethod
|
|
|
|
def wrap(seed):
|
|
|
|
if seed is None:
|
|
|
|
return None
|
|
|
|
if isinstance(seed, Util.RandomSeed):
|
|
|
|
return seed
|
|
|
|
return Util.RandomSeed(seed)
|
|
|
|
@staticmethod
|
|
|
|
def get(seed, extra_seed = None):
|
|
|
|
if seed is None:
|
|
|
|
return None
|
|
|
|
if isinstance(seed, Util.RandomSeed):
|
|
|
|
seed = seed._next()
|
|
|
|
else:
|
|
|
|
seed = str(seed)
|
|
|
|
if extra_seed is None:
|
|
|
|
try:
|
|
|
|
extra_seed = Util.RandomSeed._extra_seed
|
|
|
|
except:
|
|
|
|
extra_seed = os.environ.get('NM_TEST_NETWORKMANAGER_SERVICE_SEED', '')
|
|
|
|
Util.RandomSeed._extra_seed = extra_seed
|
|
|
|
return extra_seed + seed
|
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
@staticmethod
|
clients/tests: seed generated numbers for test-networkmanager-service.py
At several places, "test-networkmanager-service.py" uses generated numbers
with a defined seed. For example, generated connection's UUID is
generated in a predictable, but randomized way (if you forgive the
inprecise use of the word "random" in context of using a deterministic
seed).
Aside the connection's UUID, this becomes more interesting in the next commit
where the stub server generates a list of IP and DHCP settings in a predictable
randomized way.
For "clients/tests" we spawn the test service multiple times, but also
create similar environments by calling init_001(). This is done for
convenience, where out of lazyness all the tests share one setup. But it's
still a good idea that these tests generate slightly different setups,
wherever applicable. this increases the possible setups which get tested.
For example, the number of static IPv4 addresses (the following commit) is
interested to explicitly test for zero or a non-zero number of
addresses. If all tests happen to use the same seed, the tests are expected
to also generate the same number of addresses, and we miss an opportunity to
hit interesting test cases.
There is still no guarantee that all interesting cases are hit, the chances are just
better. The approach of generating the setup randomly, does not preclude that
the stub-server allows to explicitly configure the setup. However, due to the
sheer number of combinations that might be interesting to test, it's much simpler
to rely on some randomization and have the justifid hope we catch interesting cases.
Also in terms of runtime of the test, the cli unit tests should complete within
few seconds. Testing every combination would result in huge tests and long runtimes.
Also, the patch refactors generating random numbers in
"test-networkmanager-service.py". For example, it introduces
Util.RandomSeed(), which can be used to generate a sequence of different
random numbers. It works by having an internal state and a counter which is
combined to chain the seed and generate different numbers on each call.
2018-06-07 15:42:31 +00:00
|
|
|
def random_stream(seed, length = None):
|
|
|
|
seed = Util.RandomSeed.wrap(seed)
|
|
|
|
# generates a stream of integers, in the range [0..255]
|
|
|
|
if seed is None:
|
|
|
|
# without a seed, we generate new random numbers.
|
|
|
|
while length is None or length > 0:
|
|
|
|
yield random.randint(0, 255)
|
|
|
|
if length is not None:
|
|
|
|
length -= 1
|
|
|
|
return
|
2018-05-14 12:22:09 +00:00
|
|
|
v = None
|
|
|
|
while length is None or length > 0:
|
|
|
|
if not v:
|
clients/tests: seed generated numbers for test-networkmanager-service.py
At several places, "test-networkmanager-service.py" uses generated numbers
with a defined seed. For example, generated connection's UUID is
generated in a predictable, but randomized way (if you forgive the
inprecise use of the word "random" in context of using a deterministic
seed).
Aside the connection's UUID, this becomes more interesting in the next commit
where the stub server generates a list of IP and DHCP settings in a predictable
randomized way.
For "clients/tests" we spawn the test service multiple times, but also
create similar environments by calling init_001(). This is done for
convenience, where out of lazyness all the tests share one setup. But it's
still a good idea that these tests generate slightly different setups,
wherever applicable. this increases the possible setups which get tested.
For example, the number of static IPv4 addresses (the following commit) is
interested to explicitly test for zero or a non-zero number of
addresses. If all tests happen to use the same seed, the tests are expected
to also generate the same number of addresses, and we miss an opportunity to
hit interesting test cases.
There is still no guarantee that all interesting cases are hit, the chances are just
better. The approach of generating the setup randomly, does not preclude that
the stub-server allows to explicitly configure the setup. However, due to the
sheer number of combinations that might be interesting to test, it's much simpler
to rely on some randomization and have the justifid hope we catch interesting cases.
Also in terms of runtime of the test, the cli unit tests should complete within
few seconds. Testing every combination would result in huge tests and long runtimes.
Also, the patch refactors generating random numbers in
"test-networkmanager-service.py". For example, it introduces
Util.RandomSeed(), which can be used to generate a sequence of different
random numbers. It works by having an internal state and a counter which is
combined to chain the seed and generate different numbers on each call.
2018-06-07 15:42:31 +00:00
|
|
|
s = Util.RandomSeed.get(seed)
|
2018-05-14 12:22:09 +00:00
|
|
|
s = s.encode('utf8')
|
|
|
|
v = hashlib.sha256(s).hexdigest()
|
|
|
|
yield int(v[0:2], 16)
|
|
|
|
v = v[2:]
|
|
|
|
if length is not None:
|
|
|
|
length -= 1
|
|
|
|
|
|
|
|
@staticmethod
|
clients/tests: seed generated numbers for test-networkmanager-service.py
At several places, "test-networkmanager-service.py" uses generated numbers
with a defined seed. For example, generated connection's UUID is
generated in a predictable, but randomized way (if you forgive the
inprecise use of the word "random" in context of using a deterministic
seed).
Aside the connection's UUID, this becomes more interesting in the next commit
where the stub server generates a list of IP and DHCP settings in a predictable
randomized way.
For "clients/tests" we spawn the test service multiple times, but also
create similar environments by calling init_001(). This is done for
convenience, where out of lazyness all the tests share one setup. But it's
still a good idea that these tests generate slightly different setups,
wherever applicable. this increases the possible setups which get tested.
For example, the number of static IPv4 addresses (the following commit) is
interested to explicitly test for zero or a non-zero number of
addresses. If all tests happen to use the same seed, the tests are expected
to also generate the same number of addresses, and we miss an opportunity to
hit interesting test cases.
There is still no guarantee that all interesting cases are hit, the chances are just
better. The approach of generating the setup randomly, does not preclude that
the stub-server allows to explicitly configure the setup. However, due to the
sheer number of combinations that might be interesting to test, it's much simpler
to rely on some randomization and have the justifid hope we catch interesting cases.
Also in terms of runtime of the test, the cli unit tests should complete within
few seconds. Testing every combination would result in huge tests and long runtimes.
Also, the patch refactors generating random numbers in
"test-networkmanager-service.py". For example, it introduces
Util.RandomSeed(), which can be used to generate a sequence of different
random numbers. It works by having an internal state and a counter which is
combined to chain the seed and generate different numbers on each call.
2018-06-07 15:42:31 +00:00
|
|
|
def random_int(seed, v_start = _DEFAULT_ARG, v_end = _DEFAULT_ARG):
|
|
|
|
# - if neither start not end is give, return a number in the range
|
|
|
|
# u32 range [0, 0xFFFFFFFF]
|
|
|
|
# - if only start is given (the first argument), interpret it as
|
|
|
|
# the range of the interval. That is, return random number in
|
|
|
|
# range [0, start-1]
|
|
|
|
# - if end and start is given, return a random number with this
|
|
|
|
# range (inclusive!): [start, end]
|
|
|
|
if v_end is _DEFAULT_ARG:
|
|
|
|
# if only one edge is provided (no v_end), then the range
|
|
|
|
# is [0, v_start[. That is, random_int(seed, 5), returns
|
|
|
|
# values from 0 to 4.
|
|
|
|
if v_start is _DEFAULT_ARG:
|
|
|
|
# by default, return a 32u integer.
|
|
|
|
v_end = 0x100000000
|
|
|
|
else:
|
|
|
|
v_end = v_start
|
|
|
|
v_start = 0
|
|
|
|
else:
|
|
|
|
if v_start is _DEFAULT_ARG:
|
|
|
|
raise TestError("Cannot specify end without start")
|
|
|
|
# if a full range is provided, v_end is included.
|
|
|
|
# random_int(seed, 0, 4) returns values from 0 to 4.
|
|
|
|
v_end += 1
|
2018-05-14 12:22:09 +00:00
|
|
|
n = 0
|
|
|
|
span = v_end - v_start
|
clients/tests: seed generated numbers for test-networkmanager-service.py
At several places, "test-networkmanager-service.py" uses generated numbers
with a defined seed. For example, generated connection's UUID is
generated in a predictable, but randomized way (if you forgive the
inprecise use of the word "random" in context of using a deterministic
seed).
Aside the connection's UUID, this becomes more interesting in the next commit
where the stub server generates a list of IP and DHCP settings in a predictable
randomized way.
For "clients/tests" we spawn the test service multiple times, but also
create similar environments by calling init_001(). This is done for
convenience, where out of lazyness all the tests share one setup. But it's
still a good idea that these tests generate slightly different setups,
wherever applicable. this increases the possible setups which get tested.
For example, the number of static IPv4 addresses (the following commit) is
interested to explicitly test for zero or a non-zero number of
addresses. If all tests happen to use the same seed, the tests are expected
to also generate the same number of addresses, and we miss an opportunity to
hit interesting test cases.
There is still no guarantee that all interesting cases are hit, the chances are just
better. The approach of generating the setup randomly, does not preclude that
the stub-server allows to explicitly configure the setup. However, due to the
sheer number of combinations that might be interesting to test, it's much simpler
to rely on some randomization and have the justifid hope we catch interesting cases.
Also in terms of runtime of the test, the cli unit tests should complete within
few seconds. Testing every combination would result in huge tests and long runtimes.
Also, the patch refactors generating random numbers in
"test-networkmanager-service.py". For example, it introduces
Util.RandomSeed(), which can be used to generate a sequence of different
random numbers. It works by having an internal state and a counter which is
combined to chain the seed and generate different numbers on each call.
2018-06-07 15:42:31 +00:00
|
|
|
assert span > 0
|
|
|
|
for r in Util.random_stream(seed):
|
2018-05-14 12:22:09 +00:00
|
|
|
n = n * 256 + r
|
|
|
|
if n > span:
|
|
|
|
break
|
|
|
|
return v_start + (n % span)
|
|
|
|
|
|
|
|
@staticmethod
|
clients/tests: seed generated numbers for test-networkmanager-service.py
At several places, "test-networkmanager-service.py" uses generated numbers
with a defined seed. For example, generated connection's UUID is
generated in a predictable, but randomized way (if you forgive the
inprecise use of the word "random" in context of using a deterministic
seed).
Aside the connection's UUID, this becomes more interesting in the next commit
where the stub server generates a list of IP and DHCP settings in a predictable
randomized way.
For "clients/tests" we spawn the test service multiple times, but also
create similar environments by calling init_001(). This is done for
convenience, where out of lazyness all the tests share one setup. But it's
still a good idea that these tests generate slightly different setups,
wherever applicable. this increases the possible setups which get tested.
For example, the number of static IPv4 addresses (the following commit) is
interested to explicitly test for zero or a non-zero number of
addresses. If all tests happen to use the same seed, the tests are expected
to also generate the same number of addresses, and we miss an opportunity to
hit interesting test cases.
There is still no guarantee that all interesting cases are hit, the chances are just
better. The approach of generating the setup randomly, does not preclude that
the stub-server allows to explicitly configure the setup. However, due to the
sheer number of combinations that might be interesting to test, it's much simpler
to rely on some randomization and have the justifid hope we catch interesting cases.
Also in terms of runtime of the test, the cli unit tests should complete within
few seconds. Testing every combination would result in huge tests and long runtimes.
Also, the patch refactors generating random numbers in
"test-networkmanager-service.py". For example, it introduces
Util.RandomSeed(), which can be used to generate a sequence of different
random numbers. It works by having an internal state and a counter which is
combined to chain the seed and generate different numbers on each call.
2018-06-07 15:42:31 +00:00
|
|
|
def random_bool(seed):
|
|
|
|
return Util.random_int(seed, 0, 1) == 1
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def random_subset(seed, all_set):
|
|
|
|
all_set = list(all_set)
|
|
|
|
result = []
|
|
|
|
seed = Util.RandomSeed.wrap(seed)
|
|
|
|
for i in list(range(Util.random_int(Util.RandomSeed.get(seed), len(all_set) + 1))):
|
|
|
|
idx = Util.random_int(Util.RandomSeed.get(seed), len(all_set))
|
|
|
|
result.append(all_set[idx])
|
|
|
|
del all_set[idx]
|
|
|
|
return result
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def random_mac(seed):
|
|
|
|
return '%02X:%02X:%02X:%02X:%02X:%02X' % tuple(Util.random_stream(seed, 6))
|
2014-01-09 21:19:07 +00:00
|
|
|
|
2018-06-06 18:28:17 +00:00
|
|
|
@staticmethod
|
|
|
|
def random_ip(seed, net = None, family = None):
|
|
|
|
if net is not None:
|
|
|
|
mask, prefix, family = Util.ip_net_parse(net, family)
|
|
|
|
a_mask, unused = Util.ip_addr_pton(mask, family)
|
|
|
|
else:
|
|
|
|
prefix = None
|
|
|
|
Util.addr_family_check(family)
|
|
|
|
if family == socket.AF_INET:
|
|
|
|
l = 4
|
|
|
|
else:
|
|
|
|
l = 16
|
|
|
|
a = tuple(Util.random_stream(seed, l))
|
|
|
|
if prefix is not None:
|
|
|
|
a2 = []
|
|
|
|
for i in range(l):
|
|
|
|
if prefix == 0:
|
|
|
|
c = a[i]
|
|
|
|
elif prefix >= 8:
|
|
|
|
c = a_mask[i]
|
|
|
|
prefix -= 8
|
|
|
|
else:
|
|
|
|
c = 0xFF & (0xFF << (8 - prefix))
|
|
|
|
c = (a[i] & ~c) | (a_mask[i] & c)
|
|
|
|
prefix = 0
|
|
|
|
a2.append(c)
|
|
|
|
a = tuple(a2)
|
|
|
|
return (Util.ip_addr_ntop(a, family), family)
|
|
|
|
|
2018-06-04 18:33:35 +00:00
|
|
|
@staticmethod
|
|
|
|
def eprint(*args, **kwargs):
|
|
|
|
print(*args, file=sys.stderr, **kwargs)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def variant_from_dbus(val):
|
|
|
|
if isinstance(val, (dbus.String, str)):
|
|
|
|
return GLib.Variant('s', str(val))
|
|
|
|
if isinstance(val, dbus.UInt32):
|
|
|
|
return GLib.Variant('u', int(val))
|
|
|
|
if isinstance(val, dbus.Boolean):
|
|
|
|
return GLib.Variant('b', bool(val))
|
|
|
|
if isinstance(val, dbus.Byte):
|
|
|
|
return GLib.Variant('y', int(val))
|
|
|
|
if isinstance(val, dbus.Array):
|
|
|
|
try:
|
|
|
|
if val.signature == 's':
|
|
|
|
return GLib.Variant('as', [Util.variant_from_dbus(x) for x in val])
|
|
|
|
if val.signature == 'b':
|
|
|
|
return GLib.Variant('ab', [Util.variant_from_dbus(x) for x in val])
|
|
|
|
if val.signature == 'y':
|
|
|
|
return GLib.Variant('ay', [int(x) for x in val])
|
|
|
|
if val.signature == 'u':
|
|
|
|
return GLib.Variant('au', [Util.variant_from_dbus(x) for x in val])
|
|
|
|
if val.signature == 'ay':
|
|
|
|
return GLib.Variant('aay', [Util.variant_from_dbus(x) for x in val])
|
|
|
|
if val.signature == 'au':
|
|
|
|
return GLib.Variant('aau', [Util.variant_from_dbus(x) for x in val])
|
|
|
|
if val.signature == 'a{sv}':
|
2018-06-05 09:26:03 +00:00
|
|
|
return GLib.Variant('aa{sv}', [collections.OrderedDict([(str(k), Util.variant_from_dbus(v)) for k, v in addr.items()]) for addr in val])
|
2018-06-04 18:33:35 +00:00
|
|
|
if val.signature == '(ayuay)':
|
|
|
|
return GLib.Variant('a(ayuay)', [Util.variant_from_dbus(x) for x in val])
|
|
|
|
if val.signature == '(ayuayu)':
|
|
|
|
return GLib.Variant('a(ayuayu)', [Util.variant_from_dbus(x) for x in val])
|
|
|
|
except Exception as e:
|
|
|
|
raise Exception("Cannot convert array element to type '%s': %s" % (val.signature, e.message))
|
|
|
|
if isinstance(val, dbus.Dictionary):
|
|
|
|
if val.signature == 'ss':
|
|
|
|
return GLib.Variant('a{ss}', collections.OrderedDict([(str(k), str(v)) for k, v in val.items()]))
|
|
|
|
if val.signature == 'sv':
|
|
|
|
return GLib.Variant('a{sv}', collections.OrderedDict([(str(k), Util.variant_from_dbus(v)) for k, v in val.items()]))
|
|
|
|
if val.signature == 'sa{sv}':
|
|
|
|
c = collections.OrderedDict([
|
|
|
|
(str(key1),
|
|
|
|
collections.OrderedDict([(str(key2), Util.variant_from_dbus(arr2)) for key2, arr2 in arr1.items()])
|
|
|
|
) for key1, arr1 in val.items()
|
|
|
|
])
|
|
|
|
return GLib.Variant('a{sa{sv}}', c)
|
|
|
|
|
|
|
|
raise Exception("Unsupported type for value '%s'" % (repr(val)))
|
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
###############################################################################
|
2014-01-09 21:19:07 +00:00
|
|
|
|
2018-06-05 08:51:16 +00:00
|
|
|
IFACE_DBUS = 'org.freedesktop.DBus'
|
2018-06-06 18:28:17 +00:00
|
|
|
IFACE_OBJECT_MANAGER = 'org.freedesktop.DBus.ObjectManager'
|
2018-06-05 08:51:16 +00:00
|
|
|
IFACE_CONNECTION = 'org.freedesktop.NetworkManager.Settings.Connection'
|
|
|
|
IFACE_DEVICE = 'org.freedesktop.NetworkManager.Device'
|
|
|
|
IFACE_WIFI = 'org.freedesktop.NetworkManager.Device.Wireless'
|
|
|
|
IFACE_WIMAX = 'org.freedesktop.NetworkManager.Device.WiMax'
|
|
|
|
IFACE_TEST = 'org.freedesktop.NetworkManager.LibnmGlibTest'
|
|
|
|
IFACE_NM = 'org.freedesktop.NetworkManager'
|
|
|
|
IFACE_SETTINGS = 'org.freedesktop.NetworkManager.Settings'
|
|
|
|
IFACE_AGENT_MANAGER = 'org.freedesktop.NetworkManager.AgentManager'
|
|
|
|
IFACE_AGENT = 'org.freedesktop.NetworkManager.SecretAgent'
|
|
|
|
IFACE_WIRED = 'org.freedesktop.NetworkManager.Device.Wired'
|
|
|
|
IFACE_VLAN = 'org.freedesktop.NetworkManager.Device.Vlan'
|
|
|
|
IFACE_WIFI_AP = 'org.freedesktop.NetworkManager.AccessPoint'
|
|
|
|
IFACE_WIMAX_NSP = 'org.freedesktop.NetworkManager.WiMax.Nsp'
|
|
|
|
IFACE_ACTIVE_CONNECTION = 'org.freedesktop.NetworkManager.Connection.Active'
|
2018-06-05 18:23:31 +00:00
|
|
|
IFACE_VPN_CONNECTION = 'org.freedesktop.NetworkManager.VPN.Connection'
|
2018-06-05 08:51:16 +00:00
|
|
|
IFACE_DNS_MANAGER = 'org.freedesktop.NetworkManager.DnsManager'
|
2018-06-06 18:28:17 +00:00
|
|
|
IFACE_IP4_CONFIG = 'org.freedesktop.NetworkManager.IP4Config'
|
|
|
|
IFACE_IP6_CONFIG = 'org.freedesktop.NetworkManager.IP6Config'
|
|
|
|
IFACE_DHCP4_CONFIG = 'org.freedesktop.NetworkManager.DHCP4Config'
|
|
|
|
IFACE_DHCP6_CONFIG = 'org.freedesktop.NetworkManager.DHCP6Config'
|
2018-06-05 08:51:16 +00:00
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
2018-06-05 08:51:16 +00:00
|
|
|
class BusErr:
|
2018-06-05 08:51:16 +00:00
|
|
|
|
2018-06-05 08:51:16 +00:00
|
|
|
class UnknownInterfaceException(dbus.DBusException):
|
|
|
|
_dbus_error_name = IFACE_DBUS + '.UnknownInterface'
|
2018-06-05 08:51:16 +00:00
|
|
|
|
2018-06-05 08:51:16 +00:00
|
|
|
class UnknownPropertyException(dbus.DBusException):
|
|
|
|
_dbus_error_name = IFACE_DBUS + '.UnknownProperty'
|
2018-06-05 08:51:16 +00:00
|
|
|
|
2018-06-05 08:51:16 +00:00
|
|
|
class InvalidPropertyException(dbus.DBusException):
|
|
|
|
_dbus_error_name = IFACE_CONNECTION + '.InvalidProperty'
|
2018-06-05 08:51:16 +00:00
|
|
|
|
2018-06-05 08:51:16 +00:00
|
|
|
class MissingPropertyException(dbus.DBusException):
|
|
|
|
_dbus_error_name = IFACE_CONNECTION + '.MissingProperty'
|
2018-06-05 08:51:16 +00:00
|
|
|
|
2018-06-05 08:51:16 +00:00
|
|
|
class InvalidSettingException(dbus.DBusException):
|
|
|
|
_dbus_error_name = IFACE_CONNECTION + '.InvalidSetting'
|
2018-06-05 08:51:16 +00:00
|
|
|
|
2018-06-05 08:51:16 +00:00
|
|
|
class MissingSettingException(dbus.DBusException):
|
|
|
|
_dbus_error_name = IFACE_CONNECTION + '.MissingSetting'
|
2018-06-05 08:51:16 +00:00
|
|
|
|
2018-06-05 08:51:16 +00:00
|
|
|
class NotSoftwareException(dbus.DBusException):
|
|
|
|
_dbus_error_name = IFACE_DEVICE + '.NotSoftware'
|
2018-06-05 08:51:16 +00:00
|
|
|
|
2018-06-05 08:51:16 +00:00
|
|
|
class ApNotFoundException(dbus.DBusException):
|
|
|
|
_dbus_error_name = IFACE_WIFI + '.AccessPointNotFound'
|
2018-06-05 08:51:16 +00:00
|
|
|
|
2018-06-05 08:51:16 +00:00
|
|
|
class NspNotFoundException(dbus.DBusException):
|
|
|
|
_dbus_error_name = IFACE_WIMAX + '.NspNotFound'
|
2018-06-05 08:51:16 +00:00
|
|
|
|
2018-06-05 08:51:16 +00:00
|
|
|
class PermissionDeniedException(dbus.DBusException):
|
|
|
|
_dbus_error_name = IFACE_NM + '.PermissionDenied'
|
2018-06-05 08:51:16 +00:00
|
|
|
|
2018-06-05 08:51:16 +00:00
|
|
|
class UnknownDeviceException(dbus.DBusException):
|
|
|
|
_dbus_error_name = IFACE_NM + '.UnknownDevice'
|
2018-06-05 08:51:16 +00:00
|
|
|
|
2018-06-05 08:51:16 +00:00
|
|
|
class UnknownConnectionException(dbus.DBusException):
|
|
|
|
_dbus_error_name = IFACE_NM + '.UnknownConnection'
|
2018-06-05 08:51:16 +00:00
|
|
|
|
2018-06-05 08:51:16 +00:00
|
|
|
class InvalidHostnameException(dbus.DBusException):
|
|
|
|
_dbus_error_name = IFACE_SETTINGS + '.InvalidHostname'
|
2018-06-05 08:51:16 +00:00
|
|
|
|
2018-06-05 08:51:16 +00:00
|
|
|
class NoSecretsException(dbus.DBusException):
|
|
|
|
_dbus_error_name = IFACE_AGENT_MANAGER + '.NoSecrets'
|
|
|
|
|
|
|
|
class UserCanceledException(dbus.DBusException):
|
|
|
|
_dbus_error_name = IFACE_AGENT_MANAGER + '.UserCanceled'
|
2018-06-05 08:51:16 +00:00
|
|
|
|
2018-06-04 18:33:35 +00:00
|
|
|
@staticmethod
|
|
|
|
def from_nmerror(e):
|
|
|
|
try:
|
|
|
|
domain, code = (e.domain, e.code)
|
|
|
|
except:
|
|
|
|
return None
|
|
|
|
if domain == GLib.quark_to_string(NM.ConnectionError.quark()):
|
|
|
|
if code == NM.ConnectionError.MISSINGSETTING:
|
|
|
|
return BusErr.MissingSettingException(e.message)
|
|
|
|
if code == NM.ConnectionError.INVALIDPROPERTY:
|
|
|
|
return BusErr.InvalidPropertyException(e.message)
|
|
|
|
return None
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def raise_nmerror(e):
|
|
|
|
e2 = BusErr.from_nmerror(e)
|
|
|
|
if e2 is not None:
|
|
|
|
raise e2
|
|
|
|
raise e
|
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
class NmUtil:
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def con_hash_to_connection(con_hash, do_verify = False, do_normalize = False):
|
|
|
|
|
|
|
|
x_con = []
|
|
|
|
for v_setting_name, v_setting in list(con_hash.items()):
|
|
|
|
if isinstance(v_setting_name, (dbus.String, str)):
|
|
|
|
v_setting_name = str(v_setting_name)
|
|
|
|
else:
|
|
|
|
raise Exception("Expected string dict, but got '%s' key" % (v_setting_name))
|
|
|
|
x_setting = []
|
|
|
|
for v_property_name, v_value in list(v_setting.items()):
|
|
|
|
if isinstance(v_property_name, (dbus.String, str)):
|
|
|
|
v_property_name = str(v_property_name)
|
|
|
|
else:
|
|
|
|
raise Exception("Expected string dict, but got '%s' subkey under %s (%s)" % (v_property_name, v_setting_name, repr(con_hash)))
|
|
|
|
try:
|
|
|
|
v = Util.variant_from_dbus(v_value)
|
|
|
|
except Exception as e:
|
|
|
|
raise Exception("Unsupported value %s.%s = %s (%s)" % (v_setting_name, v_property_name, v_value, str(e)))
|
|
|
|
x_setting.append((v_property_name, v))
|
|
|
|
|
|
|
|
x_con.append((v_setting_name, collections.OrderedDict(x_setting)))
|
|
|
|
|
|
|
|
x_con = GLib.Variant('a{sa{sv}}', collections.OrderedDict(x_con))
|
|
|
|
|
|
|
|
assert GLib.Variant.equal(x_con, Util.variant_from_dbus(con_hash))
|
|
|
|
|
|
|
|
try:
|
|
|
|
con = NM.SimpleConnection.new_from_dbus(x_con)
|
|
|
|
except:
|
|
|
|
if do_verify:
|
|
|
|
raise
|
|
|
|
return None
|
|
|
|
|
|
|
|
if do_normalize:
|
|
|
|
try:
|
|
|
|
con.normalize()
|
|
|
|
except:
|
|
|
|
if do_verify:
|
|
|
|
raise
|
|
|
|
|
|
|
|
if do_verify:
|
|
|
|
con.verify()
|
|
|
|
|
|
|
|
return con
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def con_hash_verify(con_hash, do_verify_strict = True):
|
|
|
|
if NM.SETTING_CONNECTION_SETTING_NAME not in con_hash:
|
|
|
|
raise BusErr.MissingSettingException('connection: setting is required')
|
|
|
|
s_con = con_hash[NM.SETTING_CONNECTION_SETTING_NAME]
|
|
|
|
if NM.SETTING_CONNECTION_TYPE not in s_con:
|
|
|
|
raise BusErr.MissingPropertyException('connection.type: property is required')
|
|
|
|
if NM.SETTING_CONNECTION_UUID not in s_con:
|
|
|
|
raise BusErr.MissingPropertyException('connection.uuid: property is required')
|
|
|
|
if NM.SETTING_CONNECTION_ID not in s_con:
|
|
|
|
raise BusErr.MissingPropertyException('connection.id: property is required')
|
|
|
|
|
|
|
|
if not do_verify_strict:
|
|
|
|
return;
|
|
|
|
t = s_con[NM.SETTING_CONNECTION_TYPE]
|
|
|
|
if t not in [ NM.SETTING_WIRED_SETTING_NAME,
|
|
|
|
NM.SETTING_WIRELESS_SETTING_NAME,
|
|
|
|
NM.SETTING_VLAN_SETTING_NAME,
|
2018-06-05 18:23:31 +00:00
|
|
|
NM.SETTING_WIMAX_SETTING_NAME,
|
|
|
|
NM.SETTING_VPN_SETTING_NAME ]:
|
2018-06-04 18:33:35 +00:00
|
|
|
raise BusErr.InvalidPropertyException('connection.type: unsupported connection type "%s"' % (t))
|
|
|
|
|
|
|
|
try:
|
|
|
|
con_nm = NmUtil.con_hash_to_connection(con_hash, do_verify = True, do_normalize = True)
|
|
|
|
except Exception as e:
|
|
|
|
BusErr.raise_nmerror(e)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def con_hash_get_id(con_hash):
|
|
|
|
if NM.SETTING_CONNECTION_SETTING_NAME in con_hash:
|
|
|
|
s_con = con_hash[NM.SETTING_CONNECTION_SETTING_NAME]
|
|
|
|
if NM.SETTING_CONNECTION_ID in s_con:
|
|
|
|
return s_con[NM.SETTING_CONNECTION_ID]
|
|
|
|
return None
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def con_hash_get_uuid(con_hash):
|
|
|
|
if NM.SETTING_CONNECTION_SETTING_NAME in con_hash:
|
|
|
|
s_con = con_hash[NM.SETTING_CONNECTION_SETTING_NAME]
|
|
|
|
if NM.SETTING_CONNECTION_UUID in s_con:
|
|
|
|
return s_con[NM.SETTING_CONNECTION_UUID]
|
|
|
|
return None
|
|
|
|
|
2018-06-05 18:23:31 +00:00
|
|
|
@staticmethod
|
|
|
|
def con_hash_get_type(con_hash):
|
|
|
|
if NM.SETTING_CONNECTION_SETTING_NAME in con_hash:
|
|
|
|
s_con = con_hash[NM.SETTING_CONNECTION_SETTING_NAME]
|
|
|
|
if NM.SETTING_CONNECTION_TYPE in s_con:
|
|
|
|
return s_con[NM.SETTING_CONNECTION_TYPE]
|
|
|
|
return None
|
|
|
|
|
2018-06-05 08:51:16 +00:00
|
|
|
###############################################################################
|
|
|
|
|
2014-01-09 21:19:07 +00:00
|
|
|
class ExportedObj(dbus.service.Object):
|
2015-11-17 12:56:52 +00:00
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
DBusInterface = collections.namedtuple('DBusInterface', ['dbus_iface', 'props', 'legacy_prop_changed_func'])
|
2015-11-17 12:56:52 +00:00
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
@staticmethod
|
|
|
|
def create_path(klass, path_prefix = None):
|
|
|
|
if path_prefix is None:
|
|
|
|
path_prefix = klass.path_prefix
|
|
|
|
path = path_prefix + str(klass.path_counter_next)
|
|
|
|
klass.path_counter_next += 1
|
|
|
|
return path
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def to_path_array(src):
|
2018-06-14 14:01:33 +00:00
|
|
|
return dbus.Array([ExportedObj.to_path(o) for o in src] if src else [],
|
|
|
|
signature=dbus.Signature('o'))
|
2018-05-14 12:22:09 +00:00
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def to_path(src):
|
|
|
|
if src:
|
|
|
|
return dbus.ObjectPath(src.path)
|
|
|
|
return dbus.ObjectPath("/")
|
|
|
|
|
|
|
|
def __init__(self, object_path, ident = None):
|
|
|
|
dbus.service.Object.__init__(self)
|
|
|
|
|
|
|
|
self._dbus_ifaces = {}
|
|
|
|
self.path = object_path
|
2018-05-04 07:02:53 +00:00
|
|
|
|
|
|
|
# ident is an optional (unique) identifier for the instance.
|
|
|
|
# The test driver may set it to reference to the object by
|
|
|
|
# this identifier. For NetworkManager, the real ID of an
|
|
|
|
# object on D-Bus is the object_path. But that is generated
|
|
|
|
# by the stub server only after the test user created the
|
|
|
|
# object. The ident parameter may be specified by the user
|
|
|
|
# and thus can be hard-coded in the test.
|
|
|
|
if ident is None:
|
|
|
|
ident = object_path
|
|
|
|
self.ident = ident
|
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
def export(self):
|
|
|
|
self.add_to_connection(gl.bus, self.path)
|
|
|
|
gl.object_manager.add_object(self)
|
2016-09-20 12:39:55 +00:00
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
def unexport(self):
|
|
|
|
gl.object_manager.remove_object(self)
|
|
|
|
self.remove_from_connection()
|
2014-01-09 21:19:07 +00:00
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
def dbus_interface_add(self, dbus_iface, props, legacy_prop_changed_func = None):
|
|
|
|
self._dbus_ifaces[dbus_iface] = ExportedObj.DBusInterface(dbus_iface, props, legacy_prop_changed_func)
|
2014-01-09 21:19:07 +00:00
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
def _dbus_interface_get(self, dbus_iface):
|
|
|
|
if dbus_iface not in self._dbus_ifaces:
|
2018-06-05 08:51:16 +00:00
|
|
|
raise BusErr.UnknownInterfaceException()
|
2018-05-14 12:22:09 +00:00
|
|
|
return self._dbus_ifaces[dbus_iface]
|
2015-11-17 12:56:52 +00:00
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
def _dbus_interface_get_property(self, dbus_interface, propname = None):
|
|
|
|
props = dbus_interface.props
|
2015-11-17 12:56:52 +00:00
|
|
|
if propname is None:
|
|
|
|
return props
|
|
|
|
if propname not in props:
|
2018-06-05 08:51:16 +00:00
|
|
|
raise BusErr.UnknownPropertyException()
|
2015-11-17 12:56:52 +00:00
|
|
|
return props[propname]
|
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
def _dbus_property_get(self, dbus_iface, propname = None):
|
|
|
|
return self._dbus_interface_get_property(self._dbus_interface_get(dbus_iface),
|
|
|
|
propname)
|
|
|
|
|
2018-06-06 13:02:13 +00:00
|
|
|
def _dbus_property_set(self, dbus_iface, propname, value, allow_detect_dbus_iface = False, dry_run = False, force_update = False):
|
2018-05-15 14:20:00 +00:00
|
|
|
if allow_detect_dbus_iface and not dbus_iface:
|
|
|
|
props = None
|
|
|
|
for p, dbus_interface in self._dbus_ifaces.items():
|
|
|
|
if propname in dbus_interface.props:
|
|
|
|
if props is not None:
|
|
|
|
raise TestError("Cannot uniquely find the property '%s' on object '%s'" % (propname, self.path))
|
|
|
|
props = dbus_interface.props
|
|
|
|
dbus_iface = p
|
|
|
|
if props is None:
|
|
|
|
raise TestError("Cannot find the property '%s' on object '%s'" % (propname, self.path))
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
dbus_interface = self._dbus_interface_get(dbus_iface)
|
|
|
|
props = self._dbus_interface_get_property(dbus_interface)
|
|
|
|
except:
|
|
|
|
if dry_run:
|
|
|
|
raise TestError("No interface '%s' on '%s'" % (dbus_iface, self.path))
|
|
|
|
raise
|
|
|
|
|
|
|
|
if dry_run:
|
|
|
|
if propname not in props:
|
|
|
|
raise TestError("No property '%s' on '%s' on '%s'" % (propname, dbus_iface, self.path))
|
|
|
|
|
2018-06-05 18:23:31 +00:00
|
|
|
permission_granted = False
|
|
|
|
|
|
|
|
if isinstance(self, ActiveConnection):
|
|
|
|
if dbus_iface == IFACE_ACTIVE_CONNECTION:
|
|
|
|
if propname == PRP_ACTIVE_CONNECTION_STATE:
|
|
|
|
permission_granted = True
|
|
|
|
elif dbus_iface == IFACE_VPN_CONNECTION:
|
|
|
|
if propname == PRP_VPN_CONNECTION_VPN_STATE:
|
|
|
|
permission_granted = True
|
|
|
|
|
|
|
|
if not permission_granted:
|
2018-05-15 14:20:00 +00:00
|
|
|
raise TestError("Cannot set property '%s' on '%s' on '%s' via D-Bus" % (propname, dbus_iface, self.path))
|
|
|
|
|
2018-06-06 12:59:37 +00:00
|
|
|
return
|
|
|
|
|
2018-05-15 14:20:00 +00:00
|
|
|
assert propname in props
|
|
|
|
|
2018-06-06 13:02:13 +00:00
|
|
|
if not force_update:
|
|
|
|
if props[propname] == value:
|
|
|
|
return
|
|
|
|
|
2018-05-15 14:20:00 +00:00
|
|
|
props[propname] = value
|
2018-05-15 06:31:16 +00:00
|
|
|
self._dbus_property_notify(dbus_iface, propname)
|
|
|
|
|
2015-11-17 12:56:52 +00:00
|
|
|
def _dbus_property_notify(self, dbus_iface, propname):
|
2018-05-15 06:31:16 +00:00
|
|
|
dbus_interface = self._dbus_interface_get(dbus_iface)
|
|
|
|
prop = self._dbus_interface_get_property(dbus_interface, propname)
|
2018-05-14 12:22:09 +00:00
|
|
|
if propname is not None:
|
|
|
|
prop = { propname: prop }
|
|
|
|
ExportedObj.PropertiesChanged(self, dbus_iface, prop, [])
|
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
# the legacy_prop_changed_func signal is a legacy signal that got obsoleted by the standard
|
2018-05-14 12:22:09 +00:00
|
|
|
# PropertiesChanged signal. NetworkManager (and this stub) still emit it for backward
|
|
|
|
# compatibility reasons. Note that this stub server implementation gets this wrong,
|
|
|
|
# for example, it emits PropertiesChanged signal on org.freedesktop.NetworkManager.Device,
|
|
|
|
# which NetworkManager never did.
|
2018-07-17 13:41:29 +00:00
|
|
|
# See https://gitlab.freedesktop.org/NetworkManager/NetworkManager/blob/db80d5f62a1edf39c5970887ef7b9ec62dd4163f/src/nm-dbus-manager.c#L1274
|
2018-05-15 06:31:16 +00:00
|
|
|
if dbus_interface.legacy_prop_changed_func is not None:
|
|
|
|
dbus_interface.legacy_prop_changed_func(self, prop)
|
2016-09-19 15:16:00 +00:00
|
|
|
|
|
|
|
@dbus.service.signal(dbus.PROPERTIES_IFACE, signature='sa{sv}as')
|
|
|
|
def PropertiesChanged(self, iface, changed, invalidated):
|
|
|
|
pass
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='s', out_signature='a{sv}')
|
2015-11-17 12:56:52 +00:00
|
|
|
def GetAll(self, dbus_iface):
|
|
|
|
return self._dbus_property_get(dbus_iface)
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='ss', out_signature='v')
|
2015-11-17 12:56:52 +00:00
|
|
|
def Get(self, dbus_iface, name):
|
|
|
|
return self._dbus_property_get(dbus_iface, name)
|
2014-01-09 21:19:07 +00:00
|
|
|
|
2016-09-16 12:26:48 +00:00
|
|
|
def get_managed_ifaces(self):
|
|
|
|
my_ifaces = {}
|
2018-05-14 12:22:09 +00:00
|
|
|
for iface in self._dbus_ifaces:
|
2018-05-15 06:31:16 +00:00
|
|
|
my_ifaces[iface] = self._dbus_ifaces[iface].props
|
2018-05-15 19:04:22 +00:00
|
|
|
return my_ifaces
|
2016-09-16 12:26:48 +00:00
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
###############################################################################
|
2016-09-16 12:26:48 +00:00
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
PRP_DEVICE_UDI = "Udi"
|
|
|
|
PRP_DEVICE_IFACE = "Interface"
|
|
|
|
PRP_DEVICE_DRIVER = "Driver"
|
|
|
|
PRP_DEVICE_STATE = "State"
|
|
|
|
PRP_DEVICE_ACTIVE_CONNECTION = "ActiveConnection"
|
|
|
|
PRP_DEVICE_IP4_CONFIG = "Ip4Config"
|
|
|
|
PRP_DEVICE_IP6_CONFIG = "Ip6Config"
|
|
|
|
PRP_DEVICE_DHCP4_CONFIG = "Dhcp4Config"
|
|
|
|
PRP_DEVICE_DHCP6_CONFIG = "Dhcp6Config"
|
|
|
|
PRP_DEVICE_MANAGED = "Managed"
|
|
|
|
PRP_DEVICE_AUTOCONNECT = "Autoconnect"
|
|
|
|
PRP_DEVICE_DEVICE_TYPE = "DeviceType"
|
|
|
|
PRP_DEVICE_AVAILABLE_CONNECTIONS = "AvailableConnections"
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
class Device(ExportedObj):
|
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
path_counter_next = 1
|
|
|
|
path_prefix = "/org/freedesktop/NetworkManager/Devices/"
|
|
|
|
|
|
|
|
def __init__(self, iface, devtype, ident = None):
|
2018-05-04 07:02:53 +00:00
|
|
|
|
|
|
|
if ident is None:
|
|
|
|
ident = iface
|
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
ExportedObj.__init__(self, ExportedObj.create_path(Device), ident)
|
|
|
|
|
2018-06-06 18:28:17 +00:00
|
|
|
self.ip4_config = None
|
|
|
|
self.ip6_config = None
|
|
|
|
self.dhcp4_config = None
|
|
|
|
self.dhcp6_config = None
|
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
props = {
|
|
|
|
PRP_DEVICE_UDI: "/sys/devices/virtual/%s" % (iface),
|
|
|
|
PRP_DEVICE_IFACE: iface,
|
|
|
|
PRP_DEVICE_DRIVER: "virtual",
|
|
|
|
PRP_DEVICE_STATE: dbus.UInt32(NM.DeviceState.UNAVAILABLE),
|
|
|
|
PRP_DEVICE_ACTIVE_CONNECTION: ExportedObj.to_path(None),
|
2018-06-06 18:28:17 +00:00
|
|
|
PRP_DEVICE_IP4_CONFIG: ExportedObj.to_path(self.ip4_config),
|
|
|
|
PRP_DEVICE_IP6_CONFIG: ExportedObj.to_path(self.ip6_config),
|
|
|
|
PRP_DEVICE_DHCP4_CONFIG: ExportedObj.to_path(self.dhcp4_config),
|
|
|
|
PRP_DEVICE_DHCP6_CONFIG: ExportedObj.to_path(self.dhcp6_config),
|
2018-05-15 06:31:16 +00:00
|
|
|
PRP_DEVICE_MANAGED: True,
|
|
|
|
PRP_DEVICE_AUTOCONNECT: True,
|
|
|
|
PRP_DEVICE_DEVICE_TYPE: dbus.UInt32(devtype),
|
|
|
|
PRP_DEVICE_AVAILABLE_CONNECTIONS: ExportedObj.to_path_array([]),
|
|
|
|
}
|
|
|
|
|
|
|
|
self.dbus_interface_add(IFACE_DEVICE, props, Device.PropertiesChanged)
|
2014-01-09 21:19:07 +00:00
|
|
|
|
2018-06-06 18:28:17 +00:00
|
|
|
def start(self):
|
|
|
|
self.ip4_config = IP4Config()
|
|
|
|
self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_IP4_CONFIG, ExportedObj.to_path(self.ip4_config))
|
|
|
|
self.ip6_config = IP6Config()
|
|
|
|
self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_IP6_CONFIG, ExportedObj.to_path(self.ip6_config))
|
|
|
|
self.dhcp4_config = Dhcp4Config()
|
|
|
|
self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_DHCP4_CONFIG, ExportedObj.to_path(self.dhcp4_config))
|
|
|
|
self.dhcp6_config = Dhcp6Config()
|
|
|
|
self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_DHCP6_CONFIG, ExportedObj.to_path(self.dhcp6_config))
|
|
|
|
|
|
|
|
def stop(self):
|
|
|
|
self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_IP4_CONFIG, ExportedObj.to_path(None))
|
|
|
|
if self.ip4_config is not None:
|
|
|
|
self.ip4_config.unexport()
|
|
|
|
self.ip4_config = None
|
|
|
|
self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_IP6_CONFIG, ExportedObj.to_path(None))
|
|
|
|
if self.ip6_config is not None:
|
|
|
|
self.ip6_config.unexport()
|
|
|
|
self.ip6_config = None
|
|
|
|
self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_DHCP4_CONFIG, ExportedObj.to_path(None))
|
|
|
|
if self.dhcp4_config is not None:
|
|
|
|
self.dhcp4_config.unexport()
|
|
|
|
self.dhcp4_config = None
|
|
|
|
self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_DHCP6_CONFIG, ExportedObj.to_path(None))
|
|
|
|
if self.dhcp6_config is not None:
|
|
|
|
self.dhcp6_config.unexport()
|
|
|
|
self.dhcp6_config = None
|
|
|
|
|
2014-01-09 21:19:07 +00:00
|
|
|
@dbus.service.method(dbus_interface=IFACE_DEVICE, in_signature='', out_signature='')
|
|
|
|
def Disconnect(self):
|
|
|
|
pass
|
|
|
|
|
2014-10-15 17:47:29 +00:00
|
|
|
@dbus.service.method(dbus_interface=IFACE_DEVICE, in_signature='', out_signature='')
|
|
|
|
def Delete(self):
|
|
|
|
# We don't currently support any software device types, so...
|
2018-06-05 08:51:16 +00:00
|
|
|
raise BusErr.NotSoftwareException()
|
2014-10-15 17:47:29 +00:00
|
|
|
pass
|
|
|
|
|
2014-01-09 21:19:07 +00:00
|
|
|
@dbus.service.signal(IFACE_DEVICE, signature='a{sv}')
|
|
|
|
def PropertiesChanged(self, changed):
|
|
|
|
pass
|
|
|
|
|
2014-10-06 17:35:03 +00:00
|
|
|
def set_active_connection(self, ac):
|
2018-05-15 06:31:16 +00:00
|
|
|
self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_ACTIVE_CONNECTION, ac)
|
2014-01-09 21:19:07 +00:00
|
|
|
|
2018-06-06 13:02:13 +00:00
|
|
|
def connection_is_available(self, con_inst):
|
|
|
|
if con_inst.is_vpn():
|
|
|
|
return False
|
|
|
|
if isinstance(self, WiredDevice):
|
|
|
|
if con_inst.get_type() == NM.SETTING_WIRED_SETTING_NAME:
|
|
|
|
return True
|
|
|
|
elif isinstance(self, WifiDevice):
|
|
|
|
if con_inst.get_type() == NM.SETTING_WIRELESS_SETTING_NAME:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def available_connections_get(self):
|
2018-06-14 14:01:33 +00:00
|
|
|
return [c for c in gl.settings.get_connections() if self.connection_is_available(c)]
|
2018-06-06 13:02:13 +00:00
|
|
|
|
|
|
|
def available_connections_update(self):
|
|
|
|
self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_AVAILABLE_CONNECTIONS,
|
|
|
|
ExportedObj.to_path_array(self.available_connections_get()))
|
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
###############################################################################
|
2014-01-09 21:19:07 +00:00
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
PRP_WIRED_HW_ADDRESS = "HwAddress"
|
|
|
|
PRP_WIRED_PERM_HW_ADDRESS = "PermHwAddress"
|
|
|
|
PRP_WIRED_SPEED = "Speed"
|
|
|
|
PRP_WIRED_CARRIER = "Carrier"
|
|
|
|
PRP_WIRED_S390_SUBCHANNELS = "S390Subchannels"
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
class WiredDevice(Device):
|
2018-05-14 12:22:09 +00:00
|
|
|
def __init__(self, iface, mac = None, subchannels = None, ident = None):
|
|
|
|
Device.__init__(self, iface, NM.DeviceType.ETHERNET, ident)
|
2018-05-15 06:31:16 +00:00
|
|
|
|
2015-09-25 07:06:20 +00:00
|
|
|
if mac is None:
|
2018-05-14 12:22:09 +00:00
|
|
|
mac = Util.random_mac(self.ident)
|
2018-05-04 07:02:53 +00:00
|
|
|
if subchannels is None:
|
|
|
|
subchannels = dbus.Array(signature = 's')
|
2014-01-09 21:19:07 +00:00
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
props = {
|
|
|
|
PRP_WIRED_HW_ADDRESS: mac,
|
|
|
|
PRP_WIRED_PERM_HW_ADDRESS: mac,
|
|
|
|
PRP_WIRED_SPEED: dbus.UInt32(100),
|
|
|
|
PRP_WIRED_CARRIER: False,
|
|
|
|
PRP_WIRED_S390_SUBCHANNELS: subchannels,
|
|
|
|
}
|
2016-09-20 12:40:08 +00:00
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
self.dbus_interface_add(IFACE_WIRED, props, WiredDevice.PropertiesChanged)
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.signal(IFACE_WIRED, signature='a{sv}')
|
|
|
|
def PropertiesChanged(self, changed):
|
|
|
|
pass
|
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
###############################################################################
|
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
PRP_VLAN_HW_ADDRESS = "HwAddress"
|
|
|
|
PRP_VLAN_CARRIER = "Carrier"
|
|
|
|
PRP_VLAN_VLAN_ID = "VlanId"
|
2014-10-08 22:15:23 +00:00
|
|
|
|
|
|
|
class VlanDevice(Device):
|
2018-05-14 12:22:09 +00:00
|
|
|
def __init__(self, iface, ident = None):
|
|
|
|
Device.__init__(self, iface, NM.DeviceType.VLAN, ident)
|
2014-10-08 22:15:23 +00:00
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
props = {
|
|
|
|
PRP_VLAN_HW_ADDRESS: Util.random_mac(self.ident),
|
|
|
|
PRP_VLAN_CARRIER: False,
|
|
|
|
PRP_VLAN_VLAN_ID: dbus.UInt32(1),
|
|
|
|
}
|
2016-09-20 12:40:08 +00:00
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
self.dbus_interface_add(IFACE_VLAN, props, VlanDevice.PropertiesChanged)
|
2014-10-08 22:15:23 +00:00
|
|
|
|
|
|
|
@dbus.service.signal(IFACE_VLAN, signature='a{sv}')
|
|
|
|
def PropertiesChanged(self, changed):
|
|
|
|
pass
|
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
###############################################################################
|
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
PRP_WIFI_AP_FLAGS = "Flags"
|
|
|
|
PRP_WIFI_AP_WPA_FLAGS = "WpaFlags"
|
|
|
|
PRP_WIFI_AP_RSN_FLAGS = "RsnFlags"
|
|
|
|
PRP_WIFI_AP_SSID = "Ssid"
|
|
|
|
PRP_WIFI_AP_FREQUENCY = "Frequency"
|
|
|
|
PRP_WIFI_AP_HW_ADDRESS = "HwAddress"
|
|
|
|
PRP_WIFI_AP_MODE = "Mode"
|
|
|
|
PRP_WIFI_AP_MAX_BITRATE = "MaxBitrate"
|
|
|
|
PRP_WIFI_AP_STRENGTH = "Strength"
|
2018-06-16 11:38:45 +00:00
|
|
|
PRP_WIFI_AP_LAST_SEEN = "LastSeen"
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
class WifiAp(ExportedObj):
|
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
path_counter_next = 1
|
|
|
|
path_prefix = "/org/freedesktop/NetworkManager/AccessPoint/"
|
|
|
|
|
|
|
|
def __init__(self, ssid, bssid = None, flags = None, wpaf = None, rsnf = None, freq = None, strength = None, ident = None):
|
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
ExportedObj.__init__(self, ExportedObj.create_path(WifiAp), ident)
|
2014-01-09 21:19:07 +00:00
|
|
|
|
2018-05-04 07:02:53 +00:00
|
|
|
if flags is None:
|
|
|
|
flags = 0x1
|
|
|
|
if wpaf is None:
|
|
|
|
wpaf = 0x1cc
|
|
|
|
if rsnf is None:
|
|
|
|
rsnf = 0x1cc
|
|
|
|
if freq is None:
|
|
|
|
freq = 2412
|
|
|
|
if bssid is None:
|
2018-05-15 06:31:16 +00:00
|
|
|
bssid = Util.random_mac(self.path)
|
2018-05-04 07:02:53 +00:00
|
|
|
if strength is None:
|
clients/tests: seed generated numbers for test-networkmanager-service.py
At several places, "test-networkmanager-service.py" uses generated numbers
with a defined seed. For example, generated connection's UUID is
generated in a predictable, but randomized way (if you forgive the
inprecise use of the word "random" in context of using a deterministic
seed).
Aside the connection's UUID, this becomes more interesting in the next commit
where the stub server generates a list of IP and DHCP settings in a predictable
randomized way.
For "clients/tests" we spawn the test service multiple times, but also
create similar environments by calling init_001(). This is done for
convenience, where out of lazyness all the tests share one setup. But it's
still a good idea that these tests generate slightly different setups,
wherever applicable. this increases the possible setups which get tested.
For example, the number of static IPv4 addresses (the following commit) is
interested to explicitly test for zero or a non-zero number of
addresses. If all tests happen to use the same seed, the tests are expected
to also generate the same number of addresses, and we miss an opportunity to
hit interesting test cases.
There is still no guarantee that all interesting cases are hit, the chances are just
better. The approach of generating the setup randomly, does not preclude that
the stub-server allows to explicitly configure the setup. However, due to the
sheer number of combinations that might be interesting to test, it's much simpler
to rely on some randomization and have the justifid hope we catch interesting cases.
Also in terms of runtime of the test, the cli unit tests should complete within
few seconds. Testing every combination would result in huge tests and long runtimes.
Also, the patch refactors generating random numbers in
"test-networkmanager-service.py". For example, it introduces
Util.RandomSeed(), which can be used to generate a sequence of different
random numbers. It works by having an internal state and a counter which is
combined to chain the seed and generate different numbers on each call.
2018-06-07 15:42:31 +00:00
|
|
|
strength = Util.random_int(self.path, 100)
|
2018-05-04 07:02:53 +00:00
|
|
|
|
2014-01-09 21:19:07 +00:00
|
|
|
self.ssid = ssid
|
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
props = {
|
|
|
|
PRP_WIFI_AP_FLAGS: dbus.UInt32(flags),
|
|
|
|
PRP_WIFI_AP_WPA_FLAGS: dbus.UInt32(wpaf),
|
|
|
|
PRP_WIFI_AP_RSN_FLAGS: dbus.UInt32(rsnf),
|
|
|
|
PRP_WIFI_AP_SSID: dbus.ByteArray(self.ssid.encode('utf-8')),
|
|
|
|
PRP_WIFI_AP_FREQUENCY: dbus.UInt32(freq),
|
|
|
|
PRP_WIFI_AP_HW_ADDRESS: bssid,
|
|
|
|
PRP_WIFI_AP_MODE: dbus.UInt32(getattr(NM,'80211Mode').INFRA),
|
|
|
|
PRP_WIFI_AP_MAX_BITRATE: dbus.UInt32(54000),
|
|
|
|
PRP_WIFI_AP_STRENGTH: dbus.Byte(strength),
|
2018-06-16 11:38:45 +00:00
|
|
|
PRP_WIFI_AP_LAST_SEEN: dbus.Int32(NM.utils_get_timestamp_msec() / 1000),
|
2018-05-15 06:31:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
self.dbus_interface_add(IFACE_WIFI_AP, props, WifiAp.PropertiesChanged)
|
2016-09-20 12:40:08 +00:00
|
|
|
|
2014-01-09 21:19:07 +00:00
|
|
|
@dbus.service.signal(IFACE_WIFI_AP, signature='a{sv}')
|
|
|
|
def PropertiesChanged(self, changed):
|
|
|
|
pass
|
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
###############################################################################
|
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
PRP_WIFI_HW_ADDRESS = "HwAddress"
|
|
|
|
PRP_WIFI_PERM_HW_ADDRESS = "PermHwAddress"
|
|
|
|
PRP_WIFI_MODE = "Mode"
|
|
|
|
PRP_WIFI_BITRATE = "Bitrate"
|
|
|
|
PRP_WIFI_ACCESS_POINTS = "AccessPoints"
|
|
|
|
PRP_WIFI_ACTIVE_ACCESS_POINT = "ActiveAccessPoint"
|
|
|
|
PRP_WIFI_WIRELESS_CAPABILITIES = "WirelessCapabilities"
|
2018-02-25 13:53:44 +00:00
|
|
|
PRP_WIFI_LAST_SCAN = "LastScan"
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
class WifiDevice(Device):
|
2018-05-14 12:22:09 +00:00
|
|
|
def __init__(self, iface, mac = None, ident = None):
|
|
|
|
Device.__init__(self, iface, NM.DeviceType.WIFI, ident)
|
2018-05-15 06:31:16 +00:00
|
|
|
|
2018-05-04 07:02:53 +00:00
|
|
|
if mac is None:
|
2018-05-14 12:22:09 +00:00
|
|
|
mac = Util.random_mac(self.ident)
|
2018-05-15 06:31:16 +00:00
|
|
|
|
2014-01-09 21:19:07 +00:00
|
|
|
self.aps = []
|
2018-06-16 11:38:45 +00:00
|
|
|
self.scan_cb_id = None
|
|
|
|
|
|
|
|
# Note: we would like to simulate how nmcli calls RequestScan() and we could
|
|
|
|
# do so by using an older timestamp. However, that makes the client tests
|
|
|
|
# racy, because if a bunch of nmcli instances run in parallel against this
|
|
|
|
# service, earlier instances will issue a RequestScan(), while later instances
|
|
|
|
# won't do that (because the LastScan timestamp is already updated). That means,
|
|
|
|
# the later instances will print the scan result immediately, and in another sort
|
|
|
|
# order. That should be fixed, by nmcli not starting to print anything, before
|
|
|
|
# all RequestScan() requests complete, and thus, always print a consistent list
|
|
|
|
# of results.
|
|
|
|
ts = NM.utils_get_timestamp_msec()
|
2014-01-09 21:19:07 +00:00
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
props = {
|
|
|
|
PRP_WIFI_HW_ADDRESS: mac,
|
|
|
|
PRP_WIFI_PERM_HW_ADDRESS: mac,
|
|
|
|
PRP_WIFI_MODE: dbus.UInt32(getattr(NM,'80211Mode').INFRA),
|
|
|
|
PRP_WIFI_BITRATE: dbus.UInt32(21000),
|
|
|
|
PRP_WIFI_WIRELESS_CAPABILITIES: dbus.UInt32(0xFF),
|
|
|
|
PRP_WIFI_ACCESS_POINTS: ExportedObj.to_path_array(self.aps),
|
|
|
|
PRP_WIFI_ACTIVE_ACCESS_POINT: ExportedObj.to_path(None),
|
2018-06-16 11:38:45 +00:00
|
|
|
PRP_WIFI_LAST_SCAN: dbus.Int64(ts),
|
2018-05-15 06:31:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
self.dbus_interface_add(IFACE_WIFI, props, WifiDevice.PropertiesChanged)
|
2016-09-20 12:40:08 +00:00
|
|
|
|
2014-01-09 21:19:07 +00:00
|
|
|
@dbus.service.method(dbus_interface=IFACE_WIFI, in_signature='', out_signature='ao')
|
|
|
|
def GetAccessPoints(self):
|
|
|
|
# only include non-hidden APs
|
2018-05-14 12:22:09 +00:00
|
|
|
return ExportedObj.to_path_array([a for a in self.aps if a.ssid])
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_WIFI, in_signature='', out_signature='ao')
|
|
|
|
def GetAllAccessPoints(self):
|
|
|
|
# include all APs including hidden ones
|
2018-05-14 12:22:09 +00:00
|
|
|
return ExportedObj.to_path_array(self.aps)
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_WIFI, in_signature='a{sv}', out_signature='')
|
|
|
|
def RequestScan(self, props):
|
2018-06-16 11:38:45 +00:00
|
|
|
self.scan_cb_id = Util.g_source_remove(self.scan_cb_id)
|
|
|
|
def cb():
|
|
|
|
ts = NM.utils_get_timestamp_msec()
|
|
|
|
for ap in self.aps:
|
|
|
|
ap._dbus_property_set(IFACE_WIFI_AP, PRP_WIFI_AP_LAST_SEEN, dbus.Int32(ts / 1000))
|
|
|
|
self._dbus_property_set(IFACE_WIFI, PRP_WIFI_LAST_SCAN, dbus.Int64(ts))
|
|
|
|
self.scan_cb_id = None
|
|
|
|
return False
|
|
|
|
self.scan_cb_id = GLib.idle_add(cb)
|
2014-01-09 21:19:07 +00:00
|
|
|
pass
|
|
|
|
|
|
|
|
@dbus.service.signal(IFACE_WIFI, signature='o')
|
|
|
|
def AccessPointAdded(self, ap_path):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def add_ap(self, ap):
|
2018-05-15 08:16:14 +00:00
|
|
|
ap.export()
|
2014-01-09 21:19:07 +00:00
|
|
|
self.aps.append(ap)
|
2018-05-15 06:31:16 +00:00
|
|
|
self._dbus_property_set(IFACE_WIFI, PRP_WIFI_ACCESS_POINTS, ExportedObj.to_path_array(self.aps))
|
2018-05-14 12:22:09 +00:00
|
|
|
self.AccessPointAdded(ExportedObj.to_path(ap))
|
2018-05-04 07:02:53 +00:00
|
|
|
return ap
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
def remove_ap(self, ap):
|
|
|
|
self.aps.remove(ap)
|
2018-05-15 06:31:16 +00:00
|
|
|
self._dbus_property_set(IFACE_WIFI, PRP_WIFI_ACCESS_POINTS, ExportedObj.to_path_array(self.aps))
|
2018-05-14 12:22:09 +00:00
|
|
|
self.AccessPointRemoved(ExportedObj.to_path(ap))
|
2018-05-15 08:16:14 +00:00
|
|
|
ap.unexport()
|
|
|
|
|
2018-06-16 11:38:45 +00:00
|
|
|
def stop(self):
|
|
|
|
self.scan_cb_id = Util.g_source_remove(self.scan_cb_id)
|
|
|
|
super(WifiDevice, self).stop()
|
|
|
|
|
2018-05-15 08:16:14 +00:00
|
|
|
@dbus.service.signal(IFACE_WIFI, signature='o')
|
|
|
|
def AccessPointRemoved(self, ap_path):
|
|
|
|
pass
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.signal(IFACE_WIFI, signature='a{sv}')
|
|
|
|
def PropertiesChanged(self, changed):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def remove_ap_by_path(self, path):
|
|
|
|
for ap in self.aps:
|
|
|
|
if ap.path == path:
|
|
|
|
self.remove_ap(ap)
|
|
|
|
return
|
2018-06-05 08:51:16 +00:00
|
|
|
raise BusErr.ApNotFoundException("AP %s not found" % path)
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
###############################################################################
|
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
PRP_WIMAX_NSP_NAME = "Name"
|
|
|
|
PRP_WIMAX_NSP_SIGNAL_QUALITY = "SignalQuality"
|
|
|
|
PRP_WIMAX_NSP_NETWORK_TYPE = "NetworkType"
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
class WimaxNsp(ExportedObj):
|
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
path_counter_next = 1
|
|
|
|
path_prefix = "/org/freedesktop/NetworkManager/Nsp/"
|
|
|
|
|
|
|
|
def __init__(self, name):
|
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
ExportedObj.__init__(self, ExportedObj.create_path(WimaxNsp))
|
2014-01-09 21:19:07 +00:00
|
|
|
|
2018-06-18 08:49:46 +00:00
|
|
|
strength = Util.random_int(self.path, 100)
|
2014-01-09 21:19:07 +00:00
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
props = {
|
|
|
|
PRP_WIMAX_NSP_NAME: name,
|
2018-06-18 08:49:46 +00:00
|
|
|
PRP_WIMAX_NSP_SIGNAL_QUALITY: dbus.UInt32(strength),
|
2018-05-15 06:31:16 +00:00
|
|
|
PRP_WIMAX_NSP_NETWORK_TYPE: dbus.UInt32(NM.WimaxNspNetworkType.HOME),
|
|
|
|
}
|
|
|
|
|
|
|
|
self.dbus_interface_add(IFACE_WIMAX_NSP, props, WimaxNsp.PropertiesChanged)
|
2016-09-20 12:40:08 +00:00
|
|
|
|
2014-01-09 21:19:07 +00:00
|
|
|
@dbus.service.signal(IFACE_WIMAX_NSP, signature='a{sv}')
|
|
|
|
def PropertiesChanged(self, changed):
|
|
|
|
pass
|
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
###############################################################################
|
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
PRP_WIMAX_NSPS = "Nsps"
|
|
|
|
PRP_WIMAX_HW_ADDRESS = "HwAddress"
|
|
|
|
PRP_WIMAX_CENTER_FREQUENCY = "CenterFrequency"
|
|
|
|
PRP_WIMAX_RSSI = "Rssi"
|
|
|
|
PRP_WIMAX_CINR = "Cinr"
|
|
|
|
PRP_WIMAX_TX_POWER = "TxPower"
|
|
|
|
PRP_WIMAX_BSID = "Bsid"
|
|
|
|
PRP_WIMAX_ACTIVE_NSP = "ActiveNsp"
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
class WimaxDevice(Device):
|
2018-05-14 12:22:09 +00:00
|
|
|
def __init__(self, iface, ident = None):
|
|
|
|
Device.__init__(self, iface, NM.DeviceType.WIMAX, ident)
|
2018-05-15 06:31:16 +00:00
|
|
|
|
|
|
|
mac = Util.random_mac(self.ident)
|
|
|
|
bsid = Util.random_mac(self.ident + '.bsid')
|
|
|
|
|
2014-01-09 21:19:07 +00:00
|
|
|
self.nsps = []
|
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
props = {
|
|
|
|
PRP_WIMAX_HW_ADDRESS: mac,
|
|
|
|
PRP_WIMAX_CENTER_FREQUENCY: dbus.UInt32(2525),
|
|
|
|
PRP_WIMAX_RSSI: dbus.Int32(-48),
|
|
|
|
PRP_WIMAX_CINR: dbus.Int32(24),
|
|
|
|
PRP_WIMAX_TX_POWER: dbus.Int32(9),
|
|
|
|
PRP_WIMAX_BSID: bsid,
|
|
|
|
PRP_WIMAX_NSPS: ExportedObj.to_path_array(self.nsps),
|
|
|
|
PRP_WIMAX_ACTIVE_NSP: ExportedObj.to_path(None),
|
|
|
|
}
|
|
|
|
|
|
|
|
self.dbus_interface_add(IFACE_WIMAX, props, WimaxDevice.PropertiesChanged)
|
2016-09-20 12:40:08 +00:00
|
|
|
|
2014-01-09 21:19:07 +00:00
|
|
|
@dbus.service.method(dbus_interface=IFACE_WIMAX, in_signature='', out_signature='ao')
|
|
|
|
def GetNspList(self):
|
2018-05-14 12:22:09 +00:00
|
|
|
return ExportedObj.to_path_array(self.nsps)
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.signal(IFACE_WIMAX, signature='o')
|
|
|
|
def NspAdded(self, nsp_path):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def add_nsp(self, nsp):
|
2018-05-15 08:16:14 +00:00
|
|
|
nsp.export()
|
2014-01-09 21:19:07 +00:00
|
|
|
self.nsps.append(nsp)
|
2018-05-15 06:31:16 +00:00
|
|
|
self._dbus_property_set(IFACE_WIMAX, PRP_WIMAX_NSPS, ExportedObj.to_path_array(self.nsps))
|
2018-05-14 12:22:09 +00:00
|
|
|
self.NspAdded(ExportedObj.to_path(nsp))
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
def remove_nsp(self, nsp):
|
|
|
|
self.nsps.remove(nsp)
|
2018-05-15 06:31:16 +00:00
|
|
|
self._dbus_property_set(IFACE_WIMAX, PRP_WIMAX_NSPS, ExportedObj.to_path_array(self.nsps))
|
2018-05-14 12:22:09 +00:00
|
|
|
self.NspRemoved(ExportedObj.to_path(nsp))
|
2018-05-15 08:16:14 +00:00
|
|
|
nsp.unexport()
|
|
|
|
|
|
|
|
@dbus.service.signal(IFACE_WIMAX, signature='o')
|
|
|
|
def NspRemoved(self, nsp_path):
|
|
|
|
pass
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.signal(IFACE_WIMAX, signature='a{sv}')
|
|
|
|
def PropertiesChanged(self, changed):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def add_test_nsp(self, name):
|
2018-05-14 12:22:09 +00:00
|
|
|
nsp = WimaxNsp(name)
|
2014-01-09 21:19:07 +00:00
|
|
|
self.add_nsp(nsp)
|
2015-01-05 12:52:27 +00:00
|
|
|
return nsp
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
def remove_nsp_by_path(self, path):
|
|
|
|
for nsp in self.nsps:
|
|
|
|
if nsp.path == path:
|
|
|
|
self.remove_nsp(nsp)
|
|
|
|
return
|
2018-06-05 08:51:16 +00:00
|
|
|
raise BusErr.NspNotFoundException("NSP %s not found" % path)
|
2014-01-09 21:19:07 +00:00
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
###############################################################################
|
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
PRP_ACTIVE_CONNECTION_CONNECTION = "Connection"
|
|
|
|
PRP_ACTIVE_CONNECTION_SPECIFIC_OBJECT = "SpecificObject"
|
|
|
|
PRP_ACTIVE_CONNECTION_ID = "Id"
|
|
|
|
PRP_ACTIVE_CONNECTION_UUID = "Uuid"
|
|
|
|
PRP_ACTIVE_CONNECTION_TYPE = "Type"
|
|
|
|
PRP_ACTIVE_CONNECTION_DEVICES = "Devices"
|
|
|
|
PRP_ACTIVE_CONNECTION_STATE = "State"
|
|
|
|
PRP_ACTIVE_CONNECTION_DEFAULT = "Default"
|
|
|
|
PRP_ACTIVE_CONNECTION_IP4CONFIG = "Ip4Config"
|
|
|
|
PRP_ACTIVE_CONNECTION_DHCP4CONFIG = "Dhcp4Config"
|
|
|
|
PRP_ACTIVE_CONNECTION_DEFAULT6 = "Default6"
|
|
|
|
PRP_ACTIVE_CONNECTION_IP6CONFIG = "Ip6Config"
|
|
|
|
PRP_ACTIVE_CONNECTION_DHCP6CONFIG = "Dhcp6Config"
|
|
|
|
PRP_ACTIVE_CONNECTION_VPN = "Vpn"
|
|
|
|
PRP_ACTIVE_CONNECTION_MASTER = "Master"
|
2014-10-06 17:35:03 +00:00
|
|
|
|
2018-06-05 18:23:31 +00:00
|
|
|
PRP_VPN_CONNECTION_VPN_STATE = 'VpnState'
|
|
|
|
PRP_VPN_CONNECTION_BANNER = 'Banner'
|
|
|
|
|
2014-10-06 17:35:03 +00:00
|
|
|
class ActiveConnection(ExportedObj):
|
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
path_counter_next = 1
|
|
|
|
path_prefix = "/org/freedesktop/NetworkManager/ActiveConnection/"
|
|
|
|
|
2018-06-01 15:22:12 +00:00
|
|
|
def __init__(self, device, con_inst, specific_object):
|
2018-05-14 12:22:09 +00:00
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
ExportedObj.__init__(self, ExportedObj.create_path(ActiveConnection))
|
2014-10-06 17:35:03 +00:00
|
|
|
|
|
|
|
self.device = device
|
2018-06-01 15:22:12 +00:00
|
|
|
self.con_inst = con_inst
|
2018-06-06 13:02:13 +00:00
|
|
|
self.is_vpn = con_inst.is_vpn()
|
2014-10-06 17:35:03 +00:00
|
|
|
|
2018-05-14 13:49:13 +00:00
|
|
|
self._activation_id = None
|
|
|
|
|
2018-06-01 15:53:23 +00:00
|
|
|
s_con = con_inst.con_hash[NM.SETTING_CONNECTION_SETTING_NAME]
|
2018-05-15 06:31:16 +00:00
|
|
|
|
|
|
|
props = {
|
2018-06-01 15:22:12 +00:00
|
|
|
PRP_ACTIVE_CONNECTION_CONNECTION: ExportedObj.to_path(con_inst),
|
2018-05-15 06:31:16 +00:00
|
|
|
PRP_ACTIVE_CONNECTION_SPECIFIC_OBJECT: ExportedObj.to_path(specific_object),
|
2018-06-01 15:53:23 +00:00
|
|
|
PRP_ACTIVE_CONNECTION_ID: s_con[NM.SETTING_CONNECTION_ID],
|
|
|
|
PRP_ACTIVE_CONNECTION_UUID: s_con[NM.SETTING_CONNECTION_UUID],
|
|
|
|
PRP_ACTIVE_CONNECTION_TYPE: s_con[NM.SETTING_CONNECTION_TYPE],
|
2018-05-15 06:31:16 +00:00
|
|
|
PRP_ACTIVE_CONNECTION_DEVICES: ExportedObj.to_path_array([self.device]),
|
|
|
|
PRP_ACTIVE_CONNECTION_STATE: dbus.UInt32(NM.ActiveConnectionState.UNKNOWN),
|
|
|
|
PRP_ACTIVE_CONNECTION_DEFAULT: False,
|
|
|
|
PRP_ACTIVE_CONNECTION_IP4CONFIG: ExportedObj.to_path(None),
|
|
|
|
PRP_ACTIVE_CONNECTION_DHCP4CONFIG: ExportedObj.to_path(None),
|
|
|
|
PRP_ACTIVE_CONNECTION_DEFAULT6: False,
|
|
|
|
PRP_ACTIVE_CONNECTION_IP6CONFIG: ExportedObj.to_path(None),
|
|
|
|
PRP_ACTIVE_CONNECTION_DHCP6CONFIG: ExportedObj.to_path(None),
|
2018-06-06 13:02:13 +00:00
|
|
|
PRP_ACTIVE_CONNECTION_VPN: self.is_vpn,
|
2018-05-15 06:31:16 +00:00
|
|
|
PRP_ACTIVE_CONNECTION_MASTER: ExportedObj.to_path(None),
|
|
|
|
}
|
|
|
|
|
|
|
|
self.dbus_interface_add(IFACE_ACTIVE_CONNECTION, props, ActiveConnection.PropertiesChanged)
|
2016-09-20 12:40:08 +00:00
|
|
|
|
2018-06-06 13:02:13 +00:00
|
|
|
if self.is_vpn:
|
2018-06-05 18:23:31 +00:00
|
|
|
props = {
|
|
|
|
PRP_VPN_CONNECTION_VPN_STATE: dbus.UInt32(NM.VpnConnectionState.UNKNOWN),
|
|
|
|
PRP_VPN_CONNECTION_BANNER: '*** VPN connection %s ***' % (con_inst.get_id()),
|
|
|
|
}
|
|
|
|
|
|
|
|
self.dbus_interface_add(IFACE_VPN_CONNECTION, props, ActiveConnection.VpnPropertiesChanged)
|
|
|
|
|
|
|
|
|
2018-05-14 13:49:13 +00:00
|
|
|
def _set_state(self, state, reason):
|
2018-05-15 06:31:16 +00:00
|
|
|
state = dbus.UInt32(state)
|
|
|
|
self._dbus_property_set(IFACE_ACTIVE_CONNECTION, PRP_ACTIVE_CONNECTION_STATE, state)
|
|
|
|
self.StateChanged(state, dbus.UInt32(reason))
|
2018-05-14 13:49:13 +00:00
|
|
|
|
|
|
|
def activation_cancel(self):
|
2018-06-16 11:38:45 +00:00
|
|
|
self._activation_id = Util.g_source_remove(self._activation_id)
|
2018-05-14 13:49:13 +00:00
|
|
|
|
|
|
|
def _activation_step2(self):
|
|
|
|
assert self._activation_id is not None
|
|
|
|
self._activation_id = None
|
|
|
|
self._set_state(NM.ActiveConnectionState.ACTIVATED, NM.ActiveConnectionStateReason.UNKNOWN)
|
|
|
|
return False
|
|
|
|
|
|
|
|
def _activation_step1(self):
|
|
|
|
assert self._activation_id is not None
|
|
|
|
self._activation_id = GLib.timeout_add(50, self._activation_step2)
|
|
|
|
self.device.set_active_connection(self)
|
|
|
|
self._set_state(NM.ActiveConnectionState.ACTIVATING, NM.ActiveConnectionStateReason.UNKNOWN)
|
|
|
|
return False
|
|
|
|
|
|
|
|
def start_activation(self):
|
|
|
|
assert self._activation_id is None
|
|
|
|
self._activation_id = GLib.timeout_add(50, self._activation_step1)
|
|
|
|
|
2018-06-05 18:23:31 +00:00
|
|
|
@dbus.service.signal(IFACE_VPN_CONNECTION, signature='a{sv}')
|
|
|
|
def PropertiesChanged(self, changed):
|
|
|
|
pass
|
|
|
|
VpnPropertiesChanged = PropertiesChanged
|
|
|
|
|
2014-10-06 17:35:03 +00:00
|
|
|
@dbus.service.signal(IFACE_ACTIVE_CONNECTION, signature='a{sv}')
|
|
|
|
def PropertiesChanged(self, changed):
|
|
|
|
pass
|
|
|
|
|
2018-05-14 13:49:13 +00:00
|
|
|
@dbus.service.signal(IFACE_ACTIVE_CONNECTION, signature='uu')
|
|
|
|
def StateChanged(self, state, reason):
|
|
|
|
pass
|
|
|
|
|
2018-06-05 18:23:31 +00:00
|
|
|
@dbus.service.signal(IFACE_VPN_CONNECTION, signature='uu')
|
|
|
|
def VpnStateChanged(self, state, reason):
|
|
|
|
pass
|
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
###############################################################################
|
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
PRP_NM_DEVICES = 'Devices'
|
|
|
|
PRP_NM_ALL_DEVICES = 'AllDevices'
|
|
|
|
PRP_NM_NETWORKING_ENABLED = 'NetworkingEnabled'
|
|
|
|
PRP_NM_WWAN_ENABLED = 'WwanEnabled'
|
|
|
|
PRP_NM_WWAN_HARDWARE_ENABLED = 'WwanHardwareEnabled'
|
|
|
|
PRP_NM_WIRELESS_ENABLED = 'WirelessEnabled'
|
|
|
|
PRP_NM_WIRELESS_HARDWARE_ENABLED = 'WirelessHardwareEnabled'
|
|
|
|
PRP_NM_WIMAX_ENABLED = 'WimaxEnabled'
|
|
|
|
PRP_NM_WIMAX_HARDWARE_ENABLED = 'WimaxHardwareEnabled'
|
|
|
|
PRP_NM_ACTIVE_CONNECTIONS = 'ActiveConnections'
|
|
|
|
PRP_NM_PRIMARY_CONNECTION = 'PrimaryConnection'
|
|
|
|
PRP_NM_ACTIVATING_CONNECTION = 'ActivatingConnection'
|
|
|
|
PRP_NM_STARTUP = 'Startup'
|
|
|
|
PRP_NM_STATE = 'State'
|
|
|
|
PRP_NM_VERSION = 'Version'
|
|
|
|
PRP_NM_CONNECTIVITY = 'Connectivity'
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
class NetworkManager(ExportedObj):
|
2018-05-15 06:31:16 +00:00
|
|
|
def __init__(self):
|
|
|
|
ExportedObj.__init__(self, "/org/freedesktop/NetworkManager")
|
2014-01-09 21:19:07 +00:00
|
|
|
self.devices = []
|
|
|
|
self.active_connections = []
|
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
props = {
|
|
|
|
PRP_NM_DEVICES: ExportedObj.to_path_array(self.devices),
|
|
|
|
PRP_NM_ALL_DEVICES: ExportedObj.to_path_array(self.devices),
|
|
|
|
PRP_NM_NETWORKING_ENABLED: True,
|
|
|
|
PRP_NM_WWAN_ENABLED: True,
|
|
|
|
PRP_NM_WWAN_HARDWARE_ENABLED: True,
|
|
|
|
PRP_NM_WIRELESS_ENABLED: True,
|
|
|
|
PRP_NM_WIRELESS_HARDWARE_ENABLED: True,
|
|
|
|
PRP_NM_WIMAX_ENABLED: True,
|
|
|
|
PRP_NM_WIMAX_HARDWARE_ENABLED: True,
|
|
|
|
PRP_NM_ACTIVE_CONNECTIONS: ExportedObj.to_path_array(self.active_connections),
|
|
|
|
PRP_NM_PRIMARY_CONNECTION: ExportedObj.to_path(None),
|
|
|
|
PRP_NM_ACTIVATING_CONNECTION: ExportedObj.to_path(None),
|
|
|
|
PRP_NM_STARTUP: False,
|
|
|
|
PRP_NM_STATE: dbus.UInt32(NM.State.DISCONNECTED),
|
|
|
|
PRP_NM_VERSION: "0.9.9.0",
|
|
|
|
PRP_NM_CONNECTIVITY: dbus.UInt32(NM.ConnectivityState.NONE),
|
|
|
|
}
|
|
|
|
|
|
|
|
self.dbus_interface_add(IFACE_NM, props, NetworkManager.PropertiesChanged)
|
2018-05-14 12:22:09 +00:00
|
|
|
self.export()
|
2016-09-20 12:40:08 +00:00
|
|
|
|
2014-01-09 21:19:07 +00:00
|
|
|
@dbus.service.signal(IFACE_NM, signature='u')
|
|
|
|
def StateChanged(self, new_state):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def set_state(self, new_state):
|
2018-05-15 06:31:16 +00:00
|
|
|
self._dbus_property_set(IFACE_NM, PRP_NM_STATE, state)
|
2014-01-09 21:19:07 +00:00
|
|
|
self.StateChanged(dbus.UInt32(self.state))
|
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='ao')
|
|
|
|
def GetDevices(self):
|
2018-05-14 12:22:09 +00:00
|
|
|
return ExportedObj.to_path_array(self.devices)
|
2014-01-09 21:19:07 +00:00
|
|
|
|
2014-10-10 19:28:49 +00:00
|
|
|
@dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='ao')
|
|
|
|
def GetAllDevices(self):
|
2018-05-14 12:22:09 +00:00
|
|
|
return ExportedObj.to_path_array(self.devices)
|
2014-10-10 19:28:49 +00:00
|
|
|
|
2014-01-09 21:19:07 +00:00
|
|
|
@dbus.service.method(dbus_interface=IFACE_NM, in_signature='s', out_signature='o')
|
|
|
|
def GetDeviceByIpIface(self, ip_iface):
|
2018-06-05 08:51:16 +00:00
|
|
|
d = self.find_device_first(ip_iface = ip_iface, require = BusErr.UnknownDeviceException)
|
2018-05-14 12:22:09 +00:00
|
|
|
return ExportedObj.to_path(d)
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_NM, in_signature='ooo', out_signature='o')
|
|
|
|
def ActivateConnection(self, conpath, devpath, specific_object):
|
2014-10-08 22:15:23 +00:00
|
|
|
try:
|
2018-06-01 15:22:12 +00:00
|
|
|
con_inst = gl.settings.get_connection(conpath)
|
2014-10-08 22:15:23 +00:00
|
|
|
except Exception as e:
|
2018-06-05 08:51:16 +00:00
|
|
|
raise BusErr.UnknownConnectionException("Connection not found")
|
2014-10-08 22:15:23 +00:00
|
|
|
|
2018-06-01 15:22:12 +00:00
|
|
|
con_hash = con_inst.con_hash
|
2018-06-05 18:23:31 +00:00
|
|
|
con_type = NmUtil.con_hash_get_type(con_hash)
|
2014-10-08 22:15:23 +00:00
|
|
|
|
2018-05-09 10:46:34 +00:00
|
|
|
device = self.find_device_first(path = devpath)
|
2018-06-05 18:23:31 +00:00
|
|
|
if not device:
|
|
|
|
if con_type == NM.SETTING_WIRED_SETTING_NAME:
|
|
|
|
device = self.find_device_first(dev_type = WiredDevice)
|
|
|
|
elif con_type == NM.SETTING_WIRELESS_SETTING_NAME:
|
|
|
|
device = self.find_device_first(dev_type = WifiDevice)
|
|
|
|
elif con_type == NM.SETTING_VLAN_SETTING_NAME:
|
|
|
|
ifname = con_hash[NM.SETTING_CONNECTION_SETTING_NAME]['interface-name']
|
|
|
|
device = VlanDevice(ifname)
|
|
|
|
self.add_device(device)
|
|
|
|
elif con_type == NM.SETTING_VPN_SETTING_NAME:
|
|
|
|
for ac in self.active_connections:
|
|
|
|
if ac.is_vpn:
|
|
|
|
continue
|
|
|
|
if ac.device:
|
|
|
|
device = ac.device
|
|
|
|
break
|
|
|
|
|
2014-01-09 21:19:07 +00:00
|
|
|
if not device:
|
2018-06-05 08:51:16 +00:00
|
|
|
raise BusErr.UnknownDeviceException("No device found for the requested iface.")
|
2014-08-29 16:27:47 +00:00
|
|
|
|
|
|
|
# See if we need secrets. For the moment, we only support WPA
|
2018-06-01 14:41:46 +00:00
|
|
|
if '802-11-wireless-security' in con_hash:
|
|
|
|
s_wsec = con_hash['802-11-wireless-security']
|
2014-10-31 15:34:23 +00:00
|
|
|
if (s_wsec['key-mgmt'] == 'wpa-psk' and 'psk' not in s_wsec):
|
2018-06-01 14:41:46 +00:00
|
|
|
secrets = gl.agent_manager.get_secrets(con_hash, conpath, '802-11-wireless-security')
|
2014-08-29 16:27:47 +00:00
|
|
|
if secrets is None:
|
2018-06-05 08:51:16 +00:00
|
|
|
raise BusErr.NoSecretsException("No secret agent available")
|
2014-10-31 15:34:23 +00:00
|
|
|
if '802-11-wireless-security' not in secrets:
|
2018-06-05 08:51:16 +00:00
|
|
|
raise BusErr.NoSecretsException("No secrets provided")
|
2014-08-29 16:27:47 +00:00
|
|
|
s_wsec = secrets['802-11-wireless-security']
|
2014-10-31 15:34:23 +00:00
|
|
|
if 'psk' not in s_wsec:
|
2018-06-05 08:51:16 +00:00
|
|
|
raise BusErr.NoSecretsException("No secrets provided")
|
2014-08-29 16:27:47 +00:00
|
|
|
|
2018-06-01 15:22:12 +00:00
|
|
|
ac = ActiveConnection(device, con_inst, None)
|
2018-05-14 12:22:09 +00:00
|
|
|
self.active_connection_add(ac)
|
2014-10-10 21:10:28 +00:00
|
|
|
|
2018-06-05 18:23:31 +00:00
|
|
|
if NmUtil.con_hash_get_id(con_hash) == 'object-creation-failed-test':
|
2018-05-14 12:22:09 +00:00
|
|
|
# FIXME: this is not the right test, to delete the active-connection
|
|
|
|
# before returning it. It's the wrong order of what NetworkManager
|
|
|
|
# would do.
|
|
|
|
self.active_connection_remove(ac)
|
2018-05-14 13:49:13 +00:00
|
|
|
return ExportedObj.to_path(ac)
|
2018-05-14 12:22:09 +00:00
|
|
|
|
|
|
|
return ExportedObj.to_path(ac)
|
|
|
|
|
|
|
|
def active_connection_add(self, ac):
|
|
|
|
ac.export()
|
|
|
|
self.active_connections.append(ac)
|
2018-05-15 06:31:16 +00:00
|
|
|
self._dbus_property_set(IFACE_NM, PRP_NM_ACTIVE_CONNECTIONS, ExportedObj.to_path_array(self.active_connections))
|
2018-05-14 13:49:13 +00:00
|
|
|
ac.start_activation()
|
2014-10-10 21:10:28 +00:00
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
def active_connection_remove(self, ac):
|
2018-05-14 13:49:13 +00:00
|
|
|
ac.activation_cancel()
|
2018-05-14 12:22:09 +00:00
|
|
|
self.active_connections.remove(ac)
|
2018-05-15 06:31:16 +00:00
|
|
|
self._dbus_property_set(IFACE_NM, PRP_NM_ACTIVE_CONNECTIONS, ExportedObj.to_path_array(self.active_connections))
|
2018-05-14 12:22:09 +00:00
|
|
|
ac.unexport()
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_NM, in_signature='a{sa{sv}}oo', out_signature='oo')
|
2018-06-01 15:22:12 +00:00
|
|
|
def AddAndActivateConnection(self, con_hash, devpath, specific_object):
|
2018-06-05 08:51:16 +00:00
|
|
|
device = self.find_device_first(path = devpath, require = BusErr.UnknownDeviceException)
|
2018-06-01 15:22:12 +00:00
|
|
|
conpath = gl.settings.AddConnection(con_hash)
|
2014-10-06 17:35:03 +00:00
|
|
|
return (conpath, self.ActivateConnection(conpath, devpath, specific_object))
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_NM, in_signature='o', out_signature='')
|
|
|
|
def DeactivateConnection(self, active_connection):
|
|
|
|
pass
|
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_NM, in_signature='b', out_signature='')
|
|
|
|
def Sleep(self, do_sleep):
|
|
|
|
if do_sleep:
|
2018-05-15 06:31:16 +00:00
|
|
|
state = NM.State.ASLEEP
|
2014-01-09 21:19:07 +00:00
|
|
|
else:
|
2018-05-15 06:31:16 +00:00
|
|
|
state = NM.State.DISCONNECTED
|
|
|
|
self.set_state(state)
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_NM, in_signature='b', out_signature='')
|
|
|
|
def Enable(self, do_enable):
|
|
|
|
pass
|
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='a{ss}')
|
|
|
|
def GetPermissions(self):
|
|
|
|
return { "org.freedesktop.NetworkManager.enable-disable-network": "yes",
|
|
|
|
"org.freedesktop.NetworkManager.sleep-wake": "no",
|
|
|
|
"org.freedesktop.NetworkManager.enable-disable-wifi": "yes",
|
|
|
|
"org.freedesktop.NetworkManager.enable-disable-wwan": "yes",
|
|
|
|
"org.freedesktop.NetworkManager.enable-disable-wimax": "yes",
|
|
|
|
"org.freedesktop.NetworkManager.network-control": "yes",
|
|
|
|
"org.freedesktop.NetworkManager.wifi.share.protected": "yes",
|
|
|
|
"org.freedesktop.NetworkManager.wifi.share.open": "yes",
|
|
|
|
"org.freedesktop.NetworkManager.settings.modify.own": "yes",
|
|
|
|
"org.freedesktop.NetworkManager.settings.modify.system": "yes",
|
2016-06-01 10:54:05 +00:00
|
|
|
"org.freedesktop.NetworkManager.settings.modify.hostname": "yes",
|
|
|
|
"org.freedesktop.NetworkManager.settings.modify.global-dns": "no",
|
2016-05-30 13:42:44 +00:00
|
|
|
"org.freedesktop.NetworkManager.reload": "no",
|
2016-06-01 10:54:05 +00:00
|
|
|
}
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_NM, in_signature='ss', out_signature='')
|
|
|
|
def SetLogging(self, level, domains):
|
|
|
|
pass
|
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='ss')
|
|
|
|
def GetLogging(self):
|
|
|
|
return ("info", "HW,RFKILL,CORE,DEVICE,WIFI,ETHER")
|
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='u')
|
|
|
|
def CheckConnectivity(self):
|
2018-06-05 08:51:16 +00:00
|
|
|
raise BusErr.PermissionDeniedException("You fail")
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.signal(IFACE_NM, signature='o')
|
|
|
|
def DeviceAdded(self, devpath):
|
|
|
|
pass
|
|
|
|
|
2018-06-05 18:23:31 +00:00
|
|
|
def find_devices(self, ident = _DEFAULT_ARG, path = _DEFAULT_ARG, iface = _DEFAULT_ARG, ip_iface = _DEFAULT_ARG, dev_type = _DEFAULT_ARG):
|
2018-05-09 10:46:34 +00:00
|
|
|
r = None
|
2018-05-04 07:02:53 +00:00
|
|
|
for d in self.devices:
|
2018-05-09 10:46:34 +00:00
|
|
|
if ident is not _DEFAULT_ARG:
|
|
|
|
if d.ident != ident:
|
|
|
|
continue
|
|
|
|
if path is not _DEFAULT_ARG:
|
|
|
|
if d.path != path:
|
|
|
|
continue
|
|
|
|
if iface is not _DEFAULT_ARG:
|
|
|
|
if d.iface != iface:
|
|
|
|
continue
|
|
|
|
if ip_iface is not _DEFAULT_ARG:
|
|
|
|
# ignore iface/ip_iface distinction for now
|
|
|
|
if d.iface != ip_iface:
|
|
|
|
continue
|
2018-06-05 18:23:31 +00:00
|
|
|
if dev_type is not _DEFAULT_ARG:
|
|
|
|
if not isinstance(d, dev_type):
|
|
|
|
continue
|
2018-05-09 10:46:34 +00:00
|
|
|
yield d
|
|
|
|
|
2018-06-05 18:23:31 +00:00
|
|
|
def find_device_first(self, ident = _DEFAULT_ARG, path = _DEFAULT_ARG, iface = _DEFAULT_ARG, ip_iface = _DEFAULT_ARG, dev_type = _DEFAULT_ARG, require = None):
|
2018-05-09 10:46:34 +00:00
|
|
|
r = None
|
2018-06-05 18:23:31 +00:00
|
|
|
for d in self.find_devices(ident = ident, path = path, iface = iface, ip_iface = ip_iface, dev_type = dev_type):
|
2018-05-09 10:46:34 +00:00
|
|
|
r = d
|
|
|
|
break
|
|
|
|
if r is None and require:
|
|
|
|
if require is TestError:
|
|
|
|
raise TestError('Device not found')
|
2018-06-05 08:51:16 +00:00
|
|
|
raise BusErr.UnknownDeviceException('Device not found')
|
2018-05-09 10:46:34 +00:00
|
|
|
return r
|
2018-05-04 07:02:53 +00:00
|
|
|
|
2014-01-09 21:19:07 +00:00
|
|
|
def add_device(self, device):
|
2018-05-09 10:46:34 +00:00
|
|
|
if self.find_device_first(ident = device.ident, path = device.path) is not None:
|
|
|
|
raise TestError("Duplicate device ident=%s / path=%s" % (device.ident, device.path))
|
2018-05-15 08:16:14 +00:00
|
|
|
device.export()
|
2014-01-09 21:19:07 +00:00
|
|
|
self.devices.append(device)
|
2018-05-15 06:31:16 +00:00
|
|
|
self._dbus_property_set(IFACE_NM, PRP_NM_DEVICES, ExportedObj.to_path_array(self.devices))
|
|
|
|
self._dbus_property_set(IFACE_NM, PRP_NM_ALL_DEVICES, ExportedObj.to_path_array(self.devices))
|
2018-05-14 12:22:09 +00:00
|
|
|
self.DeviceAdded(ExportedObj.to_path(device))
|
2018-06-06 18:28:17 +00:00
|
|
|
device.start()
|
2018-05-04 07:02:53 +00:00
|
|
|
return device
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
def remove_device(self, device):
|
2018-06-06 18:28:17 +00:00
|
|
|
device.stop()
|
2014-01-09 21:19:07 +00:00
|
|
|
self.devices.remove(device)
|
2018-05-15 06:31:16 +00:00
|
|
|
self._dbus_property_set(IFACE_NM, PRP_NM_DEVICES, ExportedObj.to_path_array(self.devices))
|
|
|
|
self._dbus_property_set(IFACE_NM, PRP_NM_ALL_DEVICES, ExportedObj.to_path_array(self.devices))
|
2018-05-14 12:22:09 +00:00
|
|
|
self.DeviceRemoved(ExportedObj.to_path(device))
|
2018-05-15 08:16:14 +00:00
|
|
|
device.unexport()
|
|
|
|
|
2018-06-06 13:02:13 +00:00
|
|
|
def devices_available_connections_update(self):
|
|
|
|
for d in self.devices:
|
|
|
|
d.available_connections_update()
|
|
|
|
|
2018-05-15 08:16:14 +00:00
|
|
|
@dbus.service.signal(IFACE_NM, signature='o')
|
|
|
|
def DeviceRemoved(self, devpath):
|
|
|
|
pass
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.signal(IFACE_NM, signature='a{sv}')
|
|
|
|
def PropertiesChanged(self, changed):
|
|
|
|
pass
|
|
|
|
|
|
|
|
@dbus.service.method(IFACE_TEST, in_signature='', out_signature='')
|
|
|
|
def Quit(self):
|
2018-05-14 12:22:09 +00:00
|
|
|
gl.mainloop.quit()
|
2014-01-09 21:19:07 +00:00
|
|
|
|
2018-05-04 07:02:53 +00:00
|
|
|
@dbus.service.method(IFACE_TEST, in_signature='a{ss}', out_signature='a(sss)')
|
2018-05-29 08:13:18 +00:00
|
|
|
def FindConnections(self, selector_args):
|
|
|
|
return [(c.path, c.get_uuid(), c.get_id()) for c in gl.settings.find_connections(**selector_args)]
|
2018-05-04 07:02:53 +00:00
|
|
|
|
2018-05-15 14:20:00 +00:00
|
|
|
@dbus.service.method(IFACE_TEST, in_signature='a(oa(sa(sv)))', out_signature='')
|
|
|
|
def SetProperties(self, all_args):
|
|
|
|
for i in [0, 1]:
|
|
|
|
for path, iface_args in all_args:
|
|
|
|
o = gl.object_manager.find_object(path)
|
|
|
|
if o is None:
|
|
|
|
raise TestError("Object %s does not exist" % (path))
|
|
|
|
for iface_name, args in iface_args:
|
|
|
|
for propname, value in args:
|
|
|
|
o._dbus_property_set(iface_name, propname, value,
|
|
|
|
allow_detect_dbus_iface = True,
|
|
|
|
dry_run = (i == 0))
|
|
|
|
|
|
|
|
|
2018-05-04 07:02:53 +00:00
|
|
|
@dbus.service.method(IFACE_TEST, in_signature='sa{sv}', out_signature='o')
|
|
|
|
def AddObj(self, class_name, args):
|
|
|
|
if class_name in ['WiredDevice', 'WifiDevice']:
|
|
|
|
py_class = globals()[class_name]
|
2018-05-14 12:22:09 +00:00
|
|
|
d = py_class(**args)
|
|
|
|
return ExportedObj.to_path(self.add_device(d))
|
2018-05-04 07:02:53 +00:00
|
|
|
elif class_name in ['WifiAp']:
|
|
|
|
if 'device' not in args:
|
|
|
|
raise TestError('missing "device" paramter')
|
2018-05-09 10:46:34 +00:00
|
|
|
d = self.find_device_first(ident = args['device'], require = TestError)
|
2018-05-04 07:02:53 +00:00
|
|
|
del args['device']
|
|
|
|
if 'ssid' not in args:
|
2018-05-14 12:22:09 +00:00
|
|
|
args['ssid'] = d.ident + '-ap-' + str(WifiAp.path_counter_next)
|
|
|
|
ap = WifiAp(**args)
|
|
|
|
return ExportedObj.to_path(d.add_ap(ap))
|
2018-05-04 07:02:53 +00:00
|
|
|
raise TestError("Invalid python type \"%s\"" % (class_name))
|
|
|
|
|
2015-09-25 07:06:20 +00:00
|
|
|
@dbus.service.method(IFACE_TEST, in_signature='ssas', out_signature='o')
|
|
|
|
def AddWiredDevice(self, ifname, mac, subchannels):
|
2018-05-14 12:22:09 +00:00
|
|
|
dev = WiredDevice(ifname, mac, subchannels)
|
|
|
|
return ExportedObj.to_path(self.add_device(dev))
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.method(IFACE_TEST, in_signature='s', out_signature='o')
|
|
|
|
def AddWifiDevice(self, ifname):
|
2018-05-14 12:22:09 +00:00
|
|
|
dev = WifiDevice(ifname)
|
|
|
|
return ExportedObj.to_path(self.add_device(dev))
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.method(IFACE_TEST, in_signature='s', out_signature='o')
|
|
|
|
def AddWimaxDevice(self, ifname):
|
2018-05-14 12:22:09 +00:00
|
|
|
dev = WimaxDevice(ifname)
|
|
|
|
return ExportedObj.to_path(self.add_device(dev))
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.method(IFACE_TEST, in_signature='o', out_signature='')
|
|
|
|
def RemoveDevice(self, path):
|
2018-05-09 10:46:34 +00:00
|
|
|
d = self.find_device_first(path = path, require = TestError)
|
|
|
|
self.remove_device(d)
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.method(IFACE_TEST, in_signature='sss', out_signature='o')
|
2018-05-09 10:46:34 +00:00
|
|
|
def AddWifiAp(self, ident, ssid, bssid):
|
|
|
|
d = self.find_device_first(ident = ident, require = TestError)
|
2018-05-14 12:22:09 +00:00
|
|
|
ap = WifiAp(ssid, bssid)
|
|
|
|
return ExportedObj.to_path(d.add_ap(ap))
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.method(IFACE_TEST, in_signature='so', out_signature='')
|
2018-05-09 10:46:34 +00:00
|
|
|
def RemoveWifiAp(self, ident, ap_path):
|
|
|
|
d = self.find_device_first(ident = ident, require = TestError)
|
|
|
|
d.remove_ap_by_path(ap_path)
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.method(IFACE_TEST, in_signature='ss', out_signature='o')
|
2018-05-09 10:46:34 +00:00
|
|
|
def AddWimaxNsp(self, ident, name):
|
|
|
|
d = self.find_device_first(ident = ident, require = TestError)
|
2018-05-14 12:22:09 +00:00
|
|
|
return ExportedObj.to_path(d.add_test_nsp(name))
|
2014-01-09 21:19:07 +00:00
|
|
|
|
|
|
|
@dbus.service.method(IFACE_TEST, in_signature='so', out_signature='')
|
2018-05-09 10:46:34 +00:00
|
|
|
def RemoveWimaxNsp(self, ident, nsp_path):
|
|
|
|
d = self.find_device_first(ident = ident, require = TestError)
|
|
|
|
d.remove_nsp_by_path(nsp_path)
|
2014-01-09 21:19:07 +00:00
|
|
|
|
2014-08-06 22:07:42 +00:00
|
|
|
@dbus.service.method(IFACE_TEST, in_signature='', out_signature='')
|
|
|
|
def AutoRemoveNextConnection(self):
|
2018-05-14 12:22:09 +00:00
|
|
|
gl.settings.auto_remove_next_connection()
|
2014-08-06 22:07:42 +00:00
|
|
|
|
2015-12-23 12:50:19 +00:00
|
|
|
@dbus.service.method(dbus_interface=IFACE_TEST, in_signature='a{sa{sv}}b', out_signature='o')
|
2018-06-04 18:33:35 +00:00
|
|
|
def AddConnection(self, con_hash, do_verify_strict):
|
|
|
|
return gl.settings.add_connection(con_hash, do_verify_strict)
|
2015-12-23 12:50:19 +00:00
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_TEST, in_signature='sa{sa{sv}}b', out_signature='')
|
2018-06-04 18:33:35 +00:00
|
|
|
def UpdateConnection(self, path, con_hash, do_verify_strict):
|
|
|
|
return gl.settings.update_connection(con_hash, path, do_verify_strict)
|
2015-12-23 12:50:19 +00:00
|
|
|
|
2018-05-29 08:13:18 +00:00
|
|
|
@dbus.service.method(dbus_interface=IFACE_TEST, in_signature='ba{ss}', out_signature='')
|
|
|
|
def ConnectionSetVisible(self, vis, selector_args):
|
|
|
|
cons = list(gl.settings.find_connections(**selector_args))
|
|
|
|
assert(len(cons) == 1)
|
|
|
|
cons[0].SetVisible(vis)
|
|
|
|
|
2016-09-20 12:29:00 +00:00
|
|
|
@dbus.service.method(dbus_interface=IFACE_TEST, in_signature='', out_signature='')
|
|
|
|
def Restart(self):
|
2018-05-14 12:22:09 +00:00
|
|
|
gl.bus.release_name("org.freedesktop.NetworkManager")
|
|
|
|
gl.bus.request_name("org.freedesktop.NetworkManager")
|
|
|
|
|
2016-09-20 12:29:00 +00:00
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
###############################################################################
|
2015-12-23 12:50:19 +00:00
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
PRP_CONNECTION_UNSAVED = 'Unsaved'
|
2018-05-28 08:43:14 +00:00
|
|
|
PRP_CONNECTION_FILENAME = 'Filename'
|
2018-05-15 06:31:16 +00:00
|
|
|
|
2016-09-20 12:39:55 +00:00
|
|
|
class Connection(ExportedObj):
|
2018-06-04 18:33:35 +00:00
|
|
|
def __init__(self, path_counter, con_hash, do_verify_strict=True):
|
2018-05-04 07:02:53 +00:00
|
|
|
|
|
|
|
path = "/org/freedesktop/NetworkManager/Settings/Connection/%s" % (path_counter)
|
2014-10-15 18:55:41 +00:00
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
ExportedObj.__init__(self, path)
|
|
|
|
|
2018-06-01 15:53:23 +00:00
|
|
|
s_con = con_hash.get(NM.SETTING_CONNECTION_SETTING_NAME)
|
|
|
|
if s_con is None:
|
|
|
|
s_con = {}
|
|
|
|
con_hash[NM.SETTING_CONNECTION_SETTING_NAME] = s_con
|
2018-06-04 18:33:35 +00:00
|
|
|
if NmUtil.con_hash_get_id(con_hash) is None:
|
2018-06-01 15:53:23 +00:00
|
|
|
s_con[NM.SETTING_CONNECTION_ID] = 'connection-%s' % (path_counter)
|
2018-06-04 18:33:35 +00:00
|
|
|
if NmUtil.con_hash_get_uuid(con_hash) is None:
|
2018-06-01 15:53:23 +00:00
|
|
|
s_con[NM.SETTING_CONNECTION_UUID] = str(uuid.uuid3(uuid.NAMESPACE_URL, path))
|
2018-06-01 14:41:46 +00:00
|
|
|
|
2018-06-04 18:33:35 +00:00
|
|
|
NmUtil.con_hash_verify(con_hash, do_verify_strict=do_verify_strict)
|
2015-12-23 12:50:19 +00:00
|
|
|
|
2018-05-04 07:02:53 +00:00
|
|
|
self.path = path
|
2018-06-01 14:41:46 +00:00
|
|
|
self.con_hash = con_hash
|
2014-07-22 22:22:23 +00:00
|
|
|
self.visible = True
|
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
props = {
|
|
|
|
PRP_CONNECTION_UNSAVED: False,
|
2018-05-28 08:43:14 +00:00
|
|
|
PRP_CONNECTION_FILENAME: "/etc/NetworkManager/system-connections/" + self.get_id(),
|
2018-05-15 06:31:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
self.dbus_interface_add(IFACE_CONNECTION, props)
|
2018-05-04 07:02:53 +00:00
|
|
|
|
2018-06-04 18:33:35 +00:00
|
|
|
def get_id(self):
|
|
|
|
return NmUtil.con_hash_get_id(self.con_hash)
|
2015-12-23 12:50:19 +00:00
|
|
|
|
2018-06-04 18:33:35 +00:00
|
|
|
def get_uuid(self):
|
|
|
|
return NmUtil.con_hash_get_uuid(self.con_hash)
|
2015-12-23 12:50:19 +00:00
|
|
|
|
2018-06-06 13:02:13 +00:00
|
|
|
def get_type(self):
|
|
|
|
return NmUtil.con_hash_get_type(self.con_hash)
|
|
|
|
|
|
|
|
def is_vpn(self):
|
|
|
|
return self.get_type() == NM.SETTING_VPN_SETTING_NAME
|
|
|
|
|
2018-06-04 18:33:35 +00:00
|
|
|
def update_connection(self, con_hash, do_verify_strict):
|
2015-12-23 12:50:19 +00:00
|
|
|
|
2018-06-04 18:33:35 +00:00
|
|
|
NmUtil.con_hash_verify(con_hash, do_verify_strict = do_verify_strict)
|
2015-12-23 12:50:19 +00:00
|
|
|
|
|
|
|
old_uuid = self.get_uuid()
|
2018-06-04 18:33:35 +00:00
|
|
|
new_uuid = NmUtil.con_hash_get_uuid(con_hash)
|
2015-12-23 12:50:19 +00:00
|
|
|
if old_uuid != new_uuid:
|
2018-06-05 08:51:16 +00:00
|
|
|
raise BusErr.InvalidPropertyException('connection.uuid: cannot change the uuid from %s to %s' % (old_uuid, new_uuid))
|
2015-12-23 12:50:19 +00:00
|
|
|
|
2018-06-01 14:41:46 +00:00
|
|
|
self.con_hash = con_hash;
|
2015-12-23 12:50:19 +00:00
|
|
|
self.Updated()
|
|
|
|
|
2014-07-22 22:22:23 +00:00
|
|
|
@dbus.service.method(dbus_interface=IFACE_CONNECTION, in_signature='', out_signature='a{sa{sv}}')
|
|
|
|
def GetSettings(self):
|
|
|
|
if not self.visible:
|
2018-06-05 08:51:16 +00:00
|
|
|
raise BusErr.PermissionDeniedException()
|
2018-06-01 14:41:46 +00:00
|
|
|
return self.con_hash
|
2014-07-22 22:22:23 +00:00
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_CONNECTION, in_signature='b', out_signature='')
|
|
|
|
def SetVisible(self, vis):
|
|
|
|
self.visible = vis
|
|
|
|
self.Updated()
|
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_CONNECTION, in_signature='', out_signature='')
|
|
|
|
def Delete(self):
|
2018-05-14 12:22:09 +00:00
|
|
|
gl.settings.delete_connection(self)
|
2014-07-22 22:22:23 +00:00
|
|
|
|
2015-12-23 12:50:19 +00:00
|
|
|
@dbus.service.method(dbus_interface=IFACE_CONNECTION, in_signature='a{sa{sv}}', out_signature='')
|
2018-06-01 14:41:46 +00:00
|
|
|
def Update(self, con_hash):
|
|
|
|
self.update_connection(con_hash, True)
|
2018-05-25 16:00:41 +00:00
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_CONNECTION, in_signature='a{sa{sv}}ua{sv}', out_signature='a{sv}')
|
2018-06-01 14:41:46 +00:00
|
|
|
def Update2(self, con_hash, flags, args):
|
|
|
|
self.update_connection(con_hash, True)
|
2018-05-25 16:00:41 +00:00
|
|
|
return []
|
2015-12-23 12:50:19 +00:00
|
|
|
|
2014-07-22 22:22:23 +00:00
|
|
|
@dbus.service.signal(IFACE_CONNECTION, signature='')
|
|
|
|
def Removed(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
@dbus.service.signal(IFACE_CONNECTION, signature='')
|
|
|
|
def Updated(self):
|
|
|
|
pass
|
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
###############################################################################
|
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
PRP_SETTINGS_HOSTNAME = 'Hostname'
|
|
|
|
PRP_SETTINGS_CAN_MODIFY = 'CanModify'
|
|
|
|
PRP_SETTINGS_CONNECTIONS = 'Connections'
|
|
|
|
|
2016-09-20 12:39:55 +00:00
|
|
|
class Settings(ExportedObj):
|
2018-05-15 06:31:16 +00:00
|
|
|
def __init__(self):
|
|
|
|
ExportedObj.__init__(self, "/org/freedesktop/NetworkManager/Settings")
|
|
|
|
|
2014-07-22 22:22:23 +00:00
|
|
|
self.connections = {}
|
2018-05-14 12:22:09 +00:00
|
|
|
self.c_counter = 0
|
2014-08-06 22:07:42 +00:00
|
|
|
self.remove_next_connection = False
|
2014-07-22 22:22:23 +00:00
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
props = {
|
|
|
|
PRP_SETTINGS_HOSTNAME: "foobar.baz",
|
|
|
|
PRP_SETTINGS_CAN_MODIFY: True,
|
|
|
|
PRP_SETTINGS_CONNECTIONS: dbus.Array([], 'o'),
|
|
|
|
}
|
|
|
|
|
|
|
|
self.dbus_interface_add(IFACE_SETTINGS, props, Settings.PropertiesChanged)
|
2018-05-14 12:22:09 +00:00
|
|
|
self.export()
|
2016-09-20 12:39:55 +00:00
|
|
|
|
2014-08-06 22:07:42 +00:00
|
|
|
def auto_remove_next_connection(self):
|
|
|
|
self.remove_next_connection = True;
|
|
|
|
|
2014-08-29 16:27:47 +00:00
|
|
|
def get_connection(self, path):
|
|
|
|
return self.connections[path]
|
|
|
|
|
2018-06-14 14:01:33 +00:00
|
|
|
def get_connections(self, stable_order = True):
|
|
|
|
cons = list(self.connections.values())
|
|
|
|
if stable_order:
|
|
|
|
cons.sort(key = lambda c: (Util.random_int(c.get_id()), Util.random_int(c.path)))
|
|
|
|
return cons
|
|
|
|
|
|
|
|
def get_connection_paths(self, stable_order = True):
|
|
|
|
return [c.path for c in self.get_connections(stable_order = stable_order)]
|
|
|
|
|
2018-05-04 07:02:53 +00:00
|
|
|
def find_connections(self, path = None, con_id = None, con_uuid = None):
|
2018-06-14 14:01:33 +00:00
|
|
|
for c in self.get_connections():
|
2018-05-04 07:02:53 +00:00
|
|
|
if path is not None:
|
|
|
|
if c.path != path:
|
|
|
|
continue
|
|
|
|
if con_id is not None:
|
|
|
|
if c.get_id() != con_id:
|
|
|
|
continue
|
|
|
|
if con_uuid is not None:
|
|
|
|
if c.get_uuid() != con_uuid:
|
|
|
|
continue
|
|
|
|
yield c
|
|
|
|
|
2014-07-22 22:22:23 +00:00
|
|
|
@dbus.service.method(dbus_interface=IFACE_SETTINGS, in_signature='', out_signature='ao')
|
|
|
|
def ListConnections(self):
|
2018-06-14 14:01:33 +00:00
|
|
|
return self.get_connection_paths()
|
2014-07-22 22:22:23 +00:00
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_SETTINGS, in_signature='a{sa{sv}}', out_signature='o')
|
2018-06-01 14:41:46 +00:00
|
|
|
def AddConnection(self, con_hash):
|
|
|
|
return self.add_connection(con_hash)
|
2015-12-23 12:50:19 +00:00
|
|
|
|
2018-06-04 18:33:35 +00:00
|
|
|
def add_connection(self, con_hash, do_verify_strict=True):
|
2018-05-14 12:22:09 +00:00
|
|
|
self.c_counter += 1
|
2018-06-04 18:33:35 +00:00
|
|
|
con_inst = Connection(self.c_counter, con_hash, do_verify_strict)
|
2015-12-23 12:50:19 +00:00
|
|
|
|
2018-06-01 15:22:12 +00:00
|
|
|
uuid = con_inst.get_uuid()
|
2018-06-14 14:01:33 +00:00
|
|
|
if uuid in [c.get_uuid() for c in self.get_connections(stable_order = False)]:
|
2018-06-05 08:51:16 +00:00
|
|
|
raise BusErr.InvalidSettingException('cannot add duplicate connection with uuid %s' % (uuid))
|
2015-12-23 12:50:19 +00:00
|
|
|
|
2018-06-01 15:22:12 +00:00
|
|
|
con_inst.export()
|
|
|
|
self.connections[con_inst.path] = con_inst
|
|
|
|
self.NewConnection(con_inst.path)
|
2018-06-14 14:01:33 +00:00
|
|
|
self._dbus_property_set(IFACE_SETTINGS, PRP_SETTINGS_CONNECTIONS, dbus.Array(self.get_connection_paths(), 'o'))
|
2014-08-06 22:07:42 +00:00
|
|
|
|
|
|
|
if self.remove_next_connection:
|
|
|
|
self.remove_next_connection = False
|
2018-06-01 15:22:12 +00:00
|
|
|
self.delete_connection(con_inst)
|
2014-08-06 22:07:42 +00:00
|
|
|
|
2018-06-06 13:02:13 +00:00
|
|
|
gl.manager.devices_available_connections_update()
|
|
|
|
|
2018-06-01 15:22:12 +00:00
|
|
|
return con_inst.path
|
2014-07-22 22:22:23 +00:00
|
|
|
|
2018-06-04 18:33:35 +00:00
|
|
|
def update_connection(self, con_hash, path=None, do_verify_strict=True):
|
2015-12-23 12:50:19 +00:00
|
|
|
if path not in self.connections:
|
2018-06-05 08:51:16 +00:00
|
|
|
raise BusErr.UnknownConnectionException('Connection not found')
|
2018-06-04 18:33:35 +00:00
|
|
|
self.connections[path].update_connection(con_hash, do_verify_strict)
|
2015-12-23 12:50:19 +00:00
|
|
|
|
2018-06-01 15:22:12 +00:00
|
|
|
def delete_connection(self, con_inst):
|
|
|
|
del self.connections[con_inst.path]
|
2018-06-14 14:01:33 +00:00
|
|
|
self._dbus_property_set(IFACE_SETTINGS, PRP_SETTINGS_CONNECTIONS, dbus.Array(self.get_connection_paths(), 'o'))
|
2018-06-01 15:22:12 +00:00
|
|
|
con_inst.Removed()
|
|
|
|
con_inst.unexport()
|
2014-07-22 22:22:23 +00:00
|
|
|
|
2018-06-06 13:02:13 +00:00
|
|
|
gl.manager.devices_available_connections_update()
|
|
|
|
|
2014-10-15 19:27:25 +00:00
|
|
|
@dbus.service.method(dbus_interface=IFACE_SETTINGS, in_signature='s', out_signature='')
|
|
|
|
def SaveHostname(self, hostname):
|
|
|
|
# Arbitrary requirement to test error handling
|
|
|
|
if hostname.find('.') == -1:
|
2018-06-05 08:51:16 +00:00
|
|
|
raise BusErr.InvalidHostnameException()
|
2018-05-15 06:31:16 +00:00
|
|
|
self._dbus_property_set(IFACE_SETTINGS, PRP_SETTINGS_HOSTNAME, hostname)
|
2014-07-22 22:22:23 +00:00
|
|
|
|
|
|
|
@dbus.service.signal(IFACE_SETTINGS, signature='o')
|
|
|
|
def NewConnection(self, path):
|
|
|
|
pass
|
|
|
|
|
|
|
|
@dbus.service.signal(IFACE_SETTINGS, signature='a{sv}')
|
|
|
|
def PropertiesChanged(self, path):
|
|
|
|
pass
|
|
|
|
|
|
|
|
@dbus.service.method(IFACE_SETTINGS, in_signature='', out_signature='')
|
|
|
|
def Quit(self):
|
2018-05-14 12:22:09 +00:00
|
|
|
gl.mainloop.quit()
|
|
|
|
|
|
|
|
###############################################################################
|
2014-07-22 22:22:23 +00:00
|
|
|
|
2018-06-06 18:28:17 +00:00
|
|
|
PRP_IP4_CONFIG_ADDRESSES = 'Addresses'
|
|
|
|
PRP_IP4_CONFIG_ADDRESSDATA = 'AddressData'
|
|
|
|
PRP_IP4_CONFIG_GATEWAY = 'Gateway'
|
|
|
|
PRP_IP4_CONFIG_ROUTES = 'Routes'
|
|
|
|
PRP_IP4_CONFIG_ROUTEDATA = 'RouteData'
|
|
|
|
PRP_IP4_CONFIG_NAMESERVERS = 'Nameservers'
|
|
|
|
PRP_IP4_CONFIG_DOMAINS = 'Domains'
|
|
|
|
PRP_IP4_CONFIG_SEARCHES = 'Searches'
|
|
|
|
PRP_IP4_CONFIG_DNSOPTIONS = 'DnsOptions'
|
|
|
|
PRP_IP4_CONFIG_DNSPRIORITY = 'DnsPriority'
|
|
|
|
PRP_IP4_CONFIG_WINSSERVERS = 'WinsServers'
|
|
|
|
|
|
|
|
class IP4Config(ExportedObj):
|
|
|
|
|
|
|
|
path_counter_next = 1
|
|
|
|
path_prefix = "/org/freedesktop/NetworkManager/IP4Config/"
|
|
|
|
|
|
|
|
def __init__(self, generate_seed = _DEFAULT_ARG):
|
|
|
|
ExportedObj.__init__(self, ExportedObj.create_path(IP4Config))
|
|
|
|
|
|
|
|
if generate_seed == _DEFAULT_ARG:
|
|
|
|
generate_seed = self.path
|
|
|
|
|
|
|
|
props = self._props_generate(generate_seed)
|
|
|
|
self.dbus_interface_add(IFACE_IP4_CONFIG, props, IP4Config.PropertiesChanged)
|
|
|
|
self.export()
|
|
|
|
|
|
|
|
def _props_generate(self, generate_seed):
|
|
|
|
seed = Util.RandomSeed.wrap(generate_seed)
|
|
|
|
|
|
|
|
gateway = None
|
|
|
|
if seed:
|
|
|
|
if Util.random_bool(seed):
|
|
|
|
gateway = Util.random_ip(seed, net = '192.168.0.0/16')[0]
|
|
|
|
|
|
|
|
addrs = []
|
|
|
|
if seed:
|
|
|
|
for n in range(0, Util.random_int(seed, 4)):
|
|
|
|
a = {
|
|
|
|
'addr': Util.random_ip(seed, net = '192.168.0.0/16')[0],
|
|
|
|
'prefix': Util.random_int(seed, 17, 32),
|
|
|
|
'gateway': gateway if n == 0 else None,
|
|
|
|
}
|
|
|
|
addrs.append(a)
|
|
|
|
|
|
|
|
routes = []
|
|
|
|
if seed:
|
|
|
|
for n in range(0, Util.random_int(seed, 4)):
|
|
|
|
a = {
|
|
|
|
'dest': Util.random_ip(seed, net = '192.168.0.0/16')[0],
|
|
|
|
'prefix': Util.random_int(seed, 17, 32),
|
|
|
|
'next-hop': None if (Util.random_int(seed) % 3 == 0) else Util.random_ip(seed, net = '192.168.0.0/16')[0],
|
|
|
|
'metric': -1 if (Util.random_int(seed) % 3 == 0) else Util.random_int(seed, 0, 0xFFFFFFFF),
|
|
|
|
}
|
|
|
|
routes.append(a)
|
|
|
|
|
|
|
|
nameservers = []
|
|
|
|
if seed:
|
|
|
|
nameservers = list([Util.random_ip(seed, net = '192.168.0.0/16')[0] for x in range(Util.random_int(seed, 4))])
|
|
|
|
|
|
|
|
names_selection = ['foo1.bar', 'foo2.bar', 'foo3.bar', 'foo4.bar', 'fo.o.bar', 'fo.x.y'];
|
|
|
|
|
|
|
|
domains = []
|
|
|
|
if seed:
|
|
|
|
domains = Util.random_subset(seed, ['dom4.' + s for s in names_selection])
|
|
|
|
|
|
|
|
searches = []
|
|
|
|
if seed:
|
|
|
|
domains = Util.random_subset(seed, ['sear4.' + s for s in names_selection])
|
|
|
|
|
|
|
|
dnsoptions = []
|
|
|
|
if seed:
|
|
|
|
dnsoptions = Util.random_subset(seed, ['dns4-opt1', 'dns4-opt2', 'dns4-opt3', 'dns4-opt4'])
|
|
|
|
|
|
|
|
dnspriority = 0
|
|
|
|
if seed:
|
|
|
|
dnspriority = Util.random_int(seed, -10000, 10000)
|
|
|
|
|
|
|
|
winsservers = []
|
|
|
|
if seed:
|
|
|
|
winsservers = list([Util.random_ip(seed, net = '192.168.0.0/16')[0] for x in range(Util.random_int(seed, 4))])
|
|
|
|
|
|
|
|
return {
|
|
|
|
PRP_IP4_CONFIG_ADDRESSES: dbus.Array([
|
2018-07-11 15:53:30 +00:00
|
|
|
[ Util.ip4_addr_be32(a['addr']),
|
2018-06-06 18:28:17 +00:00
|
|
|
a['prefix'],
|
2018-07-11 15:53:30 +00:00
|
|
|
Util.ip4_addr_be32(a['gateway']) if a['gateway'] else 0
|
2018-06-06 18:28:17 +00:00
|
|
|
] for a in addrs
|
|
|
|
],
|
|
|
|
'au'),
|
|
|
|
PRP_IP4_CONFIG_ADDRESSDATA: dbus.Array([
|
|
|
|
dbus.Dictionary(collections.OrderedDict( [ ('address', dbus.String(a['addr'])),
|
|
|
|
('prefix', dbus.UInt32(a['prefix']))] + \
|
|
|
|
([ ('gateway', dbus.String(a['gateway'])) ] if a['gateway'] else [])),
|
|
|
|
'sv')
|
|
|
|
for a in addrs
|
|
|
|
],
|
|
|
|
'a{sv}'),
|
|
|
|
PRP_IP4_CONFIG_GATEWAY: dbus.String(gateway) if gateway else "",
|
|
|
|
PRP_IP4_CONFIG_ROUTES: dbus.Array([
|
2018-07-11 15:53:30 +00:00
|
|
|
[ Util.ip4_addr_be32(a['dest']),
|
2018-06-06 18:28:17 +00:00
|
|
|
a['prefix'],
|
2018-07-11 15:53:30 +00:00
|
|
|
Util.ip4_addr_be32(a['next-hop'] or '0.0.0.0'),
|
2018-06-06 18:28:17 +00:00
|
|
|
max(a['metric'], 0)
|
|
|
|
] for a in routes
|
|
|
|
],
|
|
|
|
'au'),
|
|
|
|
PRP_IP4_CONFIG_ROUTEDATA: dbus.Array([
|
|
|
|
dbus.Dictionary(collections.OrderedDict( [ ('dest', dbus.String(a['dest'])),
|
|
|
|
('prefix', dbus.UInt32(a['prefix']))] + \
|
|
|
|
([ ('next-hop', dbus.String(a['next-hop'])) ] if a['next-hop'] else []) + \
|
|
|
|
([ ('metric', dbus.UInt32(a['metric'])) ] if a['metric'] != -1 else [])),
|
|
|
|
'sv')
|
|
|
|
for a in routes
|
|
|
|
],
|
|
|
|
'a{sv}'),
|
2018-07-11 15:53:30 +00:00
|
|
|
PRP_IP4_CONFIG_NAMESERVERS: dbus.Array([dbus.UInt32(Util.ip4_addr_be32(n)) for n in nameservers], 'u'),
|
2018-06-06 18:28:17 +00:00
|
|
|
PRP_IP4_CONFIG_DOMAINS: dbus.Array(domains, 's'),
|
|
|
|
PRP_IP4_CONFIG_SEARCHES: dbus.Array(searches, 's'),
|
|
|
|
PRP_IP4_CONFIG_DNSOPTIONS: dbus.Array(dnsoptions, 's'),
|
|
|
|
PRP_IP4_CONFIG_DNSPRIORITY: dbus.Int32(dnspriority),
|
2018-07-11 15:53:30 +00:00
|
|
|
PRP_IP4_CONFIG_WINSSERVERS: dbus.Array([dbus.UInt32(Util.ip4_addr_be32(n)) for n in winsservers], 'u'),
|
2018-06-06 18:28:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
def props_regenerate(self, generate_seed):
|
|
|
|
props = self.generate_props(generate_seed)
|
|
|
|
for k,v in props.items():
|
|
|
|
self._dbus_property_set(IFACE_IP4_CONFIG, k, v)
|
|
|
|
|
|
|
|
@dbus.service.signal(IFACE_IP4_CONFIG, signature='a{sv}')
|
|
|
|
def PropertiesChanged(self, path):
|
|
|
|
pass
|
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
PRP_IP6_CONFIG_ADDRESSES = "Addresses"
|
|
|
|
PRP_IP6_CONFIG_ADDRESSDATA = "AddressData"
|
|
|
|
PRP_IP6_CONFIG_GATEWAY = "Gateway"
|
|
|
|
PRP_IP6_CONFIG_ROUTES = "Routes"
|
|
|
|
PRP_IP6_CONFIG_ROUTEDATA = "RouteData"
|
|
|
|
PRP_IP6_CONFIG_NAMESERVERS = "Nameservers"
|
|
|
|
PRP_IP6_CONFIG_DOMAINS = "Domains"
|
|
|
|
PRP_IP6_CONFIG_SEARCHES = "Searches"
|
|
|
|
PRP_IP6_CONFIG_DNSOPTIONS = "DnsOptions"
|
|
|
|
PRP_IP6_CONFIG_DNSPRIORITY = "DnsPriority"
|
|
|
|
|
|
|
|
class IP6Config(ExportedObj):
|
|
|
|
|
|
|
|
path_counter_next = 1
|
|
|
|
path_prefix = "/org/freedesktop/NetworkManager/IP6Config/"
|
|
|
|
|
|
|
|
def __init__(self, generate_seed = _DEFAULT_ARG):
|
|
|
|
ExportedObj.__init__(self, ExportedObj.create_path(IP6Config))
|
|
|
|
|
|
|
|
if generate_seed == _DEFAULT_ARG:
|
|
|
|
generate_seed = self.path
|
|
|
|
|
|
|
|
props = self._props_generate(generate_seed)
|
|
|
|
self.dbus_interface_add(IFACE_IP6_CONFIG, props, IP6Config.PropertiesChanged)
|
|
|
|
self.export()
|
|
|
|
|
|
|
|
def _props_generate(self, generate_seed):
|
|
|
|
seed = Util.RandomSeed.wrap(generate_seed)
|
|
|
|
|
|
|
|
gateway = None
|
|
|
|
if seed:
|
|
|
|
if Util.random_bool(seed):
|
|
|
|
gateway = Util.random_ip(seed, net = '2001:a::/64')[0]
|
|
|
|
|
|
|
|
addrs = []
|
|
|
|
if seed:
|
|
|
|
for n in range(0, Util.random_int(seed, 4)):
|
|
|
|
a = {
|
|
|
|
'addr': Util.random_ip(seed, net = '2001:a::/64')[0],
|
|
|
|
'prefix': Util.random_int(seed, 65, 128),
|
|
|
|
'gateway': gateway if n == 0 else None,
|
|
|
|
}
|
|
|
|
addrs.append(a)
|
|
|
|
|
|
|
|
routes = []
|
|
|
|
if seed:
|
|
|
|
for n in range(0, Util.random_int(seed, 4)):
|
|
|
|
a = {
|
|
|
|
'dest': Util.random_ip(seed, net = '2001:a::/64')[0],
|
|
|
|
'prefix': Util.random_int(seed, 65, 128),
|
|
|
|
'next-hop': None if (Util.random_int(seed) % 3 == 0) else Util.random_ip(seed, net = '2001:a::/64')[0],
|
|
|
|
'metric': -1 if (Util.random_int(seed) % 3 == 0) else Util.random_int(seed, 0, 0xFFFFFFFF),
|
|
|
|
}
|
|
|
|
routes.append(a)
|
|
|
|
|
|
|
|
nameservers = []
|
|
|
|
if seed:
|
|
|
|
nameservers = list([Util.random_ip(seed, net = '2001:a::/64')[0] for x in range(Util.random_int(seed, 4))])
|
|
|
|
|
|
|
|
names_selection = ['foo1.bar', 'foo2.bar', 'foo3.bar', 'foo4.bar', 'fo.o.bar', 'fo.x.y'];
|
|
|
|
|
|
|
|
domains = []
|
|
|
|
if seed:
|
|
|
|
domains = Util.random_subset(seed, ['dom6.' + s for s in names_selection])
|
|
|
|
|
|
|
|
searches = []
|
|
|
|
if seed:
|
|
|
|
domains = Util.random_subset(seed, ['sear6.' + s for s in names_selection])
|
|
|
|
|
|
|
|
dnsoptions = []
|
|
|
|
if seed:
|
|
|
|
dnsoptions = Util.random_subset(seed, ['dns6-opt1', 'dns6-opt2', 'dns6-opt3', 'dns6-opt4'])
|
|
|
|
|
|
|
|
dnspriority = 0
|
|
|
|
if seed:
|
|
|
|
dnspriority = Util.random_int(seed, -10000, 10000)
|
|
|
|
|
|
|
|
return {
|
|
|
|
PRP_IP6_CONFIG_ADDRESSES: dbus.Array([
|
|
|
|
[ Util.ip6_addr_ay(a['addr']),
|
|
|
|
a['prefix'],
|
|
|
|
Util.ip6_addr_ay(a['gateway'] or '::')
|
|
|
|
] for a in addrs
|
|
|
|
],
|
|
|
|
'(ayuay)'),
|
|
|
|
PRP_IP6_CONFIG_ADDRESSDATA: dbus.Array([
|
|
|
|
dbus.Dictionary(collections.OrderedDict( [ ('address', dbus.String(a['addr'])),
|
|
|
|
('prefix', dbus.UInt32(a['prefix']))] + \
|
|
|
|
([ ('gateway', dbus.String(a['gateway'])) ] if a['gateway'] else [])),
|
|
|
|
'sv')
|
|
|
|
for a in addrs
|
|
|
|
],
|
|
|
|
'a{sv}'),
|
|
|
|
PRP_IP6_CONFIG_GATEWAY: dbus.String(gateway) if gateway else "",
|
|
|
|
PRP_IP6_CONFIG_ROUTES: dbus.Array([
|
|
|
|
[ Util.ip6_addr_ay(a['dest']),
|
|
|
|
a['prefix'],
|
|
|
|
Util.ip6_addr_ay(a['next-hop'] or '::'),
|
|
|
|
max(a['metric'], 0)
|
|
|
|
] for a in routes
|
|
|
|
],
|
|
|
|
'(ayuayu)'),
|
|
|
|
PRP_IP6_CONFIG_ROUTEDATA: dbus.Array([
|
|
|
|
dbus.Dictionary(collections.OrderedDict( [ ('dest', dbus.String(a['dest'])),
|
|
|
|
('prefix', dbus.UInt32(a['prefix']))] + \
|
|
|
|
([ ('next-hop', dbus.String(a['next-hop'])) ] if a['next-hop'] else []) + \
|
|
|
|
([ ('metric', dbus.UInt32(a['metric'])) ] if a['metric'] != -1 else [])),
|
|
|
|
'sv')
|
|
|
|
for a in routes
|
|
|
|
],
|
|
|
|
'a{sv}'),
|
|
|
|
PRP_IP6_CONFIG_NAMESERVERS: dbus.Array([Util.ip6_addr_ay(n) for n in nameservers], 'ay'),
|
|
|
|
PRP_IP6_CONFIG_DOMAINS: dbus.Array(domains, 's'),
|
|
|
|
PRP_IP6_CONFIG_SEARCHES: dbus.Array(searches, 's'),
|
|
|
|
PRP_IP6_CONFIG_DNSOPTIONS: dbus.Array(dnsoptions, 's'),
|
|
|
|
PRP_IP6_CONFIG_DNSPRIORITY: dbus.Int32(dnspriority),
|
|
|
|
}
|
|
|
|
|
|
|
|
def props_regenerate(self, generate_seed):
|
|
|
|
props = self.generate_props(generate_seed)
|
|
|
|
for k,v in props.items():
|
|
|
|
self._dbus_property_set(IFACE_IP6_CONFIG, k, v)
|
|
|
|
|
|
|
|
@dbus.service.signal(IFACE_IP6_CONFIG, signature='a{sv}')
|
|
|
|
def PropertiesChanged(self, path):
|
|
|
|
pass
|
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
PRP_DHCP4_CONFIG_OPTIONS = 'Options'
|
|
|
|
|
|
|
|
class Dhcp4Config(ExportedObj):
|
|
|
|
|
|
|
|
path_counter_next = 1
|
|
|
|
path_prefix = "/org/freedesktop/NetworkManager/DHCP4Config/"
|
|
|
|
|
|
|
|
def __init__(self, generate_seed = _DEFAULT_ARG):
|
|
|
|
ExportedObj.__init__(self, ExportedObj.create_path(Dhcp4Config))
|
|
|
|
|
|
|
|
if generate_seed == _DEFAULT_ARG:
|
|
|
|
generate_seed = self.path
|
|
|
|
|
|
|
|
props = self._props_generate(generate_seed)
|
|
|
|
self.dbus_interface_add(IFACE_DHCP4_CONFIG, props, Dhcp4Config.PropertiesChanged)
|
|
|
|
self.export()
|
|
|
|
|
|
|
|
def _props_generate(self, generate_seed):
|
|
|
|
seed = Util.RandomSeed.wrap(generate_seed)
|
|
|
|
|
|
|
|
options = []
|
|
|
|
if seed:
|
|
|
|
options = Util.random_subset(seed, [('dhcp-4-opt-' + str(i), 'val-' + str(i)) for i in range(10)])
|
|
|
|
|
|
|
|
return {
|
|
|
|
PRP_DHCP4_CONFIG_OPTIONS: dbus.Dictionary(collections.OrderedDict(options),
|
|
|
|
'sv')
|
|
|
|
}
|
|
|
|
|
|
|
|
def props_regenerate(self, generate_seed):
|
|
|
|
props = self.generate_props(generate_seed)
|
|
|
|
for k,v in props.items():
|
|
|
|
self._dbus_property_set(IFACE_DHCP4_CONFIG, k, v)
|
|
|
|
|
|
|
|
@dbus.service.signal(IFACE_DHCP4_CONFIG, signature='a{sv}')
|
|
|
|
def PropertiesChanged(self, path):
|
|
|
|
pass
|
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
PRP_DHCP6_CONFIG_OPTIONS = 'Options'
|
|
|
|
|
|
|
|
class Dhcp6Config(ExportedObj):
|
|
|
|
|
|
|
|
path_counter_next = 1
|
|
|
|
path_prefix = "/org/freedesktop/NetworkManager/DHCP6Config/"
|
|
|
|
|
|
|
|
def __init__(self, generate_seed = _DEFAULT_ARG):
|
|
|
|
ExportedObj.__init__(self, ExportedObj.create_path(Dhcp6Config))
|
|
|
|
|
|
|
|
if generate_seed == _DEFAULT_ARG:
|
|
|
|
generate_seed = self.path
|
|
|
|
|
|
|
|
props = self._props_generate(generate_seed)
|
|
|
|
self.dbus_interface_add(IFACE_DHCP6_CONFIG, props, Dhcp6Config.PropertiesChanged)
|
|
|
|
self.export()
|
|
|
|
|
|
|
|
def _props_generate(self, generate_seed):
|
|
|
|
seed = Util.RandomSeed.wrap(generate_seed)
|
|
|
|
|
|
|
|
options = []
|
|
|
|
if seed:
|
|
|
|
options = Util.random_subset(seed, [('dhcp-6-opt-' + str(i), 'val-' + str(i)) for i in range(10)])
|
|
|
|
|
|
|
|
return {
|
|
|
|
PRP_DHCP4_CONFIG_OPTIONS: dbus.Dictionary(collections.OrderedDict(options),
|
|
|
|
'sv')
|
|
|
|
}
|
|
|
|
|
|
|
|
def props_regenerate(self, generate_seed):
|
|
|
|
props = self.generate_props(generate_seed)
|
|
|
|
for k,v in props.items():
|
|
|
|
self._dbus_property_set(IFACE_DHCP6_CONFIG, k, v)
|
|
|
|
|
|
|
|
@dbus.service.signal(IFACE_DHCP6_CONFIG, signature='a{sv}')
|
|
|
|
def PropertiesChanged(self, path):
|
|
|
|
pass
|
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
2018-05-15 08:06:37 +00:00
|
|
|
PRP_DNS_MANAGER_MODE = 'Mode'
|
|
|
|
PRP_DNS_MANAGER_RC_MANAGER = 'RcManager'
|
|
|
|
PRP_DNS_MANAGER_CONFIGURATION = 'Configuration'
|
|
|
|
|
|
|
|
class DnsManager(ExportedObj):
|
|
|
|
def __init__(self):
|
|
|
|
ExportedObj.__init__(self, "/org/freedesktop/NetworkManager/DnsManager")
|
|
|
|
|
|
|
|
props = {
|
|
|
|
PRP_DNS_MANAGER_MODE: "dnsmasq",
|
|
|
|
PRP_DNS_MANAGER_RC_MANAGER: "symlink",
|
|
|
|
PRP_DNS_MANAGER_CONFIGURATION: dbus.Array(
|
|
|
|
[
|
|
|
|
dbus.Dictionary(
|
|
|
|
{
|
|
|
|
'nameservers' : dbus.Array(['1.2.3.4', '5.6.7.8'], 's'),
|
|
|
|
'priority' : dbus.Int32(100),
|
|
|
|
},
|
|
|
|
'sv')
|
|
|
|
],
|
|
|
|
'a{sv}'),
|
|
|
|
}
|
|
|
|
|
|
|
|
self.dbus_interface_add(IFACE_DNS_MANAGER, props)
|
|
|
|
self.export()
|
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
2014-08-29 16:27:47 +00:00
|
|
|
PATH_SECRET_AGENT = '/org/freedesktop/NetworkManager/SecretAgent'
|
|
|
|
|
|
|
|
FLAG_ALLOW_INTERACTION = 0x1
|
|
|
|
FLAG_REQUEST_NEW = 0x2
|
|
|
|
FLAG_USER_REQUESTED = 0x4
|
|
|
|
|
|
|
|
class AgentManager(dbus.service.Object):
|
2018-05-15 06:31:16 +00:00
|
|
|
def __init__(self):
|
|
|
|
dbus.service.Object.__init__(self, gl.bus, "/org/freedesktop/NetworkManager/AgentManager")
|
2014-08-29 16:27:47 +00:00
|
|
|
self.agents = {}
|
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_AGENT_MANAGER,
|
|
|
|
in_signature='s', out_signature='',
|
|
|
|
sender_keyword='sender')
|
|
|
|
def Register(self, name, sender=None):
|
|
|
|
self.RegisterWithCapabilities(name, 0, sender)
|
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_AGENT_MANAGER,
|
|
|
|
in_signature='su', out_signature='',
|
|
|
|
sender_keyword='sender')
|
|
|
|
def RegisterWithCapabilities(self, name, caps, sender=None):
|
2018-05-14 12:22:09 +00:00
|
|
|
self.agents[sender] = gl.bus.get_object(sender, PATH_SECRET_AGENT)
|
2014-08-29 16:27:47 +00:00
|
|
|
|
|
|
|
@dbus.service.method(dbus_interface=IFACE_AGENT_MANAGER,
|
|
|
|
in_signature='', out_signature='',
|
|
|
|
sender_keyword='sender')
|
|
|
|
def Unregister(self, sender=None):
|
|
|
|
del self.agents[sender]
|
|
|
|
|
2018-06-01 14:41:46 +00:00
|
|
|
def get_secrets(self, con_hash, path, setting_name):
|
2014-08-29 16:27:47 +00:00
|
|
|
if len(self.agents) == 0:
|
|
|
|
return None
|
|
|
|
|
|
|
|
secrets = {}
|
|
|
|
for sender in self.agents:
|
|
|
|
agent = self.agents[sender]
|
|
|
|
try:
|
2018-06-01 14:41:46 +00:00
|
|
|
secrets = agent.GetSecrets(con_hash, path, setting_name,
|
2014-08-29 16:27:47 +00:00
|
|
|
dbus.Array([], 's'),
|
|
|
|
FLAG_ALLOW_INTERACTION | FLAG_USER_REQUESTED,
|
|
|
|
dbus_interface=IFACE_AGENT)
|
|
|
|
break
|
|
|
|
except dbus.DBusException as e:
|
|
|
|
if e.get_dbus_name() == IFACE_AGENT + '.UserCanceled':
|
2018-06-05 08:51:16 +00:00
|
|
|
raise BusErr.UserCanceledException('User canceled')
|
2014-08-29 16:27:47 +00:00
|
|
|
continue
|
|
|
|
return secrets
|
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
###############################################################################
|
|
|
|
|
2016-09-16 12:26:48 +00:00
|
|
|
class ObjectManager(dbus.service.Object):
|
2018-05-14 12:22:09 +00:00
|
|
|
def __init__(self, object_path):
|
|
|
|
dbus.service.Object.__init__(self, gl.bus, object_path)
|
2016-09-16 12:26:48 +00:00
|
|
|
self.objs = []
|
|
|
|
|
2018-05-15 14:20:00 +00:00
|
|
|
def find_object(self, path):
|
|
|
|
for o in self.objs:
|
|
|
|
if path == o.path:
|
|
|
|
return o
|
|
|
|
return None
|
|
|
|
|
2016-09-16 12:26:48 +00:00
|
|
|
def add_object(self, obj):
|
2018-05-14 12:22:09 +00:00
|
|
|
self.objs.append(obj)
|
2018-05-15 19:04:22 +00:00
|
|
|
self.InterfacesAdded(obj.path, obj.get_managed_ifaces())
|
2016-09-16 12:26:48 +00:00
|
|
|
|
|
|
|
def remove_object(self, obj):
|
2018-05-14 12:22:09 +00:00
|
|
|
self.objs.remove(obj)
|
2018-05-15 19:04:22 +00:00
|
|
|
self.InterfacesRemoved(obj.path, obj.get_managed_ifaces().keys())
|
2016-09-16 12:26:48 +00:00
|
|
|
|
|
|
|
@dbus.service.signal(IFACE_OBJECT_MANAGER, signature='oa{sa{sv}}')
|
|
|
|
def InterfacesAdded(self, name, ifaces):
|
|
|
|
pass
|
|
|
|
|
|
|
|
@dbus.service.signal(IFACE_OBJECT_MANAGER, signature='oas')
|
|
|
|
def InterfacesRemoved(self, name, ifaces):
|
|
|
|
pass
|
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
@dbus.service.method(dbus_interface=IFACE_OBJECT_MANAGER,
|
|
|
|
in_signature='', out_signature='a{oa{sa{sv}}}',
|
|
|
|
sender_keyword='sender')
|
|
|
|
def GetManagedObjects(self, sender=None):
|
|
|
|
managed_objects = {}
|
|
|
|
for obj in self.objs:
|
2018-05-15 19:04:22 +00:00
|
|
|
managed_objects[obj.path] = obj.get_managed_ifaces()
|
2018-05-14 12:22:09 +00:00
|
|
|
return managed_objects
|
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
2014-01-09 21:19:07 +00:00
|
|
|
def main():
|
|
|
|
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
|
|
|
|
|
|
|
random.seed()
|
|
|
|
|
2018-05-15 08:16:14 +00:00
|
|
|
global gl
|
|
|
|
gl = Global()
|
2014-08-06 22:07:42 +00:00
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
gl.mainloop = GLib.MainLoop()
|
|
|
|
gl.bus = dbus.SessionBus()
|
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
gl.object_manager = ObjectManager('/org/freedesktop')
|
|
|
|
gl.manager = NetworkManager()
|
|
|
|
gl.settings = Settings()
|
|
|
|
gl.dns_manager = DnsManager()
|
2018-05-15 08:16:14 +00:00
|
|
|
gl.agent_manager = AgentManager()
|
2014-08-06 22:07:42 +00:00
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
if not gl.bus.request_name("org.freedesktop.NetworkManager"):
|
|
|
|
raise AssertionError("Failure to request D-Bus name org.freedesktop.NetworkManager")
|
2014-01-09 21:19:07 +00:00
|
|
|
|
2014-07-31 18:00:22 +00:00
|
|
|
# Watch stdin; if it closes, assume our parent has crashed, and exit
|
2018-05-15 09:38:05 +00:00
|
|
|
id1 = GLib.IOChannel(0).add_watch(GLib.IOCondition.HUP,
|
|
|
|
lambda io, condition: gl.mainloop.quit() or True)
|
2014-07-31 18:00:22 +00:00
|
|
|
|
2018-05-14 12:22:09 +00:00
|
|
|
gl.mainloop.run()
|
2014-01-09 21:19:07 +00:00
|
|
|
|
2018-05-15 06:31:16 +00:00
|
|
|
GLib.source_remove(id1)
|
|
|
|
|
2018-05-15 08:16:14 +00:00
|
|
|
gl.agent_manager.remove_from_connection()
|
|
|
|
gl.dns_manager.unexport()
|
|
|
|
gl.settings.unexport()
|
|
|
|
gl.manager.unexport()
|
|
|
|
gl.object_manager.remove_from_connection()
|
|
|
|
|
2014-01-09 21:19:07 +00:00
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|