diff options
Diffstat (limited to 'tools')
| -rwxr-xr-x | tools/check-compare-generated.sh | 18 | ||||
| -rwxr-xr-x | tools/check-config-options.sh | 8 | ||||
| -rwxr-xr-x | tools/check-docs.sh | 1 | ||||
| -rwxr-xr-x | tools/check-gitlab-ci.sh | 37 | ||||
| -rwxr-xr-x | tools/check-settings-docs.sh | 19 | ||||
| -rwxr-xr-x | tools/check-tree.sh | 24 | ||||
| -rwxr-xr-x | tools/create-exports-NetworkManager.sh | 21 | ||||
| -rwxr-xr-x | tools/enums-to-docbook.pl | 2 | ||||
| -rwxr-xr-x | tools/generate-docs-nm-property-infos.pl | 2 | ||||
| -rwxr-xr-x | tools/generate-docs-nm-settings-docs-gir.py | 2 | ||||
| -rwxr-xr-x | tools/generate-docs-nm-settings-docs-merge.py | 2 | ||||
| -rwxr-xr-x | tools/run-nm-test.sh | 68 | ||||
| -rwxr-xr-x | tools/test-networkmanager-service.py | 270 |
13 files changed, 408 insertions, 66 deletions
diff --git a/tools/check-compare-generated.sh b/tools/check-compare-generated.sh new file mode 100755 index 00000000..44b70f95 --- /dev/null +++ b/tools/check-compare-generated.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +set -e + +srcdir="$1" +builddir="$2" +doc_h="$3" + +[ -n "$NMTST_NO_CHECK_SETTINGS_DOCS" ] && exit 0 + +cmp -s "${srcdir}/${doc_h}.in" "${builddir}/${doc_h}" && exit 0 + +if [ "$NM_TEST_REGENERATE" = 1 ] ; then + cp -f "${builddir}/${doc_h}" "${srcdir}/${doc_h}.in" +else + echo "*** Error: the generated file '${builddir}/${doc_h}' differs from the source file '${srcdir}/${doc_h}.in'. You probably should copy the generated file over to the source file. You can skip this test by setting NMTST_NO_CHECK_SETTINGS_DOCS=yes. You can also automatically copy the file by rerunning the test with NM_TEST_REGENERATE=1" + exit 1 +fi diff --git a/tools/check-config-options.sh b/tools/check-config-options.sh index 7a775955..4cbd4855 100755 --- a/tools/check-config-options.sh +++ b/tools/check-config-options.sh @@ -5,21 +5,21 @@ ret=0 get_supported_options() { - awk '/START OPTION LIST/{flag=1;next}/END OPTION LIST/{flag=0}flag' "$srcdir/src/nm-config.c" | + awk '/START OPTION LIST/{flag=1;next}/END OPTION LIST/{flag=0}flag' "$srcdir/src/core/nm-config.c" | grep -o 'NM_CONFIG_KEYFILE_KEY_\w*' } get_missing_options() { - grep -v '/\* check-config-options skip \*/' "$srcdir/src/nm-config.h" | + grep -v '/\* check-config-options skip \*/' "$srcdir/src/core/nm-config.h" | grep -o 'NM_CONFIG_KEYFILE_KEY_\w*' | grep -v -Fx -f <(get_supported_options) } get_src_con_defaults() { - sed -ne 's/.*\<NM_CON_DEFAULT\s*("\([^"]*\)").*/\1/p' $(find "$srcdir/src/" -name \*.c ! -name test\*.c) - sed -ne 's/.*\<NM_CON_DEFAULT_NOP\s*("\([^"]*\)").*/\1/p' $(find "$srcdir/src/" -name \*.c ! -name test\*.c) + sed -n 's/\<NM_CON_DEFAULT/\n\0/gp' $(find "$srcdir/src/core/" -name \*.c ! -name test\*.c) | + sed -n 's/.*\<NM_CON_DEFAULT\(_NOP\)\?\s*("\([^"]*\)").*/\2/p' } get_man_con_defaults() diff --git a/tools/check-docs.sh b/tools/check-docs.sh index e0ed7837..f4f05b91 100755 --- a/tools/check-docs.sh +++ b/tools/check-docs.sh @@ -71,6 +71,7 @@ annotation-glossary api-index-full nm-dbus-interface nm-errors +nm-keyfile nm-utils nm-version " diff --git a/tools/check-gitlab-ci.sh b/tools/check-gitlab-ci.sh new file mode 100755 index 00000000..8ad0fbb2 --- /dev/null +++ b/tools/check-gitlab-ci.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +set -e + +if [ "$NMTST_SKIP_CHECK_GITLAB_CI" = 1 ]; then + exit 0 +fi + +if [ $# -eq 0 ] ; then + BASEDIR="$(dirname "$(readlink -f "$0")")/.." +elif [ $# -eq 1 ] ; then + BASEDIR="$1" +else + echo "invalid arguments" + exit 1 +fi + +cd "$BASEDIR" + +if ! [ -f ./.gitlab-ci.yml ] ; then + # we have no gitlab-ci. Probably this is not a git-checkout + # but a dist'ed source-tree. Nothing to check. + exit 0 +fi + +if ! command -v ci-fairy &> /dev/null ; then + # ci-fairy not available. Cannot check. + exit 0 +fi + + +if [ "$NM_TEST_REGENERATE" == 1 ] ; then + ci-fairy generate-template + exit 0 +fi + +diff "./.gitlab-ci.yml" <(ci-fairy generate-template -o /dev/stdout) diff --git a/tools/check-settings-docs.sh b/tools/check-settings-docs.sh deleted file mode 100755 index 8695ccc0..00000000 --- a/tools/check-settings-docs.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -srcdir=$1 -builddir=$2 -doc_h=$3 - -if [ -z "$NMTST_NO_CHECK_SETTINGS_DOCS" ] ; then - if ! cmp -s "${srcdir}/${doc_h}.in" "${builddir}/${doc_h}"; then - if [ "$NM_TEST_REGENERATE" = 1 ] ; then - cp -f "${builddir}/${doc_h}" "${srcdir}/${doc_h}.in" - else - echo "*** Error: the generated file '${builddir}/${doc_h}' differs from the source file '${srcdir}/${doc_h}.in'. You probably should copy the generated file over to the source file. You can skip this test by setting NMTST_NO_CHECK_SETTINGS_DOCS=yes. You can also automatically copy the file by rerunning the test with NM_TEST_REGENERATE=1" - exit 1 - fi - fi -fi - -exit 0 - diff --git a/tools/check-tree.sh b/tools/check-tree.sh new file mode 100755 index 00000000..cff85c3e --- /dev/null +++ b/tools/check-tree.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +set -e + +TOP_DIR="$(dirname "$0")/.." + +die() { + printf 'FAIL: %s\n' "$*" >&2 + exit 1 +} + +check_cmp() { + local a="$1" + local b="$2" + + cmp "$TOP_DIR/$a" "$TOP_DIR/$b" && return 0 + + diff "$TOP_DIR/$a" "$TOP_DIR/$b" || : + die "files \"$a\" and \"$b\" differ!" +} + +check_cmp shared/nm-base/nm-ethtool-utils-base.h libnm/nm-ethtool-utils.h +check_cmp libnm-core/nm-meta-setting-base-impl.h clients/common/nm-meta-setting-base-impl.h +check_cmp libnm-core/nm-meta-setting-base-impl.c clients/common/nm-meta-setting-base-impl.c diff --git a/tools/create-exports-NetworkManager.sh b/tools/create-exports-NetworkManager.sh index 6cb7c2e7..f7fd3bab 100755 --- a/tools/create-exports-NetworkManager.sh +++ b/tools/create-exports-NetworkManager.sh @@ -8,7 +8,7 @@ die() { exit 1 } -# generates the linker version script src/NetworkManager.ver +# generates the linker version script src/core/NetworkManager.ver # by looking at the symbols needed by the device and settings # plugins. Note that this depends on how NetworkManager and # the plugins are build. For example, compiling without @@ -40,7 +40,10 @@ call_nm() { } get_symbols_nm () { - base=./src/NetworkManager-all-sym + base=./src/core/.libs/NetworkManager-all-sym + if ! test -f "$base"; then + base=./src/core/NetworkManager-all-sym + fi call_nm "$base" | sed -n 's/^[tTDGRBS] //p' | _sort @@ -53,9 +56,9 @@ EOF } get_symbols_missing() { - (for f in $(find ./src/settings/plugins/*/${libs} \ - ./src/devices/*/${libs} \ - ./src/ppp/${libs} -name '*.so' 2>/dev/null); do + (for f in $(find ./src/core/settings/plugins/*/${libs} \ + ./src/core/devices/*/${libs} \ + ./src/core/ppp/${libs} -name '*.so' 2>/dev/null); do call_nm "$f" | sed -n 's/^\([U]\) \(\(nm_\|nmp_\|_nm\|NM\|_NM\|nmtst_\|c_siphash_\|c_list_\).*\)$/\2/p' done) | @@ -79,7 +82,7 @@ do_rebuild() { } do_update() { - do_generate > ./src/NetworkManager.ver + do_generate > ./src/core/NetworkManager.ver } SYMBOLS_MISSING="$(get_symbols_missing | pretty)" @@ -107,7 +110,7 @@ else libs=.libs/ fi -test -f ./src/${libs}libNetworkManager.a || die "must be called from NetworkManager top build dir after building the tree" +test -f ./src/core/${libs}libNetworkManager.a || die "must be called from NetworkManager top build dir after building the tree" case "$1" in rebuild) @@ -122,8 +125,8 @@ case "$1" in if test -z "${NM_BUILD_NO_CREATE_EXPORTS+x}"; then do_update else - if test -f "./src/NetworkManager.ver"; then - touch ./src/NetworkManager.ver + if test -f "./src/core/NetworkManager.ver"; then + touch ./src/core/NetworkManager.ver fi fi ;; diff --git a/tools/enums-to-docbook.pl b/tools/enums-to-docbook.pl index f422acbd..8439eaee 100755 --- a/tools/enums-to-docbook.pl +++ b/tools/enums-to-docbook.pl @@ -1,5 +1,5 @@ #!/usr/bin/perl -n -# SPDX-License-Identifier: GPL-2.0+ +# SPDX-License-Identifier: GPL-2.0-or-later # # Copyright (C) 2016 Red Hat, Inc. # diff --git a/tools/generate-docs-nm-property-infos.pl b/tools/generate-docs-nm-property-infos.pl index bbdec3b6..f850ee74 100755 --- a/tools/generate-docs-nm-property-infos.pl +++ b/tools/generate-docs-nm-property-infos.pl @@ -1,5 +1,5 @@ #!/usr/bin/env perl -# SPDX-License-Identifier: GPL-2.0+ +# SPDX-License-Identifier: GPL-2.0-or-later # # Copyright (C) 2014 Red Hat, Inc. # diff --git a/tools/generate-docs-nm-settings-docs-gir.py b/tools/generate-docs-nm-settings-docs-gir.py index 317b3297..6df85190 100755 --- a/tools/generate-docs-nm-settings-docs-gir.py +++ b/tools/generate-docs-nm-settings-docs-gir.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# SPDX-License-Identifier: LGPL-2.1+ +# SPDX-License-Identifier: LGPL-2.1-or-later # # Copyright (C) 2009 - 2017 Red Hat, Inc. # diff --git a/tools/generate-docs-nm-settings-docs-merge.py b/tools/generate-docs-nm-settings-docs-merge.py index 0da3a0bb..5fe61997 100755 --- a/tools/generate-docs-nm-settings-docs-merge.py +++ b/tools/generate-docs-nm-settings-docs-merge.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# SPDX-License-Identifier: LGPL-2.1+ +# SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import print_function diff --git a/tools/run-nm-test.sh b/tools/run-nm-test.sh index f452d9d4..6d835a8f 100755 --- a/tools/run-nm-test.sh +++ b/tools/run-nm-test.sh @@ -23,6 +23,43 @@ _is_true() { esac } +usage() { + echo "$0 [\$OPTIONS] [--] \$TEST [\$TEST_OPTIONS]" + echo "" + echo " Runs the unit test with setting up dbus-session (as necessary)," + echo " optionally build the test first, and run valgrind" + echo "" + echo " --help|-h: help" + echo " --launch-dbus: the test runner by default automatically launches a D-Bus session" + echo " depending on a hard-coded list of tests that require it. This flag overwrites" + echo " the automatism to always launch a D-Bus session" + echo " --no-launch-dbus|-D: prevent launching a D-Bus session" + echo " --no-libtool: when running with valgrind, the script tries automatically to" + echo " use libtool as necessary. This disables libtool usage" + echo " --make-first|-m: before running the test, make it (only works with autotools build)" + echo " --valgrind|-v: run under valgrind" + echo " --no-valgrind|-V: disable running under valgrind (overrides NMTST_USE_VALGRIND=1)" + echo " -d: set NMTST_DEBUG=d" + echo " --test|-t \$TEST: set the test that should be run" + echo "" + echo " With \"--test\" and \"--\" you can select the test and which arguments are" + echo " passed to the test. You can omit these, in which case the first unknown parameter" + echo " is the test and all other unknown parameters are passed to the test. For example" + echo " $0 -m --test src/core/tests/test-core -- -p /general/match-spec/device" + echo " can also be called as" + echo " $0 src/core/tests/test-core -p /general/match-spec/device -m" + echo "" + echo " The following environment variables are honored:" + echo " NMTST_USE_VALGRIND=0|1: enable/disable valgrind" + echo " NMTST_LIBTOOL=: libtool path (or disable)" + echo " NMTST_LAUNCH_DBUS=0|1: whether to lounch a D-Bus session" + echo " NMTST_SET_DEBUG=0|1: saet NMTST_DEBUG=d" + echo "" + echo " This script is also called by the build system as test wrapper. In that case" + echo " different, internal command line syntax is used. In that case, environment variables" + echo " are still honored, so \`NMTST_USE_VALGRIND=1 make check\` works as expected" +} + SCRIPT_PATH="${SCRIPT_PATH:-$(readlink -f "$(dirname "$0")")}" VALGRIND_ERROR=37 @@ -90,6 +127,7 @@ if [ "$CALLED_FROM_MAKE" == 1 ]; then TEST="$1"; shift NMTST_MAKE_FIRST=0 + TEST_ARGV=("$@") else if [[ -z "${NMTST_USE_VALGRIND+x}" ]]; then # by default, disable valgrind checks. @@ -103,9 +141,14 @@ else else NMTST_LIBTOOL=("$NMTST_LIBTOOL" "--mode=execute") fi + TEST_ARGV=() unset TEST while test $# -gt 0; do case "$1" in + --help|-h) + usage + exit 0 + ;; "--launch-dbus") NMTST_LAUNCH_DBUS=1 shift @@ -141,19 +184,26 @@ else ;; "--") shift + if test -z "${TEST+x}"; then + TEST="$1"; + shift + fi + TEST_ARGV+=("$@") break ;; *) - break + if test -z "${TEST+x}"; then + TEST="$1"; + else + TEST_ARGV+=("$1") + fi + shift ;; esac done # we support calling the script directly. In this case, # only pass the path to the test to run. - if test -z "${TEST+x}"; then - TEST="$1"; shift - fi if [[ -z "${NMTST_SUPPRESSIONS+x}" ]]; then NMTST_SUPPRESSIONS="$SCRIPT_PATH/../valgrind.suppressions" fi @@ -178,6 +228,8 @@ if [ "$NMTST_SET_DEBUG" == 1 -a -z "${NMTST_DEBUG+x}" ]; then export NMTST_DEBUG=d fi +[ -n "$TEST" ] || die "Missing test name. Specify it on the command line." + if _is_true "$NMTST_MAKE_FIRST" 0; then git_dir="$(readlink -f "$(git rev-parse --show-toplevel)")" rel_path="$(realpath --relative-to="$git_dir" -m "$TEST" 2>/dev/null)" || die "cannot resolve test-name \"$TEST\". Did you call the script properly?" @@ -207,7 +259,7 @@ fi NMTST_DBUS_RUN_SESSION=() if _is_true "$NMTST_LAUNCH_DBUS"; then - if ! which dbus-run-session &>/dev/null ; then + if ! command -v dbus-run-session &>/dev/null ; then eval `dbus-launch --sh-syntax` trap "kill $DBUS_SESSION_BUS_PID" EXIT else @@ -244,12 +296,12 @@ fi if ! _is_true "$NMTST_USE_VALGRIND" 0; then export NM_TEST_UNDER_VALGRIND=0 exec "${NMTST_DBUS_RUN_SESSION[@]}" \ - "$TEST" "$@" + "$TEST" "${TEST_ARGV[@]}" die "exec \"$TEST\" failed" fi if [[ -z "${NMTST_VALGRIND}" ]]; then - NMTST_VALGRIND=`which valgrind` || die "cannot find valgrind binary. Set \$NMTST_VALGRIND" + NMTST_VALGRIND="$(command -v valgrind)" || die "cannot find valgrind binary. Set \$NMTST_VALGRIND" else test -e "${NMTST_VALGRIND}" || die "cannot find valgrind binary from NMTST_VALGRIND=\"${NMTST_VALGRIND}\"" fi @@ -276,7 +328,7 @@ export NM_TEST_UNDER_VALGRIND=1 --num-callers=100 \ --log-file="$LOGFILE" \ "$TEST" \ - "$@" + "${TEST_ARGV[@]}" RESULT=$? test -s "$LOGFILE" diff --git a/tools/test-networkmanager-service.py b/tools/test-networkmanager-service.py index 359c5e5d..fe5e4d44 100755 --- a/tools/test-networkmanager-service.py +++ b/tools/test-networkmanager-service.py @@ -299,6 +299,8 @@ class Util: return GLib.Variant("u", int(val)) if isinstance(val, dbus.UInt64): return GLib.Variant("t", int(val)) + if isinstance(val, dbus.Int32): + return GLib.Variant("i", int(val)) if isinstance(val, dbus.Boolean): return GLib.Variant("b", bool(val)) if isinstance(val, dbus.Byte): @@ -389,6 +391,7 @@ 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_MODEM = "org.freedesktop.NetworkManager.Device.Modem" IFACE_VLAN = "org.freedesktop.NetworkManager.Device.Vlan" IFACE_WIFI_AP = "org.freedesktop.NetworkManager.AccessPoint" IFACE_ACTIVE_CONNECTION = "org.freedesktop.NetworkManager.Connection.Active" @@ -404,46 +407,74 @@ IFACE_DHCP6_CONFIG = "org.freedesktop.NetworkManager.DHCP6Config" class BusErr: class UnknownInterfaceException(dbus.DBusException): - _dbus_error_name = IFACE_DBUS + ".UnknownInterface" + def __init__(self, *args, **kwargs): + self._dbus_error_name = "{}.UnknownInterface".format(IFACE_DBUS) + dbus.DBusException.__init__(self, *args, **kwargs) class UnknownPropertyException(dbus.DBusException): - _dbus_error_name = IFACE_DBUS + ".UnknownProperty" + def __init__(self, *args, **kwargs): + self._dbus_error_name = "{}.UnknownProperty".format(IFACE_DBUS) + dbus.DBusException.__init__(self, *args, **kwargs) class InvalidPropertyException(dbus.DBusException): - _dbus_error_name = IFACE_CONNECTION + ".InvalidProperty" + def __init__(self, *args, **kwargs): + self._dbus_error_name = "{}.InvalidProperty".format(IFACE_CONNECTION) + dbus.DBusException.__init__(self, *args, **kwargs) class MissingPropertyException(dbus.DBusException): - _dbus_error_name = IFACE_CONNECTION + ".MissingProperty" + def __init__(self, *args, **kwargs): + self._dbus_error_name = "{}.MissingProperty".format(IFACE_CONNECTION) + dbus.DBusException.__init__(self, *args, **kwargs) class InvalidSettingException(dbus.DBusException): - _dbus_error_name = IFACE_CONNECTION + ".InvalidSetting" + def __init__(self, *args, **kwargs): + self._dbus_error_name = "{}.InvalidSetting".format(IFACE_CONNECTION) + dbus.DBusException.__init__(self, *args, **kwargs) class MissingSettingException(dbus.DBusException): - _dbus_error_name = IFACE_CONNECTION + ".MissingSetting" + def __init__(self, *args, **kwargs): + self._dbus_error_name = "{}.MissingSetting".format(IFACE_CONNECTION) + dbus.DBusException.__init__(self, *args, **kwargs) class NotSoftwareException(dbus.DBusException): - _dbus_error_name = IFACE_DEVICE + ".NotSoftware" + def __init__(self, *args, **kwargs): + self._dbus_error_name = "{}.NotSoftware".format(IFACE_DEVICE) + dbus.DBusException.__init__(self, *args, **kwargs) class ApNotFoundException(dbus.DBusException): - _dbus_error_name = IFACE_WIFI + ".AccessPointNotFound" + def __init__(self, *args, **kwargs): + self._dbus_error_name = "{}.AccessPointNotFound".format(IFACE_WIFI) + dbus.DBusException.__init__(self, *args, **kwargs) class PermissionDeniedException(dbus.DBusException): - _dbus_error_name = IFACE_NM + ".PermissionDenied" + def __init__(self, *args, **kwargs): + self._dbus_error_name = "{}.PermissionDenied".format(IFACE_NM) + dbus.DBusException.__init__(self, *args, **kwargs) class UnknownDeviceException(dbus.DBusException): - _dbus_error_name = IFACE_NM + ".UnknownDevice" + def __init__(self, *args, **kwargs): + self._dbus_error_name = "{}.UnknownDevice".format(IFACE_NM) + dbus.DBusException.__init__(self, *args, **kwargs) class UnknownConnectionException(dbus.DBusException): - _dbus_error_name = IFACE_NM + ".UnknownConnection" + def __init__(self, *args, **kwargs): + self._dbus_error_name = "{}.UnknownConnection".format(IFACE_NM) + dbus.DBusException.__init__(self, *args, **kwargs) class InvalidHostnameException(dbus.DBusException): - _dbus_error_name = IFACE_SETTINGS + ".InvalidHostname" + def __init__(self, *args, **kwargs): + self._dbus_error_name = "{}.InvalidHostname".format(IFACE_SETTINGS) + dbus.DBusException.__init__(self, *args, **kwargs) class NoSecretsException(dbus.DBusException): - _dbus_error_name = IFACE_AGENT_MANAGER + ".NoSecrets" + def __init__(self, *args, **kwargs): + self._dbus_error_name = "{}.NoSecrets".format(IFACE_AGENT_MANAGER) + dbus.DBusException.__init__(self, *args, **kwargs) class UserCanceledException(dbus.DBusException): - _dbus_error_name = IFACE_AGENT_MANAGER + ".UserCanceled" + def __init__(self, *args, **kwargs): + self._dbus_error_name = "{}.UserCanceled".format(IFACE_AGENT_MANAGER) + dbus.DBusException.__init__(self, *args, **kwargs) @staticmethod def from_nmerror(e): @@ -778,6 +809,7 @@ class ExportedObj(dbus.service.Object): PRP_DEVICE_UDI = "Udi" PRP_DEVICE_IFACE = "Interface" +PRP_DEVICE_IPIFACE = "IpInterface" PRP_DEVICE_DRIVER = "Driver" PRP_DEVICE_STATE = "State" PRP_DEVICE_STATE_REASON = "StateReason" @@ -813,9 +845,15 @@ class Device(ExportedObj): self.prp_state = NM.DeviceState.UNAVAILABLE + if devtype == NM.DeviceType.MODEM: + udi = "/org/freedesktop/ModemManager1/Modem/0" + else: + udi = "/sys/devices/virtual/%s" % iface + props = { - PRP_DEVICE_UDI: "/sys/devices/virtual/%s" % (iface), + PRP_DEVICE_UDI: udi, PRP_DEVICE_IFACE: iface, + PRP_DEVICE_IPIFACE: iface, PRP_DEVICE_DRIVER: "virtual", PRP_DEVICE_STATE: dbus.UInt32(self.prp_state), PRP_DEVICE_STATE_REASON: dbus.Struct( @@ -1018,10 +1056,32 @@ class Device(ExportedObj): raise BusErr.NotSoftwareException() pass + @dbus.service.signal(IFACE_DEVICE, signature="uuu") + def StateChanged(self, new_state, old_state, reason): + pass + @dbus.service.signal(IFACE_DEVICE, signature="a{sv}") def PropertiesChanged(self, changed): pass + def set_state(self, state, reason): + # libnm is plugged on notify::state-reason and not on state-changed dbus signal + # so we must simulate the change of property to emit a state-changed signal on libnm + self._dbus_property_set(IFACE_DEVICE, PRP_NM_STATE, dbus.UInt32(state)) + self._dbus_property_set( + IFACE_DEVICE, + PRP_DEVICE_STATE_REASON, + (dbus.UInt32(state), dbus.UInt32(reason)), + ) + old_state = self.prp_state + self.prp_state = state + self.StateChanged( + dbus.UInt32(self.prp_state), dbus.UInt32(old_state), dbus.UInt32(reason) + ) + + def set_carrier_status(self, carrier_status): + self._dbus_property_set(IFACE_WIRED, PRP_WIRED_CARRIER, carrier_status) + def set_active_connection(self, ac): self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_ACTIVE_CONNECTION, ac) @@ -1048,6 +1108,14 @@ class Device(ExportedObj): ExportedObj.to_path_array(self.available_connections_get()), ) + @dbus.service.method(IFACE_TEST, in_signature="", out_signature="") + def Start(self): + self.start() + + @dbus.service.method(IFACE_TEST, in_signature="", out_signature="") + def Stop(self): + self.stop() + ############################################################################### @@ -1071,7 +1139,7 @@ class WiredDevice(Device): PRP_WIRED_HW_ADDRESS: mac, PRP_WIRED_PERM_HW_ADDRESS: mac, PRP_WIRED_SPEED: dbus.UInt32(100), - PRP_WIRED_CARRIER: False, + PRP_WIRED_CARRIER: True, PRP_WIRED_S390_SUBCHANNELS: subchannels, } @@ -1083,6 +1151,30 @@ class WiredDevice(Device): ############################################################################### +PM_CURRENT_CAPABILITIES = "CurrentCapabilities" +PM_MODEM_CAPABILITIES = "ModemCapabilities" + +# capability to make device seen compatible with GSM connection +NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS = 0x00000004 + + +class ModemDevice(Device): + def __init__(self, iface): + Device.__init__(self, iface, NM.DeviceType.MODEM) + + props = { + PM_CURRENT_CAPABILITIES: dbus.UInt32(NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS), + PM_MODEM_CAPABILITIES: dbus.UInt32(0), + } + + self.dbus_interface_add(IFACE_MODEM, props, ModemDevice.PropertiesChanged) + + @dbus.service.signal(IFACE_MODEM, signature="a{sv}") + def PropertiesChanged(self, changed): + pass + + +############################################################################### PRP_VLAN_HW_ADDRESS = "HwAddress" PRP_VLAN_CARRIER = "Carrier" @@ -1331,6 +1423,8 @@ class ActiveConnection(ExportedObj): self.is_vpn = con_inst.is_vpn() self._activation_id = None + self._deactivation_id = None + self.activation_state_change_delay_ms = 50 s_con = con_inst.con_hash[NM.SETTING_CONNECTION_SETTING_NAME] @@ -1382,23 +1476,72 @@ class ActiveConnection(ExportedObj): def _activation_step2(self): assert self._activation_id is not None self._activation_id = None - self._set_state( - NM.ActiveConnectionState.ACTIVATED, NM.ActiveConnectionStateReason.UNKNOWN - ) + + s_con = self.con_inst.con_hash[NM.SETTING_CONNECTION_SETTING_NAME] + conn_id = s_con[NM.SETTING_CONNECTION_ID] + + if gl.force_activation_failure.get(conn_id, False): + self._set_state( + NM.ActiveConnectionState.DEACTIVATED, + NM.ActiveConnectionStateReason.UNKNOWN, + ) + self.device.set_state(NM.DeviceState.FAILED, NM.DeviceStateReason.UNKNOWN) + else: + self._set_state( + NM.ActiveConnectionState.ACTIVATED, + NM.ActiveConnectionStateReason.UNKNOWN, + ) + self.device.set_state(NM.DeviceState.ACTIVATED, NM.DeviceStateReason.NONE) return False def _activation_step1(self): assert self._activation_id is not None - self._activation_id = GLib.timeout_add(50, self._activation_step2) + self._activation_id = GLib.timeout_add( + self.activation_state_change_delay_ms, self._activation_step2 + ) self.device.set_active_connection(self) + self.device.set_state(NM.DeviceState.PREPARE, NM.DeviceStateReason.NONE) self._set_state( NM.ActiveConnectionState.ACTIVATING, NM.ActiveConnectionStateReason.UNKNOWN ) return False + def _deactivation_step1(self): + assert self._deactivation_id is not None + self._deactivation_id = None + self.device.set_state( + NM.DeviceState.DISCONNECTED, NM.DeviceStateReason.USER_REQUESTED + ) + self._set_state( + NM.ActiveConnectionState.DEACTIVATED, + NM.ActiveConnectionStateReason.USER_DISCONNECTED, + ) + + return False + + def set_state(self, state, reason): + self._set_state(state, reason) + def start_activation(self): assert self._activation_id is None - self._activation_id = GLib.timeout_add(50, self._activation_step1) + self._activation_id = GLib.timeout_add( + self.activation_state_change_delay_ms, self._activation_step1 + ) + + def start_deactivation(self): + assert self._deactivation_id is None + self._set_state( + NM.ActiveConnectionState.DEACTIVATING, + NM.ActiveConnectionStateReason.USER_DISCONNECTED, + ) + self.device.set_state( + NM.DeviceState.DEACTIVATING, NM.DeviceStateReason.USER_REQUESTED + ) + self._set_state( + NM.ActiveConnectionState.DEACTIVATING, + NM.ActiveConnectionStateReason.USER_DISCONNECTED, + ) + self._deactivation_id = GLib.timeout_add(50, self._deactivation_step1) @dbus.service.signal(IFACE_VPN_CONNECTION, signature="a{sv}") def PropertiesChanged(self, changed): @@ -1587,7 +1730,16 @@ class NetworkManager(ExportedObj): @dbus.service.method(dbus_interface=IFACE_NM, in_signature="o", out_signature="") def DeactivateConnection(self, active_connection): - pass + # Look for an active connection with the same object path + for ac in self.active_connections: + if ac.path == str(active_connection): + ac.activation_cancel() + ac.start_deactivation() + return + + raise BusErr.UnknownConnectionException( + "Connection not found: %s" % str(active_connection) + ) @dbus.service.method(dbus_interface=IFACE_NM, in_signature="b", out_signature="") def Sleep(self, do_sleep): @@ -1778,6 +1930,11 @@ class NetworkManager(ExportedObj): return ExportedObj.to_path(self.add_device(dev)) @dbus.service.method(IFACE_TEST, in_signature="s", out_signature="o") + def AddModemDevice(self, ifname): + dev = ModemDevice(ifname) + return ExportedObj.to_path(self.add_device(dev)) + + @dbus.service.method(IFACE_TEST, in_signature="s", out_signature="o") def AddWifiDevice(self, ifname): dev = WifiDevice(ifname) return ExportedObj.to_path(self.add_device(dev)) @@ -1808,6 +1965,64 @@ class NetworkManager(ExportedObj): def AddConnection(self, con_hash, do_verify_strict): return gl.settings.add_connection(con_hash, do_verify_strict) + @dbus.service.method(dbus_interface=IFACE_TEST, in_signature="sb", out_signature="") + def SetActiveConnectionFailure(self, connection_id, failure): + gl.force_activation_failure[connection_id] = failure + + @dbus.service.method(dbus_interface=IFACE_TEST, in_signature="ou", out_signature="") + def SetActiveConnectionStateChangedDelay(self, devpath, delay_ms): + for ac in reversed(self.active_connections): + if ac.device.path == devpath: + ac.activation_state_change_delay_ms = delay_ms + return + raise BusErr.UnknownDeviceException( + "Device with iface '%s' not found" % devpath + ) + + @dbus.service.method( + dbus_interface=IFACE_TEST, in_signature="ouu", out_signature="" + ) + def SetActiveConnectionState(self, devpath, state, reason): + for ac in reversed(self.active_connections): + if ac.device.path == devpath: + ac.set_state(state, reason) + return + raise BusErr.UnknownDeviceException( + "Device with iface '%s' not found" % devpath + ) + + @dbus.service.method( + dbus_interface=IFACE_TEST, in_signature="ouu", out_signature="" + ) + def SetDeviceState(self, devpath, state, reason): + try: + nmstate = NM.DeviceState(state) + except ValueError as e: + raise BusErr.InvalidPropertyException("Invalid device state: " % e) + + try: + nmreason = NM.DeviceStateReason(reason) + except ValueError as e: + raise BusErr.InvalidPropertyException("Invalid device state reason: " % e) + + for d in self.devices: + if d.path == devpath: + d.set_state(nmstate, nmreason) + return + raise BusErr.UnknownDeviceException( + "Device with iface '%s' not found" % devpath + ) + + @dbus.service.method(dbus_interface=IFACE_TEST, in_signature="ob", out_signature="") + def SetCarrierStatus(self, devpath, status): + for d in self.devices: + if d.path == devpath: + d.set_carrier_status(status) + return + raise BusErr.UnknownDeviceException( + "Device with iface '%s' not found" % devpath + ) + @dbus.service.method( dbus_interface=IFACE_TEST, in_signature="sa{sa{sv}}b", out_signature="" ) @@ -2007,6 +2222,12 @@ class Settings(ExportedObj): def AddConnection(self, con_hash): return self.add_connection(con_hash) + @dbus.service.method( + dbus_interface=IFACE_SETTINGS, in_signature="", out_signature="b" + ) + def ReloadConnections(self): + return True + def add_connection(self, con_hash, do_verify_strict=True): self.c_counter += 1 con_inst = Connection(self.c_counter, con_hash, do_verify_strict) @@ -2280,6 +2501,10 @@ class IP4Config(ExportedObj): for k, v in props.items(): self._dbus_property_set(IFACE_IP4_CONFIG, k, v) + @dbus.service.method(IFACE_TEST, in_signature="s", out_signature="") + def SetGateway(self, gateway): + self._dbus_property_set(IFACE_IP4_CONFIG, PRP_IP4_CONFIG_GATEWAY, gateway) + @dbus.service.signal(IFACE_IP4_CONFIG, signature="a{sv}") def PropertiesChanged(self, path): pass @@ -2721,6 +2946,7 @@ def main(): gl.mainloop = GLib.MainLoop() gl.bus = dbus.SessionBus() + gl.force_activation_failure = {} gl.object_manager = ObjectManager("/org/freedesktop") gl.manager = NetworkManager() |