summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--.mailmap3
-rwxr-xr-xAUTHORS24
-rw-r--r--COPYING.LGPLv2502
-rw-r--r--ChangeLog26
-rw-r--r--Makefile.am26
-rwxr-xr-xMakefile.plugins64
-rwxr-xr-xREADME38
-rwxr-xr-xTODO35
-rwxr-xr-xacinclude.m44
-rwxr-xr-xclient/agent.c16
-rwxr-xr-xclient/commands.c210
-rw-r--r--client/dbus_helpers.c33
-rw-r--r--client/dbus_helpers.h2
-rwxr-xr-xclient/ins.c22
-rwxr-xr-xclient/vpnconnections.c2
-rw-r--r--configure.ac140
-rwxr-xr-xdoc/agent-api.txt6
-rwxr-xr-xdoc/clock-api.txt9
-rw-r--r--doc/coding-style.txt17
-rwxr-xr-xdoc/config-format.txt2
-rw-r--r--doc/connman-service.config.5.in9
-rw-r--r--doc/connman-vpn-provider.config.5.in2
-rw-r--r--doc/connman-vpn.conf.5.in36
-rw-r--r--doc/connman.conf.5.in26
-rw-r--r--doc/connmanctl.1.in2
-rwxr-xr-xdoc/counter-api.txt4
-rwxr-xr-xdoc/manager-api.txt2
-rwxr-xr-xdoc/overview-api.txt2
-rwxr-xr-xdoc/peer-api.txt4
-rwxr-xr-xdoc/plugin-api.txt2
-rwxr-xr-xdoc/session-api.txt2
-rwxr-xr-xdoc/session-overview.txt2
-rwxr-xr-xdoc/technology-api.txt7
-rw-r--r--doc/vpn-agent-api.txt93
-rw-r--r--doc/vpn-config-format.txt139
-rwxr-xr-xdoc/vpn-connection-api.txt70
-rwxr-xr-xdoc/vpn-overview.txt41
-rw-r--r--doc/wifi-p2p-overview.txt2
-rwxr-xr-xgdbus/watch.c107
-rwxr-xr-xgdhcp/client.c43
-rwxr-xr-xgdhcp/common.c34
-rwxr-xr-xgdhcp/common.h5
-rwxr-xr-xgdhcp/gdhcp.h1
-rwxr-xr-xgdhcp/server.c12
-rwxr-xr-xgsupplicant/dbus.c5
-rwxr-xr-xgsupplicant/gsupplicant.h87
-rwxr-xr-xgsupplicant/supplicant.c842
-rwxr-xr-xgweb/gresolv.c5
-rwxr-xr-xgweb/gweb.c3
-rwxr-xr-xinclude/device.h22
-rw-r--r--include/inet.h11
-rwxr-xr-xinclude/ipaddress.h4
-rwxr-xr-xinclude/log.h12
-rwxr-xr-xinclude/network.h25
-rwxr-xr-xinclude/option.h35
-rwxr-xr-xinclude/provider.h8
-rwxr-xr-xinclude/service.h12
-rwxr-xr-xinclude/setting.h15
-rwxr-xr-xinclude/task.h6
-rwxr-xr-xinclude/technology.h11
-rw-r--r--isu/isu.cfg8
-rw-r--r--isu/system-services/connman.service24
-rw-r--r--packaging/connman.spec68
-rwxr-xr-xplugins/bluetooth.c5
-rwxr-xr-xplugins/dundee.c2
-rw-r--r--plugins/ethernet.c195
-rwxr-xr-xplugins/gadget.c1
-rw-r--r--plugins/iwd.c1132
-rwxr-xr-xplugins/loopback.c26
-rwxr-xr-xplugins/neard.c6
-rwxr-xr-xplugins/ofono.c10
-rwxr-xr-xplugins/session_policy_local.c6
-rwxr-xr-xplugins/tist.c2
-rwxr-xr-xplugins/vpn.c369
-rwxr-xr-xplugins/wifi.c1049
-rw-r--r--resources/var/lib/connman/settings1
-rw-r--r--[-rwxr-xr-x]scripts/vpn-script.c (renamed from scripts/openconnect-script.c)8
-rwxr-xr-xsrc/agent.c8
-rwxr-xr-xsrc/bridge.c3
-rwxr-xr-xsrc/clock.c60
-rw-r--r--src/config.c33
-rwxr-xr-xsrc/connection.c38
-rw-r--r--src/connman-robot.conf47
-rw-r--r--src/connman.conf7
-rwxr-xr-xsrc/connman.h60
-rwxr-xr-xsrc/dbus.c26
-rwxr-xr-xsrc/device.c272
-rw-r--r--src/dhcp.c59
-rwxr-xr-xsrc/dhcpv6.c2
-rw-r--r--src/dns-systemd-resolved.c4
-rwxr-xr-xsrc/dnsproxy.c178
-rw-r--r--src/error.c9
-rw-r--r--src/firewall-nftables.c26
-rw-r--r--src/inet.c676
-rwxr-xr-xsrc/ipaddress.c12
-rwxr-xr-xsrc/ipconfig.c520
-rwxr-xr-xsrc/iptables.c14
-rwxr-xr-xsrc/log.c39
-rwxr-xr-xsrc/main.c322
-rwxr-xr-xsrc/main.conf51
-rwxr-xr-xsrc/main_robot.conf262
-rwxr-xr-xsrc/main_tv.conf7
-rwxr-xr-xsrc/manager.c62
-rw-r--r--src/mesh.c2
-rwxr-xr-xsrc/network.c281
-rw-r--r--src/notifier.c2
-rwxr-xr-xsrc/ntp.c12
-rwxr-xr-xsrc/peer.c7
-rwxr-xr-xsrc/provider.c142
-rwxr-xr-xsrc/resolver.c39
-rw-r--r--src/rtnl.c139
-rwxr-xr-xsrc/service.c1774
-rw-r--r--src/session.c2
-rw-r--r--src/shared/mnlg.c331
-rw-r--r--src/shared/mnlg.h27
-rwxr-xr-xsrc/shared/netlink.c666
-rwxr-xr-xsrc/shared/netlink.h53
-rwxr-xr-xsrc/shared/util.c40
-rwxr-xr-xsrc/shared/util.h5
-rwxr-xr-xsrc/stats.c8
-rwxr-xr-xsrc/storage.c26
-rwxr-xr-xsrc/task.c17
-rw-r--r--src/technology.c486
-rwxr-xr-xsrc/tethering.c5
-rwxr-xr-xsrc/timeserver.c113
-rwxr-xr-xsrc/timezone.c5
-rwxr-xr-xsrc/wispr.c73
-rwxr-xr-xtest/backtrace8
-rwxr-xr-xtest/connect-provider24
-rwxr-xr-xtest/disable-tethering8
-rwxr-xr-xtest/enable-tethering10
-rwxr-xr-xtest/get-global-timeservers2
-rwxr-xr-xtest/get-proxy-autoconfig16
-rwxr-xr-xtest/get-services10
-rwxr-xr-xtest/get-state2
-rwxr-xr-xtest/list-services10
-rwxr-xr-xtest/monitor-connman8
-rwxr-xr-xtest/monitor-services20
-rwxr-xr-xtest/monitor-vpn4
-rwxr-xr-xtest/p2p-on-supplicant101
-rwxr-xr-xtest/remove-provider4
-rwxr-xr-xtest/service-move-before6
-rwxr-xr-xtest/set-clock4
-rwxr-xr-xtest/set-domains4
-rwxr-xr-xtest/set-global-timeservers4
-rwxr-xr-xtest/set-ipv4-method8
-rwxr-xr-xtest/set-ipv6-method8
-rwxr-xr-xtest/set-nameservers4
-rwxr-xr-xtest/set-proxy16
-rwxr-xr-xtest/set-timeservers4
-rwxr-xr-xtest/set-timezone21
-rwxr-xr-xtest/show-introspection4
-rwxr-xr-xtest/simple-agent92
-rwxr-xr-xtest/test-clock6
-rwxr-xr-xtest/test-compat2
-rwxr-xr-xtest/test-connman78
-rwxr-xr-xtest/test-counter15
-rwxr-xr-xtest/test-manager26
-rwxr-xr-xtest/test-new-supplicant2
-rwxr-xr-xtest/test-session110
-rwxr-xr-xtest/vpn-connect4
-rwxr-xr-xtest/vpn-disconnect4
-rwxr-xr-xtest/vpn-get10
-rwxr-xr-xtest/vpn-property18
-rw-r--r--tools/ip6tables-test.c2
-rwxr-xr-xtools/iptables-test.c2
-rwxr-xr-xtools/netlink-test.c123
-rwxr-xr-xtools/stats-tool.c8
-rw-r--r--unit/test-iptables.c4
-rwxr-xr-xvpn/main.c100
-rwxr-xr-xvpn/plugins/l2tp.c180
-rw-r--r--vpn/plugins/libwireguard.c998
-rwxr-xr-xvpn/plugins/openconnect.c1538
-rwxr-xr-xvpn/plugins/openvpn.c932
-rwxr-xr-xvpn/plugins/pptp.c198
-rwxr-xr-xvpn/plugins/vpn.c167
-rwxr-xr-xvpn/plugins/vpn.h5
-rwxr-xr-xvpn/plugins/vpnc.c628
-rw-r--r--vpn/plugins/wireguard.c794
-rw-r--r--vpn/plugins/wireguard.h103
-rwxr-xr-xvpn/vpn-agent.c146
-rwxr-xr-xvpn/vpn-agent.h12
-rwxr-xr-xvpn/vpn-config.c28
-rwxr-xr-xvpn/vpn-ipconfig.c10
-rwxr-xr-xvpn/vpn-provider.c1341
-rwxr-xr-xvpn/vpn-provider.h29
-rwxr-xr-xvpn/vpn-rtnl.c127
-rw-r--r--vpn/vpn-settings.c314
-rw-r--r--vpn/vpn-util.c224
-rwxr-xr-xvpn/vpn.h36
191 files changed, 17383 insertions, 4242 deletions
diff --git a/.gitignore b/.gitignore
index b43336c9..cd7d8810 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,6 +26,8 @@ autom4te.cache
test-driver
m4/
!m4/configmake.m4
+TAGS
+cscope.*
connman.pc
include/connman
@@ -40,7 +42,7 @@ src/connman-wait-online.service
src/connmand-wait-online
plugins/connman.policy
scripts/connman
-scripts/openconnect-script
+scripts/vpn-script
scripts/openvpn-script
scripts/connman_resolvconf.conf
client/connmanctl
diff --git a/.mailmap b/.mailmap
index 1e374a64..ef44bd6e 100644
--- a/.mailmap
+++ b/.mailmap
@@ -11,3 +11,6 @@ Bing Niu <bing.niu@intel.com> <bing.niu@intel.com>
Naveen Singh <naveensingh0977@gmail.com> <naveensingh0977@gmail.com>
Mylène Josserand <josserand.mylene@gmail.com> <josserand.mylene@gmail.com>
Måns Rullgård <mans@mansr.com> <mans@mansr.com>
+Emmanuel VAUTRIN <Emmanuel.VAUTRIN@cpexterne.org> <Emmanuel.VAUTRIN@cpexterne.org>
+Simon Holesch <Simon.Holesch@bshg.com> <Simon.Holesch@bshg.com>
+Nishant Chaprana <n.chaprana@samsung.com> <n.chaprana@samsung.com>
diff --git a/AUTHORS b/AUTHORS
index b992c4ed..3ed09850 100755
--- a/AUTHORS
+++ b/AUTHORS
@@ -145,7 +145,7 @@ André Draszik <andre.draszik@jci.com>
Chris Novakovic <chris@chrisn.me.uk>
Ryan Schaefer <ryan.schaefer@flukenetworks.com>
Nicolas Cornu <n.cornu@overkiz.com>
-Rahul Jain <rahul.jain@samsung.com
+Rahul Jain <rahul.jain@samsung.com>
Benoît Monin <benoit.monin@gmx.fr>
Jussi Laakkonen <jussi.laakkonen@jolla.com>
Vivien Henriet <v.henriet@overkiz.com>
@@ -154,3 +154,25 @@ Volodymyr Ostap <ostvolodymyr@gmail.com>
Artem Yamshanov <me@anticode.ninja>
Matthias Berndt <matthias_berndt@gmx.de>
Henrik Persson <Henrik.Persson@verisure.com>
+Nicola Lunghi <nick83ola@gmail.com>
+Yasser <yasser.toor@gmail.com>
+Matt Vogt <matthew.vogt@jollamobile.com>
+David Llewellyn-Jones <david.llewellyn-jones@jolla.com>
+David Weidenkopf <David.Weidenkopf@Arthrex.com>
+Maxime Roussin-Bélanger <maxime.roussinbelanger@gmail.com>
+Holesch, Simon (GED-SDD1) <Simon.Holesch@bshg.com>
+Christoph Steiger <c.steiger@lemonage.de>
+Markus Held <mjh42@gmx.de>
+Sergey Matyukevich <geomatsi@gmail.com>
+Pieter Cardoen <P.Cardoen@TELEVIC.com>
+Emmanuel Vautrin <emmanuel.vautrin@cpexterne.org>
+Boleslaw Tokarski <boleslaw.tokarski@jolla.com>
+Gabriel FORTE <gforte@wyplay.com>
+Colin Wee <cwee@tesla.com>
+Valery Kashcheev <v.kascheev@omp.ru>
+Alyssa Ross <hi@alyssa.is>
+Ariel D'Alessandro <ariel.dalessandro@collabora.com>
+Lukáš Karas <lukas.karas@centrum.cz>
+Michael Nazzareno Trimarchi <michael@amarulasolutions.com>
+Christian Taedcke <christian.taedcke@lemonbeat.com>
+Matthias Gerstner <mgerstner@suse.de>
diff --git a/COPYING.LGPLv2 b/COPYING.LGPLv2
new file mode 100644
index 00000000..4362b491
--- /dev/null
+++ b/COPYING.LGPLv2
@@ -0,0 +1,502 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/ChangeLog b/ChangeLog
index 9418de1b..11566a53 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+ver 1.41:
+ Fix issue with RTNL netlink message alignment.
+ Fix issue with dnsproxy and timeout for TCP feature.
+ Fix issue with dnsproxy and busy loop in TCP server.
+ Fix issue with WiFi connection with no passphrase.
+ Add support for wpa_supplicant and WPA3-SAE functionality.
+ Add support for D-Bus ObjectManager interface.
+
+ver 1.40:
+ Fix issue with handling WiFi disconnecting status.
+ Fix issue with handling WiFi auto-connect and iwd backend.
+ Fix issue with DNS Proxy stack-based buffer overflow attack.
+
+ver 1.39:
+ Fix issue with scanning state synchronization and iwd.
+ Fix issue with invalid key with 4-way handshake offloading.
+ Fix issue with DNS proxy length checks to prevent buffer overflow.
+ Fix issue with DHCP leaking stack data via uninitialized variable.
+
+ver 1.38:
+ Fix issue with online check on IP address update.
+ Fix issue with OpenVPN and encrypted private keys.
+ Fix issue with finishing of VPN connections.
+ Add support for updated stable iwd APIs.
+ Add support for WireGuard networks.
+
ver 1.37:
Fix issue with handling invalid gateway addresses.
Fix issue with handling updates of default gateway.
diff --git a/Makefile.am b/Makefile.am
index d502be72..9a756a49 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -21,7 +21,7 @@ endif
nodist_include_HEADERS = include/version.h
noinst_HEADERS = include/rtnl.h include/task.h \
- include/dbus.h include/option.h \
+ include/dbus.h \
include/provider.h include/vpn-dbus.h \
include/utsname.h include/timeserver.h include/proxy.h \
include/technology.h include/setting.h \
@@ -59,7 +59,6 @@ stats_sources = src/nostats.c
endif
shared_sources = src/shared/util.h src/shared/util.c \
- src/shared/netlink.h src/shared/netlink.c \
src/shared/arp.h src/shared/arp.c
if DATAFILES
@@ -181,7 +180,7 @@ endif
if NFTABLES
src_connmand_SOURCES += src/firewall-nftables.c
-src_connmand_LDADD += @NFTABLES_LIBS@
+src_connmand_LDADD += @NFTABLES_LIBS@ @LIBMNL_LIBS@
endif
if VPN
@@ -221,8 +220,8 @@ vpn_connman_vpnd_SOURCES = $(gdhcp_sources) $(builtin_vpn_sources) \
src/ippool.c src/bridge.c src/nat.c src/ipaddress.c \
src/inotify.c src/firewall-iptables.c src/ipv6pd.c src/peer.c \
src/peer_service.c src/machine.c src/util.c \
- vpn/vpn-agent.c vpn/vpn-agent.h \
- vpn/vpn-config.c src/acd.c
+ vpn/vpn-agent.c vpn/vpn-util.c vpn/vpn-agent.h \
+ vpn/vpn-config.c vpn/vpn-settings.c src/acd.c
if TIZEN_EXT_WIFI_MESH
vpn_connman_vpnd_SOURCES += src/mesh.c src/mesh-netlink.c
@@ -337,8 +336,8 @@ src_connmand_CFLAGS += @XTABLES_CFLAGS@
endif
if NFTABLES
-AM_CFLAGS += @NFTABLES_CFLAGS@
-src_connmand_CFLAGS += @NFTABLES_CFLAGS@
+AM_CFLAGS += @NFTABLES_CFLAGS@ @LIBMNL_CFLAGS@
+src_connmand_CFLAGS += @NFTABLES_CFLAGS@ @LIBMNL_CFLAGS@
endif
if TIZEN_EXT_WIFI_MESH
@@ -374,9 +373,7 @@ if TIZEN_EXT_WIFI_MESH
client_connmanctl_SOURCES += client/mesh.c client/mesh.h
endif
-if TIZEN_EXT_INS
client_connmanctl_SOURCES += client/ins.c client/ins.h
-endif
client_connmanctl_LDADD = gdbus/libgdbus-internal.la @DBUS_LIBS@ @GLIB_LIBS@ @DLOG_LIBS@ \
-lreadline -ldl -lncurses
@@ -406,7 +403,7 @@ noinst_PROGRAMS += tools/supplicant-test \
tools/tap-test tools/wpad-test \
tools/stats-tool tools/private-network-test \
tools/session-test \
- tools/dnsproxy-test tools/netlink-test
+ tools/dnsproxy-test
tools_supplicant_test_SOURCES = tools/supplicant-test.c \
tools/supplicant-dbus.h tools/supplicant-dbus.c \
@@ -479,10 +476,6 @@ endif
tools_dnsproxy_test_SOURCES = tools/dnsproxy-test.c
tools_dnsproxy_test_LDADD = @GLIB_LIBS@
-tools_netlink_test_SOURCES = src/shared/util.c src/shared/netlink.c \
- tools/netlink-test.c
-tools_netlink_test_LDADD = @GLIB_LIBS@
-
endif
test_scripts = test/get-state test/list-services \
@@ -638,5 +631,10 @@ include/connman/%.h: $(abs_top_srcdir)/include/%.h
$(AM_V_at)$(MKDIR_P) include/connman
$(AM_V_GEN)$(LN_S) $< $@
+isudir = /etc/isu/connman
+isu_DATA = isu/isu.cfg
+isusystemservicedir = /etc/isu/connman/system-services/
+isusystemservice_DATA = isu/system-services/connman.service
+
clean-local:
@$(RM) -rf include/connman $(MANUAL_PAGES)
diff --git a/Makefile.plugins b/Makefile.plugins
index 56fc4b32..a0c17cfa 100755
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -74,36 +74,63 @@ if VPN
builtin_modules += vpn
builtin_sources += plugins/vpn.c
+if WIREGUARD
+builtin_vpn_source = vpn/plugins/vpn.c vpn/plugins/vpn.h
+if WIREGUARD_BUILTIN
+builtin_vpn_modules += wireguard
+builtin_vpn_sources += src/shared/mnlg.h src/shared/mnlg.c \
+ vpn/plugins/wireguard.h vpn/plugins/libwireguard.c \
+ vpn/plugins/wireguard.c
+builtin_vpn_cflags += @LIBMNL_CFLAGS@ -DWIREGUARD=\"@WIREGUARD@\"
+builtin_vpn_libadd += @LIBMNL_LIBS@
+else
+vpn_plugin_LTLIBRARIES += vpn/plugins/wireguard.la
+vpn_plugin_objects += $(plugins_wireguard_la_OBJECTS)
+vpn_plugins_wireguard_la_SOURCES = src/shared/mnlg.h src/shared/mnlg.c \
+ vpn/plugins/wireguard.h \
+ vpn/plugins/libwireguard.c \
+ vpn/plugins/wireguard.c
+vpn_plugins_wireguard_la_CFLAGS = $(plugin_cflags) @LIBMNL_CFLAGS@ \
+ -DWIREGUARD=\"@WIREGUARD@\" \
+ -DVPN_STATEDIR=\""$(vpn_statedir)"\" \
+ -DSCRIPTDIR=\""$(build_scriptdir)"\"
+vpn_plugins_wireguard_la_LDFLAGS = $(plugin_ldflags)
+vpn_plugins_wireguard_la_LIBADD = @LIBMNL_LIBS@
+endif
+endif
+
if OPENCONNECT
+builtin_vpn_source = vpn/plugins/vpn.c vpn/plugins/vpn.h
if OPENCONNECT_BUILTIN
builtin_vpn_modules += openconnect
builtin_vpn_sources += vpn/plugins/openconnect.c
-builtin_vpn_source = vpn/plugins/vpn.c vpn/plugins/vpn.h
-builtin_vpn_cflags += -DOPENCONNECT=\"@OPENCONNECT@\"
+builtin_vpn_cflags += -DOPENCONNECT=\"@OPENCONNECT@\" \
+ @LIBOPENCONNECT_CFLAGS@
+builtin_vpn_libadd += @LIBOPENCONNECT_LIBS@
else
vpn_plugin_LTLIBRARIES += vpn/plugins/openconnect.la
vpn_plugin_objects += $(plugins_openconnect_la_OBJECTS)
-vpn_plugins_openconnect_la_SOURCES = vpn/plugins/vpn.h vpn/plugins/vpn.c \
- vpn/plugins/openconnect.c
+vpn_plugins_openconnect_la_SOURCES = vpn/plugins/openconnect.c
vpn_plugins_openconnect_la_CFLAGS = $(plugin_cflags) \
-DOPENCONNECT=\"@OPENCONNECT@\" \
-DVPN_STATEDIR=\""$(vpn_statedir)"\" \
- -DSCRIPTDIR=\""$(build_scriptdir)"\"
+ -DSCRIPTDIR=\""$(build_scriptdir)"\" \
+ @LIBOPENCONNECT_CFLAGS@
vpn_plugins_openconnect_la_LDFLAGS = $(plugin_ldflags)
+vpn_plugins_openconnect_la_LIBADD = @LIBOPENCONNECT_LIBS@
endif
endif
if OPENVPN
+builtin_vpn_source = vpn/plugins/vpn.c vpn/plugins/vpn.h
if OPENVPN_BUILTIN
builtin_vpn_modules += openvpn
builtin_vpn_sources += vpn/plugins/openvpn.c
-builtin_vpn_source = vpn/plugins/vpn.c vpn/plugins/vpn.h
builtin_vpn_cflags += -DOPENVPN=\"@OPENVPN@\"
else
vpn_plugin_LTLIBRARIES += vpn/plugins/openvpn.la
vpn_plugin_objects += $(plugins_openvpn_la_OBJECTS)
-vpn_plugins_openvpn_la_SOURCES = vpn/plugins/vpn.h vpn/plugins/vpn.c \
- vpn/plugins/openvpn.c
+vpn_plugins_openvpn_la_SOURCES = vpn/plugins/openvpn.c
vpn_plugins_openvpn_la_CFLAGS = $(plugin_cflags) -DOPENVPN=\"@OPENVPN@\" \
-DVPN_STATEDIR=\""$(vpn_statedir)"\" \
-DSCRIPTDIR=\""$(build_scriptdir)"\"
@@ -131,16 +158,15 @@ endif
endif
if VPNC
+builtin_vpn_source = vpn/plugins/vpn.c vpn/plugins/vpn.h
if VPNC_BUILTIN
builtin_vpn_modules += vpnc
builtin_vpn_sources += vpn/plugins/vpnc.c
-builtin_vpn_source = vpn/plugins/vpn.c vpn/plugins/vpn.h
builtin_vpn_cflags += -DVPNC=\"@VPNC@\"
else
vpn_plugin_LTLIBRARIES += vpn/plugins/vpnc.la
vpn_plugin_objects += $(plugins_vpnc_la_OBJECTS)
-vpn_plugins_vpnc_la_SOURCES = vpn/plugins/vpn.h vpn/plugins/vpn.c \
- vpn/plugins/vpnc.c
+vpn_plugins_vpnc_la_SOURCES = vpn/plugins/vpnc.c
vpn_plugins_vpnc_la_CFLAGS = $(plugin_cflags) -DVPNC=\"@VPNC@\" \
-DVPN_STATEDIR=\""$(vpn_statedir)"\" \
-DSCRIPTDIR=\""$(build_scriptdir)"\"
@@ -149,16 +175,15 @@ endif
endif
if L2TP
+builtin_vpn_source = vpn/plugins/vpn.c vpn/plugins/vpn.h
if L2TP_BUILTIN
builtin_vpn_modules += l2tp
builtin_vpn_sources += vpn/plugins/l2tp.c
-builtin_vpn_source = vpn/plugins/vpn.c vpn/plugins/vpn.h
builtin_vpn_cflags += -DL2TP=\"@L2TP@\"
else
vpn_plugin_LTLIBRARIES += vpn/plugins/l2tp.la
vpn_plugin_objects += $(plugins_l2tp_la_OBJECTS)
-vpn_plugins_l2tp_la_SOURCES = vpn/plugins/vpn.h vpn/plugins/vpn.c \
- vpn/plugins/l2tp.c
+vpn_plugins_l2tp_la_SOURCES = vpn/plugins/l2tp.c
vpn_plugins_l2tp_la_CFLAGS = $(plugin_cflags) -DL2TP=\"@L2TP@\" \
-DVPN_STATEDIR=\""$(vpn_statedir)"\" \
-DSCRIPTDIR=\""$(build_scriptdir)"\"
@@ -167,16 +192,15 @@ endif
endif
if PPTP
+builtin_vpn_source = vpn/plugins/vpn.c vpn/plugins/vpn.h
if PPTP_BUILTIN
builtin_vpn_modules += pptp
builtin_vpn_sources += vpn/plugins/pptp.c
-builtin_vpn_source = vpn/plugins/vpn.c vpn/plugins/vpn.h
builtin_vpn_cflags += -DPPPD=\"@PPPD@\" -DPPTP=\"@PPTP@\"
else
vpn_plugin_LTLIBRARIES += vpn/plugins/pptp.la
vpn_plugin_objects += $(plugins_pptp_la_OBJECTS)
-vpn_plugins_pptp_la_SOURCES = vpn/plugins/vpn.h vpn/plugins/vpn.c \
- vpn/plugins/pptp.c
+vpn_plugins_pptp_la_SOURCES = vpn/plugins/pptp.c
vpn_plugins_pptp_la_CFLAGS = $(plugin_cflags) -DPPPD=\"@PPPD@\" \
-DPPTP=\"@PPTP@\" \
-DVPN_STATEDIR=\""$(vpn_statedir)"\" \
@@ -230,14 +254,12 @@ plugins_iospm_la_LDFLAGS = $(plugin_ldflags)
endif
if OPENCONNECT
-script_PROGRAMS += scripts/openconnect-script
-
scripts_openconnect_script_LDADD = @DBUS_LIBS@ @DLOG_LIBS@
else
if VPNC
-script_PROGRAMS += scripts/openconnect-script
+script_PROGRAMS += scripts/vpn-script
-scripts_openconnect_script_LDADD = @DBUS_LIBS@ @DLOG_LIBS@
+scripts_vpn_script_LDADD = @DBUS_LIBS@
endif
endif
diff --git a/README b/README
index f16b9ec0..e3268c82 100755
--- a/README
+++ b/README
@@ -278,7 +278,7 @@ If timing conditions are relevant then it is recommended command to
get log traces as follows:
connmand -d 2>&1 | ts '[%H:%M:%.S]' | tee connman.log
-The 'ts' program is normaly avialable in the moreutils package.
+The 'ts' program is normally available in the moreutils package.
Kernel configuration
@@ -368,6 +368,15 @@ routes will not be set by ConnMan if the uplink is a cellular
network. While the same setup works well for a WiFi or ethernet
uplink.
+Up to (at least) version 2.4.5 of OpenVPN getting information about
+private key decryption failures via management channel is missing. This
+will result in attempting with the invalid key over and over as the
+information about failed decryprion is not delivered to OpenVPN plugin.
+The following patch to OpenVPN is required for the private key
+decryption failures to be sent:
+https://git.sailfishos.org/mer-core/openvpn/blob/
+4f4b4af116292a207416c8a990392e35a6fc41af/rpm/privatekey-passphrase-
+handling.diff
GnuTLS
======
@@ -399,8 +408,17 @@ from ipv4.connman.net (for IPv4 connectivity) and ipv6.connman.net
(for IPv6 connectivity). The used URL looks like this
http://ipv{4|6}.connman.net/online/status.html
+When an online check request fails, another one is triggered after a
+longer interval. The intervals follow the square series of numbers
+in a specific range, by default [1, 12], corresponding to the following
+intervals, in seconds: 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121 and 144.
+
See connman.conf(5) for the EnableOnlineCheck option, if you need to
disable the feature.
+It is also possible to specify other URLs via OnlineCheckIPv4URL and
+OnlineCheckIPv6URL options.
+The range of intervals between two online check requests can be fine-tuned
+via OnlineCheckInitialInterval and OnlineCheckMaxInterval options.
During the online check procedure, ConnMan will temporarily install
a host route to both the ipv4.connman.net and ipv6.connman.net so that
@@ -418,7 +436,7 @@ the online check request (example):
Connection: close
Currently following information is returned from connman.net if
-the connection is successfull (200 OK http response code is returned):
+the connection is successful (200 OK http response code is returned):
Server: nginx
Date: Mon, 09 Jun 2014 09:25:42 GMT
Content-Type: text/html
@@ -435,10 +453,16 @@ Information
===========
Mailing list:
- connman@connman.net
+ connman@lists.linux.dev
+
+If you would like to subscribe to receive mail in your inbox, just
+send a (empty) message from your email account to
+
+ connman+subscribe@lists.linux.dev
-For additional information about the project visit ConnMan web site:
- https://01.org/connman
- http://www.connman.net
+Mailing list archive:
+ https://lore.kernel.org/connman
-You can report bugs at https://01.org/jira/browse/CM
+IRC:
+ ircs://irc.oftc.net:6697/#connman (for SSL)
+ irc://irc.oftc.net:6667/#connman (for non-SSL)
diff --git a/TODO b/TODO
index c1694e3d..c10b8ce1 100755
--- a/TODO
+++ b/TODO
@@ -194,6 +194,41 @@ VPN
ids and passphrases.
+- Change OpenConnect plugin to use libopenconnect
+
+ Priority: Medium
+ Complexity: C4
+
+ Current implementation of OpenConnect uses screenscraping and interactive
+ mode for accepting self signed certificates and reacting to PKCS pass
+ phrase requests. This should be replaced with libopenconnect use. It may be
+ worthwhile to attempt to replace the whole authentication with the use of
+ openconnect_obtain_cookie() whatever authentication type is used. This
+ would lead to using only the cookie when connecting (--cookie-on-stdin)
+ and would cleanup the code at run_connect().
+
+ The usage of stdout can be removed as unnecessary. Cookie should be
+ retrieved with openconnect_obtain_cookie(). Remove this also from
+ connman_task_run().
+
+ Function is_valid_protocol() must use openconnect_get_supported_protocols.
+ Also the static const char *protocols[] would be unnecessary.
+
+ Reading the stderr with byte-by-byte approach is to be removed, as well as
+ are the PKCS failures and requests in stderr IO channel processing.
+
+ The use of interactive mode toggle is to be removed. Non-interactive mode
+ must be used, which leads to using --syslog with each authentication type
+ as task arg.
+
+ If the peer certificate cannot be verified with normal means it is because
+ the peer certificate is self signed and the user setting
+ "AllowSelfSignedCert" has to be used for the verify certificate callback
+ reply. The callback for certificate validation must return zero if user has
+ allowed self signed certificates. In such case save the SHA1 fingerprint of
+ server certificate as it is done now, otherwise indicate error to
+ libopenconnect.
+
Tools
=====
diff --git a/acinclude.m4 b/acinclude.m4
index 9e8e0dc5..262465d8 100755
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -21,7 +21,9 @@ AC_DEFUN([COMPILER_FLAGS], [
CFLAGS+=" -Wdeclaration-after-statement"
CFLAGS+=" -Wmissing-declarations"
CFLAGS+=" -Wredundant-decls"
- CFLAGS+=" -Wcast-align"
+ if ( $CC -v 2>/dev/null | grep "gcc version" ); then
+ CFLAGS+=" -Wcast-align"
+ fi
CFLAGS="$CFLAGS -DG_DISABLE_DEPRECATED"
fi
])
diff --git a/client/agent.c b/client/agent.c
index d0208892..94ace7cd 100755
--- a/client/agent.c
+++ b/client/agent.c
@@ -100,6 +100,8 @@ static struct agent_input_data vpnagent_input_handler[] = {
request_input_string_return },
{ "OpenConnect.VPNHost", false, "OpenConnect VPN server? ",
request_input_string_return },
+ { "OpenConnect.SecondPassword", false, "VPN one-time password? ",
+ request_input_string_return },
{ "Username", false, "VPN username? ", request_input_string_return },
{ "Password", false, "VPN password? ", request_input_string_return },
{ },
@@ -710,8 +712,8 @@ static const GDBusMethodTable agent_methods[] = {
{ },
};
-static int agent_register_return(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int agent_register_return(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
DBusConnection *connection = user_data;
@@ -768,8 +770,8 @@ int __connmanctl_agent_register(DBusConnection *connection)
return result;
}
-static int agent_unregister_return(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int agent_unregister_return(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
if (error) {
fprintf(stderr, "Error unregistering Agent: %s\n", error);
@@ -819,8 +821,8 @@ static const GDBusMethodTable vpn_agent_methods[] = {
{ },
};
-static int vpn_agent_register_return(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int vpn_agent_register_return(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
DBusConnection *connection = user_data;
@@ -872,7 +874,7 @@ int __connmanctl_vpn_agent_register(DBusConnection *connection)
return result;
}
-static int vpn_agent_unregister_return(DBusMessageIter *iter,
+static int vpn_agent_unregister_return(DBusMessageIter *iter, int errnum,
const char *error, void *user_data)
{
if (error) {
diff --git a/client/commands.c b/client/commands.c
index a8f3e9db..2fd8af54 100755
--- a/client/commands.c
+++ b/client/commands.c
@@ -39,7 +39,7 @@
#include "dbus_helpers.h"
#include "input.h"
#include "services.h"
-#if defined TIZEN_EXT_INS
+#if defined TIZEN_EXT
#include "ins.h"
#endif
#include "tethering.h"
@@ -148,7 +148,7 @@ static int parse_args(char *arg, struct connman_option *options)
return '?';
}
-static int enable_return(DBusMessageIter *iter, const char *error,
+static int enable_return(DBusMessageIter *iter, int errnum, const char *error,
void *user_data)
{
char *tech = user_data;
@@ -160,10 +160,19 @@ static int enable_return(DBusMessageIter *iter, const char *error,
else
str = tech;
- if (!error)
+ switch (errnum) {
+ case 0:
fprintf(stdout, "Enabled %s\n", str);
- else
+ break;
+ case -ENODEV:
+ fprintf(stderr, "%s is not available\n", str);
+ break;
+ case -EALREADY:
+ fprintf(stderr, "%s is already enabled\n", str);
+ break;
+ default:
fprintf(stderr, "Error %s: %s\n", str, error);
+ }
g_free(user_data);
@@ -197,7 +206,7 @@ static int cmd_enable(char *args[], int num, struct connman_option *options)
"Powered", DBUS_TYPE_BOOLEAN, &b);
}
-static int disable_return(DBusMessageIter *iter, const char *error,
+static int disable_return(DBusMessageIter *iter, int errnum, const char *error,
void *user_data)
{
char *tech = user_data;
@@ -209,10 +218,19 @@ static int disable_return(DBusMessageIter *iter, const char *error,
else
str = tech;
- if (!error)
- fprintf(stdout, "Disabled %s\n", str);
- else
+ switch (errnum) {
+ case 0:
+ fprintf(stdout, "Disable %s\n", str);
+ break;
+ case -ENODEV:
+ fprintf(stderr, "%s is not available\n", str);
+ break;
+ case -EALREADY:
+ fprintf(stderr, "%s is already disabled\n", str);
+ break;
+ default:
fprintf(stderr, "Error %s: %s\n", str, error);
+ }
g_free(user_data);
@@ -246,7 +264,7 @@ static int cmd_disable(char *args[], int num, struct connman_option *options)
"Powered", DBUS_TYPE_BOOLEAN, &b);
}
-static int state_print(DBusMessageIter *iter, const char *error,
+static int state_print(DBusMessageIter *iter, int errnum, const char *error,
void *user_data)
{
DBusMessageIter entry;
@@ -273,7 +291,7 @@ static int cmd_state(char *args[], int num, struct connman_option *options)
state_print, NULL, NULL, NULL);
}
-static int clock_print(DBusMessageIter *iter, const char *error,
+static int clock_print(DBusMessageIter *iter, int errnum, const char *error,
void *user_data)
{
DBusMessageIter entry;
@@ -300,7 +318,7 @@ static int cmd_clock(char *args[], int num, struct connman_option *options)
clock_print, NULL, NULL, NULL);
}
-static int services_list(DBusMessageIter *iter, const char *error,
+static int services_list(DBusMessageIter *iter, int errnum, const char *error,
void *user_data)
{
if (!error) {
@@ -313,9 +331,9 @@ static int services_list(DBusMessageIter *iter, const char *error,
return 0;
}
-#if defined TIZEN_EXT_INS
-static int ins_list(DBusMessageIter *iter, const char *error,
- void *user_data)
+#if defined TIZEN_EXT
+static int ins_list(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
char *filter = user_data;
@@ -332,7 +350,7 @@ static int ins_list(DBusMessageIter *iter, const char *error,
}
#endif
-static int peers_list(DBusMessageIter *iter,
+static int peers_list(DBusMessageIter *iter, int errnum,
const char *error, void *user_data)
{
if (!error) {
@@ -344,7 +362,7 @@ static int peers_list(DBusMessageIter *iter,
return 0;
}
-static int tethering_clients_list(DBusMessageIter *iter,
+static int tethering_clients_list(DBusMessageIter *iter, int errnum,
const char *error, void *user_data)
{
if (!error) {
@@ -356,7 +374,7 @@ static int tethering_clients_list(DBusMessageIter *iter,
return 0;
}
-static int object_properties(DBusMessageIter *iter,
+static int object_properties(DBusMessageIter *iter, int errnum,
const char *error, void *user_data)
{
char *path = user_data;
@@ -427,7 +445,7 @@ static int cmd_services(char *args[], int num, struct connman_option *options)
object_properties, path, NULL, NULL);
}
-#if defined TIZEN_EXT_INS
+#if defined TIZEN_EXT
static int cmd_ins(char *args[], int num, struct connman_option *options)
{
char *filter = NULL;
@@ -472,7 +490,7 @@ static int cmd_peers(char *args[], int num, struct connman_option *options)
object_properties, path, NULL, NULL);
}
-static int technology_print(DBusMessageIter *iter, const char *error,
+static int technology_print(DBusMessageIter *iter, int errnum, const char *error,
void *user_data)
{
DBusMessageIter array;
@@ -519,8 +537,8 @@ struct tether_enable {
dbus_bool_t enable;
};
-static int tether_set_return(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int tether_set_return(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
struct tether_enable *tether = user_data;
char *str;
@@ -575,20 +593,23 @@ struct tether_properties {
int ssid_result;
int passphrase_result;
int set_tethering;
+ int freq_result;
};
static int tether_update(struct tether_properties *tether)
{
int ret;
- if (tether->ssid_result == 0 && tether->passphrase_result == 0) {
+ if (tether->ssid_result == 0 && tether->passphrase_result == 0 &&
+ tether->freq_result == 0) {
ret = tether_set("wifi", tether->set_tethering);
g_free(tether);
return ret;
}
if (tether->ssid_result != -EINPROGRESS &&
- tether->passphrase_result != -EINPROGRESS) {
+ tether->passphrase_result != -EINPROGRESS &&
+ tether->freq_result != -EINPROGRESS) {
g_free(tether);
return 0;
}
@@ -596,8 +617,8 @@ static int tether_update(struct tether_properties *tether)
return -EINPROGRESS;
}
-static int tether_set_ssid_return(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int tether_set_ssid_return(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
struct tether_properties *tether = user_data;
@@ -612,8 +633,8 @@ static int tether_set_ssid_return(DBusMessageIter *iter, const char *error,
return tether_update(tether);
}
-static int tether_set_passphrase_return(DBusMessageIter *iter,
- const char *error, void *user_data)
+static int tether_set_passphrase_return(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
struct tether_properties *tether = user_data;
@@ -628,9 +649,25 @@ static int tether_set_passphrase_return(DBusMessageIter *iter,
return tether_update(tether);
}
-static int tether_set_ssid(char *ssid, char *passphrase, int set_tethering)
+static int tether_set_freq_return(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
+{
+ struct tether_properties *tether = user_data;
+
+ if (!error) {
+ fprintf(stdout, "Wifi access point frequency set\n");
+ tether->freq_result = 0;
+ } else {
+ fprintf(stderr, "Error setting wifi frequency: %s\n", error);
+ tether->freq_result = -EINVAL;
+ }
+
+ return tether_update(tether);
+}
+
+static int tether_set_ssid(char *ssid, char *passphrase, int set_tethering, int freq)
{
- struct tether_properties *tether = g_new(struct tether_properties, 1);
+ struct tether_properties *tether = g_new0(struct tether_properties, 1);
tether->set_tethering = set_tethering;
@@ -646,12 +683,24 @@ static int tether_set_ssid(char *ssid, char *passphrase, int set_tethering)
tether_set_passphrase_return, tether,
"TetheringPassphrase", DBUS_TYPE_STRING, &passphrase);
+ if (freq > 0) {
+ tether->freq_result =__connmanctl_dbus_set_property(connection,
+ "/net/connman/technology/wifi",
+ "net.connman.Technology",
+ tether_set_freq_return, tether,
+ "TetheringFreq", DBUS_TYPE_INT32, &freq);
+ }
+
if (tether->ssid_result != -EINPROGRESS &&
- tether->passphrase_result != -EINPROGRESS) {
+ tether->passphrase_result != -EINPROGRESS &&
+ tether->freq_result != -EINPROGRESS) {
g_free(tether);
return -ENXIO;
}
+#if defined TIZEN_EXT
+ g_free(tether);
+#endif
return -EINPROGRESS;
}
@@ -1235,24 +1284,30 @@ static int cmd_tether(char *args[], int num, struct connman_option *options)
if (num < 3)
return -EINVAL;
- passphrase = args[num - 1];
- ssid = args[num - 2];
-
set_tethering = parse_boolean(args[2]);
if (strcmp(args[1], "wifi") == 0) {
+ int freq = 0;
- if (num > 5)
+ if (num > 6)
return -E2BIG;
- if (num == 5 && set_tethering == -1)
+ if (num >= 5 && set_tethering == -1)
return -EINVAL;
if (num == 4)
set_tethering = -1;
+ if (num == 6) {
+ freq = atoi(args[num - 1]);
+ num --;
+ }
+
+ passphrase = args[num - 1];
+ ssid = args[num - 2];
+
if (num > 3)
- return tether_set_ssid(ssid, passphrase, set_tethering);
+ return tether_set_ssid(ssid, passphrase, set_tethering, freq);
}
if (num > 3)
@@ -1278,7 +1333,7 @@ static int cmd_tethering_clients(char *args[], int num, struct connman_option *o
tethering_clients_list, NULL, NULL, NULL);
}
-static int scan_return(DBusMessageIter *iter, const char *error,
+static int scan_return(DBusMessageIter *iter, int ernnum, const char *error,
void *user_data)
{
char *path = user_data;
@@ -1314,8 +1369,8 @@ static int cmd_scan(char *args[], int num, struct connman_option *options)
scan_return, path, NULL, NULL);
}
-static int connect_return(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int connect_return(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
char *path = user_data;
@@ -1355,8 +1410,8 @@ static int cmd_connect(char *args[], int num, struct connman_option *options)
iface, "Connect", connect_return, path, NULL, NULL);
}
-static int disconnect_return(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int disconnect_return(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
char *path = user_data;
@@ -1402,8 +1457,8 @@ struct move_service {
char *target;
};
-static int move_before_return(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int move_before_return(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
struct move_service *services = user_data;
char *service;
@@ -1460,8 +1515,8 @@ static int cmd_service_move_before(char *args[], int num,
services->target);
}
-static int move_after_return(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int move_after_return(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
struct move_service *services = user_data;
char *service;
@@ -1518,8 +1573,8 @@ static int cmd_service_move_after(char *args[], int num,
services->target);
}
-static int config_return(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int config_return(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
char *service_name = user_data;
@@ -2022,7 +2077,6 @@ static void monitor_del(char *interface)
int i;
char *rule;
-
for (i = 0; monitor[i].interface; i++) {
if (g_strcmp0(interface, monitor[i].interface) == 0) {
if (monitor[i].enabled == false)
@@ -2175,8 +2229,8 @@ static int cmd_agent(char *args[], int num, struct connman_option *options)
return 0;
}
-static int vpnconnections_properties(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int vpnconnections_properties(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
char *path = user_data;
char *str;
@@ -2205,8 +2259,8 @@ static int vpnconnections_properties(DBusMessageIter *iter, const char *error,
return 0;
}
-static int vpnconnections_list(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int vpnconnections_list(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
if (!error)
__connmanctl_vpnconnections_list(iter);
@@ -2397,8 +2451,8 @@ static void session_notify_remove(void)
session_notify_path = NULL;
}
-static int session_connect_cb(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int session_connect_cb(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
if (error) {
fprintf(stderr, "Error: %s\n", error);
@@ -2408,7 +2462,6 @@ static int session_connect_cb(DBusMessageIter *iter, const char *error,
return -EINPROGRESS;
}
-
static int session_connect(void)
{
return __connmanctl_dbus_method_call(connection, "net.connman",
@@ -2416,8 +2469,8 @@ static int session_connect(void)
session_connect_cb, NULL, NULL, NULL);
}
-static int session_disconnect_cb(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int session_disconnect_cb(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
if (error)
fprintf(stderr, "Error: %s\n", error);
@@ -2432,8 +2485,8 @@ static int session_disconnect(void)
session_disconnect_cb, NULL, NULL, NULL);
}
-static int session_create_cb(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int session_create_cb(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
gboolean connect = GPOINTER_TO_INT(user_data);
char *str;
@@ -2605,8 +2658,8 @@ static int session_create(gboolean connect, char *args[], int num,
return res;
}
-static int session_destroy_cb(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int session_destroy_cb(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
if (error) {
fprintf(stderr, "Error destroying session: %s", error);
@@ -2637,8 +2690,8 @@ static int session_destroy(void)
session_destroy_append, session_path);
}
-static int session_config_return(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int session_config_return(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
char *property_name = user_data;
@@ -2990,7 +3043,7 @@ static struct connman_option service_options[] = {
{ NULL, }
};
-#if defined TIZEN_EXT_INS
+#if defined TIZEN_EXT
static struct connman_option ins_options[] = {
{"all", 'a', ""},
{"filter-ssid", 's', "ssid"},
@@ -3000,7 +3053,12 @@ static struct connman_option ins_options[] = {
#endif
static struct connman_option config_options[] = {
+#if defined TIZEN_EXT
+ {"nameservers", 'n', "ipv4.manual|ipv4.dhcp|ipv6.manual|ipv6.dhcp\n"
+ "\t\t\t<dns1> [<dns2>] [<dns3>]"},
+#else
{"nameservers", 'n', "<dns1> [<dns2>] [<dns3>]"},
+#endif
{"timeservers", 't', "<ntp1> [<ntp2>] [...]"},
{"domains", 'd', "<domain1> [<domain2>] [...]"},
{"mdns", 'm', "yes|no"},
@@ -3125,8 +3183,8 @@ static char *lookup_mesh(const char *text, int state)
}
#endif
-static int peer_service_cb(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int peer_service_cb(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
bool registration = GPOINTER_TO_INT(user_data);
@@ -3441,7 +3499,7 @@ static const struct {
lookup_mesh },
#endif
{ "tether", "<technology> on|off\n"
- " wifi [on|off] <ssid> <passphrase> ",
+ " wifi [on|off] <ssid> <passphrase> [<freq>] ",
NULL, cmd_tether,
"Enable, disable tethering, set SSID and passphrase for wifi",
lookup_tether },
@@ -3449,7 +3507,7 @@ static const struct {
"Display tethering clients", NULL },
{ "services", "[<service>]", service_options, cmd_services,
"Display services", lookup_service_arg },
-#if defined TIZEN_EXT_INS
+#if defined TIZEN_EXT
{ "ins", NULL, ins_options, cmd_ins,
"Display intelligent network selection", NULL },
#endif
@@ -3667,8 +3725,8 @@ static void update_services(DBusMessageIter *iter)
}
}
-static int populate_service_hash(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int populate_service_hash(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
if (error) {
fprintf(stderr, "Error getting services: %s", error);
@@ -3725,8 +3783,8 @@ static void add_vpnconnections(DBusMessageIter *iter)
}
}
-static int populate_vpnconnection_hash(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int populate_vpnconnection_hash(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
DBusMessageIter array;
@@ -3799,8 +3857,8 @@ static void update_peers(DBusMessageIter *iter)
}
}
-static int populate_peer_hash(DBusMessageIter *iter,
- const char *error, void *user_data)
+static int populate_peer_hash(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
if (error) {
fprintf(stderr, "Error getting peers: %s", error);
@@ -3864,8 +3922,8 @@ static void update_technologies(DBusMessageIter *iter)
}
}
-static int populate_technology_hash(DBusMessageIter *iter, const char *error,
- void *user_data)
+static int populate_technology_hash(DBusMessageIter *iter, int errnum,
+ const char *error, void *user_data)
{
if (error) {
fprintf(stderr, "Error getting technologies: %s\n", error);
diff --git a/client/dbus_helpers.c b/client/dbus_helpers.c
index 8c6bdbb3..1c68a28a 100644
--- a/client/dbus_helpers.c
+++ b/client/dbus_helpers.c
@@ -30,6 +30,34 @@
#define TIMEOUT 120000
+#ifndef DBUS_ERROR_UNKNOWN_METHOD
+#define DBUS_ERROR_UNKNOWN_METHOD "org.freedesktop.DBus.Error.UnknownMethod"
+#endif
+
+#ifndef DBUS_ERROR_UNKNOWN_PROPERTY
+#define DBUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty"
+#endif
+
+#ifndef DBUS_ERROR_UNKNOWN_OBJECT
+#define DBUS_ERROR_UNKNOWN_OBJECT "org.freedesktop.DBus.Error.UnknownObject"
+#endif
+
+static int string2errno(const char *error)
+{
+ if (!g_strcmp0(error, DBUS_ERROR_UNKNOWN_METHOD))
+ return -ENOTSUP;
+ if (!g_strcmp0(error, DBUS_ERROR_UNKNOWN_PROPERTY))
+ return -ENOENT;
+ if (!g_strcmp0(error, DBUS_ERROR_UNKNOWN_OBJECT))
+ return -ENODEV;
+ if (!g_strcmp0(error, "net.connman.Error.AlreadyEnabled"))
+ return -EALREADY;
+ if (!g_strcmp0(error, "net.connman.Error.AlreadyDisabled"))
+ return -EALREADY;
+
+ return -EINVAL;
+}
+
void __connmanctl_dbus_print(DBusMessageIter *iter, const char *pre,
const char *dict, const char *sep)
{
@@ -159,14 +187,15 @@ static void dbus_method_reply(DBusPendingCall *call, void *user_data)
dbus_error_init(&err);
dbus_set_error_from_message(&err, reply);
- callback->cb(NULL, err.message, callback->user_data);
+ callback->cb(NULL, string2errno(err.name), err.message,
+ callback->user_data);
dbus_error_free(&err);
goto end;
}
dbus_message_iter_init(reply, &iter);
- res = callback->cb(&iter, NULL, callback->user_data);
+ res = callback->cb(&iter, 0, NULL, callback->user_data);
end:
__connmanctl_redraw_rl();
diff --git a/client/dbus_helpers.h b/client/dbus_helpers.h
index 69458395..85fbdef2 100644
--- a/client/dbus_helpers.h
+++ b/client/dbus_helpers.h
@@ -38,7 +38,7 @@ void __connmanctl_dbus_print(DBusMessageIter *iter, const char *pre,
const char *dict, const char *sep);
typedef int (*connmanctl_dbus_method_return_func_t)(DBusMessageIter *iter,
- const char *error, void *user_data);
+ int errnum, const char *error, void *user_data);
typedef void (*connmanctl_dbus_append_func_t)(DBusMessageIter *iter,
void *user_data);
diff --git a/client/ins.c b/client/ins.c
index 6403f610..929c6a93 100755
--- a/client/ins.c
+++ b/client/ins.c
@@ -95,7 +95,7 @@ static GSList *get_bssid_list(DBusMessageIter *iter, struct ins_info_s *ins_info
if (strcmp(property, "BSSID") == 0) {
bssid_info = g_try_new0(struct bssid_info_s, 1);
if (!bssid_info)
- continue;
+ break;
dbus_message_iter_next(&entry);
dbus_message_iter_recurse(&entry, &val);
@@ -157,19 +157,19 @@ static void print_ins_info(int *rank, struct ins_info_s *ins_info,
char *path, char *filter, DBusMessageIter *iter)
{
char *name = "";
- char *security;
+ char *security = "";
char *str = NULL;
int count = 0;
char *property;
- unsigned char strength;
- unsigned int frequency;
- int score_INS;
- int score_last_user_selection;
- int score_last_connected;
- int score_frequency;
- int score_security_priority;
- int score_internet_connection;
- int score_strength;
+ unsigned char strength = 0;
+ unsigned int frequency = 0;
+ int score_INS = 0;
+ int score_last_user_selection = 0;
+ int score_last_connected = 0;
+ int score_frequency = 0;
+ int score_security_priority = 0;
+ int score_internet_connection = 0;
+ int score_strength = 0;
GSList *bssid_list = NULL;
DBusMessageIter entry, val, dict;
diff --git a/client/vpnconnections.c b/client/vpnconnections.c
index d7bcbfee..7cef6bbe 100755
--- a/client/vpnconnections.c
+++ b/client/vpnconnections.c
@@ -72,7 +72,7 @@ static void print_connection(char *path, DBusMessageIter *iter)
else
str = path;
- fprintf(stdout, " %c %-20s %s", state, name, str);
+ fprintf(stdout, " %c %-20s vpn_%s", state, name, str);
}
void __connmanctl_vpnconnections_list(DBusMessageIter *iter)
diff --git a/configure.ac b/configure.ac
index 62ab2a36..9a2f65d5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
AC_PREREQ(2.60)
-AC_INIT(connman, 1.37)
+AC_INIT(connman, 1.41)
AC_CONFIG_MACRO_DIR([m4])
@@ -36,14 +36,14 @@ AC_PROG_LIBTOOL
gl_CONFIGMAKE_PREP
-AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization],
+AC_ARG_ENABLE(optimization, AS_HELP_STRING([--disable-optimization],
[disable code optimization through compiler]), [
if (test "${enableval}" = "no"); then
CFLAGS="$CFLAGS -O0 -U_FORTIFY_SOURCE"
fi
])
-AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],
+AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug],
[enable compiling with debugging information]), [
if (test "${enableval}" = "yes" &&
test "${ac_cv_prog_cc_g}" = "yes"); then
@@ -51,7 +51,7 @@ AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],
fi
])
-AC_ARG_ENABLE(pie, AC_HELP_STRING([--enable-pie],
+AC_ARG_ENABLE(pie, AS_HELP_STRING([--enable-pie],
[enable position independent executables flag]), [
if (test "${enableval}" = "yes" &&
test "${ac_cv_prog_cc_pie}" = "yes"); then
@@ -61,54 +61,47 @@ AC_ARG_ENABLE(pie, AC_HELP_STRING([--enable-pie],
])
AC_ARG_ENABLE(hh2serial-gps,
- AC_HELP_STRING([--enable-hh2serial-gps], [enable hh2serial GPS support]),
+ AS_HELP_STRING([--enable-hh2serial-gps], [enable hh2serial GPS support]),
[enable_hh2serial_gps=${enableval}], [enable_hh2serial_gps="no"])
AM_CONDITIONAL(HH2SERIAL_GPS, test "${enable_hh2serial_gps}" != "no")
AM_CONDITIONAL(HH2SERIAL_GPS_BUILTIN, test "${enable_hh2serial_gps}" = "builtin")
AC_ARG_ENABLE(telephony,
- AC_HELP_STRING([--enable-telephony], [enable Telephony support]),
+ AS_HELP_STRING([--enable-telephony], [enable Telephony support]),
[enable_telephony=${enableval}], [enable_telephony="yes"])
AM_CONDITIONAL(TELEPHONY, test "${enable_telephony}" != "no")
AM_CONDITIONAL(TELEPHONY_BUILTIN, test "${enable_telephony}" = "builtin")
AC_ARG_ENABLE(tizen-ext,
- AC_HELP_STRING([--enable-tizen-ext], [enable TIZEN extensions]),
+ AS_HELP_STRING([--enable-tizen-ext], [enable TIZEN extensions]),
[if (test "${enableval}" = "yes"); then
CFLAGS="$CFLAGS -DTIZEN_EXT"
LIBS="$LIBS -lsmack"
fi])
AM_CONDITIONAL(TIZEN_EXT, test "${enable-tizen-ext}" != "no")
-AC_ARG_ENABLE(tizen-ext-ins,
- AC_HELP_STRING([--enable-tizen-ext-ins], [enable TIZEN extensions for INS]),
- [if (test "${enableval}" = "yes"); then
- CFLAGS="$CFLAGS -DTIZEN_EXT_INS"
- fi])
-AM_CONDITIONAL(TIZEN_EXT_INS, test "${enable_tizen_ext_ins}" != "no")
-
AC_ARG_ENABLE(tizen-ext-wifi-mesh,
- AC_HELP_STRING([--enable-tizen-ext-wifi-mesh], [enable TIZEN extensions for Wi-Fi Mesh]),
+ AS_HELP_STRING([--enable-tizen-ext-wifi-mesh], [enable TIZEN extensions for Wi-Fi Mesh]),
[CFLAGS="$CFLAGS -DTIZEN_EXT_WIFI_MESH"], [enable_tizen_ext_wifi_mesh="no"])
AM_CONDITIONAL(TIZEN_EXT_WIFI_MESH, test "${enable_tizen_ext_wifi_mesh}" != "no")
AC_ARG_ENABLE(tizen-ext-eap-on-ethernet,
- AC_HELP_STRING([--enable-tizen-ext-eap-on-ethernet], [enable TIZEN extensions for EAP on Ethernet]),
+ AS_HELP_STRING([--enable-tizen-ext-eap-on-ethernet], [enable TIZEN extensions for EAP on Ethernet]),
[CFLAGS="$CFLAGS -DTIZEN_EXT_EAP_ON_ETHERNET"], [enable_tizen_ext_eap_on_ethernet="no"])
AM_CONDITIONAL(TIZEN_EXT_EAP_ON_ETHERNET, test "${enable_tizen_ext_eap_on_ethernet}" != "no")
AC_ARG_ENABLE(tizen-maintain-online,
- AC_HELP_STRING([--enable-tizen-maintain-online], [enable TIZEN extensions]),
+ AS_HELP_STRING([--enable-tizen-maintain-online], [enable TIZEN extensions]),
[if (test "${enableval}" = "yes"); then
CFLAGS="$CFLAGS -DTIZEN_MAINTAIN_ONLINE"
LIBS="$LIBS -lsmack"
fi])
-AC_ARG_WITH(openconnect, AC_HELP_STRING([--with-openconnect=PROGRAM],
+AC_ARG_WITH(openconnect, AS_HELP_STRING([--with-openconnect=PROGRAM],
[specify location of openconnect binary]), [path_openconnect=${withval}])
AC_ARG_ENABLE(openconnect,
- AC_HELP_STRING([--enable-openconnect], [enable openconnect support]),
+ AS_HELP_STRING([--enable-openconnect], [enable openconnect support]),
[enable_openconnect=${enableval}], [enable_openconnect="no"])
if (test "${enable_openconnect}" != "no"); then
if (test -z "${path_openconnect}"); then
@@ -120,15 +113,17 @@ if (test "${enable_openconnect}" != "no"); then
OPENCONNECT="${path_openconnect}"
AC_SUBST(OPENCONNECT)
fi
+ PKG_CHECK_MODULES(LIBOPENCONNECT, openconnect >= 8, [],
+ AC_MSG_ERROR(openconnect >= 8 is required))
fi
AM_CONDITIONAL(OPENCONNECT, test "${enable_openconnect}" != "no")
AM_CONDITIONAL(OPENCONNECT_BUILTIN, test "${enable_openconnect}" = "builtin")
-AC_ARG_WITH(openvpn, AC_HELP_STRING([--with-openvpn=PROGRAM],
+AC_ARG_WITH(openvpn, AS_HELP_STRING([--with-openvpn=PROGRAM],
[specify location of openvpn binary]), [path_openvpn=${withval}])
AC_ARG_ENABLE(openvpn,
- AC_HELP_STRING([--enable-openvpn], [enable openvpn support]),
+ AS_HELP_STRING([--enable-openvpn], [enable openvpn support]),
[enable_openvpn=${enableval}], [enable_openvpn="no"])
if (test "${enable_openvpn}" != "no"); then
if (test -z "${path_openvpn}"); then
@@ -144,11 +139,11 @@ fi
AM_CONDITIONAL(OPENVPN, test "${enable_openvpn}" != "no")
AM_CONDITIONAL(OPENVPN_BUILTIN, test "${enable_openvpn}" = "builtin")
-AC_ARG_WITH(ipsec, AC_HELP_STRING([--with-ipsec=PROGRAM],
+AC_ARG_WITH(ipsec, AS_HELP_STRING([--with-ipsec=PROGRAM],
[specify location of ipsec binary]), [path_ipsec=${withval}])
AC_ARG_ENABLE(ipsec,
- AC_HELP_STRING([--enable-ipsec], [enable ipsec support]),
+ AS_HELP_STRING([--enable-ipsec], [enable ipsec support]),
[enable_ipsec=${enableval}], [enable_ipsec="no"])
if (test "${enable_ipsec}" != "no"); then
PKG_CHECK_MODULES(GIO, gio-2.0 >= 2.28, dummy=yes,
@@ -168,11 +163,11 @@ fi
AM_CONDITIONAL(IPSEC, test "${enable_ipsec}" != "no")
AM_CONDITIONAL(IPSEC_BUILTIN, test "${enable_ipsec}" = "builtin")
-AC_ARG_WITH(vpnc, AC_HELP_STRING([--with-vpnc=PROGRAM],
+AC_ARG_WITH(vpnc, AS_HELP_STRING([--with-vpnc=PROGRAM],
[specify location of vpnc binary]), [path_vpnc=${withval}])
AC_ARG_ENABLE(vpnc,
- AC_HELP_STRING([--enable-vpnc], [enable vpnc support]),
+ AS_HELP_STRING([--enable-vpnc], [enable vpnc support]),
[enable_vpnc=${enableval}], [enable_vpnc="no"])
if (test "${enable_vpnc}" != "no"); then
if (test -z "${path_vpnc}"); then
@@ -188,11 +183,11 @@ fi
AM_CONDITIONAL(VPNC, test "${enable_vpnc}" != "no")
AM_CONDITIONAL(VPNC_BUILTIN, test "${enable_vpnc}" = "builtin")
-AC_ARG_WITH(l2tp, AC_HELP_STRING([--with-l2tp=PROGRAM],
+AC_ARG_WITH(l2tp, AS_HELP_STRING([--with-l2tp=PROGRAM],
[specify location of l2tp binary]), [path_l2tp=${withval}])
AC_ARG_ENABLE(l2tp,
- AC_HELP_STRING([--enable-l2tp], [enable l2tp support]),
+ AS_HELP_STRING([--enable-l2tp], [enable l2tp support]),
[enable_l2tp=${enableval}], [enable_l2tp="no"])
if (test "${enable_l2tp}" != "no"); then
if (test -z "${path_pppd}"); then
@@ -213,11 +208,11 @@ fi
AM_CONDITIONAL(L2TP, test "${enable_l2tp}" != "no")
AM_CONDITIONAL(L2TP_BUILTIN, test "${enable_l2tp}" = "builtin")
-AC_ARG_WITH(pptp, AC_HELP_STRING([--with-pptp=PROGRAM],
+AC_ARG_WITH(pptp, AS_HELP_STRING([--with-pptp=PROGRAM],
[specify location of pptp binary]), [path_pptp=${withval}])
AC_ARG_ENABLE(pptp,
- AC_HELP_STRING([--enable-pptp], [enable pptp support]),
+ AS_HELP_STRING([--enable-pptp], [enable pptp support]),
[enable_pptp=${enableval}], [enable_pptp="no"])
if (test "${enable_pptp}" != "no"); then
if (test -z "${path_pppd}"); then
@@ -256,23 +251,23 @@ AC_CHECK_FUNC(signalfd, dummy=yes,
AC_CHECK_LIB(dl, dlopen, dummy=yes,
AC_MSG_ERROR(dynamic linking loader is required))
-AC_ARG_ENABLE(iospm, AC_HELP_STRING([--enable-iospm],
+AC_ARG_ENABLE(iospm, AS_HELP_STRING([--enable-iospm],
[enable Intel OSPM support]), [enable_iospm=${enableval}])
AM_CONDITIONAL(IOSPM, test "${enable_iospm}" = "yes")
AC_ARG_ENABLE(tist,
- AC_HELP_STRING([--enable-tist], [enable TI Shared Transport support]),
+ AS_HELP_STRING([--enable-tist], [enable TI Shared Transport support]),
[enable_tist=${enableval}], [enable_tist="no"])
AM_CONDITIONAL(TIST, test "${enable_tist}" != "no")
AM_CONDITIONAL(TIST_BUILTIN, test "${enable_tist}" = "builtin")
AC_ARG_ENABLE(session-policy-local,
- AC_HELP_STRING([--enable-session-policy-local], [enable local file Session policy configuration support]),
+ AS_HELP_STRING([--enable-session-policy-local], [enable local file Session policy configuration support]),
[enable_session_policy_local=${enableval}], [enable_session_policy_local="no"])
AM_CONDITIONAL(SESSION_POLICY_LOCAL, test "${enable_session_policy_local}" != "no")
AM_CONDITIONAL(SESSION_POLICY_LOCAL_BUILTIN, test "${enable_session_policy_local}" = "builtin")
-AC_ARG_WITH(stats-max-file-size, AC_HELP_STRING([--with-stats-max-file-size=SIZE],
+AC_ARG_WITH(stats-max-file-size, AS_HELP_STRING([--with-stats-max-file-size=SIZE],
[Maximal size of a statistics round robin file]),
[stats_max_file_size=${withval}])
@@ -298,8 +293,8 @@ PKG_CHECK_MODULES(LIBNL_GENL, libnl-genl-3.0, dummy=yes,
AC_SUBST(LIBNL_GENL_CFLAGS)
AC_SUBST(LIBNL_GENL_LIBS)
-PKG_CHECK_MODULES(LIBSYSTEMD, libsystemd-daemon, dummy=yes,
- AC_MSG_ERROR(libsystemd-daemon library is required))
+PKG_CHECK_MODULES(LIBSYSTEMD, libsystemd, dummy=yes,
+ AC_MSG_ERROR(libsystemd library is required))
AC_SUBST(LIBSYSTEMD_CFLAGS)
AC_SUBST(LIBSYSTEMD_LIBS)
@@ -313,7 +308,7 @@ PKG_CHECK_MODULES(DLOG, dlog, dummy=yes,
AC_SUBST(DLOG_CFLAGS)
AC_SUBST(DLOG_LIBS)
-AC_ARG_WITH(dbusconfdir, AC_HELP_STRING([--with-dbusconfdir=PATH],
+AC_ARG_WITH(dbusconfdir, AS_HELP_STRING([--with-dbusconfdir=PATH],
[path to D-Bus config directory]), [path_dbusconf=${withval}],
[path_dbusconf="`$PKG_CONFIG --variable=sysconfdir dbus-1`"])
if (test -z "${path_dbusconf}"); then
@@ -323,7 +318,7 @@ else
fi
AC_SUBST(DBUS_CONFDIR)
-AC_ARG_WITH(dbusdatadir, AC_HELP_STRING([--with-dbusdatadir=PATH],
+AC_ARG_WITH(dbusdatadir, AS_HELP_STRING([--with-dbusdatadir=PATH],
[path to D-Bus data directory]), [path_dbusdata=${withval}],
[path_dbusdata="`$PKG_CONFIG --variable=datadir dbus-1`"])
if (test -z "${path_dbusdata}"); then
@@ -333,7 +328,7 @@ else
fi
AC_SUBST(DBUS_DATADIR)
-AC_ARG_WITH([systemdunitdir], AC_HELP_STRING([--with-systemdunitdir=DIR],
+AC_ARG_WITH([systemdunitdir], AS_HELP_STRING([--with-systemdunitdir=DIR],
[path to systemd service directory]), [path_systemdunit=${withval}],
[path_systemdunit="`$PKG_CONFIG --variable=systemdsystemunitdir systemd`"])
if (test -n "${path_systemdunit}"); then
@@ -342,7 +337,7 @@ if (test -n "${path_systemdunit}"); then
fi
AM_CONDITIONAL(SYSTEMD, test -n "${path_systemdunit}")
-AC_ARG_WITH([tmpfilesdir], AC_HELP_STRING([--with-tmpfilesdir=DIR],
+AC_ARG_WITH([tmpfilesdir], AS_HELP_STRING([--with-tmpfilesdir=DIR],
[path to systemd tmpfiles.d directory]), [path_tmpfiles=${withval}],
[path_tmpfiles="`$PKG_CONFIG --variable=tmpfilesdir systemd`"])
if (test -n "${path_tmpfiles}"); then
@@ -350,7 +345,7 @@ if (test -n "${path_tmpfiles}"); then
AC_SUBST(SYSTEMD_TMPFILESDIR)
fi
-AC_ARG_WITH(firewall, AC_HELP_STRING([--with-firewall=TYPE],
+AC_ARG_WITH(firewall, AS_HELP_STRING([--with-firewall=TYPE],
[specify which firewall type is used iptables or nftables [default=iptables]]),
[firewall_type=${withval}],
[firewall_type="iptables"])
@@ -369,25 +364,35 @@ if (test "${firewall_type}" = "iptables"); then
fi
AM_CONDITIONAL(XTABLES, test "${found_iptables}" != "no")
+found_libmnl="no"
+if (test "${firewall_type}" = "nftables" -o \
+ "${enable_wireguard}" != "no"); then
+ PKG_CHECK_MODULES(LIBMNL, [libmnl >= 1.0.0], [found_libmnl="yes"],
+ AC_MSG_ERROR([libmnl >= 1.0.0 not found]))
+ AC_SUBST(LIBMNL_CFLAGS)
+ AC_SUBST(LIBMNL_LIBS)
+fi
+AM_CONDITIONAL(LIBMNL, test "${found_libmnl}" != "no")
+
found_nftables="no"
if (test "${firewall_type}" = "nftables"); then
- PKG_CHECK_MODULES(NFTABLES, [libnftnl >= 1.0.4 libmnl >= 1.0.0], [found_nftables="yes"],
- AC_MSG_ERROR([libnftnl >= 1.0.4 or libmnl >= 1.0.0 not found]))
+ PKG_CHECK_MODULES(NFTABLES, [libnftnl >= 1.0.4], [found_nftables="yes"],
+ AC_MSG_ERROR([libnftnl >= 1.0.4]))
AC_SUBST(NFTABLES_CFLAGS)
AC_SUBST(NFTABLES_LIBS)
fi
AM_CONDITIONAL(NFTABLES, test "${found_nftables}" != "no")
-AC_ARG_ENABLE(test, AC_HELP_STRING([--enable-test],
+AC_ARG_ENABLE(test, AS_HELP_STRING([--enable-test],
[enable test/example scripts]), [enable_test=${enableval}])
AM_CONDITIONAL(TEST, test "${enable_test}" = "yes")
-AC_ARG_ENABLE(nmcompat, AC_HELP_STRING([--enable-nmcompat],
+AC_ARG_ENABLE(nmcompat, AS_HELP_STRING([--enable-nmcompat],
[enable Network Manager support]),
[enable_nmcompat=${enableval}], [enable_nmcompat="no"])
AM_CONDITIONAL(NMCOMPAT, test "${enable_nmcompat}" != "no")
-AC_ARG_ENABLE(polkit, AC_HELP_STRING([--enable-polkit],
+AC_ARG_ENABLE(polkit, AS_HELP_STRING([--enable-polkit],
[enable PolicyKit support]),
[enable_polkit=${enableval}], [enable_polkit="no"])
if (test "${enable_polkit}" != "no"); then
@@ -400,77 +405,83 @@ if (test "${enable_polkit}" != "no"); then
fi
AM_CONDITIONAL(POLKIT, test "${enable_polkit}" != "no")
-AC_ARG_ENABLE(selinux, AC_HELP_STRING([--enable-selinux],
+AC_ARG_ENABLE(selinux, AS_HELP_STRING([--enable-selinux],
[enable selinux support]),
[enable_selinux=${enableval}], [enable_selinux="no"])
AM_CONDITIONAL(SELINUX, test "${enable_selinux}" != "no")
-AC_ARG_ENABLE(loopback, AC_HELP_STRING([--disable-loopback],
+AC_ARG_ENABLE(loopback, AS_HELP_STRING([--disable-loopback],
[disable loopback support]),
[enable_loopback=${enableval}])
AM_CONDITIONAL(LOOPBACK, test "${enable_loopback}" != "no")
-AC_ARG_ENABLE(ethernet, AC_HELP_STRING([--disable-ethernet],
+AC_ARG_ENABLE(ethernet, AS_HELP_STRING([--disable-ethernet],
[disable Ethernet support]),
[enable_ethernet=${enableval}])
AM_CONDITIONAL(ETHERNET, test "${enable_ethernet}" != "no")
-AC_ARG_ENABLE(gadget, AC_HELP_STRING([--disable-gadget],
+AC_ARG_ENABLE(wireguard, AS_HELP_STRING([--disable-wireguard],
+ [disable Wireguard support]),
+ [enable_wireguard=${enableval}])
+AM_CONDITIONAL(WIREGUARD, test "${enable_wireguard}" != "no")
+AM_CONDITIONAL(WIREGUARD_BUILTIN, test "${enable_wireguard}" = "builtin")
+
+AC_ARG_ENABLE(gadget, AS_HELP_STRING([--disable-gadget],
[disable USB Gadget support]),
[enable_gadget=${enableval}])
AM_CONDITIONAL(GADGET, test "${enable_gadget}" != "no")
-AC_ARG_ENABLE(wifi, AC_HELP_STRING([--disable-wifi],
+AC_ARG_ENABLE(wifi, AS_HELP_STRING([--disable-wifi],
[disable WiFi support]),
[enable_wifi=${enableval}])
AM_CONDITIONAL(WIFI, test "${enable_wifi}" != "no")
-AC_ARG_ENABLE(iwd, AC_HELP_STRING([--enable-iwd],
+AC_ARG_ENABLE(iwd, AS_HELP_STRING([--enable-iwd],
[enable iwd support]),
[enable_iwd=${enableval}])
AM_CONDITIONAL(IWD, test "${enable_iwd}" = "yes")
-AC_ARG_ENABLE(bluetooth, AC_HELP_STRING([--disable-bluetooth],
+AC_ARG_ENABLE(bluetooth, AS_HELP_STRING([--disable-bluetooth],
[disable Bluetooth support]),
[enable_bluetooth=${enableval}])
AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no")
-AC_ARG_ENABLE(ofono, AC_HELP_STRING([--disable-ofono],
+AC_ARG_ENABLE(ofono, AS_HELP_STRING([--disable-ofono],
[disable oFono support]),
[enable_ofono=${enableval}])
AM_CONDITIONAL(OFONO, test "${enable_ofono}" != "no")
-AC_ARG_ENABLE(dundee, AC_HELP_STRING([--disable-dundee],
+AC_ARG_ENABLE(dundee, AS_HELP_STRING([--disable-dundee],
[disable dundee support (Bluetooth DUN)]),
[enable_dundee=${enableval}])
AM_CONDITIONAL(DUNDEE, test "${enable_dundee}" != "no")
-AC_ARG_ENABLE(pacrunner, AC_HELP_STRING([--disable-pacrunner],
+AC_ARG_ENABLE(pacrunner, AS_HELP_STRING([--disable-pacrunner],
[disable PACrunner support]),
[enable_pacrunner=${enableval}])
AM_CONDITIONAL(PACRUNNER, test "${enable_pacrunner}" != "no")
-AC_ARG_ENABLE(neard, AC_HELP_STRING([--disable-neard],
+AC_ARG_ENABLE(neard, AS_HELP_STRING([--disable-neard],
[disable Neard support]),
[enable_neard=${enableval}])
AM_CONDITIONAL(NEARD, test "${enable_neard}" != "no")
-AC_ARG_ENABLE(wispr, AC_HELP_STRING([--disable-wispr],
+AC_ARG_ENABLE(wispr, AS_HELP_STRING([--disable-wispr],
[disable WISPr support]),
[enable_wispr=${enableval}])
AM_CONDITIONAL(WISPR, test "${enable_wispr}" != "no")
-AC_ARG_ENABLE(backtrace, AC_HELP_STRING([--disable-backtrace],
+AC_ARG_ENABLE(backtrace, AS_HELP_STRING([--disable-backtrace],
[disable backtrace support]),
[enable_backtrace=${enableval}])
AM_CONDITIONAL(BACKTRACE, test "${enable_backtrace}" != "no")
-AC_ARG_ENABLE(tools, AC_HELP_STRING([--disable-tools],
+AC_ARG_ENABLE(tools, AS_HELP_STRING([--disable-tools],
[disable testing tools]),
[enable_tools=${enableval}])
AM_CONDITIONAL(TOOLS, test "${enable_tools}" != "no")
-AC_ARG_ENABLE(stats, AC_HELP_STRING([--disable-stats],
+AC_ARG_ENABLE(stats, AS_HELP_STRING([--disable-stats],
[disable statistics round robin file generation]),
[enable_stats=${enableval}])
AM_CONDITIONAL(STATS, test "${enable_stats}" != "no")
@@ -489,7 +500,7 @@ fi
AC_SUBST(IPTABLES_SAVE)
AC_SUBST(IP6TABLES_SAVE)
-AC_ARG_ENABLE(client, AC_HELP_STRING([--disable-client],
+AC_ARG_ENABLE(client, AS_HELP_STRING([--disable-client],
[disable command line client]),
[enable_client=${enableval}])
AM_CONDITIONAL(CLIENT, test "${enable_client}" != "no")
@@ -517,7 +528,7 @@ if (test "${enable_wifi}" != "no"); then
$PATH:/bin:/usr/bin)
fi
-AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--disable-datafiles],
+AC_ARG_ENABLE(datafiles, AS_HELP_STRING([--disable-datafiles],
[don't install configuration and data files]),
[enable_datafiles=${enableval}])
AM_CONDITIONAL(DATAFILES, test "${enable_datafiles}" != "no")
@@ -532,10 +543,11 @@ AM_CONDITIONAL(VPN, test "${enable_openconnect}" != "no" -o \
"${enable_ipsec}" != "no" -o \
"${enable_vpnc}" != "no" -o \
"${enable_l2tp}" != "no" -o \
- "${enable_pptp}" != "no")
+ "${enable_pptp}" != "no" -o \
+ "${enable_wireguard}" != "no")
AC_MSG_CHECKING(which DNS backend to use)
-AC_ARG_WITH(dns-backend, AC_HELP_STRING([--with-dns-backend=TYPE],
+AC_ARG_WITH(dns-backend, AS_HELP_STRING([--with-dns-backend=TYPE],
[specify which DNS backend to use: internal or systemd-resolved [default=internal]]),
[dns_backend=${withval}],
[dns_backend="internal"])
diff --git a/doc/agent-api.txt b/doc/agent-api.txt
index e3c1dcde..b2becd2a 100755
--- a/doc/agent-api.txt
+++ b/doc/agent-api.txt
@@ -36,7 +36,7 @@ Methods void Release()
void RequestBrowser(object service, string url)
This method gets called when it is required
- to ask the user to open a website to procceed
+ to ask the user to open a website to proceed
with login handling.
This can happen if connected to a hotspot portal
@@ -54,7 +54,7 @@ Methods void Release()
keys are the field names and the values are the
actual fields. Alternatively an error indicating that
the request got canceled can be returned.
- OperationAborted will be return on a successfull
+ OperationAborted will be return on a successful
cancel request.
Most common return field names are "Name" and of
@@ -121,7 +121,7 @@ Fields string Name
string PreviousPassphrase
The previous passphrase successfully saved, i.e.
- which led to a successfull connection. This field is
+ which led to a successful connection. This field is
provided as an informational argument when connecting
with it does not work anymore, for instance when it
has been changed on the AP. Such argument appears when
diff --git a/doc/clock-api.txt b/doc/clock-api.txt
index 6818f5a8..a7fdf555 100755
--- a/doc/clock-api.txt
+++ b/doc/clock-api.txt
@@ -85,3 +85,12 @@ Properties uint64 Time [readonly or readwrite] [experimental]
This list of servers is used when TimeUpdates is set
to auto.
+
+ boolean TimeserverSynced [readonly] [experimental]
+
+ This value indicates if the current system time
+ is synced via NTP servers.
+
+ True when TimeUpdates is set to auto and Time value
+ results from the system time synchronization with a NTP
+ server. Otherwise False.
diff --git a/doc/coding-style.txt b/doc/coding-style.txt
index 97410ce7..c2fdc717 100644
--- a/doc/coding-style.txt
+++ b/doc/coding-style.txt
@@ -155,10 +155,19 @@ for (i = 0; i < 3; i++) {
}
-M8: Use g_try_malloc instead of g_malloc
-========================================
-When g_malloc fails, the whole program would exit. Most of time, this is not
-the expected behavior, and you may want to use g_try_malloc instead.
+M8: Abort if small allocation fail
+==================================
+When g_malloc fails, the whole program would exit. Small allocations
+are very unlikely to fail and if an allocations is not possible, it is
+very likely the error code can't recover from this
+situation. Furthermore, many of the error paths are not tested at
+all. Instead use g_malloc() when the allocation fails and rely on an
+external watchdog to restart the program.
+
+Furthermore, Glib's functions such as g_strdup use g_malloc which
+obviously terminates the program anyway.
+
+For large allocation using g_try_malloc is still the right choice.
Example:
additional = g_try_malloc(len - 1); // correct
diff --git a/doc/config-format.txt b/doc/config-format.txt
index 584220f0..cdde9cbc 100755
--- a/doc/config-format.txt
+++ b/doc/config-format.txt
@@ -59,6 +59,8 @@ Allowed fields:
interface is used. The byte values must have prefix 0 added,
the bytes must be separated by ":" char and its length must be
exactly 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 = 17 characters.
+- DeviceName: The interface name where this setting should be applied, e.g.
+ eth0. The MAC address will take preference over DeviceName in matching.
- Nameservers: Comma separated list of nameservers
- SearchDomains: Comma separated list of DNS search domains
- Timeservers: Comma separated list of timeservers
diff --git a/doc/connman-service.config.5.in b/doc/connman-service.config.5.in
index eb63f225..701f61f9 100644
--- a/doc/connman-service.config.5.in
+++ b/doc/connman-service.config.5.in
@@ -59,6 +59,10 @@ IPv6 privacy settings as per RFC3041.
MAC address of the interface to be used. If not specified, the first
found interface is used. Must be in format ab:cd:ef:01:23:45.
.TP
+.BI DeviceName= ifname
+Device name the interface to be used, e.g. eth0. MAC takes preference
+over DeviceName.
+.TP
.BI Nameservers= servers
Comma separated list of nameservers.
.TP
@@ -209,6 +213,11 @@ Name = my_home_wifi
Passphrase = password
IPv4 = 192.168.2.2/255.255.255.0/192.168.2.1
MAC = 06:05:04:03:02:01
+
+[service_vlan]
+Type = ethernet
+DeviceName = enp4s0.1
+IPv4 = 192.168.1.42/255.255.255.0/192.168.1.1
.fi
.SH "SEE ALSO"
.BR connman (8)
diff --git a/doc/connman-vpn-provider.config.5.in b/doc/connman-vpn-provider.config.5.in
index 51d547b3..cea99e65 100644
--- a/doc/connman-vpn-provider.config.5.in
+++ b/doc/connman-vpn-provider.config.5.in
@@ -12,7 +12,7 @@ connection_name.config \- ConnMan vpn connection provisioning file
\fIConnMan\fP's vpn connections are configured with so called
"\fBprovisioning files\fP" which reside under \fI@vpn_storagedir@/\fP.
The files can be named anything, as long as they contain only printable
-ascii characers, for example letters, numbers and underscores. The file
+ascii characters, for example letters, numbers and underscores. The file
must end with \fB.config\fP. Each VPN connection requires a provisioning
file, but multiple connections can be specified in the same file.
.SH "FILE FORMAT"
diff --git a/doc/connman-vpn.conf.5.in b/doc/connman-vpn.conf.5.in
index 20d30fcc..22d32417 100644
--- a/doc/connman-vpn.conf.5.in
+++ b/doc/connman-vpn.conf.5.in
@@ -14,6 +14,18 @@ is a configuration file for ConnMan-VPN. The configuration file is
optional but it can be used to set up various aspects of ConnMan-VPN's
behavior. The location of the file may be changed through use of
the \fB\-\-config= \fRargument for \fBconnman-vpn\fP(8).
+.P
+DAC privileges (user, group and supplementary groups) of a VPN binary
+ran by \fBconnman-vpn\fP(8) can be controlled by this configuration.
+Configuration in
+.B connman-vpn.conf
+is for all VPN types and can be overridden by defining separate configs into
+.B @sysconfdir@/connman/vpn-plugin/
+using the plugin name + .conf suffix using the same syntax. For example,
+for OpenVPN the path to config is
+.B @sysconfdir@/connman/vpn-plugin/openvpn.conf
+which will override any value in the main configuration.
+
.SH "FILE FORMAT"
.P
The configuration file consists of sections (groups) of key-value pairs.
@@ -30,12 +42,32 @@ This section is the only mandatory section of the configuration file.
Set input request timeout. Default is 300 seconds. The request for inputs
like passphrase will timeout after certain amount of time. Use this setting
to increase the value in case of different user interface designs.
-.SH "EXAMPLE"
-The following example configuration sets InputRequestTimeout to 10 minutes.
+.SS [DACPrivileges]
+This section controls the DAC privileges to use for a VPN binary used by a VPN
+plugin. DAC privileges that can be set are user, group and supplementary groups.
+.TP
+.BI User= username/uid
+User on the system to use for running VPN binary. Username or uid can be used.
+.TP
+.BI Group= groupname/gid
+The main group to use for running VPN binary. Group name or gid can be used.
+.TP
+.BI SupplementaryGroups= groupnames/gids
+Comma separated list of supplementary groups to set for the VPN binary. Groups
+can be defined with their names or gid's.
+.SH "EXAMPLES"
+The following example configuration sets InputRequestTimeout to 10 minutes,
+runs VPNs as user "vpn_user" of group "vpn" with additional supplementary
+groups "inet" and "net_admin".
.PP
.nf
[General]
InputRequestTimeout = 600
+
+[DACPrivileges]
+User = vpn_user
+Group = vpn
+SupplementaryGroups = inet, net_admin
.fi
.SH "SEE ALSO"
.BR connman (8), \ connman-vpn (8)
diff --git a/doc/connman.conf.5.in b/doc/connman.conf.5.in
index e42b22f0..82cceb72 100644
--- a/doc/connman.conf.5.in
+++ b/doc/connman.conf.5.in
@@ -87,7 +87,7 @@ technology even if not setup and saved to storage.
List of technoolgies which are always connected regardless
of PreferredTechnologies setting (AutoConnect = true). The
default value is empty and this feature is disabled unless
-explicitely enabled in the config file.
+explicitly enabled in the config file.
.TP
.BI PreferredTechnologies= technology\fR[,...]
List of preferred technologies from the most preferred
@@ -167,6 +167,30 @@ transitioned to ONLINE state.
If this setting is false, the default service will remain in READY state.
Default value is true.
.TP
+.BI OnlineCheckIPv4URL= url, OnlineCheckIPv6URL= url
+Urls (IPv4 and IPv6 respectively) used during the online status check.
+Please refer to the README for more detailed information.
+Default values are http://ipv4.connman.net/online/status.html and
+http://ipv6.connman.net/online/status.html respectively.
+.TP
+.BI OnlineCheckInitialInterval= secs, OnlineCheckMaxInterval= secs
+Range of intervals between two online check requests.
+Please refer to the README for more detailed information.
+Default values are 1 and 12 respectively.
+.TP
+.BI EnableOnlineToReadyTransition=true\ \fR|\fB\ false
+WARNING: Experimental feature!!!
+In addition to EnableOnlineCheck setting, enable or disable use of HTTP GET
+to detect the loss of end-to-end connectivity.
+If this setting is false, when the default service transitions to ONLINE
+state, the HTTP GET request is no more called until next cycle, initiated
+by a transition of the default service to DISCONNECT state.
+If this setting is true, the HTTP GET request keeps beeing called to guarantee
+that end-to-end connectivity is still successful. If not, the default service
+will transition to READY state, enabling another service to become the
+default one, in replacement.
+Default value is false.
+.TP
.BI AutoConnectRoamingServices=true\ \fR|\fB\ false
Automatically connect roaming services. This is not recommended unless you know
you won't have any billing problem.
diff --git a/doc/connmanctl.1.in b/doc/connmanctl.1.in
index 47d9c303..d87472c3 100644
--- a/doc/connmanctl.1.in
+++ b/doc/connmanctl.1.in
@@ -47,7 +47,7 @@ Shows the abbreviated help menu in the terminal.
.PP
.TP
.B state
-Shows the system properties. Includes ths online state of the
+Shows the system properties. Includes the online state of the
system, offline mode, and session mode.
.PP
.TP
diff --git a/doc/counter-api.txt b/doc/counter-api.txt
index 32411d57..c0d9b769 100755
--- a/doc/counter-api.txt
+++ b/doc/counter-api.txt
@@ -47,12 +47,12 @@ Methods void Release()
RX.Errors
- Total number of erronous packets
+ Total number of erroneous packets
received.
TX.Errors
- Total number of erronous packets
+ Total number of erroneous packets
sent.
RX.Dropped
diff --git a/doc/manager-api.txt b/doc/manager-api.txt
index bfb07bd3..6eaa0a38 100755
--- a/doc/manager-api.txt
+++ b/doc/manager-api.txt
@@ -149,7 +149,7 @@ Methods dict GetProperties()
creation of a tun/tap interface, and IP
configuration, NAT and IP forwarding on that
interface.
- An object path, a dictionnary and a file descriptor
+ An object path, a dictionary and a file descriptor
with IP settings are returned.
Possible Errors: [service].Error.InvalidArguments
diff --git a/doc/overview-api.txt b/doc/overview-api.txt
index fd51d706..d7f9d897 100755
--- a/doc/overview-api.txt
+++ b/doc/overview-api.txt
@@ -214,7 +214,7 @@ with spaces.
In addition to WiFi naming, WiFi networks are subject to a grouping policy
performed around SSID and security type. This means that one service will be
-seen for N WiFi networks providing the same SSID and the same security metod.
+seen for N WiFi networks providing the same SSID and the same security method.
For instance, if 5 APs are servicing an SSID called "TEST" with WPA2
authentication and 3 APs are servicing the same SSID with open authentication
method, the user will see only two services listed with the name "TEST"
diff --git a/doc/peer-api.txt b/doc/peer-api.txt
index cc094ff2..5256c5ee 100755
--- a/doc/peer-api.txt
+++ b/doc/peer-api.txt
@@ -98,5 +98,5 @@ Properties string State [readonly] [experimental]
array{byte} WiFiDisplayIEs [readonly]
- The TLV formated byte array representing the
- WiFi Display Informations Elements.
+ The TLV formatted byte array representing the
+ WiFi Display Information Elements.
diff --git a/doc/plugin-api.txt b/doc/plugin-api.txt
index 36391e96..8a6e0e84 100755
--- a/doc/plugin-api.txt
+++ b/doc/plugin-api.txt
@@ -157,7 +157,7 @@ associate the new Network with the existing Device entity (the local Bluetooth
Adapter).
Then in the vtable's connect method all the needed pieces to perform a
-connection shall be perfomed.
+connection shall be performed.
To learn how to use the connman_network_*() functions such as
connman_network_set_index() and connman_network_set_connected() see
diff --git a/doc/session-api.txt b/doc/session-api.txt
index 46ac5f3d..8bfcf6b0 100755
--- a/doc/session-api.txt
+++ b/doc/session-api.txt
@@ -140,7 +140,7 @@ Settings string State [readonly]
The services are sorted in the order of the bearer
entries in this list.
- Also "*" matches any bearer. This is usefull to prefer
+ Also "*" matches any bearer. This is useful to prefer
certain bearers such as 'wifi' with a fallback to any
other available bearer.
diff --git a/doc/session-overview.txt b/doc/session-overview.txt
index 976c3518..70dd9ee2 100755
--- a/doc/session-overview.txt
+++ b/doc/session-overview.txt
@@ -26,7 +26,7 @@ behind this is that a session doesn't request a connection for itself
instead waits until another session actively requires to go online.
This is comparable to piggy-backing.
-Connnect()
+Connect()
+------+
| v
+------------+
diff --git a/doc/technology-api.txt b/doc/technology-api.txt
index f22e9b29..cdf30396 100755
--- a/doc/technology-api.txt
+++ b/doc/technology-api.txt
@@ -100,3 +100,10 @@ Properties boolean Powered [readwrite]
This property is only valid for the WiFi technology,
and is then mapped to the WPA pre-shared key clients
will have to use in order to establish a connection.
+
+ int TetheringFreq [readwrite]
+
+ The tethering access point frequency
+
+ This property is only valid for the WiFi technology and it's
+ optional. Default frequency is 2412 Mhz.
diff --git a/doc/vpn-agent-api.txt b/doc/vpn-agent-api.txt
index 72bee9db..ecc8faaa 100644
--- a/doc/vpn-agent-api.txt
+++ b/doc/vpn-agent-api.txt
@@ -78,24 +78,90 @@ Fields string Username
string OpenConnect.ClientCert
Informational field containing a pkcs11 URL or a path
- name for the client certificate.
+ name for the client certificate.
string OpenConnect.Cookie
Return the OpenConnect cookie value that is used for
authenticating the VPN session.
+ string OpenConnect.Group
+
+ Choose authentication login group.
+
+ string OpenConnect.PKCSClientCert
+
+ Informational field containing a PKCS#1/PKCS#8/PKCS#12
+ URL or a path name for the PKCS#1/PKCS#8/PKCS#12 client
+ certificate.
+
+ string OpenConnect.PKCSPassword
+
+ Password for decrypting PKCS#8/PKCS#12 client
+ certificate.
+
+ string OpenConnect.SecondPassword
+
+ Second factor password for authentication.
+
string OpenConnect.ServerCert
Return the OpenConnect server hash used to identify
the final server after possible web authentication
logins, selections and redirections.
+ boolean OpenConnect.UseSecondPassword
+
+ Indicates that second factor password is used
+ for selected authentication group.
+
string OpenConnect.VPNHost
Return the final VPN server to use after possible
web authentication logins, selections and redirections.
+ string OpenVPN.PrivateKeyPassword
+
+ Return the private key password used to decrypt the
+ encrypted OpenVPN private key file.
+
+ boolean AllowStoreCredentials
+
+ Indicates to the receiving UI whether the values
+ entered by the user can be stored for future use.
+ "Requirement" should be set to "control". A "Value"
+ of true indicates that the option to store the
+ credentials can be offered to the user, false
+ indicates that no such option should be presented.
+
+ boolean AllowRetrieveCredentials
+
+ Tells the receiving UI whether to attempt to retrieve
+ previously stored values. "Requirement" should be set
+ to "control". "Value" should be set to true if
+ previously stored values can be used, false otherwise.
+
+ boolean KeepCredentials
+
+ Indicates to the receiving UI whether to keep ("Value"
+ is set "true") or clear ("Value" is set "false") the
+ credentials or not. "Requirement" should be set to
+ "control". By default this is not required to be set
+ and is handled only when explicitly defined as "true".
+ This is useful in case of having both the
+ AllowStoreCredentials and the AllowRetrieveCredentials
+ set as "false", but clearing credentials is not
+ required. In such case the value can be explicitly set
+ to "true". An example case is when the password for
+ encrypted Private Key is requested.
+
+ string VpnAgent.AuthFailure
+
+ Informational field that can be used to indicate VPN
+ agent that previous authentication has failed and new
+ credentials should be requested from user. Additional
+ information about the failure can be added as "Value".
+
Arguments string Type
Contains the type of a field. For example "password",
@@ -104,8 +170,8 @@ Arguments string Type
string Requirement
Contains the requirement option. Valid values are
- "mandatory", "optional", "alternate" or
- "informational".
+ "mandatory", "optional", "alternate", "informational"
+ and "control".
The "alternate" value specifies that this field can be
returned as an alternative to another one.
@@ -117,6 +183,11 @@ Arguments string Type
is here only to provide an information so a value is
attached to it.
+ A "control" argument is used to specify behaviour. The
+ effect will depend on the field name and value, but
+ control fields will not usually be presented directly
+ to the user, and are not expected to be returned.
+
array{string} Alternates
Contains the list of alternate field names this
@@ -156,3 +227,19 @@ Examples Requesting a username and password for L2TP network
"Requirement" : "informational"
} }
==> { "OpenConnect.Cookie" : "0123456@adfsf@asasdf" }
+
+ Requesting a username and password but without allowing
+ the values entered by the user to be stored.
+
+ RequestInput("/vpn3",
+ { "Username" : { "Type" : "string",
+ "Requirement" : "mandatory"
+ } }
+ { "Password" : { "Type" : "password",
+ "Requirement" : "mandatory"
+ } }
+ { "AllowStoreCredentials" : { "Type" : "boolean",
+ "Requirement" : "control",
+ "Value" : false
+ } }
+ ==> { "Username" : "foo", "Password" : "secret123" }
diff --git a/doc/vpn-config-format.txt b/doc/vpn-config-format.txt
index cb0f16a8..f2adf299 100644
--- a/doc/vpn-config-format.txt
+++ b/doc/vpn-config-format.txt
@@ -32,12 +32,13 @@ Each provisioned provider must start with the [provider_*] tag.
Replace * with an identifier unique to the config file.
Allowed fields:
-- Type: Provider type. Value of OpenConnect, OpenVPN, VPNC, L2TP or PPTP
+- Type: Provider type. Value of OpenConnect, OpenVPN, VPNC, L2TP, PPTP or
+ WireGuard
VPN related parameters (M = mandatory, O = optional):
- Name: A user defined name for the VPN (M)
- Host: VPN server IP address (M)
-- Domain: Domain name for the VPN service (M)
+- Domain: Domain name for the VPN service (O)
- Networks: The networks behind the VPN link can be defined here. This can
be missing if all traffic should go via VPN tunnel. If there are more
than one network, then separate them by comma. Format of the entry
@@ -54,8 +55,9 @@ OpenConnect VPN supports following options (see openconnect(8) for details):
OpenConnect.CACert --cafile File containing other Certificate
Authorities in addition to the ones
in the system trust database (O)
- OpenConnect.ClientCert --certificate Client certificate file, if needed
- by web authentication (O)
+ OpenConnect.ClientCert --certificate Client certificate file, needed
+ by web authentication when AuthType
+ is set as "publickey" (O)
VPN.MTU --mtu Request MTU from server as the MTU
of the tunnel (O)
OpenConnect.Cookie --cookie-on-stdin Cookie received as a result of the
@@ -68,8 +70,73 @@ OpenConnect VPN supports following options (see openconnect(8) for details):
Only usable for extremely simple VPN
configurations and should normally
be set only via the VPN Agent API.
-If OpenConnect.Cookie or OpenConnect.ServerCert are missing, the VPN Agent will
-be contacted to supply the information.
+ OpenConnect.AllowSelfSignedCert none Additional option to define if self
+ signed server certificates are
+ allowed. Boolean string and defaults
+ to false, value "true" enables the
+ option. Affects to the OpenConnect
+ internal function only: --servercert
+ is not added to startup parameters
+ and receiving self signed cert from
+ server terminates the connection if
+ set as false (or omitted) (O)
+ OpenConnect.AuthType Type of authentication used with
+ OpenConnect. Applicable values are
+ "cookie", "cookie_with_userpass",
+ "userpass", "publickey" and
+ "pkcs". Value "cookie" is basic
+ cookie based authentication. Value
+ "cookie_with_userpass" means that
+ credentials are used to retrieve the
+ connection cookie, which hides the
+ username from commandline. With
+ value "userpass" username and
+ password are used. Value "publickey"
+ requires CACert and UserPrivateKey
+ to be set. Value "pkcs" uses the
+ PKCSClientCert and requests password
+ input. Defaults to "cookie" (O)
+ cookie --cookie-on-stdin Default cookie based authentication
+ cookie_with_userpass Two phased connection, first
+ authentication: --cookieonly authenticate with credentials then
+ --passwd-on-stdin use cookie for connection. Username
+ --user is hidden from commandline during
+ connection: --cookie-on-stdin connection.
+ userpass --passwd-on-stdin Credential based authentication,
+ --user username is visible on commandline.
+ publickey --clientcert Non-encrypted client certificate and
+ --sslkey private key file is used for auth.
+ pkcs --cliencert Authenticate with PKCS#1/PKCS#8/
+ PKCS#12 client certificate.
+ OpenConnect.DisableIPv6 --disable-ipv6 Do not ask for IPv6 connectivity.
+ Boolean string and defaults to
+ false, value "true" enables the
+ option (O)
+ OpenConnect.NoDTLS --no-dtls Disable DTLS and ESP (O)
+ OpenConnect.NoHTTPKeepalive --no-http-keepalive Disable HTTP connection
+ re-use to workaround issues with
+ some servers. Boolean string and
+ defaults to false, value "true"
+ enables the option (O)
+ OpenConnect.PKCSClientCert --certificate Certificate and private key in
+ a PKCS#1/PKCS#8/PKCS#12 structure.
+ Needed when AuthType is "pkcs" (O)
+ OpenConnect.Usergroup --usergroup Set login usergroup on remote server
+ (O)
+ OpenConnect.UserPrivateKey --sslkey SSL private key file needed by web
+ authentication when AuthType is set
+ as "publickey" (O)
+
+The VPN agent will be contacted to supply the information based on the
+authentication type as follows:
+ Authentication type Information requested Saved with name
+ cookie OpenConnect.Cookie OpenConnect.Cookie
+ cookie_with_userpass Username OpenConnect.Username
+ Password OpenConnect.Password
+ userpass Username OpenConnect.Username
+ Password OpenConnect.Password
+ publickey <none>
+ pkcs OpenConnect.PKCSPassword OpenConnect.PKCSPassword
OpenVPN VPN supports following options (see openvpn(8) for details):
Option name OpenVPN option Description
@@ -92,6 +159,11 @@ OpenVPN VPN supports following options (see openvpn(8) for details):
OpenVPN 2.3+.
OpenVPN.TLSAuth sub-option of --tls-remote (O)
OpenVPN.TLSAuthDir sub-option of --tls-remote (O)
+ OpenVPN.TLSCipher --tls-cipher Add an additional layer of HMAC
+ authentication on top of the TLS
+ control channel to mitigate DoS attacks
+ and attacks on the TLS stack. Static
+ key file given as parameter (0)
OpenVPN.Cipher --cipher Encrypt packets with cipher algorithm
given as parameter (O)
OpenVPN.Auth --auth Authenticate packets with HMAC using
@@ -182,7 +254,6 @@ L2TP VPN supports following options (see xl2tpd.conf(5) and pppd(8) for details)
PPPD.ReqMPPEStateful mppe-stateful Allow MPPE to use stateful mode (O)
PPPD.NoVJ novj No Van Jacobson compression (O)
-
PPTP VPN supports following options (see pptp(8) and pppd(8) for details)
Option name pptp config value Description
PPTP.User - PPTP user name, asked from the user
@@ -207,35 +278,19 @@ PPTP VPN supports following options (see pptp(8) and pppd(8) for details)
PPPD.RequirMPPEStateful mppe-stateful Allow MPPE to use stateful mode (O)
PPPD.NoVJ novj No Van Jacobson compression (O)
-IPsec VPN supports following options (see swanctl.conf(5) for details):
- Option name IPSec config value Description
- IPsec.Version Version IKE major version to use for connection (M)
- IPsec.LeftAddrs local_addrs Local address(es) to use for IKE communication (M)
- IPsec.RightAddrs remote_addrs Remote address(es) to use for IKE communication (M)
-
-
- IPsec.LocalAuth local.auth Authentication to perform locally (M)
- IPsec.LocalCerts local.certs Certificate candidate to use for authentication (O)
- IPsec.LocalID local.id IKE identity to use for authentication round (O)
- IPsec.LocalXauthID local.xauth_id Client XAuth username used in the XAuth exchange (O)
- IPsec.LocalXauthAuth local-xauth.auth Xauth round authentication to perform locally (O)
- IPsec.LocalXauthXauthID local-xauth.xauth_id Xauth round client XAuth username used in the XAuth exchange (O)
-
- IPsec.RemoteAuth remote.auth Authentication to expect from remote (M)
- IPsec.RemoteCerts remote.certs Certificate candidate to use for authentication (O)
- IPsec.RemoteID remote.id IKE identity to use for authentication round (O)
- IPsec.RemoteXauthAuth remote-xauth.auth Xauth round authentication to expect from remote (O)
- IPsec.ChildrenLocalTs children.local_ts local selectors to include in CHILD_SA (O)
- IPsec.ChildrenRemoteTs children.remote_ts Remote selectors to include in CHILD_SA (O)
+WireGuard VPN supports following options
+ Option name Description
+ WireGuard.Address Internal IP address (local/netmask/peer)
+ WireGuard.ListPort Local listen port (optional)
+ WireGuard.DNS List of nameservers separated
+ by comma (optional)
+ WireGuard.PrivateKey Private key of interface
+ WireGuard.PublicKey Public key of peer
+ WireGuard.PresharedKey Preshared key of peer (optional)
+ WireGuard.AllowedIPs See Cryptokey Routing
+ WireGuard.EndpointPort Endpoint listen port (optional)
+ WireGuard.PersistentKeepalive Keep alive in seconds (optional)
- IPsec.IKEData secret.data IKE PSK raw shared key data
- IPsec.IKEOwners secret.Owners list of shared key owner identities
- IPsec.XauthData secret.data XAUTH raw shared key data
- IPsec.XauthOwners secret.Owners list of shared key owner identities
-
- IPsec.CertType cert.type certificate type, X509|X509_AC|X509_CRL
- IPsec.CertFlag cert.flag X.509 certificate flag, NONE|CA|AA|OCSP
- IPsec.CertData cert.data PEM or DER encoded certificate data
Example
=======
@@ -259,6 +314,7 @@ L2TP.User = username
[provider_openconnect]
Type = OpenConnect
+AuthType = pkcs
Name = Connection to corporate network using Cisco VPN
Host = 7.6.5.4
Domain = corporate.com
@@ -274,3 +330,16 @@ Domain = my.home.network
OpenVPN.CACert = /etc/certs/cacert.pem
OpenVPN.Cert = /etc/certs/cert.pem
OpenVPN.Key = /etc/certs/cert.key
+
+[provider_wireguard]
+Type = WireGuard
+Name = Wireguard VPN Tunnel
+Host = 3.2.5.6
+Domain = my.home.network
+WireGuard.Address = 10.2.0.2/24
+WireGuard.ListenPort = 47824
+WireGuard.DNS = 10.2.0.1
+WireGuard.PrivateKey = qKIj010hDdWSjQQyVCnEgthLXusBgm3I6HWrJUaJymc=
+WireGuard.PublicKey = zzqUfWGIil6QxrAGz77HE5BGUEdD2PgHYnCg3CDKagE=
+WireGuard.AllowedIPs = 0.0.0.0/0, ::/0
+WireGuard.EndpointPort = 51820
diff --git a/doc/vpn-connection-api.txt b/doc/vpn-connection-api.txt
index 1fd3be26..2d3e0078 100755
--- a/doc/vpn-connection-api.txt
+++ b/doc/vpn-connection-api.txt
@@ -14,13 +14,48 @@ Methods dict GetProperties() [experimental]
void SetProperty(string name, variant value) [experimental]
- Changes the value of the specified property. Only
- properties that are listed as read-write are
- changeable. On success a PropertyChanged signal
- will be emitted.
+ Changes the value of the specified property or the
+ properties defined as a dict passed as variant, where
+ the format is equal to the dict returned by
+ GetProperties(). Only properties that are listed as
+ read-write are changeable. Property name "Properties"
+ indicates a dict of properties. On success a
+ PropertyChanged signal will be emitted for the
+ specified property or for all changed properties
+ individually. If there is no change in property value
+ no PropertyChanged signal is sent. Configuration is
+ written to disk when one or more values are changed.
+ In case a dict of properties are given, configuration
+ write is done after all properties are processed.
+ Specifics in dict use in contrast to setting a single
+ property:
+ - Dict can contain values set as empty strings
+ or arrays. This causes the values to be
+ cleared as if using ClearProperty().
+ - If there are errors with the properties,
+ InvalidProperty or PermissionDenied error is
+ returned. InvalidProperty is sent when there
+ is at least one invalid property, in this
+ case there can be also properties that
+ cannot be changed (immutable properties).
+ If there are only immutable properties
+ PermissionDenied error is returned.
+ - The properties that are invalid or immutable
+ are reported back at the end of the error
+ message as a comma separated property name
+ list.
+ - One invalid/immutable property does not
+ cause the rest of the properties to be
+ ignored. If there are valid and invalid
+ properties, the valid properties emit
+ PropertyChanged signal and invalid are
+ reported back with an InvalidProperty
+ message.
Possible Errors: [connection].Error.InvalidArguments
[connection].Error.InvalidProperty
+ [connection].Error.PermissionDenied
+ [connection].Error.NotSupported
void ClearProperty(string name) [experimental]
@@ -28,6 +63,7 @@ Methods dict GetProperties() [experimental]
Possible Errors: [connection].Error.InvalidArguments
[connection].Error.InvalidProperty
+ [connection].Error.PermissionDenied
void Connect() [experimental]
@@ -94,7 +130,14 @@ Properties string State [readonly]
configured externally via a configuration file.
The only valid operation are Connect(), Disconnect()
- and GetProperties()
+ and GetProperties()
+
+ boolean SplitRouting
+
+ This value reflects the split routing setting on
+ connmand side. By default, this value is omitted and
+ defaults to false. The value needs to be explicitly
+ set to true for VPN to be split routed.
int Index [readonly]
@@ -149,7 +192,9 @@ Properties string State [readonly]
int ProtocolFamily
Protocol family of the route. Set to 4
- if IPv4 and 6 if IPv6 route.
+ if IPv4 and 6 if IPv6 route. Set to 0
+ (PF_UNSPEC) or omit, to have it assigned
+ automatically.
string Network
@@ -190,6 +235,19 @@ Properties string State [readonly]
The VPN server activated route. These routes
are pushed to connman by VPN server.
+ string AuthErrorLimit
+
+ This value defines the amount of authentication errors
+ that are allowed before informing VPN agent to clear
+ the credentials in case there was a previous successful
+ VPN connection made within one hour. This is to be used
+ with providers that allow only one login from one
+ account at a time to prevent clearing of credentials
+ when networks are rapidly changed. This value is used
+ as an integer and if unset this default to "1" for all
+ except OpenVPN that uses value "10". Setting value "0"
+ disables the feature for the provider.
+
There can be other properties also but as the VPN
technologies are so different, they have different
kind of options that they need, so not all options
diff --git a/doc/vpn-overview.txt b/doc/vpn-overview.txt
index 42b6e94a..d2d14a0c 100755
--- a/doc/vpn-overview.txt
+++ b/doc/vpn-overview.txt
@@ -54,7 +54,46 @@ is established (meaning VPN client has managed to create a connection
to VPN server), then State property is set to "ready" and PropertyChanged
signal is sent. If the connection cannot be established, then
State property is set to "failure".
-After successfull connection, the relevant connection properties are sent
+After successful connection, the relevant connection properties are sent
by PropertyChanged signal; like IPv[4|6] information, the index of the
VPN tunneling interface (if there is any), nameserver information,
server specified routes etc.
+
+VPN agent interface
+===================
+
+VPN agent interface described in vpn-agent-api.txt is used for
+interaction between the connectivity UI and ConnMan. A VPN agent
+registered via Management interface gets requests from the VPN plugins
+to input credentials or other authentication information for the VPN
+connection and offers information about the VPN to be connected.
+
+In addition to basic credentials, there are additional types of optional
+and control parameters. The user can dictate whether to store the
+credentials with the optional SaveCredentials value. The VPN plugins can
+also define with the control values AllowStoreCredentials,
+AllowRetrieveCredentials and KeepCredentials how the VPN agent must
+handle the credentials. AllowStoreCredentials as false indicates that
+client cannot use SaveCredentials option. AllowRetrieveCredentials set
+as false, without AllowStoreCredentials set as false should not have
+that same effect and in that case user is allowed to save credentials.
+
+These three control values become useful when a VPN has two or more
+sets of authentication credentials, second of which can be requested
+when the VPN detects a need for them. The first, main credentials,
+would be requested without these control values, so user is able to
+select whether the credentials are saved or not with SaveCredentials
+value. After the VPN initializes the connection and, e.g., needs to
+decrypt a private key file, a new request is sent to VPN agent. In this
+new request both AllowStoreCredentials and AllowRetrieveCredentials are
+set as false indicating that in no circumstances existing credentials
+stored are to be used and neither there should be option visible for
+the user to select saving of the credentials. Depending on VPN agent
+implementation these values can be interpreted as clearing of all the
+existing credentials related to the VPN connection from the credential
+storage. By including the KeepCredentials as true value the VPN can,
+however, tell the VPN agent not to clear the credentials for this VPN
+connection. The KeepCredentials is used to inform the VPN agent that
+these new, second/third/etc. credentials are only to be queried from
+the user and forgotten after that, when used in conjunction with the
+AllowStoreCredentials and AllowRetrieveCredentials set as false.
diff --git a/doc/wifi-p2p-overview.txt b/doc/wifi-p2p-overview.txt
index 73b677c5..3dbee7e4 100644
--- a/doc/wifi-p2p-overview.txt
+++ b/doc/wifi-p2p-overview.txt
@@ -37,7 +37,7 @@ The UI willing to access to WiFi P2P technology should proceed this way:
Internals
=========
-Through such API, everything is made to hide irrelevant informations for the
+Through such API, everything is made to hide irrelevant information for the
applications, which are:
- Everything related to the P2P group and the Group Owner (GO)
diff --git a/gdbus/watch.c b/gdbus/watch.c
index 1ca3c4bd..8fa76cda 100755
--- a/gdbus/watch.c
+++ b/gdbus/watch.c
@@ -136,84 +136,55 @@ static struct filter_data *filter_data_find(DBusConnection *connection)
return NULL;
}
-#if defined TIZEN_EXT
-#define SENDER_PREFIX ",sender='%s'"
-#define PATH_PREFIX ",path='%s'"
-#define IFACE_PREFIX ",interface='%s'"
-#define MEMBER_PREFIX ",member='%s'"
-#define ARG0_PREFIX ",arg0='%s'"
-
-static gboolean check_rule_length(int remains, const char *prefix, const char *data)
-{
- if (!prefix || !data)
- return FALSE;
-
- return strlen(prefix) - 2 + strlen(data) < remains;
-}
-
-static void format_rule(struct filter_data *data, char *rule, size_t size)
+static char *format_rule(struct filter_data *data)
{
+ char *rule, *tmp;
const char *sender;
- int offset;
- offset = snprintf(rule, size, "type='signal'");
+ rule = g_strdup("type='signal'");
sender = data->name ? : data->owner;
- if (sender &&
- check_rule_length(size - offset, SENDER_PREFIX, sender))
- offset += snprintf(rule + offset, size - offset,
- SENDER_PREFIX, sender);
- if (data->path &&
- check_rule_length(size - offset, PATH_PREFIX, data->path))
- offset += snprintf(rule + offset, size - offset,
- PATH_PREFIX, data->path);
- if (data->interface &&
- check_rule_length(size - offset, IFACE_PREFIX, data->interface))
- offset += snprintf(rule + offset, size - offset,
- IFACE_PREFIX, data->interface);
- if (data->member &&
- check_rule_length(size - offset, MEMBER_PREFIX, data->member))
- offset += snprintf(rule + offset, size - offset,
- MEMBER_PREFIX, data->member);
- if (data->argument &&
- check_rule_length(size - offset, ARG0_PREFIX, data->argument))
- snprintf(rule + offset, size - offset,
- ARG0_PREFIX, data->argument);
-}
-#else
-static void format_rule(struct filter_data *data, char *rule, size_t size)
-{
- const char *sender;
- int offset;
+ if (sender) {
+ tmp = rule;
+ rule = g_strdup_printf("%s,sender='%s'", rule, sender);
+ g_free(tmp);
+ }
- offset = snprintf(rule, size, "type='signal'");
- sender = data->name ? : data->owner;
+ if (data->path) {
+ tmp = rule;
+ rule = g_strdup_printf("%s,path='%s'", rule, data->path);
+ g_free(tmp);
+ }
- if (sender)
- offset += snprintf(rule + offset, size - offset,
- ",sender='%s'", sender);
- if (data->path)
- offset += snprintf(rule + offset, size - offset,
- ",path='%s'", data->path);
- if (data->interface)
- offset += snprintf(rule + offset, size - offset,
- ",interface='%s'", data->interface);
- if (data->member)
- offset += snprintf(rule + offset, size - offset,
- ",member='%s'", data->member);
- if (data->argument)
- snprintf(rule + offset, size - offset,
- ",arg0='%s'", data->argument);
+ if (data->interface){
+ tmp = rule;
+ rule = g_strdup_printf("%s,interface='%s'", rule,
+ data->interface);
+ g_free(tmp);
+ }
+
+ if (data->member) {
+ tmp = rule;
+ rule = g_strdup_printf("%s,member='%s'", rule, data->member);
+ g_free(tmp);
+ }
+
+ if (data->argument) {
+ tmp = rule;
+ rule = g_strdup_printf("%s,arg0='%s'", rule, data->argument);
+ g_free(tmp);
+ }
+
+ return rule;
}
-#endif
static gboolean add_match(struct filter_data *data,
DBusHandleMessageFunction filter)
{
DBusError err;
- char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
+ char *rule;
- format_rule(data, rule, sizeof(rule));
+ rule = format_rule(data);
dbus_error_init(&err);
dbus_bus_add_match(data->connection, rule, &err);
@@ -221,21 +192,23 @@ static gboolean add_match(struct filter_data *data,
error("Adding match rule \"%s\" failed: %s", rule,
err.message);
dbus_error_free(&err);
+ g_free(rule);
return FALSE;
}
data->handle_func = filter;
data->registered = TRUE;
+ g_free(rule);
return TRUE;
}
static gboolean remove_match(struct filter_data *data)
{
DBusError err;
- char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
+ char *rule;
- format_rule(data, rule, sizeof(rule));
+ rule = format_rule(data);
dbus_error_init(&err);
@@ -244,9 +217,11 @@ static gboolean remove_match(struct filter_data *data)
error("Removing owner match rule for %s failed: %s",
rule, err.message);
dbus_error_free(&err);
+ g_free(rule);
return FALSE;
}
+ g_free(rule);
return TRUE;
}
diff --git a/gdhcp/client.c b/gdhcp/client.c
index 2bdc6163..905cecf2 100755
--- a/gdhcp/client.c
+++ b/gdhcp/client.c
@@ -52,10 +52,11 @@
#if defined TIZEN_EXT
#define REQUEST_TIMEOUT 1
+#define REQUEST_RETRIES 14
#else
#define REQUEST_TIMEOUT 5
-#endif
#define REQUEST_RETRIES 3
+#endif
#if defined TIZEN_EXT
#define DISCOVER_TIMEOUT_WIFI 1
@@ -562,7 +563,8 @@ static int send_request(GDHCPClient *dhcp_client)
if (dhcp_client->state == RENEWING)
return dhcp_send_kernel_packet(&packet,
dhcp_client->requested_ip, CLIENT_PORT,
- dhcp_client->server_ip, SERVER_PORT);
+ dhcp_client->server_ip, SERVER_PORT,
+ dhcp_client->interface);
return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT,
INADDR_BROADCAST, SERVER_PORT,
@@ -586,7 +588,8 @@ static int send_release(GDHCPClient *dhcp_client,
dhcp_add_option_uint32(&packet, DHCP_SERVER_ID, server);
return dhcp_send_kernel_packet(&packet, ciaddr, CLIENT_PORT,
- server, SERVER_PORT);
+ server, SERVER_PORT,
+ dhcp_client->interface);
}
static gboolean ipv4ll_probe_timeout(gpointer dhcp_data);
@@ -1670,12 +1673,12 @@ static void start_request(GDHCPClient *dhcp_client)
NULL);
}
-static uint32_t get_lease(struct dhcp_packet *packet)
+static uint32_t get_lease(struct dhcp_packet *packet, uint16_t packet_len)
{
uint8_t *option;
uint32_t lease_seconds;
- option = dhcp_get_option(packet, DHCP_LEASE_TIME);
+ option = dhcp_get_option(packet, packet_len, DHCP_LEASE_TIME);
if (!option)
return 3600;
@@ -2267,7 +2270,8 @@ static void get_dhcpv6_request(GDHCPClient *dhcp_client,
}
}
-static void get_request(GDHCPClient *dhcp_client, struct dhcp_packet *packet)
+static void get_request(GDHCPClient *dhcp_client, struct dhcp_packet *packet,
+ uint16_t packet_len)
{
GDHCPOptionType type;
GList *list, *value_list;
@@ -2278,7 +2282,7 @@ static void get_request(GDHCPClient *dhcp_client, struct dhcp_packet *packet)
for (list = dhcp_client->request_list; list; list = list->next) {
code = (uint8_t) GPOINTER_TO_INT(list->data);
- option = dhcp_get_option(packet, code);
+ option = dhcp_get_option(packet, packet_len, code);
if (!option) {
g_hash_table_remove(dhcp_client->code_value_hash,
GINT_TO_POINTER((int) code));
@@ -2310,7 +2314,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
{
GDHCPClient *dhcp_client = user_data;
struct sockaddr_in dst_addr = { 0 };
- struct dhcp_packet packet;
+ struct dhcp_packet packet = { 0 };
struct dhcpv6_packet *packet6 = NULL;
uint8_t *message_type = NULL, *client_id = NULL, *option,
*server_id = NULL;
@@ -2346,6 +2350,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
re = dhcp_recv_l2_packet(&packet,
dhcp_client->listener_sockfd,
&dst_addr);
+ pkt_len = (uint16_t)(unsigned int)re;
xid = packet.xid;
} else if (dhcp_client->listen_mode == L3) {
if (dhcp_client->type == G_DHCP_IPV6) {
@@ -2410,7 +2415,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
dhcp_client->status_code = status;
}
} else {
- message_type = dhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
+ message_type = dhcp_get_option(&packet, pkt_len, DHCP_MESSAGE_TYPE);
if (!message_type)
return TRUE;
}
@@ -2427,7 +2432,10 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
dhcp_client->timeout = 0;
dhcp_client->retry_times = 0;
- option = dhcp_get_option(&packet, DHCP_SERVER_ID);
+ option = dhcp_get_option(&packet, pkt_len, DHCP_SERVER_ID);
+ if (!option)
+ return TRUE;
+
dhcp_client->server_ip = get_be32(option);
dhcp_client->requested_ip = ntohl(packet.yiaddr);
@@ -2477,13 +2485,13 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
remove_timeouts(dhcp_client);
- dhcp_client->lease_seconds = get_lease(&packet);
+ dhcp_client->lease_seconds = get_lease(&packet, pkt_len);
#if defined TIZEN_EXT
dhcp_client->dhcp_lease_seconds = dhcp_client->lease_seconds;
#endif
- get_request(dhcp_client, &packet);
+ get_request(dhcp_client, &packet, pkt_len);
switch_listening_mode(dhcp_client, L_NONE);
@@ -2491,8 +2499,10 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
dhcp_client->assigned_ip = get_ip(packet.yiaddr);
if (dhcp_client->state == REBOOTING) {
- option = dhcp_get_option(&packet,
+ option = dhcp_get_option(&packet, pkt_len,
DHCP_SERVER_ID);
+ if (!option)
+ return TRUE;
dhcp_client->server_ip = get_be32(option);
}
@@ -3126,6 +3136,13 @@ int g_dhcp_client_get_index(GDHCPClient *dhcp_client)
return dhcp_client->ifindex;
}
+#if defined TIZEN_EXT
+char *g_dhcp_client_get_interface(GDHCPClient *dhcp_client)
+{
+ return dhcp_client->interface;
+}
+#endif
+
char *g_dhcp_client_get_server_address(GDHCPClient *dhcp_client)
{
if (!dhcp_client)
diff --git a/gdhcp/common.c b/gdhcp/common.c
index 8f7a65cc..c8916aa8 100755
--- a/gdhcp/common.c
+++ b/gdhcp/common.c
@@ -73,18 +73,21 @@ GDHCPOptionType dhcp_get_code_type(uint8_t code)
return OPTION_UNKNOWN;
}
-uint8_t *dhcp_get_option(struct dhcp_packet *packet, int code)
+uint8_t *dhcp_get_option(struct dhcp_packet *packet, uint16_t packet_len, int code)
{
int len, rem;
- uint8_t *optionptr;
+ uint8_t *optionptr, *options_end;
+ size_t options_len;
uint8_t overload = 0;
/* option bytes: [code][len][data1][data2]..[dataLEN] */
optionptr = packet->options;
rem = sizeof(packet->options);
+ options_len = packet_len - (sizeof(*packet) - sizeof(packet->options));
+ options_end = optionptr + options_len - 1;
while (1) {
- if (rem <= 0)
+ if ((rem <= 0) && (optionptr + OPT_CODE > options_end))
/* Bad packet, malformed option field */
return NULL;
@@ -115,14 +118,25 @@ uint8_t *dhcp_get_option(struct dhcp_packet *packet, int code)
break;
}
+ if (optionptr + OPT_LEN > options_end) {
+ /* bad packet, would read length field from OOB */
+ return NULL;
+ }
+
len = 2 + optionptr[OPT_LEN];
rem -= len;
if (rem < 0)
continue; /* complain and return NULL */
- if (optionptr[OPT_CODE] == code)
- return optionptr + OPT_DATA;
+ if (optionptr[OPT_CODE] == code) {
+ if (optionptr + len > options_end) {
+ /* bad packet, option length points OOB */
+ return NULL;
+ } else {
+ return optionptr + OPT_DATA;
+ }
+ }
if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD)
overload |= optionptr[OPT_DATA];
@@ -595,7 +609,8 @@ int dhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
int dhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
uint32_t source_ip, int source_port,
- uint32_t dest_ip, int dest_port)
+ uint32_t dest_ip, int dest_port,
+ const char *interface)
{
struct sockaddr_in client;
int fd, n, opt = 1;
@@ -609,6 +624,13 @@ int dhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
if (fd < 0)
return -errno;
+ if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
+ interface, strlen(interface) + 1) < 0) {
+ int err = errno;
+ close(fd);
+ return -err;
+ }
+
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
int err = errno;
close(fd);
diff --git a/gdhcp/common.h b/gdhcp/common.h
index 6899499e..8f63fd75 100755
--- a/gdhcp/common.h
+++ b/gdhcp/common.h
@@ -179,7 +179,7 @@ struct in6_pktinfo {
};
#endif
-uint8_t *dhcp_get_option(struct dhcp_packet *packet, int code);
+uint8_t *dhcp_get_option(struct dhcp_packet *packet, uint16_t packet_len, int code);
uint8_t *dhcpv6_get_option(struct dhcpv6_packet *packet, uint16_t pkt_len,
int code, uint16_t *option_len, int *option_count);
uint8_t *dhcpv6_get_sub_option(unsigned char *option, uint16_t max_len,
@@ -210,7 +210,8 @@ int dhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
int dhcpv6_send_packet(int index, struct dhcpv6_packet *dhcp_pkt, int len);
int dhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
uint32_t source_ip, int source_port,
- uint32_t dest_ip, int dest_port);
+ uint32_t dest_ip, int dest_port,
+ const char *interface);
int dhcp_l3_socket(int port, const char *interface, int family);
int dhcp_recv_l3_packet(struct dhcp_packet *packet, int fd);
int dhcpv6_recv_l3_packet(struct dhcpv6_packet **packet, unsigned char *buf,
diff --git a/gdhcp/gdhcp.h b/gdhcp/gdhcp.h
index d9944882..041ae81b 100755
--- a/gdhcp/gdhcp.h
+++ b/gdhcp/gdhcp.h
@@ -157,6 +157,7 @@ char *g_dhcp_client_get_server_address(GDHCPClient *client);
#if defined TIZEN_EXT
int g_dhcp_client_get_dhcp_lease_duration(GDHCPClient *client);
+char *g_dhcp_client_get_interface(GDHCPClient *dhcp_client);
#endif
char *g_dhcp_client_get_address(GDHCPClient *client);
diff --git a/gdhcp/server.c b/gdhcp/server.c
index 85405f19..52ea2a55 100755
--- a/gdhcp/server.c
+++ b/gdhcp/server.c
@@ -413,7 +413,7 @@ error:
}
-static uint8_t check_packet_type(struct dhcp_packet *packet)
+static uint8_t check_packet_type(struct dhcp_packet *packet, uint16_t packet_len)
{
uint8_t *type;
@@ -423,7 +423,7 @@ static uint8_t check_packet_type(struct dhcp_packet *packet)
if (packet->op != BOOTREQUEST)
return 0;
- type = dhcp_get_option(packet, DHCP_MESSAGE_TYPE);
+ type = dhcp_get_option(packet, packet_len, DHCP_MESSAGE_TYPE);
if (!type)
return 0;
@@ -651,6 +651,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
struct dhcp_lease *lease;
uint32_t requested_nip = 0;
uint8_t type, *server_id_option, *request_ip_option;
+ uint16_t packet_len;
int re;
if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
@@ -661,12 +662,13 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
re = dhcp_recv_l3_packet(&packet, dhcp_server->listener_sockfd);
if (re < 0)
return TRUE;
+ packet_len = (uint16_t)(unsigned int)re;
- type = check_packet_type(&packet);
+ type = check_packet_type(&packet, packet_len);
if (type == 0)
return TRUE;
- server_id_option = dhcp_get_option(&packet, DHCP_SERVER_ID);
+ server_id_option = dhcp_get_option(&packet, packet_len, DHCP_SERVER_ID);
if (server_id_option) {
uint32_t server_nid =
get_unaligned((const uint32_t *) server_id_option);
@@ -675,7 +677,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
return TRUE;
}
- request_ip_option = dhcp_get_option(&packet, DHCP_REQUESTED_IP);
+ request_ip_option = dhcp_get_option(&packet, packet_len, DHCP_REQUESTED_IP);
if (request_ip_option)
requested_nip = get_be32(request_ip_option);
diff --git a/gsupplicant/dbus.c b/gsupplicant/dbus.c
index 9ad8e080..73c9acec 100755
--- a/gsupplicant/dbus.c
+++ b/gsupplicant/dbus.c
@@ -497,7 +497,10 @@ int supplicant_dbus_method_call(const char *path,
if (!path || !interface || !method)
return -EINVAL;
-
+#if defined TIZEN_EXT
+ if (strlen(path) == 0)
+ return -EINVAL;
+#endif
method_call = g_try_new0(struct method_call_data, 1);
if (!method_call)
return -ENOMEM;
diff --git a/gsupplicant/gsupplicant.h b/gsupplicant/gsupplicant.h
index d748ff63..61b63dd6 100755
--- a/gsupplicant/gsupplicant.h
+++ b/gsupplicant/gsupplicant.h
@@ -71,6 +71,7 @@ extern "C" {
#define G_SUPPLICANT_KEYMGMT_WPS (1 << 9)
#if defined TIZEN_EXT
#define G_SUPPLICANT_KEYMGMT_SAE (1 << 10)
+#define G_SUPPLICANT_KEYMGMT_FT_SAE (1 << 11)
#define G_SUPPLICANT_KEYMGMT_OWE (1 << 22)
#define G_SUPPLICANT_KEYMGMT_DPP (1 << 23)
#endif
@@ -127,6 +128,7 @@ typedef enum {
G_SUPPLICANT_SECURITY_SAE,
G_SUPPLICANT_SECURITY_OWE,
G_SUPPLICANT_SECURITY_DPP,
+ G_SUPPLICANT_SECURITY_PSK_SHA256,
#endif
} GSupplicantSecurity;
@@ -187,6 +189,12 @@ typedef enum {
} GSupplicantINSPreferredFreq;
#endif
+typedef enum {
+ G_SUPPLICANT_MFP_NONE,
+ G_SUPPLICANT_MFP_OPTIONAL,
+ G_SUPPLICANT_MFP_REQUIRED,
+} GSupplicantMfpOptions;
+
struct _GSupplicantSSID {
#if defined TIZEN_EXT
void *ssid;
@@ -224,12 +232,16 @@ struct _GSupplicantSSID {
GSupplicantEapKeymgmt eap_keymgmt;
const char *phase1;
const char *pac_file;
- uint16_t ieee80211w;
unsigned int keymgmt;
const char *connector;
const char *c_sign_key;
const char *net_access_key;
+ bool is_passphrase_alloc;
+ bool is_connector_alloc;
+ bool is_c_sign_key_alloc;
+ bool is_net_access_key_alloc;
#endif
+ GSupplicantMfpOptions ieee80211w;
};
typedef struct _GSupplicantSSID GSupplicantSSID;
@@ -280,6 +292,30 @@ struct _GSupplicantP2PServiceParams {
typedef struct _GSupplicantP2PServiceParams GSupplicantP2PServiceParams;
+#if defined TIZEN_EXT
+#define WIFI_BSSID_STR_LEN 18
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+
+#define WIFI_BSSID_LEN_MAX 6
+
+struct g_connman_bssids {
+ unsigned char bssid[WIFI_BSSID_LEN_MAX];
+ uint16_t strength;
+ uint16_t frequency;
+ uint16_t assoc_reject_cnt;
+ bool is_last_connected;
+ unsigned int est_throughput;
+ int score_snr;
+ int score_last_connected_bssid;
+ int score_assoc_reject;
+ int score_frequency;
+ int score_strength;
+ int score_est_throughput;
+ int ins_score;
+};
+#endif
+
/* global API */
typedef void (*GSupplicantCountryCallback) (int result,
const char *alpha2,
@@ -305,13 +341,19 @@ typedef void (*GSupplicantInterfaceCallback) (int result,
#if defined TIZEN_EXT
typedef void (*GSupplicantMaxSpeedCallback) (int result, int maxspeed,
- int strength, void *user_data);
+ int strength, int snr, void *user_data,
+ unsigned int est_throughput);
#endif
void g_supplicant_interface_cancel(GSupplicantInterface *interface);
int g_supplicant_interface_create(const char *ifname, const char *driver,
const char *bridge,
+#ifdef TIZEN_EXT
+ unsigned int mac_policy,
+ unsigned int preassoc_mac_policy,
+ unsigned int random_mac_lifetime,
+#endif /* TIZEN_EXT */
GSupplicantInterfaceCallback callback,
void *user_data);
int g_supplicant_interface_remove(GSupplicantInterface *interface,
@@ -366,6 +408,14 @@ int g_supplicant_interface_disconnect(GSupplicantInterface *interface,
GSupplicantInterfaceCallback callback,
void *user_data);
+int g_supplicant_interface_set_bss_expiration_age(GSupplicantInterface *interface,
+ unsigned int bss_expiration_age);
+
+#if defined TIZEN_EXT
+void g_supplicant_interface_remove_network(GSupplicantInterface *interface,
+ GSupplicantSSID *ssid);
+#endif
+
int g_supplicant_interface_set_apscan(GSupplicantInterface *interface,
unsigned int ap_scan);
@@ -375,6 +425,25 @@ void *g_supplicant_interface_get_data(GSupplicantInterface *interface);
const char *g_supplicant_interface_get_ifname(GSupplicantInterface *interface);
#if defined TIZEN_EXT
bool g_supplicant_interface_get_is_5_0_ghz_supported(GSupplicantInterface *interface);
+bool g_supplicant_interface_get_is_6_0_ghz_supported(GSupplicantInterface *interface);
+unsigned char *g_supplicant_interface_get_add_network_bssid(GSupplicantInterface *interface);
+
+typedef void (*GSupplicantMacPolicyCallback) (int result, unsigned int policy, void *user_data);
+int g_supplicant_interface_set_mac_policy(GSupplicantInterface *interface,
+ GSupplicantMacPolicyCallback callback,
+ unsigned int policy,
+ void *user_data);
+
+int g_supplicant_interface_set_preassoc_mac_policy(GSupplicantInterface *interface,
+ GSupplicantMacPolicyCallback callback,
+ unsigned int policy,
+ void *user_data);
+
+typedef void (*GSupplicantRandomMaclifetimeCallback) (int result, unsigned int lifetime, void *user_data);
+int g_supplicant_interface_set_random_mac_lifetime(GSupplicantInterface *interface,
+ GSupplicantRandomMaclifetimeCallback callback,
+ unsigned int lifetime,
+ void *user_data);
#endif
const char *g_supplicant_interface_get_driver(GSupplicantInterface *interface);
GSupplicantState g_supplicant_interface_get_state(GSupplicantInterface *interface);
@@ -472,25 +541,29 @@ const char *g_supplicant_network_get_eap(GSupplicantNetwork *network);
const char *g_supplicant_network_get_identity(GSupplicantNetwork *network);
const char *g_supplicant_network_get_phase2(GSupplicantNetwork *network);
unsigned int g_supplicant_network_get_keymgmt(GSupplicantNetwork *network);
+dbus_bool_t g_supplicant_network_get_privacy(GSupplicantNetwork *network);
void *g_supplicant_network_get_wifi_vsie(GSupplicantNetwork *network);
const unsigned char *g_supplicant_network_get_countrycode(GSupplicantNetwork
*network);
+dbus_bool_t g_supplicant_network_is_pmf_required(GSupplicantNetwork *network);
void *g_supplicant_network_get_bssid_list(GSupplicantNetwork *network);
GSupplicantPhy_mode g_supplicant_network_get_phy_mode(GSupplicantNetwork *network);
dbus_bool_t g_supplicant_network_get_transition_mode(GSupplicantNetwork *network);
const unsigned char *g_supplicant_network_get_transition_mode_bssid(GSupplicantNetwork *network);
const void *g_supplicant_network_get_transition_mode_ssid(GSupplicantNetwork *network,
unsigned int *transition_mode_ssid_len);
+void g_supplicant_network_set_signal(GSupplicantNetwork *network, int signal);
+void g_supplicant_network_set_bss_signal(GSupplicantNetwork *network,
+ int signal, int snr);
+GSupplicantNetwork *g_supplicant_interface_get_network(GSupplicantInterface *interface,
+ const char *group);
-#endif
-#if defined TIZEN_EXT
void g_supplicant_network_set_last_connected_bssid(GSupplicantNetwork *network, const unsigned char *bssid);
const unsigned char *g_supplicant_network_get_last_connected_bssid(GSupplicantNetwork *network);
void g_supplicant_network_update_assoc_reject(GSupplicantInterface *interface,
GSupplicantNetwork *network);
GHashTable *g_supplicant_network_get_assoc_reject_table(GSupplicantNetwork *network);
-GSupplicantNetwork *g_supplicant_interface_get_network(GSupplicantInterface *interface,
- const char *group);
+GHashTable *g_supplicant_network_clone_assoc_reject_table(GSupplicantNetwork *network);
#endif
#if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
@@ -554,7 +627,7 @@ void g_supplicant_set_ins_settings(GSupplicantINSPreferredFreq preferred_freq_bs
bool last_connected_bssid, bool assoc_reject, bool signal_bssid,
unsigned int preferred_freq_bssid_score, unsigned int last_connected_bssid_score,
unsigned int assoc_reject_score, int signal_level3_5ghz, int signal_level3_24ghz);
-#endif
+#endif /* defined TIZEN_EXT */
#if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
void g_supplicant_replace_config_file(const char *ifname, const char *config_file);
diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c
index 86100ebe..d0033ed3 100755
--- a/gsupplicant/supplicant.c
+++ b/gsupplicant/supplicant.c
@@ -54,7 +54,6 @@
#define WLAN_EID_SUPP_RATES 1
#define WLAN_EID_EXT_SUPP_RATES 50
#define COUNTRY_CODE_LENGTH 2
-#define WIFI_BSSID_LEN_MAX 6
#endif
#if defined TIZEN_EXT
@@ -123,6 +122,7 @@ static struct strvalmap keymgmt_map[] = {
{ "wps", G_SUPPLICANT_KEYMGMT_WPS },
#if defined TIZEN_EXT
{ "sae", G_SUPPLICANT_KEYMGMT_SAE },
+ { "ft-sae", G_SUPPLICANT_KEYMGMT_FT_SAE },
{ "owe", G_SUPPLICANT_KEYMGMT_OWE },
{ "dpp", G_SUPPLICANT_KEYMGMT_DPP },
#endif
@@ -193,7 +193,7 @@ static struct _GSupplicantINSSettings ins_settings;
static unsigned char invalid_bssid[WIFI_BSSID_LEN_MAX] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
-#endif
+#endif /* defined TIZEN_EXT */
static GHashTable *interface_table;
static GHashTable *bss_mapping;
@@ -263,6 +263,7 @@ struct _GSupplicantInterface {
struct added_network_information network_info;
#if defined TIZEN_EXT
dbus_bool_t is_5_0_Ghz_supported;
+ dbus_bool_t is_6_0_Ghz_supported;
int disconnect_reason;
#endif
#if defined TIZEN_EXT
@@ -304,6 +305,9 @@ struct g_supplicant_bss {
dbus_bool_t hs20;
unsigned char country_code[COUNTRY_CODE_LENGTH];
GSupplicantPhy_mode phy_mode;
+ dbus_int16_t snr;
+ dbus_uint32_t est_throughput;
+ dbus_bool_t psk_sha256;
#endif
unsigned int wps_capabilities;
#if defined TIZEN_EXT
@@ -314,6 +318,7 @@ struct g_supplicant_bss {
unsigned int transition_mode_ssid_len;
unsigned char transition_mode_bssid[6];
unsigned char transition_mode_ssid[32];
+ dbus_bool_t pmf_required;
#endif
};
@@ -343,6 +348,7 @@ struct _GSupplicantNetwork {
unsigned char country_code[COUNTRY_CODE_LENGTH];
GSupplicantPhy_mode phy_mode;
dbus_bool_t owe_transition_mode;
+ dbus_bool_t privacy;
unsigned int transition_mode_ssid_len;
unsigned char transition_mode_bssid[6];
unsigned char transition_mode_ssid[32];
@@ -398,6 +404,11 @@ struct interface_create_data {
char *ifname;
char *driver;
char *bridge;
+#if defined TIZEN_EXT
+ unsigned int mac_addr;
+ unsigned int preassoc_mac_addr;
+ unsigned int random_mac_lifetime;
+#endif /* TIZEN_EXT */
#if defined TIZEN_EXT_WIFI_MESH
char *parent_ifname;
bool is_mesh_interface;
@@ -427,21 +438,6 @@ struct interface_scan_data {
};
#if defined TIZEN_EXT
-struct g_connman_bssids {
- unsigned char bssid[WIFI_BSSID_LEN_MAX];
- uint16_t strength;
- uint16_t frequency;
- uint16_t assoc_reject_cnt;
- bool is_last_connected;
-#if defined TIZEN_EXT_INS
- int score_last_connected_bssid;
- int score_assoc_reject;
- int score_frequency;
- int score_strength;
-#endif
- int ins_score;
-};
-
struct update_bssid_data {
GSupplicantNetwork *network;
unsigned char last_connected_bssid[WIFI_BSSID_LEN_MAX];
@@ -543,6 +539,8 @@ static const char *security2string(GSupplicantSecurity security)
case G_SUPPLICANT_SECURITY_IEEE8021X:
return "ieee8021x";
#if defined TIZEN_EXT
+ case G_SUPPLICANT_SECURITY_PSK_SHA256:
+ return "psk_sha256";
case G_SUPPLICANT_SECURITY_FT_PSK:
return "ft_psk";
case G_SUPPLICANT_SECURITY_FT_IEEE8021X:
@@ -672,6 +670,10 @@ static int store_network_information(GSupplicantInterface * interface,
if ((ssid->security == G_SUPPLICANT_SECURITY_WEP ||
ssid->security == G_SUPPLICANT_SECURITY_PSK ||
+#if defined TIZEN_EXT
+ ssid->security == G_SUPPLICANT_SECURITY_SAE ||
+ ssid->security == G_SUPPLICANT_SECURITY_PSK_SHA256 ||
+#endif
ssid->security == G_SUPPLICANT_SECURITY_NONE) &&
ssid->passphrase) {
interface->network_info.passphrase = g_strdup(ssid->passphrase);
@@ -1309,12 +1311,35 @@ static void interface_capability(const char *key, DBusMessageIter *iter,
dbus_message_iter_get_basic(iter, &is_5_0_Ghz_supported);
interface->is_5_0_Ghz_supported = is_5_0_Ghz_supported;
+ } else if (g_strcmp0(key, "Is6GhzSupported") == 0) {
+ dbus_bool_t is_6_0_Ghz_supported;
+
+ dbus_message_iter_get_basic(iter, &is_6_0_Ghz_supported);
+ interface->is_6_0_Ghz_supported = is_6_0_Ghz_supported;
#endif
} else
SUPPLICANT_DBG("key %s type %c",
key, dbus_message_iter_get_arg_type(iter));
}
+static void set_bss_expiration_age(DBusMessageIter *iter, void *user_data)
+{
+ unsigned int bss_expiration_age = GPOINTER_TO_UINT(user_data);
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32,
+ &bss_expiration_age);
+}
+
+int g_supplicant_interface_set_bss_expiration_age(GSupplicantInterface *interface,
+ unsigned int bss_expiration_age)
+{
+ return supplicant_dbus_property_set(interface->path,
+ SUPPLICANT_INTERFACE ".Interface",
+ "BSSExpireAge", DBUS_TYPE_UINT32_AS_STRING,
+ set_bss_expiration_age, NULL,
+ GUINT_TO_POINTER(bss_expiration_age), NULL);
+}
+
struct set_apscan_data
{
unsigned int ap_scan;
@@ -1402,10 +1427,26 @@ const char *g_supplicant_interface_get_ifname(GSupplicantInterface *interface)
bool g_supplicant_interface_get_is_5_0_ghz_supported(GSupplicantInterface *interface)
{
if (!interface)
- return NULL;
+ return false;
return interface->is_5_0_Ghz_supported;
}
+
+bool g_supplicant_interface_get_is_6_0_ghz_supported(GSupplicantInterface *interface)
+{
+ if (!interface)
+ return false;
+
+ return interface->is_6_0_Ghz_supported;
+}
+
+unsigned char *g_supplicant_interface_get_add_network_bssid(GSupplicantInterface *interface)
+{
+ if (!interface)
+ return NULL;
+
+ return (unsigned char *)interface->add_network_bssid;
+}
#endif
const char *g_supplicant_interface_get_driver(GSupplicantInterface *interface)
@@ -1544,7 +1585,7 @@ const char *g_supplicant_network_get_path(GSupplicantNetwork *network)
const char *g_supplicant_network_get_mode(GSupplicantNetwork *network)
{
if (!network)
- return G_SUPPLICANT_MODE_UNKNOWN;
+ return NULL;
return mode2string(network->mode);
}
@@ -1552,7 +1593,7 @@ const char *g_supplicant_network_get_mode(GSupplicantNetwork *network)
const char *g_supplicant_network_get_security(GSupplicantNetwork *network)
{
if (!network)
- return G_SUPPLICANT_SECURITY_UNKNOWN;
+ return NULL;
return security2string(network->security);
}
@@ -1577,6 +1618,32 @@ dbus_int16_t g_supplicant_network_get_signal(GSupplicantNetwork *network)
return network->signal;
}
+#if defined TIZEN_EXT
+void g_supplicant_network_set_signal(GSupplicantNetwork *network, int signal)
+{
+ if (!network)
+ return;
+
+ network->signal = (dbus_int16_t)signal;
+}
+
+void g_supplicant_network_set_bss_signal(GSupplicantNetwork *network,
+ int signal, int snr)
+{
+ struct g_supplicant_bss *best_bss;
+
+ if (!network)
+ return;
+
+ best_bss = network->best_bss;
+ if (!best_bss)
+ return;
+
+ best_bss->signal = (dbus_int16_t)signal;
+ best_bss->snr = (dbus_int16_t)snr;
+}
+#endif
+
dbus_uint16_t g_supplicant_network_get_frequency(GSupplicantNetwork *network)
{
if (!network)
@@ -1719,12 +1786,20 @@ const char *g_supplicant_network_get_phase2(GSupplicantNetwork *network)
unsigned int g_supplicant_network_get_keymgmt(GSupplicantNetwork *network)
{
- if (network == NULL)
+ if (!network)
return 0;
return network->keymgmt;
}
+dbus_bool_t g_supplicant_network_get_privacy(GSupplicantNetwork *network)
+{
+ if (!network)
+ return FALSE;
+
+ return network->privacy;
+}
+
const unsigned char *g_supplicant_network_get_countrycode(GSupplicantNetwork
*network)
{
@@ -1733,6 +1808,14 @@ const unsigned char *g_supplicant_network_get_countrycode(GSupplicantNetwork
return network->country_code;
}
+
+dbus_bool_t g_supplicant_network_is_pmf_required(GSupplicantNetwork *network)
+{
+ if (!network || !network->best_bss)
+ return FALSE;
+
+ return network->best_bss->pmf_required;
+}
#endif
const unsigned char *g_supplicant_peer_get_widi_ies(GSupplicantPeer *peer,
@@ -1828,6 +1911,7 @@ const unsigned char *g_supplicant_network_get_bssid(GSupplicantNetwork *network)
return (const unsigned char *)network->best_bss->bssid;
}
+
dbus_bool_t g_supplicant_network_get_transition_mode(GSupplicantNetwork *network)
{
if (network == NULL)
@@ -1836,7 +1920,6 @@ dbus_bool_t g_supplicant_network_get_transition_mode(GSupplicantNetwork *network
return network->owe_transition_mode;
}
-
const unsigned char *g_supplicant_network_get_transition_mode_bssid(GSupplicantNetwork *network)
{
if (network == NULL)
@@ -1871,12 +1954,11 @@ const char *g_supplicant_network_get_enc_mode(GSupplicantNetwork *network)
return NULL;
if (network->best_bss->security == G_SUPPLICANT_SECURITY_PSK ||
-#if defined TIZEN_EXT
- network->best_bss->security == G_SUPPLICANT_SECURITY_SAE ||
- network->best_bss->security == G_SUPPLICANT_SECURITY_OWE ||
- network->best_bss->security == G_SUPPLICANT_SECURITY_DPP ||
-#endif /* TIZEN_EXT */
- network->best_bss->security == G_SUPPLICANT_SECURITY_IEEE8021X) {
+ network->best_bss->security == G_SUPPLICANT_SECURITY_SAE ||
+ network->best_bss->security == G_SUPPLICANT_SECURITY_OWE ||
+ network->best_bss->security == G_SUPPLICANT_SECURITY_DPP ||
+ network->best_bss->security == G_SUPPLICANT_SECURITY_PSK_SHA256 ||
+ network->best_bss->security == G_SUPPLICANT_SECURITY_IEEE8021X) {
unsigned int pairwise;
pairwise = network->best_bss->rsn_pairwise |
@@ -1903,12 +1985,9 @@ bool g_supplicant_network_get_rsn_mode(GSupplicantNetwork *network)
if (network == NULL || network->best_bss == NULL)
return 0;
-#if defined TIZEN_EXT
- if (network->best_bss->security == G_SUPPLICANT_SECURITY_SAE ||
- network->best_bss->security == G_SUPPLICANT_SECURITY_OWE ||
+ if (network->best_bss->security == G_SUPPLICANT_SECURITY_OWE ||
network->best_bss->security == G_SUPPLICANT_SECURITY_DPP)
return false;
-#endif /* TIZEN_EXT */
if (network->best_bss->rsn_selected) {
const char *mode = g_supplicant_network_get_enc_mode(network);
@@ -2087,8 +2166,22 @@ static int calculate_score_strength(dbus_int16_t strength)
return score;
}
+static int calculate_score_est_throughput(dbus_uint32_t est_throughput)
+{
+ int score = 0;
+
+ if (est_throughput >= 10000)
+ score = est_throughput / 10000;
+
+ if (score > 40)
+ score = 40;
+
+ return score;
+}
+
static int calculate_score(bool is_last_connected, uint16_t assoc_reject_cnt,
- dbus_int16_t strength, dbus_uint16_t frequency)
+ dbus_uint16_t frequency, dbus_int16_t strength,
+ dbus_int16_t snr, dbus_uint32_t est_throughput)
{
int score = 0;
@@ -2096,6 +2189,8 @@ static int calculate_score(bool is_last_connected, uint16_t assoc_reject_cnt,
score += calculate_score_assoc_reject(assoc_reject_cnt);
score += calculate_score_frequency(strength, frequency);
score += calculate_score_strength(strength);
+ score += (int)snr;
+ score += calculate_score_est_throughput(est_throughput);
return score;
}
@@ -2118,20 +2213,25 @@ static void update_bssid_list(gpointer key, gpointer value, gpointer user_data)
bssids->strength = 100;
bssids->frequency = bss->frequency;
-
- bssids->assoc_reject_cnt = get_assoc_reject_cnt(bssid_data->assoc_reject_table, bssids->bssid);
-
- bssids->is_last_connected = compare_bssid(bssids->bssid, bssid_data->last_connected_bssid);
-
-#if defined TIZEN_EXT_INS
- bssids->score_last_connected_bssid = calculate_score_last_connected_bssid(bssids->is_last_connected);
- bssids->score_assoc_reject = calculate_score_assoc_reject(bssids->assoc_reject_cnt);
- bssids->score_frequency = calculate_score_frequency(bss->signal, bssids->frequency);
- bssids->score_strength = calculate_score_strength(bssids->strength);
-#endif
-
- bssids->ins_score = calculate_score(bssids->is_last_connected,
- bssids->assoc_reject_cnt, bssids->frequency, bss->signal);
+ bssids->est_throughput = bss->est_throughput;
+ bssids->score_snr = (int)bss->snr;
+
+ if (TIZEN_INS_ENABLED) {
+ bssids->assoc_reject_cnt = get_assoc_reject_cnt(bssid_data->assoc_reject_table, bssids->bssid);
+ bssids->is_last_connected = compare_bssid(bssids->bssid, bssid_data->last_connected_bssid);
+
+ bssids->score_last_connected_bssid = calculate_score_last_connected_bssid(bssids->is_last_connected);
+ bssids->score_assoc_reject = calculate_score_assoc_reject(bssids->assoc_reject_cnt);
+ bssids->score_frequency = calculate_score_frequency(bss->signal, bssids->frequency);
+ bssids->score_strength = calculate_score_strength(bss->signal);
+ bssids->score_est_throughput = calculate_score_est_throughput(bss->est_throughput);
+
+ bssids->ins_score = calculate_score(bssids->is_last_connected,
+ bssids->assoc_reject_cnt, bssids->frequency, bss->signal,
+ bss->snr, bss->est_throughput);
+ } else {
+ bssids->ins_score = bss->signal;
+ }
bssid_data->bssid_list = g_slist_append(bssid_data->bssid_list, bssids);
} else
@@ -2149,21 +2249,31 @@ static gint cmp_bss(gconstpointer a, gconstpointer b)
if (entry_a->ins_score < entry_b->ins_score)
return 1;
+ if (entry_a->ins_score == entry_b->ins_score) {
+ if (entry_a->strength >= entry_b->strength)
+ return -1;
+ else
+ return 1;
+ }
+
return 0;
}
-#if defined TIZEN_EXT_INS
static void print_bssid_sort(gpointer data, gpointer user_data)
{
struct g_connman_bssids *bssids = data;
- SUPPLICANT_DBG("bssid[" MACSTR "] total[%2d] freq[%2d] "
- "last_conn[%2d] assoc_reject[%2d] strength[%2d]",
- MAC2STR(bssids->bssid), bssids->ins_score,
+ GSupplicantNetwork *network = (GSupplicantNetwork *) user_data;
+
+ if (!bssids || !network)
+ return;
+
+ SUPPLICANT_DBG("ssid [%-20s] bssid[" MACSTR "] total[%2d] freq[%2d] "
+ "last_conn[%2d] assoc_reject[%2d] strength[%2d] rssi[%2d]",
+ network->ssid, MAC2STR(bssids->bssid), bssids->ins_score,
bssids->score_frequency, bssids->score_last_connected_bssid,
- bssids->score_assoc_reject, bssids->score_strength);
+ bssids->score_assoc_reject, bssids->score_strength, bssids->strength - 120);
}
-#endif
void *g_supplicant_network_get_bssid_list(GSupplicantNetwork *network)
{
@@ -2179,9 +2289,8 @@ void *g_supplicant_network_get_bssid_list(GSupplicantNetwork *network)
g_hash_table_foreach(network->bss_table, update_bssid_list, &bssid_data);
bssid_data.bssid_list = g_slist_sort(bssid_data.bssid_list, cmp_bss);
-#if defined TIZEN_EXT_INS
- g_slist_foreach(bssid_data.bssid_list, print_bssid_sort, NULL);
-#endif
+ if (TIZEN_INS_ENABLED && !simplified_log)
+ g_slist_foreach(bssid_data.bssid_list, print_bssid_sort, (gpointer)network);
return bssid_data.bssid_list;
}
@@ -2251,6 +2360,42 @@ GHashTable *g_supplicant_network_get_assoc_reject_table(GSupplicantNetwork *netw
return network->assoc_reject_table;
}
+static void copy_assoc_reject(gpointer key, gpointer value, gpointer user_data)
+{
+ struct assoc_reject_data *cloned_assoc_data;
+ struct assoc_reject_data *assoc_data = value;
+ GHashTable *cloned_assoc_reject_table = user_data;
+
+ if (assoc_data && cloned_assoc_reject_table) {
+ cloned_assoc_data = g_try_new0(struct assoc_reject_data, 1);
+ if (!cloned_assoc_data)
+ return;
+
+ cloned_assoc_data->bssid = g_strdup(assoc_data->bssid);
+ cloned_assoc_data->reject_time_list = g_slist_copy(assoc_data->reject_time_list);
+ g_hash_table_insert(cloned_assoc_reject_table,
+ cloned_assoc_data->bssid, cloned_assoc_data);
+ }
+}
+
+GHashTable *g_supplicant_network_clone_assoc_reject_table(GSupplicantNetwork *network)
+{
+ GHashTable *cloned_assoc_reject_table;
+
+ if (!network)
+ return NULL;
+
+ GHashTable *assoc_reject_table = g_supplicant_network_get_assoc_reject_table(network);
+ if (!assoc_reject_table)
+ return NULL;
+
+ cloned_assoc_reject_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, remove_assoc_data);
+ g_hash_table_foreach(assoc_reject_table, copy_assoc_reject, cloned_assoc_reject_table);
+
+ return cloned_assoc_reject_table;
+}
+
GSupplicantNetwork *g_supplicant_interface_get_network(GSupplicantInterface *interface,
const char *group)
{
@@ -2259,7 +2404,7 @@ GSupplicantNetwork *g_supplicant_interface_get_network(GSupplicantInterface *int
return g_hash_table_lookup(interface->network_table, group);
}
-#endif
+#endif /* defined TIZEN_EXT */
static void merge_network(GSupplicantNetwork *network)
{
@@ -2312,8 +2457,16 @@ static void merge_network(GSupplicantNetwork *network)
g_string_append_printf(str, "_mesh");
#endif
+#if defined TIZEN_EXT
if (g_strcmp0(key_mgmt, "WPA-PSK") == 0)
g_string_append_printf(str, "_psk");
+ else if (g_strcmp0(key_mgmt, "SAE") == 0)
+ g_string_append_printf(str, "_sae");
+#else
+ if ((g_strcmp0(key_mgmt, "WPA-PSK") == 0) ||
+ (g_strcmp0(key_mgmt, "SAE") == 0))
+ g_string_append_printf(str, "_psk");
+#endif
#if defined TIZEN_EXT
else if (g_strcmp0(key_mgmt, "WPA-EAP") == 0)
g_string_append_printf(str, "_ieee8021x");
@@ -2489,7 +2642,14 @@ static char *create_group(struct g_supplicant_bss *bss)
if (mode)
g_string_append_printf(str, "_%s", mode);
+#if defined TIZEN_EXT
+ if (bss->security == G_SUPPLICANT_SECURITY_PSK_SHA256)
+ security = "psk";
+ else
+ security = security2string(bss->security);
+#else
security = security2string(bss->security);
+#endif
if (security)
g_string_append_printf(str, "_%s", security);
@@ -2499,8 +2659,15 @@ static char *create_group(struct g_supplicant_bss *bss)
static void update_network_with_best_bss(GSupplicantNetwork *network,
struct g_supplicant_bss *best_bss)
{
+ /*
+ * Do not change best BSS if we are connected.
+ */
+ if (network->interface->state == G_SUPPLICANT_STATE_COMPLETED && network->best_bss)
+ return;
+
network->signal = best_bss->signal;
network->frequency = best_bss->frequency;
+ network->phy_mode = best_bss->phy_mode;
network->best_bss = best_bss;
}
@@ -2515,18 +2682,24 @@ static bool update_best_bss(GSupplicantNetwork *network,
return true;
}
- score_new = calculate_score(
- compare_bssid(bss->bssid, network->last_connected_bssid),
- get_assoc_reject_cnt(network->assoc_reject_table, bss->bssid),
- bss->frequency, bss->signal);
+ if (TIZEN_INS_ENABLED) {
+ score_new = calculate_score(
+ compare_bssid(bss->bssid, network->last_connected_bssid),
+ get_assoc_reject_cnt(network->assoc_reject_table, bss->bssid),
+ bss->frequency, bss->signal, bss->snr, bss->est_throughput);
- score_best = calculate_score(
- compare_bssid(network->best_bss->bssid, network->last_connected_bssid),
- get_assoc_reject_cnt(network->assoc_reject_table, network->best_bss->bssid),
- network->best_bss->frequency, network->best_bss->signal);
+ score_best = calculate_score(
+ compare_bssid(network->best_bss->bssid, network->last_connected_bssid),
+ get_assoc_reject_cnt(network->assoc_reject_table, network->best_bss->bssid),
+ network->best_bss->frequency, network->best_bss->signal,
+ network->best_bss->snr, network->best_bss->est_throughput);
+ } else {
+ score_new = bss->signal;
+ score_best = network->best_bss->signal;
+ }
if (score_new > score_best) {
- SUPPLICANT_DBG("new[" MACSTR "][%u] : best[" MACSTR "][%u]",
+ SUPPLICANT_DBG("new[" MACSTR "][%d] : best[" MACSTR "][%d]",
MAC2STR(bss->bssid), score_new,
MAC2STR(network->best_bss->bssid), score_best);
@@ -2577,6 +2750,7 @@ static int add_or_replace_bss_to_network(struct g_supplicant_bss *bss)
network->name = create_name(bss->ssid, bss->ssid_len);
network->mode = bss->mode;
network->security = bss->security;
+ network->keymgmt = bss->keymgmt;
network->ssid_len = bss->ssid_len;
memcpy(network->ssid, bss->ssid, bss->ssid_len);
network->signal = bss->signal;
@@ -2590,6 +2764,7 @@ static int add_or_replace_bss_to_network(struct g_supplicant_bss *bss)
#if defined TIZEN_EXT
network->owe_transition_mode = bss->owe_transition_mode;
+ network->privacy = bss->privacy;
memcpy(network->transition_mode_ssid, bss->transition_mode_ssid, bss->transition_mode_ssid_len);
memcpy(network->transition_mode_bssid, bss->transition_mode_bssid, WIFI_BSSID_LEN_MAX);
@@ -2869,6 +3044,7 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data)
unsigned char *ext_rates = NULL;
unsigned int max_rate = 0;
unsigned int max_ext_rate = 0;
+ unsigned int offset = 0;
bool ht = false;
bool vht = false;
#endif
@@ -2886,6 +3062,8 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data)
#if defined TIZEN_EXT
#define VENDOR_SPECIFIC_INFO 0xDD
#define WLAN_EID_COUNTRY 7
+#define WLAN_EID_RSN_INFO 48
+#define RSN_CAPABILITY_MFP_REQ (1 << 6)
#endif
dbus_message_iter_recurse(iter, &array);
@@ -2903,7 +3081,7 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data)
unsigned char *vsie;
int vsie_len = 0;
- if(ie[0] == VENDOR_SPECIFIC_INFO && memcmp(ie+2, OWE_WFA_OUI, sizeof(OWE_WFA_OUI)) == 0) {
+ if (ie[0] == VENDOR_SPECIFIC_INFO && memcmp(ie+2, OWE_WFA_OUI, sizeof(OWE_WFA_OUI)) == 0) {
SUPPLICANT_DBG("IE: match vendor specific data : OWE Transition Mode");
/*
@@ -2933,7 +3111,7 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data)
continue;
}
- if(ie[0] == VENDOR_SPECIFIC_INFO && memcmp(ie+2, WPS_OUI, sizeof(WPS_OUI)) != 0) {
+ if (ie[0] == VENDOR_SPECIFIC_INFO && memcmp(ie+2, WPS_OUI, sizeof(WPS_OUI)) != 0) {
if (!simplified_log)
SUPPLICANT_DBG("IE: match vendor specific data");
@@ -2949,7 +3127,7 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data)
continue;
}
- if(ie[0] == WLAN_EID_COUNTRY && ie[1] >= 2) {
+ if (ie[0] == WLAN_EID_COUNTRY && ie[1] >= 2) {
/* Add country code only if it is a valid alphabet */
if (ie[2] >= 65 && ie[2] <= 90 && ie[3] >= 65 && ie[3] <= 90) {
memcpy(bss->country_code, ie+2, COUNTRY_CODE_LENGTH);
@@ -2994,6 +3172,18 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data)
}
continue;
}
+
+ if (ie[0] == WLAN_EID_RSN_INFO && ie[1] >= 20) {
+ r_len = ie[1];
+ offset = 10 + ie[8] * 4;
+ offset += ie[offset] * 4 + 2;
+
+ if (offset <= r_len + 1 &&
+ (ie[offset] & RSN_CAPABILITY_MFP_REQ) != 0)
+ bss->pmf_required = TRUE;
+
+ continue;
+ }
#endif
if (ie[0] != WMM_WPA1_WPS_INFO || ie[1] < WPS_INFO_MIN_LEN ||
memcmp(ie+2, WPS_OUI, sizeof(WPS_OUI)) != 0)
@@ -3050,12 +3240,13 @@ static void bss_compute_security(struct g_supplicant_bss *bss)
#if defined TIZEN_EXT
bss->ft_ieee8021x = FALSE;
bss->ft_psk = FALSE;
+ GSupplicantInterface *interface = bss->interface;
#endif
#if defined TIZEN_EXT
if (bss->keymgmt &
(G_SUPPLICANT_KEYMGMT_WPA_EAP |
- G_SUPPLICANT_KEYMGMT_WPA_EAP_256))
+ G_SUPPLICANT_KEYMGMT_WPA_EAP_256))
bss->ieee8021x = TRUE;
else if (bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPA_FT_EAP)
bss->ft_ieee8021x = TRUE;
@@ -3069,8 +3260,13 @@ static void bss_compute_security(struct g_supplicant_bss *bss)
#if defined TIZEN_EXT
if (bss->keymgmt &
+ G_SUPPLICANT_KEYMGMT_WPA_PSK_256) {
+ bss->psk_sha256 = TRUE;
+ }
+
+ if (bss->keymgmt &
(G_SUPPLICANT_KEYMGMT_WPA_PSK |
- G_SUPPLICANT_KEYMGMT_WPA_PSK_256))
+ G_SUPPLICANT_KEYMGMT_WPA_PSK_256))
bss->psk = TRUE;
else if (bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPA_FT_PSK)
bss->ft_psk = TRUE;
@@ -3083,7 +3279,9 @@ static void bss_compute_security(struct g_supplicant_bss *bss)
#endif
#if defined TIZEN_EXT
- if (bss->keymgmt & G_SUPPLICANT_KEYMGMT_SAE)
+ if (bss->keymgmt &
+ (G_SUPPLICANT_KEYMGMT_SAE |
+ G_SUPPLICANT_KEYMGMT_FT_SAE))
bss->sae = TRUE;
if (bss->keymgmt & G_SUPPLICANT_KEYMGMT_OWE)
bss->owe = TRUE;
@@ -3093,15 +3291,24 @@ static void bss_compute_security(struct g_supplicant_bss *bss)
if (bss->ieee8021x)
bss->security = G_SUPPLICANT_SECURITY_IEEE8021X;
+#if defined TIZEN_EXT
+ else if (bss->ft_ieee8021x)
+ bss->security = G_SUPPLICANT_SECURITY_IEEE8021X;
+ else if (bss->sae) {
+ if (!bss->psk)
+ bss->security = G_SUPPLICANT_SECURITY_SAE;
+ else if (interface->keymgmt_capa & G_SUPPLICANT_KEYMGMT_SAE)
+ bss->security = G_SUPPLICANT_SECURITY_SAE;
+ else
+ bss->security = G_SUPPLICANT_SECURITY_PSK;
+ } else if (bss->psk_sha256)
+ bss->security = G_SUPPLICANT_SECURITY_PSK_SHA256;
+#endif
else if (bss->psk)
bss->security = G_SUPPLICANT_SECURITY_PSK;
#if defined TIZEN_EXT
else if (bss->ft_psk)
bss->security = G_SUPPLICANT_SECURITY_FT_PSK;
- else if (bss->ft_ieee8021x == TRUE)
- bss->security = G_SUPPLICANT_SECURITY_IEEE8021X;
- else if (bss->sae)
- bss->security = G_SUPPLICANT_SECURITY_SAE;
else if (bss->owe || bss->owe_transition_mode)
bss->security = G_SUPPLICANT_SECURITY_OWE;
else if (bss->dpp)
@@ -3215,6 +3422,17 @@ static void bss_property(const char *key, DBusMessageIter *iter,
dbus_bool_t hs20 = FALSE;
dbus_message_iter_get_basic(iter, &hs20);
bss->hs20 = hs20;
+ } else if (g_strcmp0(key, "SNR") == 0) {
+ dbus_int16_t snr = 0;
+
+ dbus_message_iter_get_basic(iter, &snr);
+ bss->snr = snr;
+ } else if (g_strcmp0(key, "EstThroughput") == 0) {
+ dbus_uint32_t est_throughput = 0;
+
+ dbus_message_iter_get_basic(iter, &est_throughput);
+ if (est_throughput != 0)
+ bss->est_throughput = est_throughput;
#endif
} else if (g_strcmp0(key, "IEs") == 0)
bss_process_ies(iter, bss);
@@ -3329,6 +3547,8 @@ static void update_signal(gpointer key, gpointer value,
if (!network->best_bss || (network->best_bss == bss)) {
if (bss->signal > network->signal) {
network->signal = bss->signal;
+ network->frequency = bss->frequency;
+ network->phy_mode = bss->phy_mode;
network->best_bss = bss;
}
return;
@@ -3405,7 +3625,7 @@ static void remove_timer_for_last_connected(GSupplicantInterface *interface)
}
}
}
-#endif
+#endif /* defined TIZEN_EXT */
static void interface_current_bss(GSupplicantInterface *interface,
DBusMessageIter *iter)
@@ -3413,6 +3633,13 @@ static void interface_current_bss(GSupplicantInterface *interface,
GSupplicantNetwork *network;
struct g_supplicant_bss *bss;
const char *path;
+#if defined TIZEN_EXT
+ char curr_bssid_buff[WIFI_BSSID_STR_LEN] = {0,};
+ char best_bssid_buff[WIFI_BSSID_STR_LEN] = {0,};
+ char *curr_bssid_str = curr_bssid_buff;
+ char *best_bssid_str = best_bssid_buff;
+ gboolean update = FALSE;
+#endif
dbus_message_iter_get_basic(iter, &path);
if (g_strcmp0(path, "/") == 0) {
@@ -3432,7 +3659,17 @@ static void interface_current_bss(GSupplicantInterface *interface,
interface->current_network = network;
#if defined TIZEN_EXT
- SUPPLICANT_DBG("current network [%p]", interface->current_network);
+ snprintf(curr_bssid_str, WIFI_BSSID_STR_LEN, MACSTR, MAC2STR(bss->bssid));
+ snprintf(best_bssid_str, WIFI_BSSID_STR_LEN, MACSTR, MAC2STR(network->best_bss->bssid));
+
+ SUPPLICANT_DBG("current network [%p], Passed bss %s, best bss %s",
+ interface->current_network, curr_bssid_str, best_bssid_str);
+
+ if (network->frequency != bss->frequency) {
+ network->frequency = bss->frequency;
+ network->phy_mode = bss->phy_mode;
+ update = TRUE;
+ }
#endif
if (bss != network->best_bss) {
@@ -3451,9 +3688,19 @@ static void interface_current_bss(GSupplicantInterface *interface,
network->signal = bss->signal;
callback_network_changed(network, "Signal");
+#if defined TIZEN_EXT
+ update = FALSE;
+ } else {
+ update = TRUE;
+#endif
}
}
+#if defined TIZEN_EXT
+ if (update)
+ callback_network_changed(network, "");
+#endif
+
/*
* wpa_s could notify about CurrentBSS in any state once
* it got associated. It is not sure such notification will
@@ -3476,7 +3723,8 @@ static void interface_current_bss(GSupplicantInterface *interface,
case G_SUPPLICANT_STATE_COMPLETED:
callback_network_associated(network);
#if defined TIZEN_EXT
- add_timer_for_last_connected(interface);
+ if (TIZEN_INS_ENABLED)
+ add_timer_for_last_connected(interface);
#endif
break;
}
@@ -3635,15 +3883,17 @@ static void interface_property(const char *key, DBusMessageIter *iter,
callback_interface_state(interface);
}
#if defined TIZEN_EXT
- switch (interface->state) {
- case G_SUPPLICANT_STATE_COMPLETED:
- add_timer_for_last_connected(interface);
- break;
- case G_SUPPLICANT_STATE_DISCONNECTED:
- remove_timer_for_last_connected(interface);
- break;
- default:
- break;
+ if (TIZEN_INS_ENABLED) {
+ switch (interface->state) {
+ case G_SUPPLICANT_STATE_COMPLETED:
+ add_timer_for_last_connected(interface);
+ break;
+ case G_SUPPLICANT_STATE_DISCONNECTED:
+ remove_timer_for_last_connected(interface);
+ break;
+ default:
+ break;
+ }
}
#endif
if (interface->ap_create_in_progress) {
@@ -4112,10 +4362,20 @@ static void signal_network_removed(const char *path, DBusMessageIter *iter)
interface_network_removed(iter, interface);
}
+
#if defined TIZEN_EXT
-void *copy_vsie_list(gconstpointer src, gpointer data)
+gpointer copy_vsie_list(gconstpointer src, gpointer data)
{
- return g_strdup(src);
+ unsigned char *str = (unsigned char *)src;
+ unsigned char *vsie;
+ vsie = g_try_malloc0(str[1]+2);
+
+ if (vsie)
+ memcpy(vsie, str, str[1]+2);
+ else
+ SUPPLICANT_DBG("Failed to allocate memory");
+
+ return vsie;
}
#endif
@@ -4218,8 +4478,11 @@ static void signal_bss_changed(const char *path, DBusMessageIter *iter)
supplicant_dbus_property_foreach(iter, bss_property, bss);
#if defined TIZEN_EXT
- network->frequency = bss->frequency;
- network->phy_mode = bss->phy_mode;
+ if (network->interface->state != G_SUPPLICANT_STATE_COMPLETED &&
+ bss == network->best_bss) {
+ network->frequency = bss->frequency;
+ network->phy_mode = bss->phy_mode;
+ }
#endif
old_security = network->security;
bss_compute_security(bss);
@@ -5600,7 +5863,7 @@ static void interface_create_result(const char *error,
SUPPLICANT_DBG("");
if (error) {
- g_message("error %s", error);
+ g_warning("error %s", error);
err = -EIO;
goto done;
}
@@ -5668,6 +5931,19 @@ static void interface_create_params(DBusMessageIter *iter, void *user_data)
DBUS_TYPE_STRING, &config_file);
}
+#ifdef TIZEN_EXT
+ if (data->driver && g_strstr_len(data->driver, strlen(data->driver), "nl80211")) {
+ supplicant_dbus_dict_append_basic(&dict, "MacAddr",
+ DBUS_TYPE_UINT32, &data->mac_addr);
+
+ supplicant_dbus_dict_append_basic(&dict, "PreassocMacAddr",
+ DBUS_TYPE_UINT32, &data->preassoc_mac_addr);
+
+ supplicant_dbus_dict_append_basic(&dict, "RandAddrLifetime",
+ DBUS_TYPE_UINT32, &data->random_mac_lifetime);
+ }
+#endif /* TIZEN_EXT */
+
#if defined TIZEN_EXT_WIFI_MESH
if (data->is_mesh_interface) {
if (data->parent_ifname)
@@ -5931,6 +6207,11 @@ int g_supplicant_interface_mesh_peer_change_status(
int g_supplicant_interface_create(const char *ifname, const char *driver,
const char *bridge,
+#ifdef TIZEN_EXT
+ unsigned int mac_policy,
+ unsigned int preassoc_mac_policy,
+ unsigned int random_mac_lifetime,
+#endif /* TIZEN_EXT */
GSupplicantInterfaceCallback callback,
void *user_data)
{
@@ -5953,6 +6234,11 @@ int g_supplicant_interface_create(const char *ifname, const char *driver,
data->driver = g_strdup(driver);
data->bridge = g_strdup(bridge);
data->callback = callback;
+#ifdef TIZEN_EXT
+ data->mac_addr = mac_policy;
+ data->preassoc_mac_addr = preassoc_mac_policy;
+ data->random_mac_lifetime = random_mac_lifetime;
+#endif /* TIZEN_EXT */
data->user_data = user_data;
ret = supplicant_dbus_method_call(SUPPLICANT_PATH,
@@ -6342,6 +6628,8 @@ static void interface_signalpoll_result(const char *error,
int err = 0;
dbus_int32_t maxspeed = 0;
dbus_int32_t strength = 0;
+ dbus_int32_t snr = 0;
+ dbus_uint32_t est_throughput = 0;
DBusMessageIter sub_iter, dict;
if (error) {
@@ -6350,7 +6638,12 @@ static void interface_signalpoll_result(const char *error,
goto out;
}
- dbus_message_iter_get_arg_type(iter);
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT) {
+ err = -EINVAL;
+ SUPPLICANT_DBG("invalid reply");
+ goto out;
+ }
+
dbus_message_iter_recurse(iter, &sub_iter);
dbus_message_iter_recurse(&sub_iter, &dict);
@@ -6368,19 +6661,27 @@ static void interface_signalpoll_result(const char *error,
if (g_strcmp0(key, "linkspeed") == 0) {
dbus_message_iter_get_basic(&value, &maxspeed);
SUPPLICANT_DBG("linkspeed = %d", maxspeed);
- break;
} else if (g_strcmp0(key, "rssi") == 0) {
dbus_message_iter_get_basic(&value, &strength);
SUPPLICANT_DBG("Strength = %d", strength);
- break;
+ } else if (g_strcmp0(key, "SNR") == 0) {
+ dbus_message_iter_get_basic(&value, &snr);
+ SUPPLICANT_DBG("SNR = %d", snr);
}
+ break;
+ case DBUS_TYPE_UINT32:
+ if (g_strcmp0(key, "est_throughput") == 0) {
+ dbus_message_iter_get_basic(&value, &est_throughput);
+ SUPPLICANT_DBG("est_throughput = %u", est_throughput);
+ }
+ break;
}
dbus_message_iter_next(&dict);
}
out:
if(data->callback)
- data->callback(err, maxspeed, strength, data->user_data);
+ data->callback(err, maxspeed, strength, snr, data->user_data, est_throughput);
g_free(data->path);
dbus_free(data);
@@ -6473,10 +6774,14 @@ static void interface_select_network_result(const char *error,
#if defined TIZEN_EXT
g_free(data->ssid->ssid);
- g_free((char *)data->ssid->passphrase);
- g_free((char *)data->ssid->connector);
- g_free((char *)data->ssid->c_sign_key);
- g_free((char *)data->ssid->net_access_key);
+ if (data->ssid->is_passphrase_alloc)
+ g_free((char *)data->ssid->passphrase);
+ if (data->ssid->is_connector_alloc)
+ g_free((char *)data->ssid->connector);
+ if (data->ssid->is_c_sign_key_alloc)
+ g_free((char *)data->ssid->c_sign_key);
+ if (data->ssid->is_net_access_key_alloc)
+ g_free((char *)data->ssid->net_access_key);
#endif
g_free(data->ssid);
dbus_free(data);
@@ -6565,10 +6870,14 @@ error:
g_free(data->path);
#if defined TIZEN_EXT
g_free(data->ssid->ssid);
- g_free((char *)data->ssid->passphrase);
- g_free((char *)data->ssid->connector);
- g_free((char *)data->ssid->c_sign_key);
- g_free((char *)data->ssid->net_access_key);
+ if (data->ssid->is_passphrase_alloc)
+ g_free((char *)data->ssid->passphrase);
+ if (data->ssid->is_connector_alloc)
+ g_free((char *)data->ssid->connector);
+ if (data->ssid->is_c_sign_key_alloc)
+ g_free((char *)data->ssid->c_sign_key);
+ if (data->ssid->is_net_access_key_alloc)
+ g_free((char *)data->ssid->net_access_key);
#endif
g_free(data->ssid);
g_free(data);
@@ -6719,10 +7028,8 @@ static void add_network_security_tls(DBusMessageIter *dict,
if (!ssid->private_key_path)
return;
-#if !defined TIZEN_EXT
if (!ssid->private_key_passphrase)
return;
-#endif
if (ssid->ca_cert_path)
supplicant_dbus_dict_append_basic(dict, "ca_cert",
@@ -6731,11 +7038,9 @@ static void add_network_security_tls(DBusMessageIter *dict,
supplicant_dbus_dict_append_basic(dict, "private_key",
DBUS_TYPE_STRING,
&ssid->private_key_path);
-#if !defined TIZEN_EXT
supplicant_dbus_dict_append_basic(dict, "private_key_passwd",
DBUS_TYPE_STRING,
&ssid->private_key_passphrase);
-#endif
supplicant_dbus_dict_append_basic(dict, "client_cert",
DBUS_TYPE_STRING,
&ssid->client_cert_path);
@@ -7030,17 +7335,6 @@ static void add_network_security_proto(DBusMessageIter *dict,
}
#if defined TIZEN_EXT
-static void add_network_ieee80211w(DBusMessageIter *dict, GSupplicantSSID *ssid)
-{
- if (ssid->security != G_SUPPLICANT_SECURITY_SAE
- && ssid->security != G_SUPPLICANT_SECURITY_OWE
- && ssid->security != G_SUPPLICANT_SECURITY_DPP)
- return;
-
- supplicant_dbus_dict_append_basic(dict, "ieee80211w", DBUS_TYPE_UINT32,
- &ssid->ieee80211w);
-}
-
static void add_network_security_connector(DBusMessageIter *dict, GSupplicantSSID *ssid)
{
if (ssid->connector && strlen(ssid->connector) > 0) {
@@ -7106,8 +7400,16 @@ static void add_network_security_net_access_key(DBusMessageIter *dict, GSupplica
#endif
+static void add_network_ieee80211w(DBusMessageIter *dict, GSupplicantSSID *ssid,
+ GSupplicantMfpOptions ieee80211w)
+{
+ supplicant_dbus_dict_append_basic(dict, "ieee80211w", DBUS_TYPE_UINT32,
+ &ieee80211w);
+}
+
static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
{
+ GSupplicantMfpOptions ieee80211w;
char *key_mgmt;
switch (ssid->security) {
@@ -7123,7 +7425,14 @@ static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
add_network_security_ciphers(dict, ssid);
break;
case G_SUPPLICANT_SECURITY_PSK:
+#if defined TIZEN_EXT
+ if (ssid->keymgmt & G_SUPPLICANT_KEYMGMT_WPA_FT_PSK)
+ key_mgmt = "FT-PSK WPA-PSK";
+ else
+ key_mgmt = "WPA-PSK";
+#else
key_mgmt = "WPA-PSK";
+#endif
add_network_security_psk(dict, ssid);
add_network_security_ciphers(dict, ssid);
add_network_security_proto(dict, ssid);
@@ -7135,6 +7444,15 @@ static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
add_network_security_proto(dict, ssid);
break;
#if defined TIZEN_EXT
+ case G_SUPPLICANT_SECURITY_PSK_SHA256:
+ if (ssid->keymgmt & G_SUPPLICANT_KEYMGMT_WPA_PSK)
+ key_mgmt = "WPA-PSK-SHA256 WPA-PSK";
+ else
+ key_mgmt = "WPA-PSK-SHA256";
+ add_network_security_psk(dict, ssid);
+ add_network_security_ciphers(dict, ssid);
+ add_network_security_proto(dict, ssid);
+ break;
case G_SUPPLICANT_SECURITY_FT_PSK:
key_mgmt = "FT-PSK";
add_network_security_psk(dict, ssid);
@@ -7148,11 +7466,24 @@ static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
add_network_security_proto(dict, ssid);
break;
case G_SUPPLICANT_SECURITY_SAE:
- if (ssid->keymgmt & G_SUPPLICANT_KEYMGMT_WPA_PSK)
- key_mgmt = "SAE WPA-PSK"; // WFA (WPA3 & WPA2 Mixed -> WPA2 only)
- else
- key_mgmt = "SAE";
+ if (ssid->keymgmt & G_SUPPLICANT_KEYMGMT_FT_SAE) {
+ if (ssid->keymgmt & G_SUPPLICANT_KEYMGMT_SAE)
+ key_mgmt = "FT-SAE SAE";
+ else
+ key_mgmt = "FT-SAE";
+ } else {
+ if (ssid->keymgmt & G_SUPPLICANT_KEYMGMT_WPA_PSK) {
+ key_mgmt = "SAE WPA-PSK";
+ ieee80211w = G_SUPPLICANT_MFP_OPTIONAL;
+ } else {
+ key_mgmt = "SAE";
+ ieee80211w = G_SUPPLICANT_MFP_REQUIRED;
+ }
+ add_network_ieee80211w(dict, ssid, ieee80211w);
+ }
add_network_security_psk(dict, ssid);
+ add_network_security_ciphers(dict, ssid);
+ add_network_security_proto(dict, ssid);
break;
case G_SUPPLICANT_SECURITY_OWE:
key_mgmt = "OWE";
@@ -7225,10 +7556,6 @@ static void interface_add_network_params(DBusMessageIter *iter, void *user_data)
add_network_security(&dict, ssid);
-#if defined TIZEN_EXT
- add_network_ieee80211w(&dict, ssid);
-#endif
-
supplicant_dbus_dict_append_fixed_array(&dict, "ssid",
DBUS_TYPE_BYTE, &ssid->ssid,
ssid->ssid_len);
@@ -7410,6 +7737,12 @@ static void decryption_request_reply(DBusPendingCall *call,
goto done;
}
+ if (!g_str_has_prefix(data->interface->path, "/")) {
+ SUPPLICANT_DBG("Invalid path %s", data->interface->path);
+ ret = -EINVAL;
+ goto done;
+ }
+
if (dbus_message_iter_init(reply, &args) == FALSE) {
SUPPLICANT_DBG("dbus_message_iter_init() failed");
ret = -EINVAL;
@@ -7418,6 +7751,7 @@ static void decryption_request_reply(DBusPendingCall *call,
dbus_message_iter_get_basic(&args, &out_data);
data->ssid->passphrase = g_strdup((const gchar *)out_data);
+ data->ssid->is_passphrase_alloc = true;
ret = supplicant_dbus_method_call(data->interface->path,
SUPPLICANT_INTERFACE ".Interface", "AddNetwork",
@@ -7431,10 +7765,14 @@ done:
callback_assoc_failed(decrypt_request_data.data->user_data);
g_free(data->path);
g_free(data->ssid->ssid);
- g_free((char *)data->ssid->passphrase);
- g_free((char *)data->ssid->connector);
- g_free((char *)data->ssid->c_sign_key);
- g_free((char *)data->ssid->net_access_key);
+ if (data->ssid->is_passphrase_alloc)
+ g_free((char *)data->ssid->passphrase);
+ if (data->ssid->is_connector_alloc)
+ g_free((char *)data->ssid->connector);
+ if (data->ssid->is_c_sign_key_alloc)
+ g_free((char *)data->ssid->c_sign_key);
+ if (data->ssid->is_net_access_key_alloc)
+ g_free((char *)data->ssid->net_access_key);
g_free(data->ssid);
dbus_free(data);
}
@@ -7467,8 +7805,16 @@ static int send_decryption_request(const char *passphrase,
if (!msg)
return -EINVAL;
+#if defined TIZEN_EXT
+ if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &passphrase,
+ DBUS_TYPE_INVALID)) {
+ SUPPLICANT_DBG("Could not fulfill decryption request");
+ return -ENOMEM;
+ }
+#else
dbus_message_append_args(msg, DBUS_TYPE_STRING, &passphrase,
DBUS_TYPE_INVALID);
+#endif
if (!dbus_connection_send_with_reply(connection, msg,
&call, DBUS_TIMEOUT_USE_DEFAULT)) {
@@ -7532,14 +7878,17 @@ static void decrypt_conf_obj_reply(DBusPendingCall *call,
if (g_strcmp0(key, "connector") == 0) {
dbus_message_iter_get_basic(&value, &out_data);
data->ssid->connector = g_strdup((const gchar *)out_data);
+ data->ssid->is_connector_alloc = true;
SUPPLICANT_DBG("connector %s", data->ssid->connector);
} else if (g_strcmp0(key, "c_sign_key") == 0) {
dbus_message_iter_get_basic(&value, &out_data);
data->ssid->c_sign_key = g_strdup((const gchar *)out_data);
+ data->ssid->is_c_sign_key_alloc = true;
SUPPLICANT_DBG("c_sign_key %s", data->ssid->c_sign_key);
} else if (g_strcmp0(key, "net_access_key") == 0) {
dbus_message_iter_get_basic(&value, &out_data);
data->ssid->net_access_key = g_strdup((const gchar *)out_data);
+ data->ssid->is_net_access_key_alloc = true;
SUPPLICANT_DBG("net_access_key %s", data->ssid->net_access_key);
}
}
@@ -7558,9 +7907,12 @@ done:
callback_assoc_failed(decrypt_request_data.data->user_data);
g_free(data->path);
g_free(data->ssid->ssid);
- g_free((char *)data->ssid->connector);
- g_free((char *)data->ssid->c_sign_key);
- g_free((char *)data->ssid->net_access_key);
+ if (data->ssid->is_connector_alloc)
+ g_free((char *)data->ssid->connector);
+ if (data->ssid->is_c_sign_key_alloc)
+ g_free((char *)data->ssid->c_sign_key);
+ if (data->ssid->is_net_access_key_alloc)
+ g_free((char *)data->ssid->net_access_key);
g_free(data->ssid);
dbus_free(data);
}
@@ -7739,7 +8091,7 @@ int g_supplicant_interface_connect(GSupplicantInterface *interface,
interface_add_network_result, data,
interface);
}
- }
+ }
if (ret < 0) {
g_free(data->path);
@@ -7944,6 +8296,49 @@ int g_supplicant_interface_disconnect(GSupplicantInterface *interface,
return ret;
}
+#if defined TIZEN_EXT
+void g_supplicant_interface_remove_network(GSupplicantInterface *interface,
+ GSupplicantSSID *ssid)
+{
+ struct interface_data *data;
+ int ret;
+
+ SUPPLICANT_DBG("");
+
+ if (!interface)
+ return;
+
+ if (interface->network_path == NULL)
+ return;
+
+ if (!interface->network_info.ssid)
+ return;
+
+ if (memcmp(interface->network_info.ssid, ssid->ssid, ssid->ssid_len))
+ return;
+
+ if (interface->network_info.security != ssid->security)
+ return;
+
+ data = dbus_malloc0(sizeof(*data));
+ if (!data)
+ return;
+
+ data->interface = interface;
+ data->path = g_strdup(interface->path);
+
+ ret = supplicant_dbus_method_call(interface->path,
+ SUPPLICANT_INTERFACE ".Interface", "RemoveNetwork",
+ network_remove_params, network_remove_result, data,
+ interface);
+
+ if (ret < 0) {
+ g_free(data->path);
+ dbus_free(data);
+ }
+}
+#endif
+
static void interface_p2p_find_result(const char *error,
DBusMessageIter *iter, void *user_data)
{
@@ -8469,7 +8864,7 @@ void g_supplicant_set_ins_settings(GSupplicantINSPreferredFreq preferred_freq_bs
SUPPLICANT_DBG("signal_level3_5ghz [%d]", signal_level3_5ghz);
SUPPLICANT_DBG("signal_level3_24ghz [%d]", signal_level3_24ghz);
}
-#endif
+#endif /* defined TIZEN_EXT */
#if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
void g_supplicant_register_eap_callback(g_supplicant_eap_callback cb)
@@ -8654,3 +9049,176 @@ void g_supplicant_unregister(const GSupplicantCallbacks *callbacks)
callbacks_pointer = NULL;
eap_methods = 0;
}
+
+#ifdef TIZEN_EXT
+struct supplicant_mac_policy {
+ GSupplicantMacPolicyCallback callback;
+ dbus_uint32_t policy;
+ const void *user_data;
+};
+
+static void mac_policy_result(const char *error,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct supplicant_mac_policy *data = user_data;
+ int result = 0;
+
+ if (!user_data)
+ return;
+
+ if (error) {
+ SUPPLICANT_DBG("Mac policy setting failure %s", error);
+ result = -EINVAL;
+ }
+
+ if (data->callback)
+ data->callback(result, data->policy,
+ (void *) data->user_data);
+
+ dbus_free(data);
+}
+
+static void mac_policy_params(DBusMessageIter *iter, void *user_data)
+{
+ struct supplicant_mac_policy *data = user_data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &(data->policy));
+}
+
+int g_supplicant_interface_set_mac_policy(GSupplicantInterface *interface,
+ GSupplicantMacPolicyCallback callback,
+ unsigned int policy,
+ void *user_data)
+{
+ struct supplicant_mac_policy *data = NULL;
+ int ret;
+
+ if (!system_available)
+ return -EFAULT;
+
+ if (!interface)
+ return -EINVAL;
+
+ data = dbus_malloc0(sizeof(*data));
+ if (!data)
+ return -ENOMEM;
+
+ data->callback = callback;
+ data->policy = policy;
+ data->user_data = user_data;
+
+ ret = supplicant_dbus_property_set(interface->path,
+ SUPPLICANT_INTERFACE ".Interface",
+ "MacAddr", DBUS_TYPE_INT32_AS_STRING,
+ mac_policy_params, mac_policy_result, data, NULL);
+ if (ret < 0) {
+ SUPPLICANT_DBG("Unable to set MacAddr configuration");
+ dbus_free(data);
+ }
+
+ return ret;
+}
+
+int g_supplicant_interface_set_preassoc_mac_policy(GSupplicantInterface *interface,
+ GSupplicantMacPolicyCallback callback,
+ unsigned int policy,
+ void *user_data)
+{
+ struct supplicant_mac_policy *data;
+ int ret;
+
+ if (!system_available)
+ return -EFAULT;
+
+ if (!interface)
+ return -EINVAL;
+
+ data = dbus_malloc0(sizeof(*data));
+ if (!data)
+ return -ENOMEM;
+
+ data->callback = callback;
+ data->policy = policy;
+ data->user_data = user_data;
+
+ ret = supplicant_dbus_property_set(interface->path,
+ SUPPLICANT_INTERFACE ".Interface",
+ "PreassocMacAddr", DBUS_TYPE_INT32_AS_STRING,
+ mac_policy_params, mac_policy_result, data, NULL);
+ if (ret < 0) {
+ SUPPLICANT_DBG("Unable to set PreassocMacAddr configuration");
+ dbus_free(data);
+ }
+
+ return ret;
+}
+
+struct supplicant_random_mac_lifetime {
+ GSupplicantRandomMaclifetimeCallback callback;
+ dbus_uint32_t lifetime;
+ const void *user_data;
+};
+
+static void random_mac_lifetime_result(const char *error,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct supplicant_random_mac_lifetime *data = user_data;
+ int result = 0;
+
+ if (!user_data)
+ return;
+
+ if (error) {
+ SUPPLICANT_DBG("Random Mac lifetime setting failure %s", error);
+ result = -EINVAL;
+ }
+
+ if (data->callback)
+ data->callback(result, data->lifetime,
+ (void *) data->user_data);
+
+ dbus_free(data);
+}
+
+static void random_mac_lifetime_params(DBusMessageIter *iter, void *user_data)
+{
+ struct supplicant_random_mac_lifetime *data = user_data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &(data->lifetime));
+}
+
+int g_supplicant_interface_set_random_mac_lifetime(GSupplicantInterface *interface,
+ GSupplicantRandomMaclifetimeCallback callback,
+ unsigned int lifetime,
+ void *user_data)
+{
+ struct supplicant_random_mac_lifetime *data;
+ int ret;
+
+ if (!system_available)
+ return -EFAULT;
+
+ if (!interface)
+ return -EINVAL;
+
+ data = dbus_malloc0(sizeof(*data));
+ if (!data)
+ return -ENOMEM;
+
+ data->callback = callback;
+ data->lifetime = lifetime;
+ data->user_data = user_data;
+
+ ret = supplicant_dbus_property_set(interface->path,
+ SUPPLICANT_INTERFACE ".Interface",
+ "RandAddrLifetime", DBUS_TYPE_UINT32_AS_STRING,
+ random_mac_lifetime_params, random_mac_lifetime_result,
+ data, NULL);
+ if (ret < 0) {
+ SUPPLICANT_DBG("Unable to set RandAddrLifetime configuration");
+ dbus_free(data);
+ }
+
+ return ret;
+}
+#endif
diff --git a/gweb/gresolv.c b/gweb/gresolv.c
index 38a554e0..954e7cfe 100755
--- a/gweb/gresolv.c
+++ b/gweb/gresolv.c
@@ -315,7 +315,8 @@ static int match_gai_table(struct sockaddr *sa, const struct gai_table *tbl)
}
}
-#define DQUAD(_a,_b,_c,_d) ( ((_a)<<24) | ((_b)<<16) | ((_c)<<8) | (_d) )
+#define DQUAD(_a,_b,_c,_d) ( (((uint32_t)_a)<<24) | (((uint32_t)_b)<<16) | \
+ (((uint32_t)_c)<<8) | ((uint32_t)_d) )
#define V4MATCH(addr, a,b,c,d, m) ( ((addr) ^ DQUAD(a,b,c,d)) >> (32 - (m)) )
#define RFC3484_SCOPE_LINK 2
@@ -326,7 +327,7 @@ static int addr_scope(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
struct sockaddr_in *sin = (void *)sa;
- guint32 addr = ntohl(sin->sin_addr.s_addr);
+ uint32_t addr = ntohl(sin->sin_addr.s_addr);
if (V4MATCH(addr, 169,254,0,0, 16) ||
V4MATCH(addr, 127,0,0,0, 8))
diff --git a/gweb/gweb.c b/gweb/gweb.c
index 7037cd94..69aea5b7 100755
--- a/gweb/gweb.c
+++ b/gweb/gweb.c
@@ -1288,7 +1288,8 @@ static bool is_ip_address(const char *host)
addr = NULL;
result = getaddrinfo(host, NULL, &hints, &addr);
- freeaddrinfo(addr);
+ if(!result)
+ freeaddrinfo(addr);
return result == 0;
}
diff --git a/include/device.h b/include/device.h
index 67d7928c..acbd1d54 100755
--- a/include/device.h
+++ b/include/device.h
@@ -118,7 +118,10 @@ void connman_device_set_max_scan_ssids(struct connman_device *device,
int connman_device_get_max_scan_ssids(struct connman_device *device);
void connman_device_set_wifi_5ghz_supported(struct connman_device *device,
bool is_5_0_ghz_supported);
+void connman_device_set_wifi_6ghz_supported(struct connman_device *device,
+ bool is_6_0_ghz_supported);
bool connman_device_get_wifi_5ghz_supported(struct connman_device *device);
+bool connman_device_get_wifi_6ghz_supported(struct connman_device *device);
#endif
int connman_device_remove_network(struct connman_device *device,
struct connman_network *network);
@@ -151,6 +154,22 @@ void connman_device_save_last_user_selection(struct connman_device *device);
void connman_device_load_last_user_selection(struct connman_device *device);
void connman_device_save_last_connected(struct connman_device *device);
void connman_device_load_last_connected(struct connman_device *device);
+
+void connman_device_mac_policy_notify(struct connman_device *device,
+ int result, unsigned int policy);
+int connman_device_set_mac_policy(struct connman_device *device,
+ unsigned int policy);
+unsigned int connman_device_get_mac_policy(struct connman_device *device);
+void connman_device_preassoc_mac_policy_notify(struct connman_device *device,
+ int result, unsigned int policy);
+int connman_device_set_preassoc_mac_policy(struct connman_device *device,
+ unsigned int policy);
+unsigned int connman_device_get_preassoc_mac_policy(struct connman_device *device);
+void connman_device_random_mac_lifetime_notify(struct connman_device *device,
+ int result, unsigned int lifetime);
+int connman_device_set_random_mac_lifetime(struct connman_device *device,
+ unsigned int lifetime);
+unsigned int connman_device_get_random_mac_lifetime(struct connman_device *device);
#endif
struct connman_device_driver {
@@ -171,6 +190,9 @@ struct connman_device_driver {
int (*specific_scan) (enum connman_service_type type,
struct connman_device *device, int scan_type,
GSList *specific_scan_list, void *user_data);
+ int (*set_mac_policy) (struct connman_device *device, unsigned int policy);
+ int (*set_preassoc_mac_policy) (struct connman_device *device, unsigned int policy);
+ int (*set_random_mac_lifetime) (struct connman_device *device, unsigned int lifetime);
#endif
#if defined TIZEN_EXT_WIFI_MESH
int (*abort_scan) (enum connman_service_type type,
diff --git a/include/inet.h b/include/inet.h
index 4844979b..579f7f7e 100644
--- a/include/inet.h
+++ b/include/inet.h
@@ -55,10 +55,11 @@ int connman_inet_clear_gateway_address(int index, const char *gateway);
int connman_inet_set_gateway_interface(int index);
int connman_inet_clear_gateway_interface(int index);
bool connman_inet_compare_subnet(int index, const char *host);
+bool connman_inet_compare_ipv6_subnet(int index, const char *host);
int connman_inet_set_ipv6_address(int index,
struct connman_ipaddress *ipaddress);
int connman_inet_clear_ipv6_address(int index,
- const char *address, int prefix_len);
+ struct connman_ipaddress *ipaddress);
int connman_inet_add_ipv6_network_route(int index, const char *host,
const char *gateway, unsigned char prefix_len);
int connman_inet_add_ipv6_host_route(int index, const char *host,
@@ -81,6 +82,14 @@ int connman_inet_ipv6_get_dest_addr(int index, char **dest);
int connman_inet_check_ipaddress(const char *host);
bool connman_inet_check_hostname(const char *ptr, size_t len);
bool connman_inet_is_ipv6_supported();
+bool connman_inet_is_default_route(int family, const char *host,
+ const char *gateway, const char *netmask);
+
+int connman_inet_get_route_addresses(int index, char **network, char **netmask,
+ char **destination);
+int connman_inet_ipv6_get_route_addresses(int index, char **network,
+ char **netmask,
+ char **destination);
#if defined TIZEN_EXT_WIFI_MESH
char *connman_inet_ifaddr(const char *name);
diff --git a/include/ipaddress.h b/include/ipaddress.h
index 3655ca86..652db0f0 100755
--- a/include/ipaddress.h
+++ b/include/ipaddress.h
@@ -22,6 +22,8 @@
#ifndef __CONNMAN_IPADDRESS_H
#define __CONNMAN_IPADDRESS_H
+#include <stdbool.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -36,6 +38,8 @@ struct connman_ipaddress;
unsigned char connman_ipaddress_calc_netmask_len(const char *netmask);
struct connman_ipaddress *connman_ipaddress_alloc(int family);
+void connman_ipaddress_set_p2p(struct connman_ipaddress *ipaddress,
+ bool value);
void connman_ipaddress_free(struct connman_ipaddress *ipaddress);
int connman_ipaddress_set_ipv4(struct connman_ipaddress *ipaddress,
const char *address, const char *netmask,
diff --git a/include/log.h b/include/log.h
index 7687ed0b..9403633d 100755
--- a/include/log.h
+++ b/include/log.h
@@ -22,6 +22,10 @@
#ifndef __CONNMAN_LOG_H
#define __CONNMAN_LOG_H
+#if defined TIZEN_EXT
+#include <stdbool.h>
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -86,6 +90,14 @@ struct connman_debug_desc {
__FILE__, __FUNCTION__ , ## arg); \
} while (0)
+#if defined TIZEN_EXT
+#define simplified_log get_simple_log_option()
+bool get_simple_log_option(void);
+void set_simple_log_option(bool option);
+void set_dlog_logging_option(bool option);
+void set_file_logging_option(bool option);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/include/network.h b/include/network.h
index c5b10552..f9bd3c0a 100755
--- a/include/network.h
+++ b/include/network.h
@@ -66,6 +66,7 @@ enum connman_network_error {
#if defined TIZEN_EXT
CONNMAN_NETWORK_ERROR_DHCP_FAIL = 5,
CONNMAN_NETWORK_ERROR_BLOCKED = 6,
+ CONNMAN_NETWORK_ERROR_AUTHENTICATE_FAIL = 7,
#else
CONNMAN_NETWORK_ERROR_BLOCKED = 5,
#endif
@@ -78,12 +79,10 @@ struct connman_bssids {
uint16_t frequency;
uint16_t assoc_reject_cnt;
bool is_last_connected;
-#if defined TIZEN_EXT_INS
int score_last_connected_bssid;
int score_assoc_reject;
int score_frequency;
int score_strength;
-#endif
int ins_score;
};
@@ -203,6 +202,10 @@ unsigned int connman_network_get_maxrate(struct connman_network *network);
int connman_network_get_maxspeed(struct connman_network *network);
+int connman_network_set_sec_list(struct connman_network *network,
+ GSList *sec_list);
+void *connman_network_get_sec_list(struct connman_network *network);
+
int connman_network_set_enc_mode(struct connman_network *network,
const char *encryption_mode);
const char *connman_network_get_enc_mode(struct connman_network *network);
@@ -230,20 +233,30 @@ unsigned char *connman_network_get_countrycode(struct connman_network *network);
int connman_network_set_bssid_list(struct connman_network *network,
GSList *bssids);
void *connman_network_get_bssid_list(struct connman_network *network);
-#if defined TIZEN_EXT
+unsigned int connman_network_get_max_bssid_count(struct connman_network *network);
+
int connman_network_set_last_connected_bssid(struct connman_network *network,
const unsigned char *bssid);
unsigned char *connman_network_get_last_connected_bssid(struct connman_network *network);
void connman_network_set_assoc_reject_table(struct connman_network *network,
GHashTable *assoc_reject_table);
GHashTable *connman_network_get_assoc_reject_table(struct connman_network *network);
-#endif
+
+__time_t connman_network_get_roam_scan_time(struct connman_network *network);
+void connman_network_set_roam_scan_time(struct connman_network *network,
+ __time_t roam_scan_time);
+int connman_network_get_snr(struct connman_network *network);
+void connman_network_set_snr(struct connman_network *network, int snr);
+unsigned int connman_network_get_est_throughput(struct connman_network *network);
+void connman_network_set_est_throughput(struct connman_network *network,
+ unsigned int est_throughput);
int connman_network_set_phy_mode(struct connman_network *network,
ieee80211_modes_e mode);
ieee80211_modes_e connman_network_get_phy_mode(struct connman_network *network);
int connman_network_set_connection_mode(struct connman_network *network,
connection_mode_e mode);
connection_mode_e connman_network_get_connection_mode(struct connman_network *network);
+int set_connected_dhcp(struct connman_network *network);
#endif
int connman_network_set_name(struct connman_network *network,
@@ -257,6 +270,8 @@ uint16_t connman_network_get_frequency(struct connman_network *network);
int connman_network_set_wifi_channel(struct connman_network *network,
uint16_t channel);
uint16_t connman_network_get_wifi_channel(struct connman_network *network);
+int connman_network_set_autoconnect(struct connman_network *network,
+ bool autoconnect);
int connman_network_set_string(struct connman_network *network,
const char *key, const char *value);
@@ -290,6 +305,8 @@ struct connman_network_driver {
void (*remove) (struct connman_network *network);
int (*connect) (struct connman_network *network);
int (*disconnect) (struct connman_network *network);
+ int (*set_autoconnect) (struct connman_network *network,
+ bool autoconnect);
#if defined TIZEN_EXT
int (*merge) (struct connman_network *network);
#endif
diff --git a/include/option.h b/include/option.h
deleted file mode 100755
index 5e97ed4c..00000000
--- a/include/option.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *
- * Connection Manager
- *
- * Copyright (C) 2007-2012 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifndef __CONNMAN_OPTION_H
-#define __CONNMAN_OPTION_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-const char *connman_option_get_string(const char *key);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __CONNMAN_OPTION_H */
diff --git a/include/provider.h b/include/provider.h
index d28651ad..1f120990 100755
--- a/include/provider.h
+++ b/include/provider.h
@@ -111,8 +111,12 @@ int connman_provider_set_domain(struct connman_provider *provider,
const char *domain);
int connman_provider_set_nameservers(struct connman_provider *provider,
char * const *nameservers);
-int connman_provider_append_route(struct connman_provider *provider,
- const char *key, const char *value);
+void connman_provider_set_autoconnect(struct connman_provider *provider,
+ bool flag);
+bool connman_provider_is_split_routing(struct connman_provider *provider);
+int connman_provider_set_split_routing(struct connman_provider *provider,
+ bool split_routing);
+int connman_provider_get_family(struct connman_provider *provider);
const char *connman_provider_get_driver_name(struct connman_provider *provider);
const char *connman_provider_get_save_group(struct connman_provider *provider);
diff --git a/include/service.h b/include/service.h
index 1e4a6926..f27e4243 100755
--- a/include/service.h
+++ b/include/service.h
@@ -100,6 +100,9 @@ enum connman_service_error {
CONNMAN_SERVICE_ERROR_AUTH_FAILED = 6,
CONNMAN_SERVICE_ERROR_INVALID_KEY = 7,
CONNMAN_SERVICE_ERROR_BLOCKED = 8,
+#if defined TIZEN_EXT
+ CONNMAN_SERVICE_ERROR_ASSOC_FAILED = 9,
+#endif
};
enum connman_service_proxy_method {
@@ -114,6 +117,7 @@ enum connman_service_connect_reason {
CONNMAN_SERVICE_CONNECT_REASON_AUTO = 1,
CONNMAN_SERVICE_CONNECT_REASON_USER = 2,
CONNMAN_SERVICE_CONNECT_REASON_SESSION = 3,
+ CONNMAN_SERVICE_CONNECT_REASON_NATIVE = 4,
};
struct connman_service;
@@ -151,6 +155,8 @@ const char *connman_service_get_proxy_url(struct connman_service *service);
const char *connman_service_get_proxy_autoconfig(struct connman_service *service);
bool connman_service_get_favorite(struct connman_service *service);
bool connman_service_get_autoconnect(struct connman_service *service);
+bool connman_service_set_autoconnect(struct connman_service *service,
+ bool autoconnect);
/* Return non-zero value to terminate the loop, zero to continue */
typedef int (* connman_service_iterate_cb) (struct connman_service *service,
@@ -194,6 +200,7 @@ gboolean connman_service_is_no_ref_user_pdn_connection(
struct connman_service *service);
struct connman_service *connman_service_get_default_connection(void);
+struct connman_service *connman_service_get_connected_service(const char *ifname);
/*
* Description: telephony plug-in requires manual PROXY setting
@@ -202,14 +209,15 @@ int connman_service_set_proxy(struct connman_service *service,
const char *proxy, gboolean active);
void connman_service_set_disconnection_requested(struct connman_service *service,
- bool disconnection_requested);
+ bool disconnection_requested);
+void connman_service_notify_reconnection_roaming(struct connman_service *service);
#endif
#if defined TIZEN_EXT
void connman_service_set_internet_connection(struct connman_service *service,
bool internet_connection);
bool connman_service_get_internet_connection(struct connman_service *service);
-DBusMessage *connman_service_get_defaut_info(DBusMessage *msg,
+DBusMessage *connman_service_create_dbus_service_reply(DBusMessage *msg,
struct connman_service *service);
#endif
diff --git a/include/setting.h b/include/setting.h
index 3625f3e3..4fb4957b 100755
--- a/include/setting.h
+++ b/include/setting.h
@@ -28,11 +28,22 @@
extern "C" {
#endif
-bool connman_setting_get_bool(const char *key);
#if defined TIZEN_EXT
-unsigned int connman_setting_get_uint(const char *key);
+/* AP selection method to be used */
+typedef enum {
+ AP_SELECTION_METHOD_NORMAL = 0,
+ AP_SELECTION_METHOD_INS = 1,
+} ap_selection_method_e;
+
+#define TIZEN_INS_ENABLED \
+ (connman_setting_get_int("ApSelectionMethod") == AP_SELECTION_METHOD_INS)
+
int connman_setting_get_int(const char *key);
#endif
+
+bool connman_setting_get_bool(const char *key);
+unsigned int connman_setting_get_uint(const char *key);
+char *connman_setting_get_string(const char *key);
char **connman_setting_get_string_list(const char *key);
unsigned int *connman_setting_get_uint_list(const char *key);
diff --git a/include/task.h b/include/task.h
index 9977d634..b124db7a 100755
--- a/include/task.h
+++ b/include/task.h
@@ -42,7 +42,11 @@ typedef void (* connman_task_exit_t) (struct connman_task *task,
typedef DBusMessage * (* connman_task_notify_t) (struct connman_task *task,
DBusMessage *message, void *user_data);
-struct connman_task *connman_task_create(const char *program);
+typedef void (* connman_task_setup_t) (void *setup_data);
+
+struct connman_task *connman_task_create(const char *program,
+ connman_task_setup_t task_setup,
+ void *setup_data);
void connman_task_destroy(struct connman_task *task);
const char *connman_task_get_path(struct connman_task *task);
diff --git a/include/technology.h b/include/technology.h
index d06678e0..c7898396 100755
--- a/include/technology.h
+++ b/include/technology.h
@@ -65,8 +65,10 @@ void connman_technology_regdom_notify(struct connman_technology *technology,
enum connman_service_type connman_technology_get_type
(struct connman_technology *technology);
-bool connman_technology_get_wifi_tethering(const char **ssid,
- const char **psk);
+
+bool connman_technology_get_wifi_tethering(const struct connman_technology *technology,
+ const char **ssid, const char **psk, int *freq);
+
bool connman_technology_is_tethering_allowed(enum connman_service_type type);
struct connman_technology_driver {
@@ -81,7 +83,6 @@ struct connman_technology_driver {
void (*remove_interface) (struct connman_technology *technology,
int index);
int (*set_tethering) (struct connman_technology *technology,
- const char *identifier, const char *passphrase,
const char *bridge, bool enabled);
int (*set_regdom) (struct connman_technology *technology,
const char *alpha2);
@@ -94,6 +95,10 @@ const char *connman_techonology_get_path(enum connman_service_type type);
void __connman_technology_notify_scan_done(const char *ifname, int val);
void __connman_technology_append_interfaces(DBusMessageIter *array,
enum connman_service_type type, const char *ifname);
+void __connman_technology_notify_device_detected_by_device(
+ struct connman_device *device, const char *ifname, bool val);
+void __connman_technology_notify_roaming_state(const char *ifname,
+ const char *state, const char *cur_bssid, const char *dst_bssid);
#endif
#ifdef __cplusplus
diff --git a/isu/isu.cfg b/isu/isu.cfg
new file mode 100644
index 00000000..ebfaa2dd
--- /dev/null
+++ b/isu/isu.cfg
@@ -0,0 +1,8 @@
+[isu]
+name=#NAME#
+version=#VERSION#
+system_service=connman.service
+
+[files]
+/usr/bin/connmand
+/etc/connman/main.conf
diff --git a/isu/system-services/connman.service b/isu/system-services/connman.service
new file mode 100644
index 00000000..78abb6e7
--- /dev/null
+++ b/isu/system-services/connman.service
@@ -0,0 +1,24 @@
+[Unit]
+Description=Connection service
+Conflicts=shutdown.target
+RequiresMountsFor=/var/lib/connman
+After=dbus.service network-pre.target systemd-sysusers.service net-config.service
+Before=network.target multi-user.target shutdown.target
+Wants=network.target
+
+[Service]
+Type=dbus
+User=network_fw
+Group=network_fw
+BusName=net.connman
+Restart=on-failure
+SmackProcessLabel=System
+BindReadOnlyPaths=#ISU_RUN_PATH#/connman/rootfs/etc/connman:/etc/connman
+BindPaths=#ISU_RUN_PATH#/connman/rootfs/usr/bin/connmand:/usr/bin/connmand
+ExecStart=/usr/bin/connmand -n --nobacktrace --noplugin vpn
+Capabilities=cap_setgid,cap_net_admin,cap_net_bind_service,cap_net_broadcast,cap_net_raw,cap_dac_override=i
+StandardOutput=null
+SecureBits=keep-caps
+
+[Install]
+WantedBy=multi-user.target
diff --git a/packaging/connman.spec b/packaging/connman.spec
index 56cf4063..c97b261d 100644
--- a/packaging/connman.spec
+++ b/packaging/connman.spec
@@ -1,11 +1,12 @@
%bcond_with connman_openconnect
+%bcond_without connman_wireguard
%bcond_without connman_openvpn
%bcond_without connman_ipsec
%bcond_without connman_vpnd
Name: connman
-Version: 1.37
-Release: 48
+Version: 1.41
+Release: 2
License: GPL-2.0+
Summary: Connection Manager
Url: http://connman.net
@@ -21,7 +22,7 @@ BuildRequires: pkgconfig(xtables)
BuildRequires: pkgconfig(libsmack)
BuildRequires: pkgconfig(libnl-3.0)
BuildRequires: pkgconfig(libnl-genl-3.0)
-BuildRequires: pkgconfig(libsystemd-daemon)
+BuildRequires: pkgconfig(libsystemd)
%if %{with connman_openconnect}
BuildRequires: openconnect
%endif
@@ -38,11 +39,11 @@ Requires: systemd
Requires(post): systemd
Requires(preun): systemd
Requires(postun): systemd
-Requires: net-config
Requires: security-config
Provides: %{name}-profile_common = %{version}-%{release}
Provides: %{name}-profile_mobile = %{version}-%{release}
Provides: %{name}-profile_wearable = %{version}-%{release}
+Provides: %{name}-profile_robot = %{version}-%{release}
%description
Connection Manager provides a daemon for managing Internet connections
@@ -88,6 +89,16 @@ Requires: %{name} = %{version}
Provides VPN support for Connman
%endif
+%if %{with connman_wireguard}
+%package plugin-wireguard
+Summary: Wireguard Support for Connman
+BuildRequires: pkgconfig(libmnl)
+Requires: %{name} = %{version}
+
+%description plugin-wireguard
+Wireguard Support for Connman.
+%endif
+
%package test
Summary: Test Scripts for Connection Manager
Group: Development/Tools
@@ -100,7 +111,7 @@ Requires: python-xml
Scripts for testing Connman and its functionality
%package devel
-Summary: Development Files for connman
+Summary: Development files for connman
Group: Development/Tools
Requires: %{name} = %{version}
@@ -136,6 +147,18 @@ Conflicts: %{name}-extension-ivi
Connman without ethernet support
This overwrites conf file of %{name}.
+%package profile_robot
+Summary: connman extension for robot profile
+Requires: %{name} = %{version}-%{release}
+%description profile_robot
+connman extension for Tizen robot profile
+
+%package isu
+Summary: connman ISU pacakge
+Group: Network & Connectivity/Connection Management
+%description isu
+Configuration files to generate the ISU (Individual Service Upgrade) package
+
%prep
%setup -q
@@ -151,8 +174,7 @@ chmod +x bootstrap
--sysconfdir=/etc \
--enable-client \
--enable-tizen-ext \
- --disable-tizen-ext-ins \
- --enable-tizen-ext-eap-on-ethernet \
+ --enable-tizen-ext-eap-on-ethernet \
--enable-pacrunner \
--enable-wifi=builtin \
%if %{with connman_openconnect}
@@ -164,6 +186,9 @@ chmod +x bootstrap
%if %{with connman_ipsec}
--enable-ipsec \
%endif
+%if %{without connman_wireguard}
+ --disable-wireguard \
+%endif
%if 0%{?enable_connman_features}
%connman_features \
%endif
@@ -207,11 +232,13 @@ mkdir -p %{buildroot}/etc/connman
cp src/main_ivi.conf %{buildroot}/etc/connman/main.conf.ivi
cp src/main_tv.conf %{buildroot}/etc/connman/main.conf.tv
cp src/main_disable_eth.conf %{buildroot}/etc/connman/main.conf.disable.eth
+cp src/main_robot.conf %{buildroot}/etc/connman/main.conf.robot
cp src/main.conf %{buildroot}/etc/connman/main.conf
rm %{buildroot}%{_sysconfdir}/dbus-1/system.d/*.conf
mkdir -p %{buildroot}%{_sysconfdir}/dbus-1/system.d/
cp src/connman.conf %{buildroot}%{_sysconfdir}/dbus-1/system.d/
+cp src/connman-robot.conf %{buildroot}%{_sysconfdir}/dbus-1/system.d/
%if %{with connman_vpnd}
cp vpn/vpn-dbus.conf %{buildroot}%{_sysconfdir}/dbus-1/system.d/connman-vpn-dbus.conf
@@ -232,10 +259,10 @@ systemctl daemon-reload
%manifest connman.manifest
%attr(500,network_fw,network_fw) %{_bindir}/connmand
%attr(500,network_fw,network_fw) %{_bindir}/connmanctl
-%attr(755,network_fw,network_fw) /%{_localstatedir}/lib/connman
%attr(600,network_fw,network_fw) /%{_localstatedir}/lib/connman/settings
%attr(644,root,root) %{_datadir}/dbus-1/system-services/net.connman.service
%attr(644,root,root) %{_sysconfdir}/dbus-1/system.d/*
+%exclude %{_sysconfdir}/dbus-1/system.d/connman-robot.conf
%attr(644,network_fw,network_fw) %{_sysconfdir}/connman/main.conf
%attr(644,root,root) %{_sysconfdir}/dbus-1/system.d/*.conf
%attr(644,root,root) %{_unitdir}/connman.service
@@ -290,20 +317,45 @@ systemctl daemon-reload
%attr(644,root,root) %{_unitdir}/connman-vpn.service
%endif
+%if %{with connman_wireguard}
+%files plugin-wireguard
+%manifest %{name}.manifest
+%{_libdir}/%{name}/plugins-vpn/wireguard.so
+%license COPYING
+%endif
+
%post extension-tv
mv -f %{_unitdir}/connman.service.tv %{_unitdir}/connman.service
mv -f %{_sysconfdir}/connman/main.conf.tv %{_sysconfdir}/connman/main.conf
+
%files extension-tv
%attr(644,network_fw,network_fw) %{_sysconfdir}/connman/main.conf.tv
%license COPYING
%attr(644,root,root) %{_unitdir}/connman.service.tv
+
%post extension-ivi
mv -f %{_sysconfdir}/connman/main.conf.ivi %{_sysconfdir}/connman/main.conf
+
%files extension-ivi
%attr(644,network_fw,network_fw) %{_sysconfdir}/connman/main.conf.ivi
%license COPYING
+
%post extension-disable-eth
mv -f %{_sysconfdir}/connman/main.conf.disable.eth %{_sysconfdir}/connman/main.conf
+
%files extension-disable-eth
%attr(644,network_fw,network_fw) %{_sysconfdir}/connman/main.conf.disable.eth
%license COPYING
+
+%post profile_robot
+mv %{_sysconfdir}/dbus-1/system.d/connman-robot.conf %{_sysconfdir}/dbus-1/system.d/connman.conf
+mv -f %{_sysconfdir}/connman/main.conf.robot %{_sysconfdir}/connman/main.conf
+
+%files profile_robot
+%manifest %{name}.manifest
+%attr(644,root,root) %{_sysconfdir}/dbus-1/system.d/connman-robot.conf
+%attr(644,network_fw,network_fw) %{_sysconfdir}/connman/main.conf.robot
+
+%files isu
+/etc/isu/connman/isu.cfg
+/etc/isu/connman/system-services/connman.service
diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c
index 704d2164..0b59a656 100755
--- a/plugins/bluetooth.c
+++ b/plugins/bluetooth.c
@@ -738,8 +738,6 @@ static bool tethering_create(const char *path,
const char *method;
bool result;
- DBG("path %s bridge %s", path, bridge);
-
if (!bridge) {
g_free(tethering);
return false;
@@ -751,6 +749,8 @@ static bool tethering_create(const char *path,
return false;
}
+ DBG("path %s bridge %s", path, bridge);
+
tethering->technology = technology;
tethering->bridge = g_strdup(bridge);
tethering->enable = enabled;
@@ -903,7 +903,6 @@ static void bluetooth_tech_remove(struct connman_technology *technology)
}
static int bluetooth_tech_set_tethering(struct connman_technology *technology,
- const char *identifier, const char *passphrase,
const char *bridge, bool enabled)
{
GHashTableIter hash_iter;
diff --git a/plugins/dundee.c b/plugins/dundee.c
index b5420acf..57571ec3 100755
--- a/plugins/dundee.c
+++ b/plugins/dundee.c
@@ -488,7 +488,7 @@ static void extract_settings(DBusMessageIter *array,
if (index < 0)
goto out;
- info->address = connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV4);
+ info->address = connman_ipaddress_alloc(AF_INET);
if (!info->address)
goto out;
diff --git a/plugins/ethernet.c b/plugins/ethernet.c
index 2a91e2f3..9d64abe4 100644
--- a/plugins/ethernet.c
+++ b/plugins/ethernet.c
@@ -54,10 +54,14 @@
#endif
#if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
-#include <connman/option.h>
#include <gsupplicant/gsupplicant.h>
#endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
+#if defined TIZEN_EXT
+#include "connman.h"
+#include "dbus.h"
+#endif
+
static bool eth_tethering = false;
struct ethernet_data {
@@ -84,7 +88,7 @@ static int get_vlan_vid(const char *ifname)
return -errno;
vifr.cmd = GET_VLAN_VID_CMD;
- strncpy(vifr.device1, ifname, sizeof(vifr.device1));
+ stpncpy(vifr.device1, ifname, sizeof(vifr.device1) - 1);
if(ioctl(sk, SIOCSIFVLAN, &vifr) >= 0)
vid = vifr.u.VID;
@@ -110,14 +114,16 @@ static int get_dsa_port(const char *ifname)
return -errno;
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ stpncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
/* check if it is a vlan and get physical interface name*/
vifr.cmd = GET_VLAN_REALDEV_NAME_CMD;
- strncpy(vifr.device1, ifname, sizeof(vifr.device1));
+ stpncpy(vifr.device1, ifname, sizeof(vifr.device1) - 1);
- if(ioctl(sk, SIOCSIFVLAN, &vifr) >= 0)
- strncpy(ifr.ifr_name, vifr.u.device2, sizeof(ifr.ifr_name));
+ if(ioctl(sk, SIOCSIFVLAN, &vifr) >= 0) {
+ stpncpy(ifr.ifr_name, vifr.u.device2, sizeof(ifr.ifr_name) - 1);
+ ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
+ }
/* get driver info */
drvinfocmd.cmd = ETHTOOL_GDRVINFO;
@@ -151,19 +157,28 @@ static void eth_network_remove(struct connman_network *network)
}
#if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
-static struct connman_network *g_network = NULL;
+#define NETCONFIG_SERVICE "net.netconfig"
+#define NETCONFIG_ETHERNET_INTERFACE NETCONFIG_SERVICE ".ethernet"
+#define NETCONFIG_ETHERNET_PATH "/net/netconfig/ethernet"
+
+struct eapol_method_call_data {
+ DBusConnection *connection;
+ struct connman_network *network;
+};
+
+static struct eapol_method_call_data enable_eapol_data;
void handle_eap_signal(GSupplicantInterface *interface, bool status)
{
DBG("captured EAP signal");
- if (!g_network)
+ if (!enable_eapol_data.network)
return;
if (g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
return;
- if (!connman_network_check_validity(g_network))
+ if (!connman_network_check_validity(enable_eapol_data.network))
return;
DBG("network is valid");
@@ -179,13 +194,13 @@ void handle_eap_signal(GSupplicantInterface *interface, bool status)
ethernet->interface = NULL;
}
- connman_network_set_error(g_network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
- g_network = NULL;
+ connman_network_set_error(enable_eapol_data.network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
+ enable_eapol_data.network = NULL;
return;
}
- connman_network_set_connected(g_network, status);
- g_network = NULL;
+ connman_network_set_connected(enable_eapol_data.network, status);
+ enable_eapol_data.network = NULL;
}
static void interface_create_callback(int result,
@@ -204,43 +219,140 @@ static void interface_create_callback(int result,
g_supplicant_interface_set_data(interface, ethernet);
}
-static int eth_network_connect(struct connman_network *network)
+static int eapol_interface_create(void)
{
- DBG("network %p", network);
-
+ struct connman_network *network = enable_eapol_data.network;
struct connman_service *service = connman_service_lookup_from_network(network);
- if (service && __connman_service_get_use_eapol(service)) {
- struct connman_device *device = connman_network_get_device(network);
- struct ethernet_data *ethernet = connman_device_get_data(device);
- const char *driver = "wired";
- int index = connman_network_get_index(network);
- char *ifname = connman_inet_ifname(index);;
- char *config_file = NULL;
+ if (!service) {
+ DBG("service not found");
+ return -1;
+ }
+
+ struct connman_device *device = connman_network_get_device(network);
+ struct ethernet_data *ethernet = connman_device_get_data(device);
+ const char *driver = "wired";
+ int index = connman_network_get_index(network);
+ char *ifname = connman_inet_ifname(index);;
+ char *config_file = NULL;
- g_supplicant_register_eap_callback(handle_eap_signal);
- g_network = network;
+ g_supplicant_register_eap_callback(handle_eap_signal);
- if (asprintf(&config_file, "/opt/usr/data/network/%s-eapol.conf", ifname) < 0) {
- g_free(ifname);
- return -ENOMEM;
- }
+ if (asprintf(&config_file, "/var/lib/connman/%s-eapol.conf", ifname) < 0) {
+ g_free(ifname);
+ return -ENOMEM;
+ }
- DBG("config_file %s", config_file);
+ DBG("config_file %s", config_file);
- g_supplicant_replace_config_file(ifname, config_file);
- free(config_file);
+ g_supplicant_replace_config_file(ifname, config_file);
+ free(config_file);
- /*
- * TODO: RemoveInterface if already present because
- * already created interface will not start EAP handshake.
- */
- g_supplicant_interface_create(ifname, driver, NULL,
- interface_create_callback, ethernet);
+ /*
+ * TODO: RemoveInterface if already present because
+ * already created interface will not start EAP handshake.
+ */
+ return g_supplicant_interface_create(ifname, driver, NULL,
+ 0, 0, 60, interface_create_callback, ethernet);
+}
- g_free(ifname);
+static void enable_eapol_reply(DBusPendingCall *call, void *user_data)
+{
+ DBusMessage *reply;
+ DBusError error;
- return 0;
+ DBG("");
+
+ reply = dbus_pending_call_steal_reply(call);
+
+ dbus_error_init(&error);
+ if (dbus_set_error_from_message(&error, reply)) {
+ DBG("enable_eapol_request() %s %s", error.name, error.message);
+ dbus_error_free(&error);
+ dbus_message_unref(reply);
+ dbus_pending_call_unref(call);
+ dbus_connection_unref(enable_eapol_data.connection);
+
+ enable_eapol_data.connection = NULL;
+ return;
+ }
+
+ if (eapol_interface_create() < 0)
+ DBG("Failed to create eapol interface");
+}
+
+static int eth_network_enable_eapol(struct connman_service *service, struct connman_network *network)
+{
+ DBusMessage *msg = NULL;
+ DBusPendingCall *call;
+
+ DBusConnection *connection = connman_dbus_get_connection();
+ if (!connection) {
+ DBG("dbus connection does not exist");
+ return -EINVAL;
+ }
+
+ msg = dbus_message_new_method_call(NETCONFIG_SERVICE, NETCONFIG_ETHERNET_PATH,
+ NETCONFIG_ETHERNET_INTERFACE, "EnableEap");
+ if (!msg) {
+ dbus_connection_unref(connection);
+ return -EINVAL;
+ }
+
+ const char *path = __connman_service_get_path(service);
+ dbus_bool_t enable = true;
+
+ dbus_message_append_args(msg, DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+ dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &enable,
+ DBUS_TYPE_INVALID);
+
+ if (!dbus_connection_send_with_reply(connection, msg,
+ &call, DBUS_TIMEOUT_USE_DEFAULT)) {
+ dbus_message_unref(msg);
+ dbus_connection_unref(connection);
+ return -EIO;
+ }
+
+ if (!call) {
+ dbus_message_unref(msg);
+ dbus_connection_unref(connection);
+ return -EIO;
+ }
+
+ enable_eapol_data.connection = connection;
+ enable_eapol_data.network = network;
+
+ dbus_pending_call_set_notify(call, enable_eapol_reply, NULL, NULL);
+ dbus_message_unref(msg);
+
+ return 0;
+}
+
+static int eth_network_connect(struct connman_network *network)
+{
+ DBG("network %p", network);
+
+ int err = 0;
+ struct connman_service *service = connman_service_lookup_from_network(network);
+
+ if (service && __connman_service_get_use_eapol(service)) {
+ /** Enable eapol on device reboot **/
+ if (__connman_service_get_connect_reason(service) != CONNMAN_SERVICE_CONNECT_REASON_USER) {
+ err = eth_network_enable_eapol(service, network);
+ if (err < 0) {
+ DBG("Failed to enable eapol");
+ return err;
+ }
+ } else {
+ err = eapol_interface_create();
+ if (err < 0) {
+ DBG("Failed to create eapol interface");
+ return err;
+ }
+
+ return 0;
+ }
}
connman_network_set_connected(network, true);
@@ -258,7 +370,7 @@ static int eth_network_disconnect(struct connman_network *network)
struct connman_device *device = connman_network_get_device(network);
struct ethernet_data *ethernet = connman_device_get_data(device);
- g_network = NULL;
+ enable_eapol_data.network = NULL;
g_supplicant_unregister_eap_callback();
if (ethernet && ethernet->interface) {
g_supplicant_interface_remove(ethernet->interface, NULL, NULL);
@@ -562,7 +674,6 @@ static void eth_tech_disable_tethering(struct connman_technology *technology,
}
static int eth_tech_set_tethering(struct connman_technology *technology,
- const char *identifier, const char *passphrase,
const char *bridge, bool enabled)
{
if (!connman_technology_is_tethering_allowed(
diff --git a/plugins/gadget.c b/plugins/gadget.c
index 1b44bbb5..2d58df3e 100755
--- a/plugins/gadget.c
+++ b/plugins/gadget.c
@@ -294,7 +294,6 @@ static void gadget_tech_disable_tethering(struct connman_technology *technology,
}
static int gadget_tech_set_tethering(struct connman_technology *technology,
- const char *identifier, const char *passphrase,
const char *bridge, bool enabled)
{
DBG("bridge %s enabled %d", bridge, enabled);
diff --git a/plugins/iwd.c b/plugins/iwd.c
index ddc9201d..2aed75b6 100644
--- a/plugins/iwd.c
+++ b/plugins/iwd.c
@@ -42,6 +42,9 @@ static GDBusProxy *agent_proxy;
static GHashTable *adapters;
static GHashTable *devices;
static GHashTable *networks;
+static GHashTable *known_networks;
+static GHashTable *stations;
+static GHashTable *access_points;
static bool agent_registered;
#define IWD_SERVICE "net.connman.iwd"
@@ -50,6 +53,9 @@ static bool agent_registered;
#define IWD_ADAPTER_INTERFACE "net.connman.iwd.Adapter"
#define IWD_DEVICE_INTERFACE "net.connman.iwd.Device"
#define IWD_NETWORK_INTERFACE "net.connman.iwd.Network"
+#define IWD_KNOWN_NETWORK_INTERFACE "net.connman.iwd.KnownNetwork"
+#define IWD_STATION_INTERFACE "net.connman.iwd.Station"
+#define IWD_AP_INTERFACE "net.connman.iwd.AccessPoint"
#define IWD_AGENT_INTERFACE "net.connman.iwd.Agent"
#define IWD_AGENT_ERROR_INTERFACE "net.connman.iwd.Agent.Error"
@@ -61,6 +67,9 @@ struct iwd_adapter {
char *vendor;
char *model;
bool powered;
+ bool ad_hoc;
+ bool station;
+ bool ap;
};
struct iwd_device {
@@ -70,7 +79,7 @@ struct iwd_device {
char *name;
char *address;
bool powered;
- bool scanning;
+ char *mode;
struct connman_device *device;
};
@@ -82,9 +91,44 @@ struct iwd_network {
char *name;
char *type;
bool connected;
+ char *known_network;
struct iwd_device *iwdd;
struct connman_network *network;
+ /* service's autoconnect */
+ bool autoconnect;
+};
+
+struct iwd_known_network {
+ GDBusProxy *proxy;
+ char *path;
+ char *name;
+ char *type;
+ bool hidden;
+ char *last_connected_time;
+ bool auto_connect;
+ int auto_connect_id;
+
+ /* service's autoconnect */
+ bool autoconnect;
+};
+
+struct iwd_station {
+ GDBusProxy *proxy;
+ char *path;
+ char *state;
+ char *connected_network;
+ bool scanning;
+};
+
+struct iwd_ap {
+ GDBusProxy *proxy;
+ char *path;
+ bool started;
+
+ int index;
+ char *bridge;
+ struct connman_technology *tech;
};
static const char *proxy_get_string(GDBusProxy *proxy, const char *property)
@@ -100,6 +144,27 @@ static const char *proxy_get_string(GDBusProxy *proxy, const char *property)
return str;
}
+static GSList *proxy_get_strings(GDBusProxy *proxy, const char *property)
+{
+ DBusMessageIter array, entry;
+ GSList *list = NULL;
+
+ if (!g_dbus_proxy_get_property(proxy, property, &array))
+ return NULL;
+
+ dbus_message_iter_recurse(&array, &entry);
+
+ while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING){
+ const char *val;
+
+ dbus_message_iter_get_basic(&entry, &val);
+ list = g_slist_prepend(list, g_strdup(val));
+ dbus_message_iter_next(&entry);
+ }
+
+ return list;
+}
+
static bool proxy_get_bool(GDBusProxy *proxy, const char *property)
{
DBusMessageIter iter;
@@ -144,18 +209,13 @@ static int cm_network_probe(struct connman_network *network)
static void update_network_connected(struct iwd_network *iwdn)
{
struct iwd_device *iwdd;
- int index;
iwdd = g_hash_table_lookup(devices, iwdn->device);
if (!iwdd)
return;
- index = connman_inet_ifindex(iwdd->name);
- if (index < 0)
- return;
-
- DBG("interface name %s index %d", iwdd->name, index);
- connman_network_set_index(iwdn->network, index);
+ DBG("interface name %s index %d", iwdd->name,
+ connman_network_get_index(iwdn->network));
connman_network_set_connected(iwdn->network, true);
}
@@ -181,7 +241,11 @@ static void cm_network_connect_cb(DBusMessage *message, void *user_data)
return;
DBG("%s connect failed: %s", path, dbus_error);
- connman_network_set_error(iwdn->network,
+ if (!strcmp(dbus_error, "net.connman.iwd.Failed"))
+ connman_network_set_error(iwdn->network,
+ CONNMAN_NETWORK_ERROR_INVALID_KEY);
+ else if (!iwdn->autoconnect)
+ connman_network_set_error(iwdn->network,
CONNMAN_NETWORK_ERROR_CONNECT_FAIL);
return;
}
@@ -238,28 +302,175 @@ static void cm_network_disconnect_cb(DBusMessage *message, void *user_data)
static int cm_network_disconnect(struct connman_network *network)
{
struct iwd_network *iwdn = connman_network_get_data(network);
- struct iwd_device *iwdd;
+ struct iwd_station *iwds;
- if (!iwdn)
+ if (!iwdn && !iwdn->iwdd)
return -EINVAL;
- iwdd = g_hash_table_lookup(devices, iwdn->device);
- if (!iwdd)
+ iwds = g_hash_table_lookup(stations, iwdn->iwdd->path);
+ if (!iwds)
return -EIO;
- if (!g_dbus_proxy_method_call(iwdd->proxy, "Disconnect",
+ connman_network_set_associating(network, false);
+
+ if (!g_dbus_proxy_method_call(iwds->proxy, "Disconnect",
NULL, cm_network_disconnect_cb, g_strdup(iwdn->path), g_free))
return -EIO;
+ return 0;
+}
+
+struct auto_connect_cb_data {
+ char *path;
+ bool auto_connect;
+};
+
+static void auto_connect_cb_free(struct auto_connect_cb_data *cbd)
+{
+ g_free(cbd->path);
+ g_free(cbd);
+}
+
+static void auto_connect_cb(const DBusError *error, void *user_data)
+{
+ struct auto_connect_cb_data *cbd = user_data;
+ struct iwd_known_network *iwdkn;
+
+ iwdkn = g_hash_table_lookup(known_networks, cbd->path);
+ if (!iwdkn)
+ goto out;
+
+ if (dbus_error_is_set(error))
+ connman_warn("WiFi known network %s property auto connect %s",
+ cbd->path, error->message);
+
+ /* property is updated via watch known_network_property_change() */
+out:
+ auto_connect_cb_free(cbd);
+}
+
+static int set_auto_connect(struct iwd_known_network *iwdkn, bool auto_connect)
+{
+ dbus_bool_t dbus_auto_connect = auto_connect;
+ struct auto_connect_cb_data *cbd;
+
+ if (proxy_get_bool(iwdkn->proxy, "AutoConnect") == auto_connect)
+ return -EALREADY;
+
+ cbd = g_new(struct auto_connect_cb_data, 1);
+ cbd->path = g_strdup(iwdkn->path);
+ cbd->auto_connect = auto_connect;
+
+ if (!g_dbus_proxy_set_property_basic(iwdkn->proxy, "AutoConnect",
+ DBUS_TYPE_BOOLEAN,
+ &dbus_auto_connect,
+ auto_connect_cb, cbd, NULL)) {
+ auto_connect_cb_free(cbd);
+ return -EIO;
+ }
+
return -EINPROGRESS;
}
+static gboolean disable_auto_connect_cb(gpointer data)
+{
+ char *path = data;
+ struct iwd_known_network *iwdkn;
+
+ iwdkn = g_hash_table_lookup(known_networks, path);
+ if (!iwdkn)
+ return FALSE;
+
+ if (set_auto_connect(iwdkn, false) != -EINPROGRESS)
+ connman_warn("Failed to disable auto connect");
+
+ iwdkn->auto_connect_id = 0;
+ return FALSE;
+}
+
+static int disable_auto_connect(struct iwd_known_network *iwdkn)
+{
+ if (iwdkn->auto_connect_id)
+ return -EBUSY;
+
+ iwdkn->auto_connect_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
+ 0,
+ disable_auto_connect_cb,
+ g_strdup(iwdkn->path),
+ g_free);
+ return 0;
+}
+
+static gboolean enable_auto_connect_cb(gpointer data)
+{
+ char *path = data;
+ struct iwd_known_network *iwdkn;
+
+ iwdkn = g_hash_table_lookup(known_networks, path);
+ if (!iwdkn)
+ return FALSE;
+
+ if (set_auto_connect(iwdkn, true) != -EINPROGRESS)
+ connman_warn("Failed to enable auto connect");
+
+ iwdkn->auto_connect_id = 0;
+ return FALSE;
+}
+
+static int enable_auto_connect(struct iwd_known_network *iwdkn)
+{
+ if (iwdkn->auto_connect_id)
+ return -EBUSY;
+
+ iwdkn->auto_connect_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
+ 0,
+ enable_auto_connect_cb,
+ g_strdup(iwdkn->path),
+ g_free);
+ return 0;
+}
+
+static int update_auto_connect(struct iwd_known_network *iwdkn)
+{
+ DBG("auto_connect %d autoconnect %d", iwdkn->auto_connect, iwdkn->autoconnect);
+
+ if (iwdkn->auto_connect == iwdkn->autoconnect)
+ return -EALREADY;
+
+ if (iwdkn->autoconnect)
+ return enable_auto_connect(iwdkn);
+ return disable_auto_connect(iwdkn);
+}
+
+static int cm_network_set_autoconnect(struct connman_network *network,
+ bool autoconnect)
+{
+ struct iwd_network *iwdn = connman_network_get_data(network);
+ struct iwd_known_network *iwdkn;
+
+ DBG("autoconnect %d", autoconnect);
+
+ iwdn->autoconnect = autoconnect;
+
+ if (!iwdn->known_network)
+ return -ENOENT;
+
+ iwdkn = g_hash_table_lookup(known_networks, iwdn->known_network);
+ if (!iwdkn)
+ return -ENOENT;
+
+ iwdkn->autoconnect = autoconnect;
+
+ return update_auto_connect(iwdkn);
+}
+
static struct connman_network_driver network_driver = {
- .name = "iwd",
- .type = CONNMAN_NETWORK_TYPE_WIFI,
- .probe = cm_network_probe,
- .connect = cm_network_connect,
- .disconnect = cm_network_disconnect,
+ .name = "iwd",
+ .type = CONNMAN_NETWORK_TYPE_WIFI,
+ .probe = cm_network_probe,
+ .connect = cm_network_connect,
+ .disconnect = cm_network_disconnect,
+ .set_autoconnect = cm_network_set_autoconnect,
};
static int cm_device_probe(struct connman_device *device)
@@ -339,6 +550,42 @@ static int cm_device_disable(struct connman_device *device)
return set_device_powered(device, false);
}
+static void cm_device_scan_cb(DBusMessage *message, void *user_data)
+{
+ const char *path = user_data;
+ struct iwd_station *iwds;
+
+ iwds = g_hash_table_lookup(stations, path);
+ if (!iwds)
+ return;
+
+ if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
+ const char *dbus_error = dbus_message_get_error_name(message);
+
+ DBG("%s scan failed: %s", path, dbus_error);
+ }
+}
+
+static int cm_device_scan(struct connman_device *device,
+ struct connman_device_scan_params *params)
+{
+ struct iwd_device *iwdd = connman_device_get_data(device);
+ struct iwd_station *iwds;
+
+ if (strcmp(iwdd->mode, "station"))
+ return -EINVAL;
+
+ iwds = g_hash_table_lookup(stations, iwdd->path);
+ if (!iwds)
+ return -EIO;
+
+ if (!g_dbus_proxy_method_call(iwds->proxy, "Scan",
+ NULL, cm_device_scan_cb, g_strdup(iwds->path), g_free))
+ return -EIO;
+
+ return -EINPROGRESS;
+}
+
static struct connman_device_driver device_driver = {
.name = "iwd",
.type = CONNMAN_DEVICE_TYPE_WIFI,
@@ -346,6 +593,7 @@ static struct connman_device_driver device_driver = {
.remove = cm_device_remove,
.enable = cm_device_enable,
.disable = cm_device_disable,
+ .scan = cm_device_scan,
};
static int cm_tech_probe(struct connman_technology *technology)
@@ -357,92 +605,273 @@ static void cm_tech_remove(struct connman_technology *technology)
{
}
-static struct connman_technology_driver tech_driver = {
- .name = "iwd",
- .type = CONNMAN_SERVICE_TYPE_WIFI,
- .probe = cm_tech_probe,
- .remove = cm_tech_remove,
+struct tech_cb_data {
+ struct iwd_device *iwdd;
+ char *path;
+ char *ssid;
+ char *passphrase;
+ char *bridge;
+ int index;
+ struct connman_technology *tech;
};
-static unsigned char calculate_strength(int strength)
+static void tech_cb_free(struct tech_cb_data *cbd)
{
- unsigned char res;
+ g_free(cbd->path);
+ g_free(cbd->ssid);
+ g_free(cbd->passphrase);
+ g_free(cbd->bridge);
+ g_free(cbd);
+}
- /*
- * Network's maximum signal strength expressed in 100 * dBm.
- * The value is the range of 0 (strongest signal) to -10000
- * (weakest signal)
- *
- * ConnMan expects it in the range from 100 (strongest) to 0
- * (weakest).
- */
- res = (unsigned char)((strength * -10000) / 100);
+static int cm_change_tethering(struct iwd_device *iwdd,
+ struct connman_technology *technology,
+ const char *identifier, const char *passphrase,
+ const char *bridge, bool enabled);
- return res;
+static void tech_ap_start_cb(DBusMessage *message, void *user_data)
+{
+
+ struct tech_cb_data *cbd = user_data;
+
+ if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
+ const char *dbus_error = dbus_message_get_error_name(message);
+
+ connman_warn("iwd device %s could not enable AccessPoint mode: %s",
+ cbd->path, dbus_error);
+ goto out;
+ }
+
+ /* wait for 'Started' signal */
+ return;
+out:
+ cm_change_tethering(cbd->iwdd, cbd->tech,
+ cbd->ssid, cbd->passphrase, cbd->bridge, false);
+ tech_cb_free(cbd);
}
-static void _update_signal_strength(const char *path, int16_t signal_strength)
+static void tech_ap_stop_cb(DBusMessage *message, void *user_data)
{
- struct iwd_network *iwdn;
+ struct tech_cb_data *cbd = user_data;
- iwdn = g_hash_table_lookup(networks, path);
- if (!iwdn)
- return;
+ if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
+ const char *dbus_error = dbus_message_get_error_name(message);
- if (!iwdn->network)
- return;
+ connman_warn("iwd device %s could not disable AccessPoint mode: %s",
+ cbd->path, dbus_error);
+ goto out;
+ }
- connman_network_set_strength(iwdn->network,
- calculate_strength(signal_strength));
+ return;
+out:
+ tech_cb_free(cbd);
}
-static void ordered_networks_cb(DBusMessage *message, void *user_data)
+static void ap_start_append(DBusMessageIter *iter, void *user_data)
{
- DBusMessageIter array, entry;
+ struct tech_cb_data *cbd = user_data;
+
+ DBG("ssid %s", cbd->ssid);
+ DBG("passphrase %s", cbd->passphrase);
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &cbd->ssid);
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &cbd->passphrase);
+}
+
+static void tech_enable_tethering_cb(const DBusError *error, void *user_data)
+{
+ struct tech_cb_data *cbd = user_data;
+ struct iwd_device *iwdd;
+ struct iwd_ap *iwdap = NULL;
DBG("");
- if (!dbus_message_iter_init(message, &array))
- return;
+ iwdd = g_hash_table_lookup(devices, cbd->path);
+ if (!iwdd) {
+ DBG("device already removed");
+ goto out;
+ }
- if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
- return;
+ if (dbus_error_is_set(error)) {
+ connman_warn("iwd device %s could not enable AcessPoint mode: %s",
+ cbd->path, error->message);
+ goto out;
+ }
- dbus_message_iter_recurse(&array, &entry);
- while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRUCT) {
- DBusMessageIter value;
- const char *path, *name, *type;
- int16_t signal_strength;
+ iwdap = g_hash_table_lookup(access_points, iwdd->path);
+ if (!iwdap) {
+ DBG("%s no ap object found", iwdd->path);
+ goto out;
+ }
+ iwdap->index = cbd->index;
+ iwdap->bridge = g_strdup(cbd->bridge);
+ iwdap->tech = cbd->tech;
- dbus_message_iter_recurse(&entry, &value);
+ if (!g_dbus_proxy_method_call(iwdap->proxy, "Start",
+ ap_start_append, tech_ap_start_cb, cbd, NULL)) {
+ connman_warn("iwd ap %s could not start AccessPoint mode: %s",
+ cbd->path, error->message);
+ goto out;
+ }
- dbus_message_iter_get_basic(&value, &path);
+ return;
+out:
+ if (iwdap) {
+ iwdap->index = -1;
+ g_free(iwdap->bridge);
+ iwdap->bridge = NULL;
+ }
+ tech_cb_free(cbd);
+}
- dbus_message_iter_next(&value);
- dbus_message_iter_get_basic(&value, &name);
+static void tech_disable_tethering_cb(const DBusError *error, void *user_data)
+{
+ struct tech_cb_data *cbd = user_data;
+ struct iwd_device *iwdd;
+ struct iwd_ap *iwdap;
- dbus_message_iter_next(&value);
- dbus_message_iter_get_basic(&value, &signal_strength);
+ DBG("");
- dbus_message_iter_next(&value);
- dbus_message_iter_get_basic(&value, &type);
+ iwdd = g_hash_table_lookup(devices, cbd->path);
+ if (!iwdd) {
+ DBG("device already removed");
+ goto out;
+ }
- _update_signal_strength(path, signal_strength);
+ if (dbus_error_is_set(error)) {
+ connman_warn("iwd device %s could not enable Station mode: %s",
+ cbd->path, error->message);
+ goto out;
+ }
- dbus_message_iter_next(&entry);
+ iwdap = g_hash_table_lookup(access_points, iwdd->path);
+ if (!iwdap) {
+ DBG("%s no ap object found", iwdd->path);
+ goto out;
}
+
+ g_free(iwdap->bridge);
+ iwdap->index = -1;
+ iwdap->bridge = NULL;
+ iwdap->tech = NULL;
+
+ if (!connman_inet_remove_from_bridge(cbd->index, cbd->bridge))
+ goto out;
+
+ connman_technology_tethering_notify(cbd->tech, false);
+
+ if (!g_dbus_proxy_method_call(iwdap->proxy, "Stop",
+ NULL, tech_ap_stop_cb, cbd, NULL)) {
+ connman_warn("iwd ap %s could not stop AccessPoint mode: %s",
+ cbd->path, error->message);
+ goto out;
+ }
+
+ return;
+out:
+ tech_cb_free(cbd);
}
-static void update_signal_strength(struct iwd_device *iwdd)
+static int cm_change_tethering(struct iwd_device *iwdd,
+ struct connman_technology *technology,
+ const char *identifier, const char *passphrase,
+ const char *bridge, bool enabled)
{
- if (!g_dbus_proxy_method_call(iwdd->proxy,
- "GetOrderedNetworks",
- NULL, ordered_networks_cb,
- NULL, NULL))
- DBG("GetOrderedNetworks() failed");
+ struct tech_cb_data *cbd;
+ int index;
+ const char *mode;
+ GDBusResultFunction cb;
+
+ index = connman_inet_ifindex(iwdd->name);
+ if (index < 0)
+ return -ENODEV;
+
+ cbd = g_new(struct tech_cb_data, 1);
+ cbd->iwdd = iwdd;
+ cbd->path = g_strdup(iwdd->path);
+ cbd->ssid = g_strdup(identifier);
+ cbd->passphrase = g_strdup(passphrase);
+ cbd->bridge = g_strdup(bridge);
+ cbd->tech = technology;
+ cbd->index = index;
+
+ if (enabled) {
+ mode = "ap";
+ cb = tech_enable_tethering_cb;
+ } else {
+ mode = "station";
+ cb = tech_disable_tethering_cb;
+ }
+
+ if (!g_dbus_proxy_set_property_basic(iwdd->proxy,
+ "Mode", DBUS_TYPE_STRING, &mode,
+ cb, cbd, NULL)) {
+ tech_cb_free(cbd);
+ return -EIO;
+ }
+
+ return 0;
}
+static int cm_tech_tethering(struct connman_technology *technology,
+ const char *bridge, bool enabled)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+ int err = 0, res;
+ const char *ssid;
+ const char *psk;
+ int freq;
+
+ connman_technology_get_wifi_tethering(technology, &ssid, &psk, &freq);
+
+ g_hash_table_iter_init(&iter, devices);
+
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ struct iwd_device *iwdd = value;
+ struct iwd_adapter *iwda;
+
+ iwda = g_hash_table_lookup(adapters, iwdd->adapter);
+ if (!iwda)
+ continue;
+
+ if (!iwda->station || !iwda->ap )
+ /* No support for Station and AccessPoint mode */
+ continue;
+
+ if (!enabled && !g_strcmp0("ap", iwdd->mode)) {
+ res = cm_change_tethering(iwdd, technology, ssid,
+ psk, bridge, enabled);
+ if (res)
+ connman_warn("%s switching to Station mode failed",
+ iwdd->path);
+ if (!err)
+ err = res;
+ continue;
+ }
+
+ if (enabled && !g_strcmp0("station", iwdd->mode)) {
+ err = cm_change_tethering(iwdd, technology, ssid,
+ psk, bridge, enabled);
+ if (err)
+ connman_warn("%s switching to AccessPoint mode failed",
+ iwdd->path);
+ break;
+ }
+ }
+
+ return err;
+}
+
+static struct connman_technology_driver tech_driver = {
+ .name = "iwd",
+ .type = CONNMAN_SERVICE_TYPE_WIFI,
+ .probe = cm_tech_probe,
+ .remove = cm_tech_remove,
+ .set_tethering = cm_tech_tethering,
+};
+
static const char *security_remap(const char *security)
{
if (!g_strcmp0(security, "open"))
@@ -484,6 +913,7 @@ static void add_network(const char *path, struct iwd_network *iwdn)
{
struct iwd_device *iwdd;
char *identifier;
+ int index;
iwdd = g_hash_table_lookup(devices, iwdn->device);
if (!iwdd)
@@ -492,13 +922,18 @@ static void add_network(const char *path, struct iwd_network *iwdn)
identifier = create_identifier(path, iwdn->type);
iwdn->network = connman_network_create(identifier,
CONNMAN_NETWORK_TYPE_WIFI);
+
+ index = connman_inet_ifindex(iwdd->name);
+ if (index >= 0)
+ connman_network_set_index(iwdn->network, index);
+
connman_network_set_data(iwdn->network, iwdn);
connman_network_set_name(iwdn->network, iwdn->name);
connman_network_set_blob(iwdn->network, "WiFi.SSID", iwdn->name,
strlen(iwdn->name));
connman_network_set_string(iwdn->network, "WiFi.Security",
- iwdn->type);
+ security_remap(iwdn->type));
connman_network_set_string(iwdn->network, "WiFi.Mode", "managed");
if (connman_device_add_network(iwdd->device, iwdn->network) < 0) {
@@ -508,7 +943,9 @@ static void add_network(const char *path, struct iwd_network *iwdn)
}
iwdn->iwdd = iwdd;
- connman_network_set_available(iwdn->network, true);
+ if (connman_network_get_strength(iwdn->network))
+ connman_network_set_available(iwdn->network, true);
+
connman_network_set_group(iwdn->network, identifier);
g_free(identifier);
@@ -630,17 +1067,14 @@ static void device_property_change(GDBusProxy *proxy, const char *name,
iwdd->powered = powered;
DBG("%s powered %d", path, iwdd->powered);
- } else if (!strcmp(name, "Scanning")) {
- dbus_bool_t scanning;
-
- dbus_message_iter_get_basic(iter, &scanning);
- iwdd->scanning = scanning;
-
- DBG("%s scanning %d", path, iwdd->scanning);
+ } else if (!strcmp(name, "Mode")) {
+ const char *mode;
- if (!iwdd->scanning)
- update_signal_strength(iwdd);
+ dbus_message_iter_get_basic(iter, &mode);
+ g_free(iwdd->mode);
+ iwdd->mode = g_strdup(mode);
+ DBG("%s mode %s", path, iwdd->mode);
}
}
@@ -648,6 +1082,7 @@ static void network_property_change(GDBusProxy *proxy, const char *name,
DBusMessageIter *iter, void *user_data)
{
struct iwd_network *iwdn;
+ struct iwd_known_network *iwdkn;
const char *path;
path = g_dbus_proxy_get_path(proxy);
@@ -667,6 +1102,180 @@ static void network_property_change(GDBusProxy *proxy, const char *name,
update_network_connected(iwdn);
else
update_network_disconnected(iwdn);
+ } else if (!strcmp(name, "KnownNetwork")) {
+ g_free(iwdn->known_network);
+ iwdn->known_network =
+ g_strdup(proxy_get_string(proxy, "KnownNetwork"));
+ if (!iwdn->known_network)
+ return;
+
+ iwdkn = g_hash_table_lookup(known_networks,
+ iwdn->known_network);
+ if (iwdkn)
+ update_auto_connect(iwdkn);
+ }
+}
+
+static unsigned char calculate_strength(int strength)
+{
+ unsigned char res;
+
+ /*
+ * Network's maximum signal strength expressed in 100 * dBm.
+ * The value is the range of 0 (strongest signal) to -10000
+ * (weakest signal)
+ *
+ * ConnMan expects it in the range from 100 (strongest) to 0
+ * (weakest).
+ */
+ res = (unsigned char)((strength + 10000) / 100);
+
+ return res;
+}
+
+static void _update_signal_strength(const char *path, int16_t signal_strength)
+{
+ struct iwd_network *iwdn;
+
+ iwdn = g_hash_table_lookup(networks, path);
+ if (!iwdn)
+ return;
+
+ connman_network_set_strength(iwdn->network,
+ calculate_strength(signal_strength));
+ connman_network_set_available(iwdn->network, true);
+ connman_network_update(iwdn->network);
+}
+
+static void ordered_networks_cb(DBusMessage *message, void *user_data)
+{
+ DBusMessageIter array, entry;
+ struct iwd_device *iwdd;
+ char *path = user_data;
+
+ DBG("");
+
+ if (!dbus_message_iter_init(message, &array))
+ return;
+
+ if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
+ return;
+
+ dbus_message_iter_recurse(&array, &entry);
+ while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRUCT) {
+ DBusMessageIter value;
+ const char *path;
+ int16_t signal_strength;
+
+
+ dbus_message_iter_recurse(&entry, &value);
+
+ dbus_message_iter_get_basic(&value, &path);
+
+ dbus_message_iter_next(&value);
+ dbus_message_iter_get_basic(&value, &signal_strength);
+
+ _update_signal_strength(path, signal_strength);
+
+ dbus_message_iter_next(&entry);
+ }
+
+ iwdd = g_hash_table_lookup(devices, path);
+ if (iwdd)
+ connman_device_set_scanning(iwdd->device,
+ CONNMAN_SERVICE_TYPE_WIFI, false);
+}
+
+static void update_signal_strength(struct iwd_station *iwds)
+{
+ if (!g_dbus_proxy_method_call(iwds->proxy,
+ "GetOrderedNetworks",
+ NULL, ordered_networks_cb,
+ g_strdup(iwds->path), g_free))
+ DBG("GetOrderedNetworks() failed");
+}
+
+static void station_property_change(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct iwd_station *iwds;
+ struct iwd_device *iwdd;
+ const char *path;
+
+ path = g_dbus_proxy_get_path(proxy);
+ iwds = g_hash_table_lookup(stations, path);
+ if (!iwds)
+ return;
+
+ if (!strcmp(name, "State")) {
+ const char *state;
+
+ dbus_message_iter_get_basic(iter, &state);
+ g_free(iwds->state);
+ iwds->state = g_strdup(state);
+
+ DBG("%s state %s", path, iwds->state);
+ } else if (!strcmp(name, "ConnectedNetwork")) {
+ const char *connected_network;
+
+ g_free(iwds->connected_network);
+ if (iter) {
+ dbus_message_iter_get_basic(iter, &connected_network);
+ iwds->connected_network = g_strdup(connected_network);
+ } else {
+ iwds->connected_network = NULL;
+ }
+
+ DBG("%s connected_network %s", path, iwds->connected_network);
+ } else if (!strcmp(name, "Scanning")) {
+ dbus_bool_t scanning;
+
+ dbus_message_iter_get_basic(iter, &scanning);
+ iwds->scanning = scanning;
+
+ if (iwds->scanning) {
+ iwdd = g_hash_table_lookup(devices, path);
+ if (iwdd)
+ connman_device_set_scanning(iwdd->device,
+ CONNMAN_SERVICE_TYPE_WIFI, true);
+ } else {
+ update_signal_strength(iwds);
+ }
+
+
+ DBG("%s scanning %d", path, iwds->scanning);
+ }
+}
+
+static void ap_property_change(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct iwd_ap *iwdap;
+ const char *path;
+ int err;
+
+ path = g_dbus_proxy_get_path(proxy);
+ iwdap = g_hash_table_lookup(access_points, path);
+ if (!iwdap)
+ return;
+
+ if (!strcmp(name, "Started")) {
+ dbus_bool_t started;
+
+ dbus_message_iter_get_basic(iter, &started);
+ iwdap->started = started;
+
+ DBG("%s started %d", path, iwdap->started);
+
+ if (iwdap->started && iwdap->index != -1) {
+ DBG("index %d bridge %s", iwdap->index, iwdap->bridge);
+ err = connman_technology_tethering_notify(
+ iwdap->tech, true);
+ if (err)
+ return;
+ err = connman_inet_add_to_bridge(
+ iwdap->index, iwdap->bridge);
+ }
}
}
@@ -718,21 +1327,61 @@ static void network_free(gpointer data)
g_free(iwdn->device);
g_free(iwdn->name);
g_free(iwdn->type);
+ g_free(iwdn->known_network);
g_free(iwdn);
}
-static void create_adapter(GDBusProxy *proxy)
+static void known_network_free(gpointer data)
{
- const char *path = g_dbus_proxy_get_path(proxy);
- struct iwd_adapter *iwda;
+ struct iwd_known_network *iwdkn = data;
+
+ if (iwdkn->proxy) {
+ g_dbus_proxy_unref(iwdkn->proxy);
+ iwdkn->proxy = NULL;
+ }
- iwda = g_try_new0(struct iwd_adapter, 1);
+ if (iwdkn->auto_connect_id)
+ g_source_remove(iwdkn->auto_connect_id);
- if (!iwda) {
- connman_error("Out of memory creating IWD adapter");
- return;
+ g_free(iwdkn->path);
+ g_free(iwdkn->name);
+ g_free(iwdkn->type);
+ g_free(iwdkn->last_connected_time);
+ g_free(iwdkn);
+}
+
+static void station_free(gpointer data)
+{
+ struct iwd_station *iwds = data;
+
+ if (iwds->proxy) {
+ g_dbus_proxy_unref(iwds->proxy);
+ iwds->proxy = NULL;
}
+ g_free(iwds->path);
+ g_free(iwds->connected_network);
+ g_free(iwds);
+}
+
+static void ap_free(gpointer data)
+{
+ struct iwd_ap *iwdap = data;
+ if (iwdap->proxy) {
+ g_dbus_proxy_unref(iwdap->proxy);
+ iwdap->proxy = NULL;
+ }
+ g_free(iwdap->bridge);
+ g_free(iwdap);
+}
+
+static void create_adapter(GDBusProxy *proxy)
+{
+ const char *path = g_dbus_proxy_get_path(proxy);
+ struct iwd_adapter *iwda;
+ GSList *modes, *list;
+
+ iwda = g_new0(struct iwd_adapter, 1);
iwda->path = g_strdup(path);
g_hash_table_replace(adapters, iwda->path, iwda);
@@ -748,8 +1397,25 @@ static void create_adapter(GDBusProxy *proxy)
iwda->model = g_strdup(proxy_get_string(proxy, "Model"));
iwda->powered = proxy_get_bool(proxy, "Powered");
- DBG("%s vendor '%s' model '%s' powered %d", path, iwda->vendor,
- iwda->model, iwda->powered);
+ modes = proxy_get_strings(proxy, "SupportedModes");
+ for (list = modes; list; list = list->next) {
+ char *m = list->data;
+
+ if (!m)
+ continue;
+
+ if (!strcmp(m, "ad-hoc"))
+ iwda->ad_hoc = true;
+ else if (!strcmp(m, "station"))
+ iwda->station = true;
+ else if (!strcmp(m, "ap"))
+ iwda->ap = true;
+ }
+ g_slist_free_full(modes, g_free);
+
+ DBG("%s vendor '%s' model '%s' powered %d ad-hoc %d station %d ap %d",
+ path, iwda->vendor, iwda->model, iwda->powered,
+ iwda->ad_hoc, iwda->station, iwda->ap);
g_dbus_proxy_set_property_watch(iwda->proxy,
adapter_property_change, NULL);
@@ -760,13 +1426,7 @@ static void create_device(GDBusProxy *proxy)
const char *path = g_dbus_proxy_get_path(proxy);
struct iwd_device *iwdd;
- iwdd = g_try_new0(struct iwd_device, 1);
-
- if (!iwdd) {
- connman_error("Out of memory creating IWD device");
- return;
- }
-
+ iwdd = g_new0(struct iwd_device, 1);
iwdd->path = g_strdup(path);
g_hash_table_replace(devices, iwdd->path, iwdd);
@@ -782,11 +1442,11 @@ static void create_device(GDBusProxy *proxy)
iwdd->name = g_strdup(proxy_get_string(proxy, "Name"));
iwdd->address = g_strdup(proxy_get_string(proxy, "Address"));
iwdd->powered = proxy_get_bool(proxy, "Powered");
- iwdd->scanning = proxy_get_bool(proxy, "Scanning");
+ iwdd->mode = g_strdup(proxy_get_string(proxy, "Mode"));
- DBG("adapter %s name %s address %s powered %d scanning %d",
+ DBG("adapter %s name %s address %s powered %d mode %s",
iwdd->adapter, iwdd->name, iwdd->address,
- iwdd->powered, iwdd->scanning);
+ iwdd->powered, iwdd->mode);
g_dbus_proxy_set_property_watch(iwdd->proxy,
device_property_change, NULL);
@@ -831,6 +1491,8 @@ static DBusMessage *agent_request_passphrase(DBusConnection *dbus_conn,
return get_reply_on_error(message, EINVAL);
passwd = connman_network_get_string(iwdn->network, "WiFi.Passphrase");
+ if (!passwd)
+ return get_reply_on_error(message, ENOKEY);
return g_dbus_create_reply(message, DBUS_TYPE_STRING, &passwd,
DBUS_TYPE_INVALID);
@@ -933,13 +1595,7 @@ static void create_network(GDBusProxy *proxy)
const char *path = g_dbus_proxy_get_path(proxy);
struct iwd_network *iwdn;
- iwdn = g_try_new0(struct iwd_network, 1);
-
- if (!iwdn) {
- connman_error("Out of memory creating IWD network");
- return;
- }
-
+ iwdn = g_new0(struct iwd_network, 1);
iwdn->path = g_strdup(path);
g_hash_table_replace(networks, iwdn->path, iwdn);
@@ -955,12 +1611,11 @@ static void create_network(GDBusProxy *proxy)
iwdn->name = g_strdup(proxy_get_string(proxy, "Name"));
iwdn->type = g_strdup(proxy_get_string(proxy, "Type"));
iwdn->connected = proxy_get_bool(proxy, "Connected");
+ iwdn->known_network = g_strdup(proxy_get_string(proxy, "KnownNetwork"));
- DBG("device %s name '%s' type %s connected %d",
- iwdn->device,
- iwdn->name,
- iwdn->type,
- iwdn->connected);
+ DBG("device %s name '%s' type %s connected %d known_network %s",
+ iwdn->device, iwdn->name, iwdn->type, iwdn->connected,
+ iwdn->known_network);
g_dbus_proxy_set_property_watch(iwdn->proxy,
network_property_change, NULL);
@@ -968,6 +1623,222 @@ static void create_network(GDBusProxy *proxy)
add_network(path, iwdn);
}
+struct auto_connect_cb_data {
+ char *path;
+ bool auto_connect;
+};
+
+static void auto_connect_cb_free(struct auto_connect_cb_data *cbd)
+{
+ g_free(cbd->path);
+ g_free(cbd);
+}
+
+static void auto_connect_cb(const DBusError *error, void *user_data)
+{
+ struct auto_connect_cb_data *cbd = user_data;
+ struct iwd_known_network *iwdkn;
+
+ iwdkn = g_hash_table_lookup(known_networks, cbd->path);
+ if (!iwdkn)
+ goto out;
+
+ if (dbus_error_is_set(error))
+ connman_warn("WiFi known network %s property auto connect %s",
+ cbd->path, error->message);
+
+ /* property is updated via watch known_network_property_change() */
+out:
+ auto_connect_cb_free(cbd);
+}
+
+static int set_auto_connect(struct iwd_known_network *iwdkn, bool auto_connect)
+{
+ dbus_bool_t dbus_auto_connect = auto_connect;
+ struct auto_connect_cb_data *cbd;
+
+ if (proxy_get_bool(iwdkn->proxy, "AutoConnect") == auto_connect)
+ return -EALREADY;
+
+ cbd = g_new(struct auto_connect_cb_data, 1);
+ cbd->path = g_strdup(iwdkn->path);
+ cbd->auto_connect = auto_connect;
+
+ if (!g_dbus_proxy_set_property_basic(iwdkn->proxy, "AutoConnect",
+ DBUS_TYPE_BOOLEAN,
+ &dbus_auto_connect,
+ auto_connect_cb, cbd, NULL)) {
+ auto_connect_cb_free(cbd);
+ return -EIO;
+ }
+
+ return -EINPROGRESS;
+}
+
+static gboolean disable_auto_connect_cb(gpointer data)
+{
+ char *path = data;
+ struct iwd_known_network *iwdkn;
+
+ iwdkn = g_hash_table_lookup(known_networks, path);
+ if (!iwdkn)
+ return FALSE;
+
+ if (set_auto_connect(iwdkn, false) != -EINPROGRESS)
+ connman_warn("Failed to disable auto connect");
+
+ iwdkn->auto_connect_id = 0;
+ return FALSE;
+}
+
+static void disable_auto_connect(struct iwd_known_network *iwdkn)
+{
+ if (iwdkn->auto_connect_id)
+ return;
+
+ iwdkn->auto_connect_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
+ 0,
+ disable_auto_connect_cb,
+ g_strdup(iwdkn->path),
+ g_free);
+}
+
+static void known_network_property_change(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct iwd_known_network *iwdkn;
+ const char *path;
+
+ path = g_dbus_proxy_get_path(proxy);
+ iwdkn = g_hash_table_lookup(known_networks, path);
+ if (!iwdkn)
+ return;
+
+ if (!strcmp(name, "AutoConnect")) {
+ dbus_bool_t auto_connect;
+
+ dbus_message_iter_get_basic(iter, &auto_connect);
+ iwdkn->auto_connect = auto_connect;
+
+ DBG("%p auto_connect %d", path, iwdkn->auto_connect);
+
+ update_auto_connect(iwdkn);
+ }
+}
+
+static void init_auto_connect(struct iwd_known_network *iwdkn)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init(&iter, networks);
+
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ struct iwd_network *iwdn = value;
+ struct iwd_known_network *kn;
+
+ if (!iwdn->known_network)
+ continue;
+
+ kn = g_hash_table_lookup(known_networks, iwdn->known_network);
+ if (iwdkn != kn)
+ continue;
+
+ iwdkn->autoconnect = iwdn->autoconnect;
+ update_auto_connect(iwdkn);
+ return;
+ }
+}
+
+static void create_know_network(GDBusProxy *proxy)
+{
+ const char *path = g_dbus_proxy_get_path(proxy);
+ struct iwd_known_network *iwdkn;
+
+ iwdkn = g_new0(struct iwd_known_network, 1);
+ iwdkn->path = g_strdup(path);
+ g_hash_table_replace(known_networks, iwdkn->path, iwdkn);
+
+ iwdkn->proxy = g_dbus_proxy_ref(proxy);
+
+ if (!iwdkn->proxy) {
+ connman_error("Cannot create IWD known network watcher %s", path);
+ g_hash_table_remove(known_networks, path);
+ return;
+ }
+
+ iwdkn->name = g_strdup(proxy_get_string(proxy, "Name"));
+ iwdkn->type = g_strdup(proxy_get_string(proxy, "Type"));
+ iwdkn->hidden = proxy_get_bool(proxy, "Hidden");
+ iwdkn->last_connected_time =
+ g_strdup(proxy_get_string(proxy, "LastConnectedTime"));
+ iwdkn->auto_connect = proxy_get_bool(proxy, "AutoConnect");
+
+ DBG("name '%s' type %s hidden %d, last_connection_time %s auto_connect %d",
+ iwdkn->name, iwdkn->type, iwdkn->hidden,
+ iwdkn->last_connected_time, iwdkn->auto_connect);
+
+ init_auto_connect(iwdkn);
+
+ g_dbus_proxy_set_property_watch(iwdkn->proxy,
+ known_network_property_change, NULL);
+}
+
+static void create_station(GDBusProxy *proxy)
+{
+ const char *path = g_dbus_proxy_get_path(proxy);
+ struct iwd_station *iwds;
+
+ iwds = g_new0(struct iwd_station, 1);
+ iwds->path = g_strdup(path);
+ g_hash_table_replace(stations, iwds->path, iwds);
+
+ iwds->proxy = g_dbus_proxy_ref(proxy);
+
+ if (!iwds->proxy) {
+ connman_error("Cannot create IWD station watcher %s", path);
+ g_hash_table_remove(stations, path);
+ return;
+ }
+
+ iwds->state = g_strdup(proxy_get_string(proxy, "State"));
+ iwds->connected_network = g_strdup(proxy_get_string(proxy, "ConnectedNetwork"));
+ iwds->scanning = proxy_get_bool(proxy, "Scanning");
+
+ DBG("state '%s' connected_network %s scanning %d",
+ iwds->state, iwds->connected_network, iwds->scanning);
+
+ g_dbus_proxy_set_property_watch(iwds->proxy,
+ station_property_change, NULL);
+}
+
+static void create_ap(GDBusProxy *proxy)
+{
+ const char *path = g_dbus_proxy_get_path(proxy);
+ struct iwd_ap *iwdap;
+
+ iwdap = g_new0(struct iwd_ap, 1);
+ iwdap->index = -1;
+
+ iwdap->path = g_strdup(path);
+ g_hash_table_replace(access_points, iwdap->path, iwdap);
+
+ iwdap->proxy = g_dbus_proxy_ref(proxy);
+
+ if (!iwdap->proxy) {
+ connman_error("Cannot create IWD access point watcher %s", path);
+ g_hash_table_remove(access_points, path);
+ return;
+ }
+
+ iwdap->started = proxy_get_bool(proxy, "Started");
+
+ DBG("started %d", iwdap->started);
+
+ g_dbus_proxy_set_property_watch(iwdap->proxy,
+ ap_property_change, NULL);
+}
+
static void object_added(GDBusProxy *proxy, void *user_data)
{
const char *interface;
@@ -989,6 +1860,12 @@ static void object_added(GDBusProxy *proxy, void *user_data)
create_device(proxy);
else if (!strcmp(interface, IWD_NETWORK_INTERFACE))
create_network(proxy);
+ else if (!strcmp(interface, IWD_KNOWN_NETWORK_INTERFACE))
+ create_know_network(proxy);
+ else if (!strcmp(interface, IWD_STATION_INTERFACE))
+ create_station(proxy);
+ else if (!strcmp(interface, IWD_AP_INTERFACE))
+ create_ap(proxy);
}
static void object_removed(GDBusProxy *proxy, void *user_data)
@@ -1013,6 +1890,12 @@ static void object_removed(GDBusProxy *proxy, void *user_data)
g_hash_table_remove(devices, path);
else if (!strcmp(interface, IWD_NETWORK_INTERFACE))
g_hash_table_remove(networks, path);
+ else if (!strcmp(interface, IWD_KNOWN_NETWORK_INTERFACE))
+ g_hash_table_remove(known_networks, path);
+ else if (!strcmp(interface, IWD_STATION_INTERFACE))
+ g_hash_table_remove(stations, path);
+ else if (!strcmp(interface, IWD_AP_INTERFACE))
+ g_hash_table_remove(access_points, path);
}
static int iwd_init(void)
@@ -1030,6 +1913,15 @@ static int iwd_init(void)
networks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
network_free);
+ known_networks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+ known_network_free);
+
+ stations = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+ station_free);
+
+ access_points = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+ ap_free);
+
if (connman_technology_driver_register(&tech_driver) < 0) {
connman_warn("Failed to initialize technology for IWD");
goto out;
@@ -1069,6 +1961,15 @@ out:
if (networks)
g_hash_table_destroy(networks);
+ if (known_networks)
+ g_hash_table_destroy(known_networks);
+
+ if (stations)
+ g_hash_table_destroy(stations);
+
+ if (access_points)
+ g_hash_table_destroy(access_points);
+
if (adapters)
g_hash_table_destroy(adapters);
@@ -1086,6 +1987,9 @@ static void iwd_exit(void)
g_dbus_client_unref(client);
+ g_hash_table_destroy(access_points);
+ g_hash_table_destroy(stations);
+ g_hash_table_destroy(known_networks);
g_hash_table_destroy(networks);
g_hash_table_destroy(devices);
g_hash_table_destroy(adapters);
diff --git a/plugins/loopback.c b/plugins/loopback.c
index 28a59c9c..d0ed6268 100755
--- a/plugins/loopback.c
+++ b/plugins/loopback.c
@@ -48,16 +48,6 @@ static in_addr_t loopback_netmask;
static char system_hostname[HOST_NAME_MAX + 1];
-static void create_hostname(void)
-{
- const char *name = "localhost";
-
- if (sethostname(name, strlen(name)) < 0)
- connman_error("Failed to set hostname to %s", name);
-
- strncpy(system_hostname, name, HOST_NAME_MAX);
-}
-
#if defined TIZEN_EXT
static void _create_hostname(void)
{
@@ -73,14 +63,14 @@ static void _create_hostname(void)
fp = fopen(WIFI_MAC, "r");
if(!fp){
connman_error("Failed to get current hostname");
- strncpy(system_hostname, dev_id, strlen(dev_id));
+ strncpy(system_hostname, dev_id, sizeof(system_hostname) - 1);
return;
}
rv = fgets(wifi_mac, HOST_NAME_MAX, fp);
if(!rv){
connman_error("Failed to get current hostname");
- strncpy(system_hostname, dev_id, strlen(dev_id));
+ strncpy(system_hostname, dev_id, sizeof(system_hostname) - 1);
fclose(fp);
return;
}
@@ -90,6 +80,17 @@ static void _create_hostname(void)
g_free(dev_id);
fclose(fp);
}
+#else
+static void create_hostname(void)
+{
+ const char *name = "localhost";
+
+ if (sethostname(name, strlen(name)) < 0)
+ connman_error("Failed to set hostname to %s", name);
+
+ strncpy(system_hostname, name, HOST_NAME_MAX);
+}
+
#endif
static int setup_hostname(void)
@@ -102,6 +103,7 @@ static int setup_hostname(void)
connman_error("Failed to get current hostname");
return -EIO;
}
+
#if defined TIZEN_EXT
if (strlen(system_hostname) > 0 &&
strcmp(system_hostname, "(none)") != 0 &&
diff --git a/plugins/neard.c b/plugins/neard.c
index 69586df6..caaea853 100755
--- a/plugins/neard.c
+++ b/plugins/neard.c
@@ -223,9 +223,9 @@ static DBusMessage *create_request_oob_reply(DBusMessage *message)
DBusMessageIter dict;
const char *ssid, *psk;
uint8_t *tlv_msg;
- int length;
+ int length, freq;
- if (!connman_technology_get_wifi_tethering(&ssid, &psk))
+ if (!connman_technology_get_wifi_tethering(NULL, &ssid, &psk, &freq))
return get_reply_on_error(message, ENOTSUP);
tlv_msg = encode_to_tlv(ssid, psk, &length);
@@ -499,7 +499,7 @@ static void register_agent_cb(DBusPendingCall *pending, void *user_data)
DBusMessage *reply;
if (!dbus_pending_call_get_completed(pending))
- return;
+ goto out;
register_call = NULL;
diff --git a/plugins/ofono.c b/plugins/ofono.c
index 82413b6e..f0bd3c5d 100755
--- a/plugins/ofono.c
+++ b/plugins/ofono.c
@@ -614,7 +614,7 @@ static void context_set_active_reply(struct modem_data *modem,
if (success) {
/*
* Don't handle do anything on success here. oFono will send
- * the change via PropertyChanged singal.
+ * the change via PropertyChanged signal.
*/
return;
}
@@ -667,7 +667,7 @@ static void cdma_cm_set_powered_reply(struct modem_data *modem,
if (success) {
/*
* Don't handle do anything on success here. oFono will send
- * the change via PropertyChanged singal.
+ * the change via PropertyChanged signal.
*/
return;
}
@@ -910,7 +910,7 @@ static void extract_ipv4_settings(DBusMessageIter *array,
if (context->ipv4_method != CONNMAN_IPCONFIG_METHOD_FIXED)
goto out;
- context->ipv4_address = connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV4);
+ context->ipv4_address = connman_ipaddress_alloc(AF_INET);
if (!context->ipv4_address) {
context->index = -1;
goto out;
@@ -998,7 +998,7 @@ static void extract_ipv6_settings(DBusMessageIter *array,
context->ipv6_method = CONNMAN_IPCONFIG_METHOD_AUTO;
context->ipv6_address =
- connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV6);
+ connman_ipaddress_alloc(AF_INET6);
if (!context->ipv6_address)
goto out;
@@ -2968,7 +2968,7 @@ static void ofono_exit(void)
if (modem_hash) {
/*
- * We should propably wait for the SetProperty() reply
+ * We should probably wait for the SetProperty() reply
* message, because ...
*/
g_hash_table_foreach(modem_hash, modem_power_down, NULL);
diff --git a/plugins/session_policy_local.c b/plugins/session_policy_local.c
index 9beb0980..32b9c697 100755
--- a/plugins/session_policy_local.c
+++ b/plugins/session_policy_local.c
@@ -66,7 +66,7 @@ static GHashTable *gid_hash; /* (gid, policy_group) */
struct policy_file {
/*
* A valid file is a keyfile with one ore more groups. All
- * groups are keept in this list.
+ * groups are kept in this list.
*/
GSList *groups;
};
@@ -134,7 +134,7 @@ static char *parse_selinux_type(const char *context)
/*
* SELinux combines Role-Based Access Control (RBAC), Type
- * Enforcment (TE) and optionally Multi-Level Security (MLS).
+ * Enforcement (TE) and optionally Multi-Level Security (MLS).
*
* When SELinux is enabled all processes and files are labeled
* with a contex that contains information such as user, role
@@ -145,7 +145,7 @@ static char *parse_selinux_type(const char *context)
*
* For identifyng application we (ab)using the type
* information. In the above example the haifux_exec_t type
- * will be transfered to haifux_t as defined in the domain
+ * will be transferred to haifux_t as defined in the domain
* transition and thus we are able to identify the application
* as haifux_t.
*/
diff --git a/plugins/tist.c b/plugins/tist.c
index cc2800a1..c3a5e694 100755
--- a/plugins/tist.c
+++ b/plugins/tist.c
@@ -578,7 +578,7 @@ static int tist_init(void)
err = install_ldisc(install_channel, true);
if (err < 0) {
- connman_error("ldisc installtion failed");
+ connman_error("ldisc installation failed");
return err;
}
}
diff --git a/plugins/vpn.c b/plugins/vpn.c
index 11bab154..42396d2a 100755
--- a/plugins/vpn.c
+++ b/plugins/vpn.c
@@ -3,6 +3,7 @@
* Connection Manager
*
* Copyright (C) 2012-2013 Intel Corporation. All rights reserved.
+ * Copyright (C) 2019-2021 Jolla Ltd. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -85,6 +86,7 @@ struct connection_data {
char *domain;
char **nameservers;
bool immutable;
+ bool default_route_set;
GHashTable *server_routes;
GHashTable *user_routes;
@@ -94,6 +96,7 @@ struct connection_data {
GResolv *resolv;
guint resolv_id;
+ guint remove_resolv_id;
};
static int set_string(struct connman_provider *provider,
@@ -151,6 +154,8 @@ static const char *get_string(struct connman_provider *provider,
return data->host_ip[0];
} else if (g_str_equal(key, "VPN.Domain"))
return data->domain;
+ else if (g_str_equal(key, "Transport"))
+ return data->service_ident;
return g_hash_table_lookup(data->setting_strings, key);
}
@@ -171,10 +176,15 @@ static char *get_ident(const char *path)
static void cancel_host_resolv(struct connection_data *data)
{
- if (data->resolv_id != 0)
+
+ if (data->remove_resolv_id)
+ g_source_remove(data->remove_resolv_id);
+
+ if (data->resolv && data->resolv_id)
g_resolv_cancel_lookup(data->resolv, data->resolv_id);
data->resolv_id = 0;
+ data->remove_resolv_id = 0;
g_resolv_unref(data->resolv);
data->resolv = NULL;
@@ -206,7 +216,7 @@ static void resolv_result(GResolvResultStatus status,
* We cannot unref the resolver here as resolv struct is manipulated
* by gresolv.c after we return from this callback.
*/
- g_idle_add(remove_resolv, data);
+ data->remove_resolv_id = g_idle_add(remove_resolv, data);
data->resolv_id = 0;
}
@@ -261,14 +271,12 @@ static bool provider_is_connected(struct connection_data *data)
static void set_provider_state(struct connection_data *data)
{
enum connman_provider_state state = CONNMAN_PROVIDER_STATE_UNKNOWN;
+ bool connected;
int err = 0;
DBG("provider %p new state %s", data->provider, data->state);
- if (!provider_is_connected(data)) {
- g_free(data->service_ident);
- data->service_ident = NULL;
- }
+ connected = provider_is_connected(data);
if (g_str_equal(data->state, "ready")) {
state = CONNMAN_PROVIDER_STATE_READY;
@@ -288,7 +296,7 @@ static void set_provider_state(struct connection_data *data)
}
connman_provider_set_state(data->provider, state);
- return;
+ goto free;
set:
if (data->cb_data)
@@ -299,6 +307,12 @@ set:
free_config_cb_data(data->cb_data);
data->cb_data = NULL;
+
+free:
+ if (!connected) {
+ g_free(data->service_ident);
+ data->service_ident = NULL;
+ }
}
static int create_provider(struct connection_data *data, void *user_data)
@@ -431,6 +445,7 @@ static int extract_ip(DBusMessageIter *array, int family,
}
connman_ipaddress_set_peer(data->ip, peer);
+ connman_ipaddress_set_p2p(data->ip, true);
return 0;
}
@@ -477,6 +492,12 @@ static int errorstr2val(const char *error) {
if (g_strcmp0(error, CONNMAN_ERROR_INTERFACE ".AlreadyConnected") == 0)
return -EISCONN;
+ if (g_strcmp0(error, CONNMAN_ERROR_INTERFACE ".NoCarrier") == 0)
+ return -ENOLINK;
+
+ if (g_strcmp0(error, CONNMAN_ERROR_INTERFACE ".OperationCanceled") == 0)
+ return -ECANCELED;
+
return -ECONNREFUSED;
}
@@ -487,19 +508,48 @@ static void connect_reply(DBusPendingCall *call, void *user_data)
struct connection_data *data = user_data;
struct config_create_data *cb_data = data->cb_data;
- if (!dbus_pending_call_get_completed(call))
+ DBG("");
+
+ if (!dbus_pending_call_get_completed(call)) {
+ connman_warn("vpn connect reply pending call incomplete");
+ goto out;
+ }
+
+ if (call != data->call) {
+ connman_error("invalid call %p to VPN connect_reply data %p "
+ " call %p ", call, data, data->call);
+ dbus_pending_call_unref(call);
return;
+ }
DBG("user_data %p path %s", user_data, cb_data ? cb_data->path : NULL);
reply = dbus_pending_call_steal_reply(call);
+ if (!reply)
+ goto out;
dbus_error_init(&error);
if (dbus_set_error_from_message(&error, reply)) {
int err = errorstr2val(error.name);
- if (err != -EINPROGRESS) {
+ switch (err) {
+ case -EINPROGRESS:
+ break;
+ /*
+ * ECANCELED means that user has canceled authentication
+ * dialog. That's not really an error, it's part of a normal
+ * workflow. We also take it as a request to turn autoconnect
+ * off, in case if it was on.
+ */
+ case -ECANCELED:
+ DBG("%s connect canceled", data->path);
+ connman_provider_set_autoconnect(data->provider, false);
+ break;
+ case -ENOLINK: /* vpnd reports that connmand is not online. */
+ case -EISCONN:
+ case -ECONNREFUSED:
+ default:
connman_error("Connect reply: %s (%s)", error.message,
error.name);
DBG("data %p cb_data %p", data, cb_data);
@@ -522,7 +572,11 @@ static void connect_reply(DBusPendingCall *call, void *user_data)
dbus_message_unref(reply);
- dbus_pending_call_unref(call);
+out:
+ dbus_pending_call_unref(data->call);
+
+ data->call = NULL;
+ data->connect_pending = false;
}
static int connect_provider(struct connection_data *data, void *user_data,
@@ -541,7 +595,10 @@ static int connect_provider(struct connection_data *data, void *user_data,
return -EINVAL;
}
- data->connect_pending = false;
+ if (data->connect_pending && data->call) {
+ connman_info("connect already pending");
+ return -EALREADY;
+ }
/* We need to pass original dbus sender to connman-vpnd,
* use a Connect2 method for that if the original dbus sender is set.
@@ -575,6 +632,14 @@ static int connect_provider(struct connection_data *data, void *user_data,
return -EINVAL;
}
+ if (data->call) {
+ dbus_pending_call_cancel(data->call);
+ dbus_pending_call_unref(data->call);
+ }
+
+ data->call = call;
+ data->connect_pending = true;
+
if (cb_data) {
g_free(cb_data->path);
cb_data->path = g_strdup(data->path);
@@ -733,12 +798,16 @@ static void get_connections_reply(DBusPendingCall *call, void *user_data)
DBUS_DICT_ENTRY_END_CHAR_AS_STRING
DBUS_STRUCT_END_CHAR_AS_STRING;
- if (!dbus_pending_call_get_completed(call))
- return;
-
DBG("");
+ if (!dbus_pending_call_get_completed(call)) {
+ connman_warn("get connections reply pending call incomplete");
+ goto out;
+ }
+
reply = dbus_pending_call_steal_reply(call);
+ if (!reply)
+ goto out;
dbus_error_init(&error);
@@ -778,6 +847,7 @@ static void get_connections_reply(DBusPendingCall *call, void *user_data)
done:
dbus_message_unref(reply);
+out:
dbus_pending_call_unref(call);
}
@@ -825,12 +895,16 @@ static void remove_connection_reply(DBusPendingCall *call, void *user_data)
DBusMessage *reply;
DBusError error;
- if (!dbus_pending_call_get_completed(call))
- return;
-
DBG("");
+ if (!dbus_pending_call_get_completed(call)) {
+ connman_warn("remove connection reply pending call incomplete");
+ goto out;
+ }
+
reply = dbus_pending_call_steal_reply(call);
+ if (!reply)
+ goto out;
dbus_error_init(&error);
@@ -848,6 +922,7 @@ static void remove_connection_reply(DBusPendingCall *call, void *user_data)
dbus_message_unref(reply);
+out:
dbus_pending_call_unref(call);
}
@@ -952,7 +1027,7 @@ static int disconnect_provider(struct connection_data *data)
if (data->disconnect_call) {
DBG("already disconnecting");
- return -EINVAL;
+ return -EALREADY;
}
message = dbus_message_new_method_call(VPN_SERVICE, data->path,
@@ -974,16 +1049,21 @@ static int disconnect_provider(struct connection_data *data)
dbus_pending_call_set_notify(data->disconnect_call, disconnect_reply,
data, NULL);
- g_free(data->service_ident);
- data->service_ident = NULL;
+ data->default_route_set = false;
connman_provider_set_state(data->provider,
CONNMAN_PROVIDER_STATE_DISCONNECT);
+
+ g_free(data->service_ident);
+ data->service_ident = NULL;
+
return -EINPROGRESS;
}
static int provider_disconnect(struct connman_provider *provider)
{
+ int err = 0;
+
struct connection_data *data;
DBG("provider %p", provider);
@@ -993,9 +1073,17 @@ static int provider_disconnect(struct connman_provider *provider)
return -EINVAL;
if (provider_is_connected(data))
- return disconnect_provider(data);
+ err = disconnect_provider(data);
- return 0;
+ if (data->call) {
+ dbus_pending_call_cancel(data->call);
+ dbus_pending_call_unref(data->call);
+ data->call = NULL;
+ }
+
+ data->connect_pending = false;
+
+ return err;
}
static void configuration_create_reply(DBusPendingCall *call, void *user_data)
@@ -1009,12 +1097,16 @@ static void configuration_create_reply(DBusPendingCall *call, void *user_data)
struct connection_data *data;
struct config_create_data *cb_data = user_data;
- if (!dbus_pending_call_get_completed(call))
- return;
-
DBG("user %p", cb_data);
+ if (!dbus_pending_call_get_completed(call)) {
+ connman_warn("configuration create reply pending call incomplete");
+ goto out;
+ }
+
reply = dbus_pending_call_steal_reply(call);
+ if (!reply)
+ goto out;
dbus_error_init(&error);
@@ -1068,6 +1160,7 @@ static void configuration_create_reply(DBusPendingCall *call, void *user_data)
done:
dbus_message_unref(reply);
+out:
dbus_pending_call_unref(call);
}
@@ -1415,6 +1508,17 @@ static void set_route(struct connection_data *data, struct vpn_route *route)
return;
}
+ DBG("set route provider %p %s/%s/%s", data->provider,
+ route->network, route->gateway,
+ route->netmask);
+
+ /* Do not add default route for split routed VPNs.*/
+ if (connman_provider_is_split_routing(data->provider) &&
+ connman_inet_is_default_route(route->family,
+ route->network, route->gateway,
+ route->netmask))
+ return;
+
if (route->family == AF_INET6) {
unsigned char prefix_len = atoi(route->netmask);
@@ -1427,6 +1531,126 @@ static void set_route(struct connection_data *data, struct vpn_route *route)
route->gateway,
route->netmask);
}
+
+ if (connman_inet_is_default_route(route->family, route->network,
+ route->gateway, route->netmask))
+ data->default_route_set = true;
+}
+
+static int save_route(GHashTable *routes, int family, const char *network,
+ const char *netmask, const char *gateway);
+
+static int add_network_route(struct connection_data *data)
+{
+ struct vpn_route rt = { 0, };
+ int err;
+
+ if (!data)
+ return -EINVAL;
+
+ rt.family = connman_provider_get_family(data->provider);
+ switch (rt.family) {
+ case PF_INET:
+ err = connman_inet_get_route_addresses(data->index,
+ &rt.network, &rt.netmask, &rt.gateway);
+ break;
+ case PF_INET6:
+ err = connman_inet_ipv6_get_route_addresses(data->index,
+ &rt.network, &rt.netmask, &rt.gateway);
+ break;
+ default:
+ connman_error("invalid protocol family %d", rt.family);
+ return -EINVAL;
+ }
+
+ DBG("network %s gateway %s netmask %s for provider %p",
+ rt.network, rt.gateway, rt.netmask,
+ data->provider);
+
+ if (err) {
+ connman_error("cannot get network/gateway/netmask for %p",
+ data->provider);
+ goto out;
+ }
+
+ err = save_route(data->server_routes, rt.family, rt.network, rt.netmask,
+ rt.gateway);
+ if (err) {
+ connman_warn("failed to add network route for provider"
+ "%p", data->provider);
+ goto out;
+ }
+
+ set_route(data, &rt);
+
+out:
+ g_free(rt.network);
+ g_free(rt.netmask);
+ g_free(rt.gateway);
+
+ return 0;
+}
+
+static bool is_valid_route_table(struct connman_provider *provider,
+ GHashTable *table)
+{
+ GHashTableIter iter;
+ gpointer value, key;
+ struct vpn_route *route;
+ size_t table_size;
+
+ if (!table)
+ return false;
+
+ table_size = g_hash_table_size(table);
+
+ /* Non-split routed may have only the default route */
+ if (table_size > 0 && !connman_provider_is_split_routing(provider))
+ return true;
+
+ /* Split routed has more than the default route */
+ if (table_size > 1)
+ return true;
+
+ /*
+ * Only one route for split routed VPN, which should not be the
+ * default route.
+ */
+ g_hash_table_iter_init(&iter, table);
+ if (!g_hash_table_iter_next(&iter, &key, &value)) /* First and only */
+ return false;
+
+ route = value;
+ if (!route)
+ return false;
+
+ DBG("check route %d %s/%s/%s", route->family, route->network,
+ route->gateway, route->netmask);
+
+ if (!connman_inet_is_default_route(route->family, route->network,
+ route->gateway, route->netmask))
+ return true;
+
+ return false;
+}
+
+static bool check_routes(struct connman_provider *provider)
+{
+ struct connection_data *data;;
+
+ DBG("provider %p", provider);
+
+ data = connman_provider_get_data(provider);
+ if (!data)
+ return false;
+
+ if (is_valid_route_table(provider, data->user_routes))
+ return true;
+
+ if (is_valid_route_table(provider, data->server_routes))
+ return true;
+
+ return false;
}
static int set_routes(struct connman_provider *provider,
@@ -1458,28 +1682,30 @@ static int set_routes(struct connman_provider *provider,
set_route(data, value);
}
- return 0;
-}
-
-static bool check_routes(struct connman_provider *provider)
-{
- struct connection_data *data;
-
- DBG("provider %p", provider);
-
- data = connman_provider_get_data(provider);
- if (!data)
- return false;
+ /* If non-split routed VPN does not have a default route, add it */
+ if (!connman_provider_is_split_routing(provider) &&
+ !data->default_route_set) {
+ int family = connman_provider_get_family(provider);
+ const char *ipaddr_any = family == AF_INET6 ?
+ "::" : "0.0.0.0";
+ struct vpn_route def_route = {family, (char*) ipaddr_any,
+ (char*) ipaddr_any, NULL};
- if (data->user_routes &&
- g_hash_table_size(data->user_routes) > 0)
- return true;
+ set_route(data, &def_route);
+ }
- if (data->server_routes &&
- g_hash_table_size(data->server_routes) > 0)
- return true;
+ /* Split routed VPN must have at least one route to the network */
+ if (connman_provider_is_split_routing(provider) &&
+ !check_routes(provider)) {
+ int err = add_network_route(data);
+ if (err) {
+ connman_warn("cannot add network route provider %p",
+ provider);
+ return err;
+ }
+ }
- return false;
+ return 0;
}
static struct connman_provider_driver provider_driver = {
@@ -1648,12 +1874,52 @@ static int save_route(GHashTable *routes, int family, const char *network,
route->gateway = g_strdup(gateway);
g_hash_table_replace(routes, key, route);
- } else
+ } else {
g_free(key);
+ return -EALREADY;
+ }
return 0;
}
+static void change_provider_split_routing(struct connman_provider *provider,
+ bool split_routing)
+{
+ struct connection_data *data;
+ int err;
+
+ if (!provider)
+ return;
+
+ if (connman_provider_is_split_routing(provider) == split_routing)
+ return;
+
+ data = connman_provider_get_data(provider);
+ if (split_routing && data && provider_is_connected(data) &&
+ !check_routes(provider)) {
+ err = add_network_route(data);
+ if (err) {
+ connman_warn("cannot add network route provider %p",
+ provider);
+ return;
+ }
+ }
+
+ err = connman_provider_set_split_routing(provider, split_routing);
+ switch (err) {
+ case 0:
+ /* fall through */
+ case -EALREADY:
+ break;
+ case -EINVAL:
+ /* fall through */
+ case -EOPNOTSUPP:
+ connman_warn("cannot change split routing %d", err);
+ default:
+ break;
+ }
+}
+
static int read_route_dict(GHashTable *routes, DBusMessageIter *dicts)
{
DBusMessageIter dict;
@@ -1830,6 +2096,10 @@ static gboolean property_changed(DBusConnection *conn,
g_free(data->domain);
data->domain = g_strdup(str);
connman_provider_set_domain(data->provider, data->domain);
+ } else if (g_str_equal(key, "SplitRouting")) {
+ dbus_bool_t split_routing;
+ dbus_message_iter_get_basic(&value, &split_routing);
+ change_provider_split_routing(data->provider, split_routing);
}
if (ip_set && err == 0) {
@@ -1909,14 +2179,19 @@ static bool vpn_is_valid_transport(struct connman_service *transport)
static void vpn_disconnect_check_provider(struct connection_data *data)
{
- if (data->service_ident && provider_is_connected(data)) {
+ if (provider_is_connected(data)) {
+ /* With NULL service ident NULL is returned immediately */
struct connman_service *service =
connman_service_lookup_from_identifier
(data->service_ident);
if (!vpn_is_valid_transport(service)) {
- disconnect_provider(data);
+ connman_provider_disconnect(data->provider);
}
+
+ /* VPN moved to be split routed, default route is not set */
+ if (connman_provider_is_split_routing(data->provider))
+ data->default_route_set = false;
}
}
diff --git a/plugins/wifi.c b/plugins/wifi.c
index 6672f0dd..68f34313 100755
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -33,6 +33,10 @@
#include <net/ethernet.h>
#include <linux/wireless.h>
+#if defined TIZEN_EXT
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
#ifndef IFF_LOWER_UP
#define IFF_LOWER_UP 0x10000
#endif
@@ -49,7 +53,6 @@
#include <connman/service.h>
#include <connman/peer.h>
#include <connman/log.h>
-#include <connman/option.h>
#include <connman/storage.h>
#include <include/setting.h>
#include <connman/provision.h>
@@ -59,19 +62,23 @@
#include <gsupplicant/gsupplicant.h>
+#include "src/shared/util.h"
+
#define CLEANUP_TIMEOUT 8 /* in seconds */
#define INACTIVE_TIMEOUT 12 /* in seconds */
#define FAVORITE_MAXIMUM_RETRIES 2
-#define BGSCAN_DEFAULT "simple:30:-45:300"
+#define BGSCAN_DEFAULT "simple:30:-65:300"
#define AUTOSCAN_EXPONENTIAL "exponential:3:300"
#define AUTOSCAN_SINGLE "single:3"
+#define SCAN_MAX_DURATION 10
#define P2P_FIND_TIMEOUT 30
#define P2P_CONNECTION_TIMEOUT 100
#define P2P_LISTEN_PERIOD 500
#define P2P_LISTEN_INTERVAL 2000
+#define ASSOC_STATUS_AUTH_TIMEOUT 16
#define ASSOC_STATUS_NO_CLIENT 17
#if defined TIZEN_EXT
#define LOAD_SHAPING_MAX_RETRIES 7
@@ -81,11 +88,52 @@
#if defined TIZEN_EXT
#define WIFI_EAP_FAST_PAC_FILE "/var/lib/wifi/wifi.pac" /* path of Pac file for EAP-FAST */
+
+ /* Wi-Fi Signal Strength (for 2.4G (dB))
+ * Excellent : ~ -63
+ * Good : -64 ~ -74
+ * Weak : -75 ~ -82
+ * Very weak : -83 ~ -88
+ * No signal : -89 ~
+ *
+ * Wi-Fi Signal Strength (for 5G (dB))
+ * Excellent : ~ -67
+ * Good : -68 ~ -76
+ * Weak : -77 ~ -82
+ * Very weak : -83 ~ -88
+ * No signal : -89 ~
+ *
+ * Wi-Fi Signal Strength (for 6G (dB))
+ *
+ * Excellent : ~ -72
+ * Good : -73 ~ -77
+ * Weak : -78 ~ -82
+ * Very weak : -83 ~ -88
+ * No signal : -89 ~
+ */
+#define RSSI_LEVEL_2_6G -78
+#define RSSI_LEVEL_2_5G -77
+#define RSSI_LEVEL_2_2_4G -75
+#define RSSI_LEVEL_3_6G -73
+#define RSSI_LEVEL_3_5G -68
+#define RSSI_LEVEL_3_2_4G -64
+#define ROAM_SCAN_INTERVAL 60 /* 60 seconds */
+#define FREQUENCY_5G_BASE 5000
+#define FREQUENCY_6G_BASE 5925
+
+static int min_snr = 0;
+static int min_rssi_2_4GHz = 0;
+static int min_rssi_5GHz = 0;
+static int min_rssi_6GHz = 0;
#endif
static struct connman_technology *wifi_technology = NULL;
static struct connman_technology *p2p_technology = NULL;
+#if defined TIZEN_EXT
+static GSupplicantState assoc_last_state = G_SUPPLICANT_STATE_UNKNOWN;
+#endif
+
enum wifi_ap_capability{
WIFI_AP_UNKNOWN = 0,
WIFI_AP_SUPPORTED = 1,
@@ -173,6 +221,9 @@ struct wifi_data {
bool allow_full_scan;
unsigned int automaxspeed_timeout;
GSupplicantScanParams *hidden_scan_params;
+ unsigned int mac_policy;
+ unsigned int preassoc_mac_policy;
+ unsigned int mac_lifetime;
#endif
int disconnect_code;
int assoc_code;
@@ -182,6 +233,15 @@ struct wifi_data {
#endif
};
+struct wifi_network {
+ unsigned int keymgmt;
+};
+
+struct disconnect_data {
+ struct wifi_data *wifi;
+ struct connman_network *network;
+};
+
#if defined TIZEN_EXT
#include "connman.h"
#include "dbus.h"
@@ -195,7 +255,6 @@ static GHashTable *failed_bssids = NULL;
static unsigned char buff_bssid[WIFI_BSSID_LEN_MAX] = { 0, };
#endif
-
static GList *iface_list = NULL;
static GList *pending_wifi_device = NULL;
@@ -204,7 +263,6 @@ static bool wfd_service_registered = false;
static void start_autoscan(struct connman_device *device);
static int tech_set_tethering(struct connman_technology *technology,
- const char *identifier, const char *passphrase,
const char *bridge, bool enabled);
#if defined TIZEN_EXT
@@ -219,6 +277,8 @@ struct enc_method_call_data {
static struct enc_method_call_data encrypt_request_data;
+static GSupplicantSecurity network_security(const char *security);
+
static void encryption_request_reply(DBusPendingCall *call,
void *user_data)
{
@@ -1125,15 +1185,23 @@ static GSupplicantP2PServiceParams *fill_in_peer_service_params(
if (version > 0) {
params->version = version;
- params->service = g_memdup(spec, spec_length);
+ if (spec_length > 0) {
+ params->service = g_malloc(spec_length);
+ memcpy(params->service, spec, spec_length);
+ }
} else if (query_length > 0 && spec_length > 0) {
- params->query = g_memdup(query, query_length);
+ params->query = g_malloc(query_length);
+ memcpy(params->query, query, query_length);
params->query_length = query_length;
- params->response = g_memdup(spec, spec_length);
+ params->response = g_malloc(spec_length);
+ memcpy(params->response, spec, spec_length);
params->response_length = spec_length;
} else {
- params->wfd_ies = g_memdup(spec, spec_length);
+ if (spec_length > 0) {
+ params->wfd_ies = g_malloc(spec_length);
+ memcpy(params->wfd_ies, spec, spec_length);
+ }
params->wfd_ies_length = spec_length;
}
@@ -1405,14 +1473,15 @@ static void wifi_newlink(unsigned flags, unsigned change, void *user_data)
}
if ((wifi->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
- if (flags & IFF_LOWER_UP) {
+ if (flags & IFF_LOWER_UP)
DBG("carrier on");
-
- handle_tethering(wifi);
- } else
+ else
DBG("carrier off");
}
+ if (flags & IFF_LOWER_UP)
+ handle_tethering(wifi);
+
wifi->flags = flags;
}
@@ -1968,11 +2037,14 @@ static int get_hidden_connections_params(struct wifi_data *wifi,
scan_params->num_ssids = i;
scan_params->ssids = g_slist_reverse(scan_params->ssids);
- scan_params->freqs = g_memdup(orig_params->freqs,
- sizeof(uint16_t) * orig_params->num_freqs);
- if (!scan_params->freqs)
+ if (orig_params->num_freqs <= 0)
goto err;
+ scan_params->freqs =
+ g_malloc(sizeof(uint16_t) * orig_params->num_freqs);
+ memcpy(scan_params->freqs, orig_params->freqs,
+ sizeof(uint16_t) *orig_params->num_freqs);
+
scan_params->num_freqs = orig_params->num_freqs;
} else
@@ -2081,8 +2153,191 @@ static void service_state_changed(struct connman_service *service,
}
}
+static gboolean need_bss_transition(uint16_t freq, int snr, int strength)
+{
+ /*
+ * Since bssid->strength is a positive value,
+ * it need to be changed to its original value.
+ */
+ int signal = strength - 120;
+
+ /*
+ * If the currently connected AP matches the following conditions,
+ * scan for BSS transition is started.
+ * - SNR is less than min_snr or RSSI is less than
+ * min_rssi_2_4GHz, min_rssi_5GHz or min_rssi_6GHz.
+ */
+ if (min_snr != 0 && snr != 0 && snr < min_snr)
+ return TRUE;
+ else if (freq > FREQUENCY_6G_BASE && signal <= min_rssi_6GHz)
+ return TRUE;
+ else if (freq > FREQUENCY_5G_BASE && signal <= min_rssi_5GHz)
+ return TRUE;
+ else if (signal <= min_rssi_2_4GHz)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean check_bss_diff(int cur_level, int sel_level, int to_5ghz,
+ unsigned int cur_est, unsigned int sel_est)
+{
+ int min_diff;
+ int diff;
+
+ /* This code is from wpa_supplicant. */
+ if (cur_level < -85) /* ..-86 dBm */
+ min_diff = 1;
+ else if (cur_level < -80) /* -85..-81 dBm */
+ min_diff = 2;
+ else if (cur_level < -75) /* -80..-76 dBm */
+ min_diff = 3;
+ else if (cur_level < -70) /* -75..-71 dBm */
+ min_diff = 4;
+ else if (cur_level < 0) /* -70..-1 dBm */
+ min_diff = 5;
+ else /* unspecified units (not in dBm) */
+ min_diff = 2;
+
+ if (cur_est > sel_est * 1.5)
+ min_diff += 10;
+ else if (cur_est > sel_est * 1.2)
+ min_diff += 5;
+ else if (cur_est > sel_est * 1.1)
+ min_diff += 2;
+ else if (cur_est > sel_est)
+ min_diff++;
+ else if (sel_est > cur_est * 1.5)
+ min_diff -= 10;
+ else if (sel_est > cur_est * 1.2)
+ min_diff -= 5;
+ else if (sel_est > cur_est * 1.1)
+ min_diff -= 2;
+ else if (sel_est > cur_est)
+ min_diff--;
+
+ if (to_5ghz)
+ min_diff -= 2;
+
+ diff = sel_level - cur_level;
+
+ if (diff < min_diff)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean check_bss_condition(uint16_t freq, uint16_t strength,
+ unsigned int est_throughput, uint16_t cur_freq, uint16_t cur_strength,
+ unsigned int cur_est_throughput)
+{
+ /*
+ * Since bssid->strength is a positive value,
+ * it need to be changed to its original value.
+ */
+ int signal = strength - 120;
+ int cur_signal = cur_strength - 120;
+ int to_5ghz = freq > 4000 && cur_freq < 4000;
+
+ DBG("cur_freq=%d cur_level=%d cur_est=%d sel_freq=%d sel_level=%d sel_est=%d",
+ cur_freq, cur_strength, cur_est_throughput,
+ freq, strength, est_throughput);
+
+ /*
+ * If the AP that matches the following conditions exists in the SCAN result,
+ * BSS transition is started.
+ */
+
+ if (est_throughput > cur_est_throughput + 5000)
+ return TRUE;
+
+ if (cur_signal > signal + to_5ghz * 2 &&
+ est_throughput < cur_est_throughput * 1.2)
+ return FALSE;
+
+ if (cur_est_throughput > est_throughput + 5000)
+ return FALSE;
+
+ return check_bss_diff(cur_signal, signal,
+ to_5ghz, cur_est_throughput, est_throughput);
+}
+
static void scan_callback_hidden(int result,
GSupplicantInterface *interface, void *user_data);
+
+static int network_disconnect(struct connman_network *network);
+
+static void start_roaming(struct wifi_data *wifi)
+{
+ bool roaming_ap_found = false;
+ GSList *bssid_list = NULL;
+
+ if (!wifi || !wifi->network)
+ return;
+
+ if (!connman_setting_get_bool("WifiRoaming"))
+ return;
+
+ struct connman_network *network = wifi->network;
+ bssid_list = connman_network_get_bssid_list(network);
+
+ if (g_slist_length(bssid_list) <= 1)
+ return;
+
+ if (!connman_network_get_connected(network))
+ return;
+
+ if (connman_network_get_bool(network, "WiFi.Roaming"))
+ return;
+
+ uint16_t cur_freq = connman_network_get_frequency(network);
+ uint8_t cur_strength = connman_network_get_strength(network);
+ unsigned int cur_est_throughput = connman_network_get_est_throughput(network);
+
+ if (!need_bss_transition(
+ cur_freq,
+ connman_network_get_snr(network),
+ cur_strength))
+ return;
+
+ unsigned char *cur_bssid = connman_network_get_bssid(network);
+
+ for (; bssid_list; bssid_list = bssid_list->next) {
+ struct g_connman_bssids *bssid = bssid_list->data;
+
+ if (memcmp(cur_bssid, bssid->bssid, WIFI_BSSID_LEN_MAX) == 0)
+ continue;
+
+ if (check_bss_condition(
+ bssid->frequency, bssid->strength, bssid->est_throughput,
+ cur_freq, cur_strength, cur_est_throughput)) {
+ roaming_ap_found = true;
+
+ char bssid_buff[WIFI_BSSID_STR_LEN] = {0,};
+ char *bssid_str = bssid_buff;
+
+ snprintf(bssid_str, WIFI_BSSID_STR_LEN, MACSTR, MAC2STR(bssid->bssid));
+ connman_network_set_string(network,
+ "WiFi.RoamingDstBSSID", bssid_str);
+ break;
+ }
+ }
+
+ if (roaming_ap_found) {
+ char bssid_buff[WIFI_BSSID_STR_LEN] = {0,};
+ char *bssid_str = bssid_buff;
+ unsigned char *bssid;
+
+ bssid = connman_network_get_bssid(network);
+ snprintf(bssid_str, WIFI_BSSID_STR_LEN, MACSTR, MAC2STR(bssid));
+ connman_network_set_string(network,
+ "WiFi.RoamingCurBSSID", bssid_str);
+
+ network_disconnect(network);
+ wifi->pending_network = network;
+ connman_network_set_bool(network, "WiFi.Roaming", true);
+ }
+}
#endif
static void scan_callback(int result, GSupplicantInterface *interface,
@@ -2152,7 +2407,8 @@ static void scan_callback(int result, GSupplicantInterface *interface,
if (service != NULL &&
(connman_service_get_favorite(service) == true) &&
(connman_service_get_autoconnect(service) == true)) {
- DBG("Favorite service exists [%s]", connman_network_get_string(network, "Name"));
+ DBG("Favorite service exists [%s]",
+ connman_network_get_string(network, "Name"));
favorite_exists = true;
break;
}
@@ -2173,7 +2429,8 @@ static void scan_callback(int result, GSupplicantInterface *interface,
/* On error, let's recall scan_callback, which will cleanup */
return scan_callback(ret, interface, user_data);
}
- }
+ } else
+ wifi->allow_full_scan = false;
#endif
scanning = connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI);
@@ -2200,12 +2457,18 @@ static void scan_callback(int result, GSupplicantInterface *interface,
connman_device_unref(device);
#if defined TIZEN_EXT
- if (wifi && wifi->scan_pending_network && result != -EIO) {
+ if (!wifi)
+ goto done;
+
+ if (wifi->scan_pending_network && result != -EIO) {
network_connect(wifi->scan_pending_network);
wifi->scan_pending_network = NULL;
connman_network_set_connecting(wifi->network);
+ } else {
+ start_roaming(wifi);
}
+done:
if (is_wifi_notifier_registered != true &&
wifi_first_scan == true && found_with_first_scan == true) {
wifi_first_scan = false;
@@ -2406,7 +2669,7 @@ static void setup_autoscan(struct wifi_data *wifi)
return;
}
-#endif
+#else
/*
* On the contrary, if BackgroundScanning is disabled, update autoscan
@@ -2430,6 +2693,7 @@ static void setup_autoscan(struct wifi_data *wifi)
wifi->autoscan = parse_autoscan_params(AUTOSCAN_SINGLE);
break;
}
+#endif
}
static void finalize_interface_creation(struct wifi_data *wifi)
@@ -2457,6 +2721,8 @@ static void interface_create_callback(int result,
void *user_data)
{
struct wifi_data *wifi = user_data;
+ char *bgscan_range_max;
+ long value;
DBG("result %d ifname %s, wifi %p", result,
g_supplicant_interface_get_ifname(interface),
@@ -2467,11 +2733,42 @@ static void interface_create_callback(int result,
wifi->interface = interface;
g_supplicant_interface_set_data(interface, wifi);
+#ifdef TIZEN_EXT
+ if (!interface)
+ return;
+ if (wifi->device &&
+ !connman_device_get_wifi_5ghz_supported(wifi->device) &&
+ !connman_device_get_wifi_6ghz_supported(wifi->device)) {
+ bool is_5_0_ghz_supported = g_supplicant_interface_get_is_5_0_ghz_supported(interface);
+ bool is_6_0_ghz_supported = g_supplicant_interface_get_is_6_0_ghz_supported(interface);
+
+ connman_device_set_wifi_5ghz_supported(wifi->device, is_5_0_ghz_supported);
+ connman_device_set_wifi_6ghz_supported(wifi->device, is_6_0_ghz_supported);
+ }
+#endif
if (g_supplicant_interface_get_ready(interface)) {
wifi->interface_ready = true;
finalize_interface_creation(wifi);
}
+
+ /*
+ * Set the BSS expiration age to match the long scanning
+ * interval to avoid the loss of unconnected networks between
+ * two scans.
+ */
+ bgscan_range_max = strrchr(BGSCAN_DEFAULT, ':');
+ if (!bgscan_range_max || strlen(bgscan_range_max) < 1)
+ return;
+
+ value = strtol(bgscan_range_max + 1, NULL, 10);
+ if (value <= 0 || errno == ERANGE)
+ return;
+
+ if (g_supplicant_interface_set_bss_expiration_age(interface,
+ value + SCAN_MAX_DURATION) < 0) {
+ connman_warn("Failed to set bss expiration age");
+ }
}
static int wifi_enable(struct connman_device *device)
@@ -2479,7 +2776,7 @@ static int wifi_enable(struct connman_device *device)
struct wifi_data *wifi = connman_device_get_data(device);
int index;
char *interface;
- const char *driver = connman_option_get_string("wifi");
+ const char *driver = connman_setting_get_string("wifi");
int ret;
DBG("device %p %p", device, wifi);
@@ -2493,6 +2790,11 @@ static int wifi_enable(struct connman_device *device)
interface = connman_inet_ifname(index);
ret = g_supplicant_interface_create(interface, driver, NULL,
+#ifdef TIZEN_EXT
+ connman_device_get_mac_policy(device),
+ connman_device_get_preassoc_mac_policy(device),
+ connman_device_get_random_mac_lifetime(device),
+#endif /* TIZEN_EXT */
interface_create_callback,
wifi);
g_free(interface);
@@ -2618,7 +2920,12 @@ static int get_latest_connections(int max_ssids,
g_key_file_free(keyfile);
continue;
}
- g_time_val_from_iso8601(str, &modified);
+#if defined TIZEN_EXT
+
+ util_iso8601_to_timeval(str, (struct timeval *)&modified);
+#else
+ util_iso8601_to_timeval(str, &modified);
+#endif
g_free(str);
ssid = g_key_file_get_string(keyfile,
@@ -2632,6 +2939,9 @@ static int get_latest_connections(int max_ssids,
g_sequence_free(latest_list);
g_key_file_free(keyfile);
g_free(ssid);
+#if defined TIZEN_EXT
+ g_strfreev(services);
+#endif
return -ENOMEM;
}
@@ -2785,7 +3095,7 @@ static void specific_scan_callback(int result, GSupplicantInterface *interface,
struct wifi_data *wifi = connman_device_get_data(device);
bool scanning;
- DBG("result %d wifi %p", result, wifi);
+ DBG("result %d device %p wifi %p", result, device, wifi);
if (wifi && wifi->scan_params) {
g_supplicant_free_scan_params(wifi->scan_params);
@@ -2799,6 +3109,8 @@ static void specific_scan_callback(int result, GSupplicantInterface *interface,
CONNMAN_SERVICE_TYPE_WIFI, false);
connman_device_unref(device);
}
+
+ start_roaming(wifi);
}
static int wifi_specific_scan(enum connman_service_type type,
@@ -2880,7 +3192,7 @@ static int wifi_specific_scan(enum connman_service_type type,
count = 0;
for (list = specific_scan_list; list; list = list->next) {
- freq = (int)list->data;
+ freq = GPOINTER_TO_INT(list->data);
scan_params->freqs[count] = freq;
DBG("scan_params->freqs[%d]: %d", count, scan_params->freqs[count]);
@@ -2954,6 +3266,99 @@ static int wifi_specific_scan(enum connman_service_type type,
return ret;
}
+
+static void wifi_mac_policy_callback(int result,
+ unsigned int policy,
+ void *user_data)
+{
+ struct connman_device *device = user_data;
+
+ if (result == 0)
+ connman_device_mac_policy_notify(device, result, policy);
+
+ connman_device_unref(device);
+}
+
+int wifi_set_mac_policy(struct connman_device *device, unsigned int policy)
+{
+ struct wifi_data *wifi = connman_device_get_data(device);
+ int ret;
+
+ if (!wifi)
+ return -EINVAL;
+
+ connman_device_ref(device);
+
+ ret = g_supplicant_interface_set_mac_policy(wifi->interface,
+ wifi_mac_policy_callback,
+ policy, device);
+ if (ret != 0)
+ connman_device_unref(device);
+
+ return ret;
+}
+
+static void wifi_preassoc_mac_policy_callback(int result,
+ unsigned int policy,
+ void *user_data)
+{
+ struct connman_device *device = user_data;
+
+ if (result == 0)
+ connman_device_preassoc_mac_policy_notify(device, result, policy);
+
+ connman_device_unref(device);
+}
+
+int wifi_set_preassoc_mac_policy(struct connman_device *device, unsigned int policy)
+{
+ struct wifi_data *wifi = connman_device_get_data(device);
+ int ret;
+
+ if (!wifi)
+ return -EINVAL;
+
+ connman_device_ref(device);
+
+ ret = g_supplicant_interface_set_preassoc_mac_policy(wifi->interface,
+ wifi_preassoc_mac_policy_callback,
+ policy, device);
+ if (ret != 0)
+ connman_device_unref(device);
+
+ return ret;
+}
+
+static void wifi_random_mac_lifetime_callback(int result,
+ unsigned int lifetime,
+ void *user_data)
+{
+ struct connman_device *device = user_data;
+
+ if (result == 0)
+ connman_device_random_mac_lifetime_notify(device, result, lifetime);
+
+ connman_device_unref(device);
+}
+
+int wifi_set_random_mac_lifetime(struct connman_device *device, unsigned int lifetime)
+{
+ struct wifi_data *wifi = connman_device_get_data(device);
+ int ret;
+
+ if (!wifi)
+ return -EINVAL;
+
+ connman_device_ref(device);
+
+ ret = g_supplicant_interface_set_random_mac_lifetime(wifi->interface,
+ wifi_random_mac_lifetime_callback,
+ lifetime, device);
+ if (ret != 0)
+ connman_device_unref(device);
+
+ return ret;
+}
#endif
#if defined TIZEN_EXT_WIFI_MESH
@@ -3329,6 +3734,9 @@ static struct connman_device_driver wifi_ng_driver = {
.set_regdom = wifi_set_regdom,
#if defined TIZEN_EXT
.specific_scan = wifi_specific_scan,
+ .set_mac_policy = wifi_set_mac_policy,
+ .set_preassoc_mac_policy = wifi_set_preassoc_mac_policy,
+ .set_random_mac_lifetime = wifi_set_random_mac_lifetime,
#endif
#if defined TIZEN_EXT_WIFI_MESH
.abort_scan = mesh_abort_scan,
@@ -3365,6 +3773,11 @@ static void network_remove(struct connman_network *network)
{
struct connman_device *device = connman_network_get_device(network);
struct wifi_data *wifi;
+#if defined TIZEN_EXT
+ GSupplicantSSID *ssid;
+ const void *ssid_data;
+ const char *security;
+#endif
DBG("network %p", network);
@@ -3385,6 +3798,35 @@ static void network_remove(struct connman_network *network)
if (wifi->scan_pending_network == network)
wifi->scan_pending_network = NULL;
+
+ /*
+ * If this remove network is for the same network
+ * for which wpa_supplicant already has a profile
+ * then need to remove that profile.
+ */
+ ssid = g_try_malloc0(sizeof(GSupplicantSSID));
+ if (!ssid)
+ return;
+
+ ssid_data = connman_network_get_blob(network, "WiFi.SSID",
+ &ssid->ssid_len);
+
+ ssid->ssid = g_try_malloc0(ssid->ssid_len);
+
+ if (!ssid->ssid) {
+ g_free(ssid);
+ return;
+ } else {
+ memcpy(ssid->ssid, ssid_data, ssid->ssid_len);
+ }
+
+ security = connman_network_get_string(network, "WiFi.Security");
+ ssid->security = network_security(security);
+
+ g_supplicant_interface_remove_network(wifi->interface, ssid);
+
+ g_free(ssid->ssid);
+ g_free(ssid);
#endif
}
@@ -3414,6 +3856,38 @@ static void connect_callback(int result, GSupplicantInterface *interface,
return;
found:
+ if (connman_network_get_bool(network, "WiFi.Roaming")) {
+ if (result < 0 ) {
+ connman_network_set_bool(network, "WiFi.Roaming", false);
+ connman_network_set_string(network,
+ "WiFi.RoamingCurBSSID", NULL);
+ } else {
+ char bssid_buff[WIFI_BSSID_STR_LEN] = {0,};
+ char *bssid_str = bssid_buff;
+ unsigned char *bssid;
+ const char *cur_bssid;
+
+ bssid = g_supplicant_interface_get_add_network_bssid(interface);
+ if (!bssid) {
+ connman_network_set_bool(network, "WiFi.Roaming", false);
+ connman_network_set_string(network,
+ "WiFi.RoamingCurBSSID", NULL);
+ } else {
+ snprintf(bssid_str,
+ WIFI_BSSID_STR_LEN,
+ MACSTR, MAC2STR(bssid));
+
+ connman_network_set_string(network,
+ "WiFi.RoamingDstBSSID", bssid_str);
+
+ cur_bssid = connman_network_get_string(network,
+ "WiFi.RoamingCurBSSID");
+
+ __connman_technology_notify_roaming_state(ifname,
+ "started", cur_bssid, bssid_str);
+ }
+ }
+ }
#endif
if (result == -ENOKEY) {
connman_network_set_error(network,
@@ -3451,6 +3925,8 @@ static GSupplicantSecurity network_security(const char *security)
return G_SUPPLICANT_SECURITY_OWE;
else if (g_str_equal(security, "dpp"))
return G_SUPPLICANT_SECURITY_DPP;
+ else if (g_str_equal(security, "psk_sha256") == TRUE)
+ return G_SUPPLICANT_SECURITY_PSK_SHA256;
#endif
return G_SUPPLICANT_SECURITY_UNKNOWN;
@@ -3473,6 +3949,7 @@ static GSupplicantEapKeymgmt network_eap_keymgmt(const char *security)
static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network)
{
+ struct wifi_network *network_data = connman_network_get_data(network);
const char *security;
#if defined TIZEN_EXT
const void *ssid_data;
@@ -3495,10 +3972,14 @@ static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network)
#endif
ssid->scan_ssid = 1;
security = connman_network_get_string(network, "WiFi.Security");
- ssid->security = network_security(security);
#if defined TIZEN_EXT
- ssid->ieee80211w = 1;
+ if (connman_network_get_psk_sha256(network))
+ security = "psk_sha256";
#endif
+ ssid->security = network_security(security);
+
+ ssid->keymgmt = network_data->keymgmt;
+ ssid->ieee80211w = G_SUPPLICANT_MFP_OPTIONAL;
ssid->passphrase = connman_network_get_string(network,
"WiFi.Passphrase");
@@ -3580,14 +4061,24 @@ static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network)
}
GSList *list;
- char buff[MAC_ADDRESS_LENGTH];
+ char buff[WIFI_BSSID_STR_LEN];
+ const char *dst_bssid = connman_network_get_string(network,
+ "WiFi.RoamingDstBSSID");
for (list = bssid_list; list; list = list->next) {
struct connman_bssids * bssids = (struct connman_bssids *)list->data;
- g_snprintf(buff, MAC_ADDRESS_LENGTH, "%02x:%02x:%02x:%02x:%02x:%02x",
- bssids->bssid[0], bssids->bssid[1], bssids->bssid[2],
- bssids->bssid[3], bssids->bssid[4], bssids->bssid[5]);
- buff[MAC_ADDRESS_LENGTH - 1] = '\0';
+ g_snprintf(buff, WIFI_BSSID_STR_LEN, MACSTR, MAC2STR(bssids->bssid));
+ buff[WIFI_BSSID_STR_LEN - 1] = '\0';
+
+ if (dst_bssid) {
+ if (g_strcmp0(dst_bssid, (const gchar *)buff) == 0) {
+ memcpy(buff_bssid, bssids->bssid, WIFI_BSSID_LEN_MAX);
+ ssid->bssid = buff_bssid;
+ ssid->freq = (unsigned int)bssids->frequency;
+ break;
+ }
+ continue;
+ }
gchar *curr_bssid = g_strdup((const gchar *)buff);
@@ -3605,6 +4096,9 @@ static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network)
}
}
+ if (dst_bssid)
+ connman_network_set_string(network, "WiFi.RoamingDstBSSID", NULL);
+
if (!list) {
ssid->bssid = connman_network_get_bssid(network);
g_hash_table_remove_all(failed_bssids);
@@ -3617,7 +4111,7 @@ done:
connman_network_get_string(network, "WiFi.KeymgmtType"));
ssid->phase1 = connman_network_get_string(network, "WiFi.Phase1");
- if(g_strcmp0(ssid->eap, "fast") == 0)
+ if (g_strcmp0(ssid->eap, "fast") == 0)
ssid->pac_file = g_strdup(WIFI_EAP_FAST_PAC_FILE);
ssid->keymgmt = connman_network_get_keymgmt(network);
@@ -3674,16 +4168,21 @@ static int network_connect(struct connman_network *network)
static void disconnect_callback(int result, GSupplicantInterface *interface,
void *user_data)
{
+ struct disconnect_data *dd = user_data;
+ struct connman_network *network = dd->network;
#if defined TIZEN_EXT
GList *list;
- struct wifi_data *wifi;
- struct connman_network *network = user_data;
+ struct wifi_data *wifi = NULL;
+ g_free(dd);
DBG("network %p result %d", network, result);
for (list = iface_list; list; list = list->next) {
wifi = list->data;
+ if (!wifi)
+ continue;
+
if (wifi->network == NULL && wifi->disconnecting == true)
wifi->disconnecting = false;
@@ -3691,27 +4190,46 @@ static void disconnect_callback(int result, GSupplicantInterface *interface,
goto found;
}
+ if (wifi && network == wifi->pending_network)
+ wifi->pending_network = NULL;
+
/* wifi_data may be invalid because wifi is already disabled */
return;
found:
#else
- struct wifi_data *wifi = user_data;
+ struct wifi_data *wifi = dd->wifi;
+ g_free(dd);
#endif
- DBG("result %d supplicant interface %p wifi %p",
- result, interface, wifi);
+ DBG("result %d supplicant interface %p wifi %p networks: current %p "
+ "pending %p disconnected %p", result, interface, wifi,
+ wifi->network, wifi->pending_network, network);
if (result == -ECONNABORTED) {
DBG("wifi interface no longer available");
return;
}
- if (wifi->network != wifi->pending_network)
- connman_network_set_connected(wifi->network, false);
- wifi->network = NULL;
+#if defined TIZEN_EXT
+ if (g_slist_find(wifi->networks, network) &&
+ wifi->network != wifi->pending_network)
+#else
+ if (g_slist_find(wifi->networks, network))
+#endif
+ connman_network_set_connected(network, false);
wifi->disconnecting = false;
+
+ if (network != wifi->network) {
+ if (network == wifi->pending_network)
+ wifi->pending_network = NULL;
+ DBG("current wifi network has changed since disconnection");
+ return;
+ }
+
+ wifi->network = NULL;
+
wifi->connected = false;
if (wifi->pending_network) {
@@ -3725,6 +4243,7 @@ found:
static int network_disconnect(struct connman_network *network)
{
struct connman_device *device = connman_network_get_device(network);
+ struct disconnect_data *dd;
struct wifi_data *wifi;
int err;
#if defined TIZEN_EXT
@@ -3767,16 +4286,16 @@ static int network_disconnect(struct connman_network *network)
wifi->disconnecting = true;
-#if defined TIZEN_EXT
- err = g_supplicant_interface_disconnect(wifi->interface,
- disconnect_callback, network);
-#else
- err = g_supplicant_interface_disconnect(wifi->interface,
- disconnect_callback, wifi);
-#endif
+ dd = g_malloc0(sizeof(*dd));
+ dd->wifi = wifi;
+ dd->network = network;
- if (err < 0)
+ err = g_supplicant_interface_disconnect(wifi->interface,
+ disconnect_callback, dd);
+ if (err < 0) {
wifi->disconnecting = false;
+ g_free(dd);
+ }
return err;
}
@@ -3854,9 +4373,20 @@ static void set_connection_mode(struct connman_network *network,
}
static void signalpoll_callback(int result, int maxspeed, int strength,
- void *user_data)
-{
+ int snr, void *user_data, unsigned int est_throughput)
+{
+ char bssid_buff[WIFI_BSSID_STR_LEN] = {0,};
+ char *bssid_str = bssid_buff;
+ unsigned char *bssid;
+ struct timespec curr_time = {0};
+ __time_t roam_scan_time;
+ const char *interface = NULL;
+ struct connman_device *device;
struct connman_network *network = user_data;
+ GSupplicantNetwork *supplicant_network;
+ struct wifi_data *wifi = NULL;
+ uint16_t freq = connman_network_get_frequency(network);
+ const char *group = connman_network_get_group(network);
if (result != 0) {
DBG("Failed to get maxspeed from signalpoll !");
@@ -3864,16 +4394,55 @@ static void signalpoll_callback(int result, int maxspeed, int strength,
return;
}
+ device = connman_network_get_device(network);
+ if (device)
+ wifi = connman_device_get_data(device);
+
+ if (group && wifi) {
+ supplicant_network = g_supplicant_interface_get_network(wifi->interface, group);
+ if (supplicant_network) {
+ g_supplicant_network_set_signal(supplicant_network, strength);
+ g_supplicant_network_set_bss_signal(supplicant_network, strength, snr);
+ }
+ }
+
strength += 120;
if (strength > 100)
strength = 100;
- DBG("maxspeed = %d, strength = %d", maxspeed, strength);
+ bssid = connman_network_get_bssid(network);
+ snprintf(bssid_str, WIFI_BSSID_STR_LEN, MACSTR, MAC2STR(bssid));
+
+ DBG("network %p, bssid %s, freq %u, maxspeed %d, strength %d, snr %d, est_throughput %u",
+ network, bssid_str, freq, maxspeed, strength, snr, est_throughput);
connman_network_set_strength(network, (uint8_t)strength);
+ connman_network_set_snr(network, snr);
+ connman_network_set_est_throughput(network, est_throughput);
connman_network_set_maxspeed(network, maxspeed);
set_connection_mode(network, maxspeed);
+ if (connman_network_get_max_bssid_count(network) <= 1)
+ goto done;
+
+ clock_gettime(CLOCK_MONOTONIC, &curr_time);
+ roam_scan_time = connman_network_get_roam_scan_time(network);
+ if (curr_time.tv_sec <= roam_scan_time + ROAM_SCAN_INTERVAL)
+ goto done;
+
+ if (device && need_bss_transition(freq, snr, strength)) {
+
+ interface = connman_device_get_string(device, "Interface");
+ __connman_technology_notify_roaming_state(interface, "required", bssid_str, NULL);
+
+ if (connman_setting_get_bool("WifiRoamingScan") == false)
+ goto done;
+
+ throw_wifi_scan(device, scan_callback);
+ connman_network_set_roam_scan_time(network, curr_time.tv_sec);
+ }
+
+done:
connman_network_unref(network);
}
@@ -3911,6 +4480,7 @@ static gboolean autosignalpoll_timeout(gpointer data)
if (wifi->network)
connman_network_unref(wifi->network);
+
return FALSE;
}
@@ -3943,6 +4513,7 @@ static void interface_added(GSupplicantInterface *interface)
#if defined TIZEN_EXT
bool is_5_0_ghz_supported = g_supplicant_interface_get_is_5_0_ghz_supported(interface);
+ bool is_6_0_ghz_supported = g_supplicant_interface_get_is_6_0_ghz_supported(interface);
#endif
struct wifi_data *wifi;
@@ -3970,6 +4541,7 @@ static void interface_added(GSupplicantInterface *interface)
connman_device_set_powered(wifi->device, true);
#if defined TIZEN_EXT
connman_device_set_wifi_5ghz_supported(wifi->device, is_5_0_ghz_supported);
+ connman_device_set_wifi_6ghz_supported(wifi->device, is_6_0_ghz_supported);
/* Max number of SSIDs supported by wlan chipset that can be scanned */
int max_scan_ssids = g_supplicant_interface_get_max_scan_ssids(interface);
connman_device_set_max_scan_ssids(wifi->device, max_scan_ssids);
@@ -4040,6 +4612,7 @@ static bool handle_wps_completion(GSupplicantInterface *interface,
if (wps) {
const unsigned char *ssid, *wps_ssid;
unsigned int ssid_len, wps_ssid_len;
+ struct disconnect_data *dd;
const char *wps_key;
/* Checking if we got associated with requested
@@ -4052,16 +4625,16 @@ static bool handle_wps_completion(GSupplicantInterface *interface,
if (!wps_ssid || wps_ssid_len != ssid_len ||
memcmp(ssid, wps_ssid, ssid_len) != 0) {
+ dd = g_malloc0(sizeof(*dd));
+ dd->wifi = wifi;
+ dd->network = network;
+
connman_network_set_associating(network, false);
-#if defined TIZEN_EXT
g_supplicant_interface_disconnect(wifi->interface,
- disconnect_callback, wifi->network);
-
+ disconnect_callback, dd);
+#if defined TIZEN_EXT
connman_network_set_bool(network, "WiFi.UseWPS", false);
connman_network_set_string(network, "WiFi.PinWPS", NULL);
-#else
- g_supplicant_interface_disconnect(wifi->interface,
- disconnect_callback, wifi);
#endif
return false;
}
@@ -4104,10 +4677,12 @@ static bool handle_wps_completion(GSupplicantInterface *interface,
static bool handle_assoc_status_code(GSupplicantInterface *interface,
struct wifi_data *wifi)
{
- if (wifi->state == G_SUPPLICANT_STATE_ASSOCIATING &&
#if defined TIZEN_EXT
- wifi->assoc_code > 0 &&
+ if ((wifi->state == G_SUPPLICANT_STATE_ASSOCIATING ||
+ wifi->state == G_SUPPLICANT_STATE_AUTHENTICATING ||
+ wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) &&
#else
+ if (wifi->state == G_SUPPLICANT_STATE_ASSOCIATING &&
wifi->assoc_code == ASSOC_STATUS_NO_CLIENT &&
#endif
wifi->load_shaping_retries < LOAD_SHAPING_MAX_RETRIES) {
@@ -4122,10 +4697,10 @@ static bool handle_4way_handshake_failure(GSupplicantInterface *interface,
struct connman_network *network,
struct wifi_data *wifi)
{
-#if defined TIZEN_EXT
- const char *security;
struct connman_service *service;
+#if defined TIZEN_EXT
+ const char *security;
if (wifi->connected)
return false;
@@ -4142,9 +4717,9 @@ static bool handle_4way_handshake_failure(GSupplicantInterface *interface,
if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
return false;
#else
- struct connman_service *service;
-
- if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
+ if ((wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE) &&
+ !((wifi->state == G_SUPPLICANT_STATE_ASSOCIATING) &&
+ (wifi->assoc_code == ASSOC_STATUS_AUTH_TIMEOUT)))
return false;
if (wifi->connected)
@@ -4180,7 +4755,8 @@ static bool handle_wifi_assoc_retry(struct connman_network *network,
return false;
}
- if (wifi->state != G_SUPPLICANT_STATE_ASSOCIATING &&
+ if (wifi->state != G_SUPPLICANT_STATE_AUTHENTICATING &&
+ wifi->state != G_SUPPLICANT_STATE_ASSOCIATING &&
wifi->state != G_SUPPLICANT_STATE_ASSOCIATED) {
wifi->assoc_retry_count = 0;
return false;
@@ -4193,6 +4769,9 @@ static bool handle_wifi_assoc_retry(struct connman_network *network,
return false;
}
+ if (wifi->state > assoc_last_state)
+ assoc_last_state = wifi->state;
+
if (++wifi->assoc_retry_count >= TIZEN_ASSOC_RETRY_COUNT) {
wifi->assoc_retry_count = 0;
@@ -4200,13 +4779,82 @@ static bool handle_wifi_assoc_retry(struct connman_network *network,
* however QA team recommends that the invalid-key error
* might be better to display for user experience.
*/
- connman_network_set_error(network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
+ switch (assoc_last_state) {
+ case G_SUPPLICANT_STATE_AUTHENTICATING:
+ connman_network_set_error(network, CONNMAN_NETWORK_ERROR_AUTHENTICATE_FAIL);
+ break;
+ case G_SUPPLICANT_STATE_ASSOCIATED:
+ connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
+ break;
+ default:
+ connman_network_set_error(network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
+ break;
+ }
return false;
}
return true;
}
+
+static void handle_wifi_roaming_complete(struct connman_network *network)
+{
+ const char *cur_bssid;
+ const char *dst_bssid;
+ const char *ifname;
+ struct connman_device *device;
+ struct connman_service *service;
+ struct connman_ipconfig *ipconfig_ipv4;
+ enum connman_ipconfig_type type;
+ enum connman_ipconfig_method method;
+
+ if (!connman_setting_get_bool("WifiRoaming") ||
+ !connman_network_get_bool(network, "WiFi.Roaming"))
+ return;
+
+ device = connman_network_get_device(network);
+ if (device) {
+ ifname = connman_device_get_string(device, "Interface");
+ cur_bssid = connman_network_get_string(network,
+ "WiFi.RoamingCurBSSID");
+ dst_bssid = connman_network_get_string(network,
+ "WiFi.RoamingDstBSSID");
+ }
+
+ if (device && ifname && cur_bssid && dst_bssid) {
+ __connman_technology_notify_roaming_state(ifname,
+ "success", cur_bssid, dst_bssid);
+ connman_network_set_bool(network,
+ "WiFi.Roaming", false);
+ connman_network_set_string(network,
+ "WiFi.RoamingCurBSSID", NULL);
+ connman_network_set_string(network,
+ "WiFi.RoamingDstBSSID", NULL);
+
+ service = connman_service_lookup_from_network(network);
+ if (!service)
+ return;
+
+ ipconfig_ipv4 = __connman_service_get_ip4config(service);
+ if (!ipconfig_ipv4) {
+ connman_error("Service has no IPv4 configuration");
+ return;
+ }
+
+ type = __connman_ipconfig_get_config_type(ipconfig_ipv4);
+ if (type != CONNMAN_IPCONFIG_TYPE_IPV4)
+ return;
+
+ method = __connman_ipconfig_get_method(ipconfig_ipv4);
+ if (method != CONNMAN_IPCONFIG_METHOD_DHCP)
+ return;
+
+ connman_network_set_bool(network, "WiFi.RoamingDHCP", true);
+
+ if (set_connected_dhcp(network) != 0)
+ connman_network_set_bool(network, "WiFi.RoamingDHCP", false);
+ }
+}
#endif
static void interface_state(GSupplicantInterface *interface)
@@ -4261,6 +4909,15 @@ static void interface_state(GSupplicantInterface *interface)
switch (state) {
case G_SUPPLICANT_STATE_SCANNING:
+#if defined TIZEN_EXT
+ if (wifi->automaxspeed_timeout != 0) {
+ g_source_remove(wifi->automaxspeed_timeout);
+ wifi->automaxspeed_timeout = 0;
+ DBG("Remove signalpoll timer!!");
+ }
+
+ if (!connman_network_get_bool(wifi->network, "WiFi.Roaming"))
+#endif
if (wifi->connected)
connman_network_set_connected(network, false);
@@ -4273,7 +4930,9 @@ static void interface_state(GSupplicantInterface *interface)
#else
stop_autoscan(device);
#endif
-
+#if defined TIZEN_EXT
+ if (!connman_network_get_bool(wifi->network, "WiFi.Roaming"))
+#endif
if (!wifi->connected)
connman_network_set_associating(network, true);
@@ -4307,6 +4966,7 @@ static void interface_state(GSupplicantInterface *interface)
}
g_hash_table_remove_all(failed_bssids);
+ handle_wifi_roaming_complete(network);
#else
/* though it should be already stopped: */
stop_autoscan(device);
@@ -4348,21 +5008,25 @@ static void interface_state(GSupplicantInterface *interface)
break;
#if defined TIZEN_EXT
- if (handle_assoc_status_code(interface, wifi)) {
- GSList *bssid_list = (GSList *)connman_network_get_bssid_list(network);
- const char *group = connman_network_get_group(network);
- GSupplicantNetwork *supplicant_network;
+ if (!wifi->connected && handle_assoc_status_code(interface, wifi)) {
+ GSList *bssid_list = NULL;
guint bssid_length = 0;
- if (group) {
- supplicant_network = g_supplicant_interface_get_network(interface, group);
+ if (TIZEN_INS_ENABLED) {
+ const char *group = connman_network_get_group(network);
+ GSupplicantNetwork *supplicant_network;
+
+ if (group) {
+ supplicant_network = g_supplicant_interface_get_network(interface, group);
- connman_network_set_assoc_reject_table(network,
- g_supplicant_network_get_assoc_reject_table(supplicant_network));
+ connman_network_set_assoc_reject_table(network,
+ g_supplicant_network_clone_assoc_reject_table(supplicant_network));
- g_supplicant_network_update_assoc_reject(interface, supplicant_network);
+ g_supplicant_network_update_assoc_reject(interface, supplicant_network);
+ }
}
+ bssid_list = (GSList *)connman_network_get_bssid_list(network);
if (bssid_list)
bssid_length = g_slist_length(bssid_list);
@@ -4373,8 +5037,6 @@ static void interface_state(GSupplicantInterface *interface)
wifi->load_shaping_retries = 0;
}
-
- g_hash_table_remove_all(failed_bssids);
#else
if (handle_assoc_status_code(interface, wifi))
break;
@@ -4390,9 +5052,10 @@ static void interface_state(GSupplicantInterface *interface)
/* See table 8-36 Reason codes in IEEE Std 802.11 */
switch (wifi->disconnect_code) {
+#if defined TIZEN_EXT
case 1: /* Unspecified reason */
/* Let's assume it's because we got blocked */
-
+#endif
case 6: /* Class 2 frame received from nonauthenticated STA */
connman_network_set_error(network,
CONNMAN_NETWORK_ERROR_BLOCKED);
@@ -4403,6 +5066,9 @@ static void interface_state(GSupplicantInterface *interface)
}
#if defined TIZEN_EXT
+ if (wifi->assoc_retry_count == 0)
+ assoc_last_state = G_SUPPLICANT_STATE_UNKNOWN;
+
/* Some of Wi-Fi networks are not comply Wi-Fi specification.
* Retry association until its retry count is expired */
if (handle_wifi_assoc_retry(network, wifi) == true) {
@@ -4411,7 +5077,7 @@ static void interface_state(GSupplicantInterface *interface)
break;
}
- if(wifi->disconnect_code > 0){
+ if (wifi->disconnect_code > 0){
DBG("Set disconnect reason code(%d)", wifi->disconnect_code);
connman_network_set_disconnect_reason(network, wifi->disconnect_code);
}
@@ -4679,8 +5345,6 @@ static void ap_create_fail(GSupplicantInterface *interface)
wifi->tethering = false;
ret = tech_set_tethering(wifi->tethering_param->technology,
- wifi->tethering_param->ssid->ssid,
- wifi->tethering_param->ssid->passphrase,
wifi->bridge, true);
if ((ret == -EOPNOTSUPP) && (wifi_technology)) {
@@ -4797,11 +5461,70 @@ static void mesh_peer_removed(GSupplicantNetwork *supplicant_network)
}
#endif
+
+#if defined TIZEN_EXT
+static GSList *get_supported_security_list(unsigned int keymgmt,
+ bool owe_transition_mode,
+ GSupplicantNetwork *supplicant_network)
+{
+ GSList *sec_list = NULL;
+ dbus_bool_t privacy = g_supplicant_network_get_privacy(supplicant_network);
+ const char *enc_mode = g_supplicant_network_get_enc_mode(supplicant_network);
+
+ if (keymgmt &
+ (G_SUPPLICANT_KEYMGMT_WPA_EAP |
+ G_SUPPLICANT_KEYMGMT_WPA_EAP_256))
+ sec_list = g_slist_prepend (sec_list, "ieee8021x");
+ else if (keymgmt & G_SUPPLICANT_KEYMGMT_WPA_FT_EAP)
+ sec_list = g_slist_prepend (sec_list, "ft_ieee8021x");
+
+ if (sec_list)
+ return sec_list;
+
+ if (keymgmt &
+ (G_SUPPLICANT_KEYMGMT_WPA_PSK |
+ G_SUPPLICANT_KEYMGMT_WPA_PSK_256)) {
+ if (!g_strcmp0(enc_mode, "aes"))
+ sec_list = g_slist_prepend (sec_list, "rsn");
+ else if (!g_strcmp0(enc_mode, "tkip"))
+ sec_list = g_slist_prepend (sec_list, "psk");
+ else if (!g_strcmp0(enc_mode, "mixed")) {
+ sec_list = g_slist_prepend (sec_list, "psk");
+ sec_list = g_slist_prepend (sec_list, "rsn");
+ }
+ }
+
+ if (keymgmt & G_SUPPLICANT_KEYMGMT_WPA_FT_PSK)
+ sec_list = g_slist_prepend (sec_list, "ft_psk");
+
+ if (keymgmt & G_SUPPLICANT_KEYMGMT_SAE)
+ sec_list = g_slist_prepend (sec_list, "sae");
+ if (keymgmt & G_SUPPLICANT_KEYMGMT_FT_SAE)
+ sec_list = g_slist_prepend (sec_list, "ft_sae");
+
+ if (keymgmt & G_SUPPLICANT_KEYMGMT_OWE || owe_transition_mode)
+ sec_list = g_slist_prepend (sec_list, "owe");
+ if (keymgmt & G_SUPPLICANT_KEYMGMT_DPP)
+ sec_list = g_slist_prepend (sec_list, "dpp");
+
+ if (sec_list)
+ return sec_list;
+
+ if (privacy)
+ sec_list = g_slist_prepend (sec_list, "wep");
+ else
+ sec_list = g_slist_prepend (sec_list, "none");
+
+ return sec_list;
+}
+#endif
+
static void network_added(GSupplicantNetwork *supplicant_network)
{
struct connman_network *network;
GSupplicantInterface *interface;
struct wifi_data *wifi;
+ struct wifi_network *network_data;
const char *name, *identifier, *security, *group, *mode;
const unsigned char *ssid;
unsigned int ssid_len;
@@ -4815,7 +5538,9 @@ static void network_added(GSupplicantNetwork *supplicant_network)
const unsigned char *transition_mode_ssid;
const unsigned char *transition_mode_bssid;
unsigned int transition_mode_ssid_len;
+ unsigned int keymgmt;
GSList *vsie_list = NULL;
+ GSList *sec_list = NULL;
const unsigned char *country_code;
ieee80211_modes_e phy_mode;
#endif
@@ -4878,8 +5603,15 @@ static void network_added(GSupplicantNetwork *supplicant_network)
}
wifi->networks = g_slist_prepend(wifi->networks, network);
+
+ network_data = g_new0(struct wifi_network, 1);
+ connman_network_set_data(network, network_data);
}
+ network_data = connman_network_get_data(network);
+ network_data->keymgmt =
+ g_supplicant_network_get_keymgmt(supplicant_network);
+
if (name && name[0] != '\0')
connman_network_set_name(network, name);
@@ -4895,6 +5627,11 @@ static void network_added(GSupplicantNetwork *supplicant_network)
connman_network_set_countrycode(network, country_code);
phy_mode = g_supplicant_network_get_phy_mode(supplicant_network);
connman_network_set_phy_mode(network, phy_mode);
+
+ if (g_strcmp0(security, "psk_sha256") == 0) {
+ connman_network_set_psk_sha256(network, true);
+ security = "psk";
+ }
#endif
connman_network_set_string(network, "WiFi.Security", security);
connman_network_set_strength(network,
@@ -4919,6 +5656,7 @@ static void network_added(GSupplicantNetwork *supplicant_network)
g_supplicant_network_get_frequency(supplicant_network));
#if defined TIZEN_EXT
+ keymgmt = g_supplicant_network_get_keymgmt(supplicant_network);
connman_network_set_bssid(network,
g_supplicant_network_get_bssid(supplicant_network));
owe_transition_mode = (bool)g_supplicant_network_get_transition_mode(supplicant_network);
@@ -4930,23 +5668,33 @@ static void network_added(GSupplicantNetwork *supplicant_network)
transition_mode_bssid = g_supplicant_network_get_transition_mode_bssid(supplicant_network);
connman_network_set_transition_mode_bssid(network, transition_mode_bssid);
}
+
+ sec_list = get_supported_security_list(keymgmt,
+ owe_transition_mode, supplicant_network);
+
+ connman_network_set_sec_list(network, sec_list);
connman_network_set_maxrate(network,
g_supplicant_network_get_maxrate(supplicant_network));
connman_network_set_enc_mode(network,
g_supplicant_network_get_enc_mode(supplicant_network));
connman_network_set_rsn_mode(network,
g_supplicant_network_get_rsn_mode(supplicant_network));
- connman_network_set_keymgmt(network,
- g_supplicant_network_get_keymgmt(supplicant_network));
+ connman_network_set_bool(network, "WiFi.PMFRequired",
+ (bool)g_supplicant_network_is_pmf_required(supplicant_network));
+ connman_network_set_keymgmt(network, keymgmt);
connman_network_set_bool(network, "WiFi.HS20AP",
g_supplicant_network_is_hs20AP(supplicant_network));
connman_network_set_bssid_list(network,
(GSList *)g_supplicant_network_get_bssid_list(supplicant_network));
- connman_network_set_last_connected_bssid(network,
- g_supplicant_network_get_last_connected_bssid(supplicant_network));
- connman_network_set_assoc_reject_table(network,
- g_supplicant_network_get_assoc_reject_table(supplicant_network));
+
+ if (TIZEN_INS_ENABLED) {
+ connman_network_set_last_connected_bssid(network,
+ g_supplicant_network_get_last_connected_bssid(supplicant_network));
+ connman_network_set_assoc_reject_table(network,
+ g_supplicant_network_clone_assoc_reject_table(supplicant_network));
+ }
#endif
+
connman_network_set_available(network, true);
connman_network_set_string(network, "WiFi.Mode", mode);
@@ -4958,11 +5706,10 @@ static void network_added(GSupplicantNetwork *supplicant_network)
connman_network_set_group(network, group);
#if defined TIZEN_EXT
- g_supplicant_network_set_last_connected_bssid(supplicant_network,
- connman_network_get_last_connected_bssid(network));
-#endif
+ if (TIZEN_INS_ENABLED)
+ g_supplicant_network_set_last_connected_bssid(supplicant_network,
+ connman_network_get_last_connected_bssid(network));
-#if defined TIZEN_EXT
if (wifi_first_scan == true)
found_with_first_scan = true;
#endif
@@ -5040,6 +5787,7 @@ static void network_removed(GSupplicantNetwork *network)
wifi->networks = g_slist_remove(wifi->networks, connman_network);
+ g_free(connman_network_get_data(connman_network));
connman_device_remove_network(wifi->device, connman_network);
connman_network_unref(connman_network);
}
@@ -5123,32 +5871,38 @@ static void network_changed(GSupplicantNetwork *network, const char *property)
update_needed = true;
}
#if defined TIZEN_EXT
- else if (g_str_equal(property, "LastConnectedBSSID")) {
- const char *ident, *group;
- char *service_ident;
- bool need_save;
-
- ident = connman_device_get_ident(wifi->device);
- group = connman_network_get_group(connman_network);
- if (ident && group) {
- service_ident = g_strdup_printf("%s_%s_%s",
- __connman_network_get_type(connman_network), ident, group);
-
- need_save = connman_device_set_last_connected_ident(wifi->device, service_ident);
- if (need_save)
- connman_device_save_last_connected(wifi->device);
- }
+ else if (TIZEN_INS_ENABLED) {
+ if (g_str_equal(property, "LastConnectedBSSID")) {
+ const char *ident, *group;
+ char *service_ident;
+ bool need_save;
+
+ ident = connman_device_get_ident(wifi->device);
+ group = connman_network_get_group(connman_network);
+ if (ident && group) {
+ service_ident = g_strdup_printf("%s_%s_%s",
+ __connman_network_get_type(connman_network), ident, group);
+
+ need_save = connman_device_set_last_connected_ident(wifi->device, service_ident);
+ if (need_save)
+ connman_device_save_last_connected(wifi->device);
+
+ g_free(service_ident);
+ }
- connman_network_set_last_connected_bssid(connman_network,
+ connman_network_set_last_connected_bssid(connman_network,
g_supplicant_network_get_last_connected_bssid(network));
- update_needed = true;
- } else if (g_str_equal(property, "UpdateAssocReject")) {
- connman_network_set_assoc_reject_table(connman_network,
- g_supplicant_network_get_assoc_reject_table(network));
- update_needed = true;
+ update_needed = true;
+ } else if (g_str_equal(property, "UpdateAssocReject")) {
+ connman_network_set_assoc_reject_table(connman_network,
+ g_supplicant_network_clone_assoc_reject_table(network));
+ update_needed = true;
+ } else {
+ update_needed = false;
+ }
}
-#endif
+#endif /* defined TIZEN_EXT */
else
update_needed = false;
@@ -5726,14 +6480,27 @@ static void tech_remove(struct connman_technology *technology)
wifi_technology = NULL;
}
-static GSupplicantSSID *ssid_ap_init(const char *ssid, const char *passphrase)
+static GSupplicantSSID *ssid_ap_init(const struct connman_technology *technology)
{
GSupplicantSSID *ap;
+ const char *ssid, *passphrase;
+ int freq;
+ bool ret;
ap = g_try_malloc0(sizeof(GSupplicantSSID));
if (!ap)
return NULL;
+ ret = connman_technology_get_wifi_tethering(technology,
+ &ssid, &passphrase,
+ &freq);
+ if (ret == false) {
+#if defined TIZEN_EXT
+ g_free(ap);
+#endif
+ return NULL;
+ }
+
ap->mode = G_SUPPLICANT_MODE_MASTER;
#if defined TIZEN_EXT
ap->ssid = (void *) ssid;
@@ -5742,7 +6509,10 @@ static GSupplicantSSID *ssid_ap_init(const char *ssid, const char *passphrase)
#endif
ap->ssid_len = strlen(ssid);
ap->scan_ssid = 0;
- ap->freq = 2412;
+ if (freq)
+ ap->freq = freq;
+ else
+ ap->freq = 2412;
if (!passphrase || strlen(passphrase) == 0) {
ap->security = G_SUPPLICANT_SECURITY_NONE;
@@ -5824,7 +6594,7 @@ static void sta_remove_callback(int result,
void *user_data)
{
struct wifi_tethering_info *info = user_data;
- const char *driver = connman_option_get_string("wifi");
+ const char *driver = connman_setting_get_string("wifi");
DBG("ifname %s result %d ", info->ifname, result);
@@ -5847,13 +6617,15 @@ static void sta_remove_callback(int result,
info->wifi->interface = NULL;
g_supplicant_interface_create(info->ifname, driver, info->wifi->bridge,
+#ifdef TIZEN_EXT
+ 0, 0, 60,
+#endif /* TIZEN_EXT */
ap_create_callback,
info);
}
static int enable_wifi_tethering(struct connman_technology *technology,
- const char *bridge, const char *identifier,
- const char *passphrase, bool available)
+ const char *bridge, bool available)
{
GList *list;
GSupplicantInterface *interface;
@@ -5906,14 +6678,14 @@ static int enable_wifi_tethering(struct connman_technology *technology,
info->wifi = wifi;
info->technology = technology;
info->wifi->bridge = bridge;
- info->ssid = ssid_ap_init(identifier, passphrase);
+ info->ssid = ssid_ap_init(technology);
if (!info->ssid)
goto failed;
info->ifname = g_strdup(ifname);
wifi->tethering_param->technology = technology;
- wifi->tethering_param->ssid = ssid_ap_init(identifier, passphrase);
+ wifi->tethering_param->ssid = ssid_ap_init(technology);
if (!wifi->tethering_param->ssid)
goto failed;
@@ -5955,7 +6727,6 @@ static int enable_wifi_tethering(struct connman_technology *technology,
}
static int tech_set_tethering(struct connman_technology *technology,
- const char *identifier, const char *passphrase,
const char *bridge, bool enabled)
{
GList *list;
@@ -5983,13 +6754,11 @@ static int tech_set_tethering(struct connman_technology *technology,
}
DBG("trying tethering for available devices");
- err = enable_wifi_tethering(technology, bridge, identifier, passphrase,
- true);
+ err = enable_wifi_tethering(technology, bridge, true);
if (err < 0) {
DBG("trying tethering for any device");
- err = enable_wifi_tethering(technology, bridge, identifier,
- passphrase, false);
+ err = enable_wifi_tethering(technology, bridge, false);
}
return err;
@@ -6019,7 +6788,7 @@ static void supp_ins_init(void)
const char *string;
GSupplicantINSPreferredFreq preferred_freq;
- string = connman_option_get_string("INSPreferredFreqBSSID");
+ string = connman_setting_get_string("INSPreferredFreqBSSID");
if (g_strcmp0(string, "5GHz") == 0)
preferred_freq = G_SUPPLICANT_INS_PREFERRED_FREQ_5GHZ;
else if (g_strcmp0(string, "2.4GHz") == 0)
@@ -6035,10 +6804,10 @@ static void supp_ins_init(void)
connman_setting_get_uint("INSLastConnectedBSSIDScore"),
connman_setting_get_uint("INSAssocRejectScore"),
connman_setting_get_int("INSSignalLevel3_5GHz"),
- connman_setting_get_int("INSSignalLevel3_24GHz")
+ connman_setting_get_int("INSSignalLevel3_2_4GHz")
);
}
-#endif
+#endif /* defined TIZEN_EXT */
static struct connman_technology_driver tech_driver = {
.name = "wifi",
@@ -6072,11 +6841,27 @@ static int wifi_init(void)
#if defined TIZEN_EXT
failed_bssids = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
-#endif
-#if defined TIZEN_EXT
- supp_ins_init();
-#endif
+ min_snr = connman_setting_get_int("WifiRoamingMinSNR");
+
+ min_rssi_2_4GHz = connman_setting_get_int("WifiRoamingMinRSSI_2_4GHz");
+ if (min_rssi_2_4GHz >= 0)
+ min_rssi_2_4GHz = RSSI_LEVEL_2_2_4G;
+
+ min_rssi_5GHz = connman_setting_get_int("WifiRoamingMinRSSI_5GHz");
+ if (min_rssi_5GHz >= 0)
+ min_rssi_5GHz = RSSI_LEVEL_2_5G;
+
+ min_rssi_6GHz = connman_setting_get_int("WifiRoamingMinRSSI_6GHz");
+ if (min_rssi_6GHz >= 0)
+ min_rssi_6GHz = RSSI_LEVEL_2_6G;
+
+ DBG("Min SNR: %d, Min RSSI: %d(2.4GHz), %d(5GHz), %d(6GHz)",
+ min_snr, min_rssi_2_4GHz, min_rssi_5GHz, min_rssi_6GHz);
+
+ if (TIZEN_INS_ENABLED)
+ supp_ins_init();
+#endif /* defined TIZEN_EXT */
return 0;
}
diff --git a/resources/var/lib/connman/settings b/resources/var/lib/connman/settings
index ba476b5d..13684c9f 100644
--- a/resources/var/lib/connman/settings
+++ b/resources/var/lib/connman/settings
@@ -1,6 +1,7 @@
[global]
OfflineMode=false
+Timeservers=pool.ntp.org;
[WiFi]
Enable=false
diff --git a/scripts/openconnect-script.c b/scripts/vpn-script.c
index 5e04144f..6e020e92 100755..100644
--- a/scripts/openconnect-script.c
+++ b/scripts/vpn-script.c
@@ -54,9 +54,11 @@ static void append(DBusMessageIter *dict, const char *pattern)
key = pattern;
value = delim + 1;
- /* We clean the environment before invoking openconnect, but
- might as well still filter out the few things that get
- added that we're not interested in */
+ /*
+ * We clean the environment before invoking openconnect/vpnc,
+ * but might as well still filter out the few things that get
+ * added that we're not interested in
+ */
if (!strcmp(key, "PWD") || !strcmp(key, "_") ||
!strcmp(key, "SHLVL") || !strcmp(key, "connman_busname") ||
!strcmp(key, "connman_network"))
diff --git a/src/agent.c b/src/agent.c
index 8f7b19ba..d4f9add4 100755
--- a/src/agent.c
+++ b/src/agent.c
@@ -238,12 +238,12 @@ int connman_agent_queue_message(void *user_context,
driver = get_driver();
DBG("driver %p", driver);
- if (driver && driver->context_ref) {
+ if (driver && driver->context_ref)
queue_data->user_context = driver->context_ref(user_context);
- queue_data->driver = driver;
- } else
+ else
queue_data->user_context = user_context;
+ queue_data->driver = driver;
queue_data->msg = dbus_message_ref(msg);
queue_data->timeout = timeout;
queue_data->callback = callback;
@@ -366,9 +366,9 @@ static void report_error_reply(DBusMessage *reply, void *user_data)
retry = true;
}
+out:
report_error->callback(report_error->user_context, retry,
report_error->user_data);
-out:
g_free(report_error);
}
diff --git a/src/bridge.c b/src/bridge.c
index cd2d9cee..df19a6af 100755
--- a/src/bridge.c
+++ b/src/bridge.c
@@ -122,7 +122,8 @@ int __connman_bridge_enable(const char *name, const char *ip_address,
err = __connman_inet_modify_address(RTM_NEWADDR,
NLM_F_REPLACE | NLM_F_ACK, index, AF_INET,
- ip_address, NULL, prefix_len, broadcast);
+ ip_address, NULL, prefix_len, broadcast,
+ false);
if (err < 0)
return err;
diff --git a/src/clock.c b/src/clock.c
index f04cf175..54552cab 100755
--- a/src/clock.c
+++ b/src/clock.c
@@ -39,6 +39,9 @@ static enum time_updates time_updates_config = TIME_UPDATES_AUTO;
static enum timezone_updates timezone_updates_config = TIMEZONE_UPDATES_AUTO;
static char *timezone_config = NULL;
+#if defined TIZEN_EXT
+static bool time_updated = false;
+#endif
static const char *time_updates2string(enum time_updates value)
{
@@ -116,6 +119,17 @@ static void clock_properties_load(void)
g_free(str);
+#if defined TIZEN_EXT
+ str = g_key_file_get_string(keyfile, "global", "Timeservers", NULL);
+
+ if (str && str[0] == ';') {
+ DBG("Set time_updates_config to MANUAL.");
+ time_updates_config = TIME_UPDATES_MANUAL;
+ }
+
+ g_free(str);
+#endif
+
g_key_file_free(keyfile);
}
@@ -173,8 +187,12 @@ static DBusMessage *get_properties(DBusConnection *conn,
{
DBusMessage *reply;
DBusMessageIter array, dict;
+ dbus_bool_t is_synced;
struct timeval tv;
const char *str;
+#if defined TIZEN_EXT
+ dbus_bool_t val = time_updated;
+#endif
DBG("conn %p", conn);
@@ -186,6 +204,12 @@ static DBusMessage *get_properties(DBusConnection *conn,
connman_dbus_dict_open(&array, &dict);
+#if defined TIZEN_EXT
+ connman_dbus_dict_append_basic(&dict, "TimeUpdated",
+ DBUS_TYPE_BOOLEAN,
+ &val);
+#endif
+
if (gettimeofday(&tv, NULL) == 0) {
dbus_uint64_t val = tv.tv_sec;
@@ -210,6 +234,10 @@ static DBusMessage *get_properties(DBusConnection *conn,
connman_dbus_dict_append_array(&dict, "Timeservers",
DBUS_TYPE_STRING, append_timeservers, NULL);
+ is_synced = __connman_timeserver_is_synced();
+ connman_dbus_dict_append_basic(&dict, "TimeserverSynced",
+ DBUS_TYPE_BOOLEAN, &is_synced);
+
connman_dbus_dict_close(&array, &dict);
return reply;
@@ -263,6 +291,7 @@ static DBusMessage *set_property(DBusConnection *conn,
if (settimeofday(&tv, NULL) < 0)
return __connman_error_invalid_arguments(msg);
+ __connman_timeserver_set_synced(false);
connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
CONNMAN_CLOCK_INTERFACE, "Time",
DBUS_TYPE_UINT64, &newval);
@@ -289,6 +318,13 @@ static DBusMessage *set_property(DBusConnection *conn,
connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
CONNMAN_CLOCK_INTERFACE, "TimeUpdates",
DBUS_TYPE_STRING, &strval);
+
+ if (newval == TIME_UPDATES_AUTO) {
+ struct connman_service *service;
+
+ service = connman_service_get_default();
+ __connman_timeserver_conf_update(service);
+ }
} else if (g_str_equal(name, "Timezone")) {
const char *strval;
@@ -362,12 +398,29 @@ static DBusMessage *set_property(DBusConnection *conn,
__connman_timeserver_system_set(str);
+#if defined TIZEN_EXT
+ if (str) {
+ if (str[0][0] == '\0') {
+ DBG("Set time_updates_config to MANUAL.");
+ time_updates_config = TIMEZONE_UPDATES_MANUAL;
+ } else {
+ DBG("Set time_updates_config to AUTO.");
+ time_updates_config = TIMEZONE_UPDATES_AUTO;
+ }
+ } else {
+ DBG("Set time_updates_config to MANUAL.");
+ time_updates_config = TIMEZONE_UPDATES_MANUAL;
+ }
+#endif
+
if (str)
g_strfreev(str);
connman_dbus_property_changed_array(CONNMAN_MANAGER_PATH,
CONNMAN_CLOCK_INTERFACE, "Timeservers",
DBUS_TYPE_STRING, append_timeservers, NULL);
+ } else if (g_str_equal(name, "TimeserverSynced")) {
+ return __connman_error_permission_denied(msg);
} else
return __connman_error_invalid_property(msg);
@@ -392,6 +445,13 @@ static const GDBusSignalTable clock_signals[] = {
static DBusConnection *connection = NULL;
+#if defined TIZEN_EXT
+void __connman_clock_set_time_updated(bool updated)
+{
+ time_updated = updated;
+}
+#endif
+
void __connman_clock_update_timezone(void)
{
DBG("");
diff --git a/src/config.c b/src/config.c
index d9907a1c..afcb0cce 100644
--- a/src/config.c
+++ b/src/config.c
@@ -72,6 +72,7 @@ struct connman_config_service {
char *ipv6_gateway;
char *ipv6_privacy;
char *mac;
+ char *devname;
bool mdns;
char **nameservers;
char **search_domains;
@@ -124,6 +125,7 @@ static bool cleanup = false;
#define SERVICE_KEY_IPv6 "IPv6"
#define SERVICE_KEY_IPv6_PRIVACY "IPv6.Privacy"
#define SERVICE_KEY_MAC "MAC"
+#define SERVICE_KEY_DEVICE_NAME "DeviceName"
#define SERVICE_KEY_NAMESERVERS "Nameservers"
#define SERVICE_KEY_SEARCH_DOMAINS "SearchDomains"
#define SERVICE_KEY_TIMESERVERS "Timeservers"
@@ -164,6 +166,7 @@ static const char *service_possible_keys[] = {
SERVICE_KEY_IPv6,
SERVICE_KEY_IPv6_PRIVACY,
SERVICE_KEY_MAC,
+ SERVICE_KEY_DEVICE_NAME,
SERVICE_KEY_MDNS,
SERVICE_KEY_NAMESERVERS,
SERVICE_KEY_SEARCH_DOMAINS,
@@ -272,6 +275,7 @@ free_only:
g_free(config_service->ipv6_gateway);
g_free(config_service->ipv6_privacy);
g_free(config_service->mac);
+ g_free(config_service->devname);
g_strfreev(config_service->nameservers);
g_strfreev(config_service->search_domains);
g_strfreev(config_service->timeservers);
@@ -498,6 +502,12 @@ static bool load_service_generic(GKeyFile *keyfile,
service->mac = str;
}
+ str = __connman_config_get_string(keyfile, group, SERVICE_KEY_DEVICE_NAME, NULL);
+ if (str) {
+ g_free(service->devname);
+ service->devname = str;
+ }
+
str = __connman_config_get_string(keyfile, group, SERVICE_KEY_DOMAIN, NULL);
if (str) {
g_free(service->domain_name);
@@ -551,6 +561,7 @@ err:
g_free(service->ipv6_address);
g_free(service->ipv6_gateway);
g_free(service->mac);
+ g_free(service->devname);
g_free(service);
return false;
@@ -1156,8 +1167,7 @@ static char *config_pem_fsid(const char *pem_file)
static void provision_service_wifi(struct connman_config_service *config,
struct connman_service *service,
- struct connman_network *network,
- const void *ssid, unsigned int ssid_len)
+ struct connman_network *network)
{
if (config->eap)
__connman_service_set_string(service, "EAP", config->eap);
@@ -1365,6 +1375,22 @@ static int try_provision_service(struct connman_config_service *config,
if (g_ascii_strcasecmp(device_addr, config->mac) != 0)
return -ENOENT;
+ } else if (config->devname) {
+ struct connman_device *device;
+ const char *devname;
+
+ device = connman_network_get_device(network);
+ if (!device) {
+ connman_error("Network device is missing");
+ return -ENODEV;
+ }
+
+ devname = connman_device_get_string(device, "Interface");
+
+ DBG("wants %s has %s", config->devname, devname);
+
+ if (g_ascii_strcasecmp(devname, config->devname) != 0)
+ return -ENOENT;
}
#if defined TIZEN_EXT
@@ -1514,8 +1540,7 @@ ipv4_out:
config->timeservers);
if (type == CONNMAN_SERVICE_TYPE_WIFI) {
- provision_service_wifi(config, service, network,
- ssid, ssid_len);
+ provision_service_wifi(config, service, network);
}
__connman_service_mark_dirty();
diff --git a/src/connection.c b/src/connection.c
index f8194a64..33f61031 100755
--- a/src/connection.c
+++ b/src/connection.c
@@ -234,6 +234,15 @@ static void set_vpn_routes(struct gateway_data *new_gateway,
if (!active_gateway->ipv4_gateway)
return;
+
+ /*
+ * If VPN server is on same subnet as we are, skip adding
+ * route.
+ */
+ if (connman_inet_compare_subnet(active_gateway->index,
+ gateway))
+ return;
+
DBG("active gw %s", active_gateway->ipv4_gateway->gateway);
if (g_strcmp0(active_gateway->ipv4_gateway->gateway,
@@ -250,6 +259,10 @@ static void set_vpn_routes(struct gateway_data *new_gateway,
if (!active_gateway->ipv6_gateway)
return;
+ if (connman_inet_compare_ipv6_subnet(active_gateway->index,
+ gateway))
+ return;
+
DBG("active gw %s", active_gateway->ipv6_gateway->gateway);
if (g_strcmp0(active_gateway->ipv6_gateway->gateway,
@@ -1019,7 +1032,7 @@ void __connman_connection_gateway_remove(struct connman_service *service,
data->ipv6_gateway, do_ipv6);
/* with vpn this will be called after the network was deleted,
- * we need to call set_default here because we will not recieve any
+ * we need to call set_default here because we will not receive any
* gateway delete notification.
* We hit the same issue if remove_gateway() fails.
*/
@@ -1123,6 +1136,29 @@ int __connman_connection_get_vpn_index(int phy_index)
return -1;
}
+int __connman_connection_get_vpn_phy_index(int vpn_index)
+{
+ GHashTableIter iter;
+ gpointer value, key;
+
+ g_hash_table_iter_init(&iter, gateway_hash);
+
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ struct gateway_data *data = value;
+
+ if (data->index != vpn_index)
+ continue;
+
+ if (data->ipv4_gateway)
+ return data->ipv4_gateway->vpn_phy_index;
+
+ if (data->ipv6_gateway)
+ return data->ipv6_gateway->vpn_phy_index;
+ }
+
+ return -1;
+}
+
int __connman_connection_init(void)
{
int err;
diff --git a/src/connman-robot.conf b/src/connman-robot.conf
new file mode 100644
index 00000000..7a2e4caf
--- /dev/null
+++ b/src/connman-robot.conf
@@ -0,0 +1,47 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <policy user="root">
+ <allow own="net.connman"/>
+ <allow send_destination="net.connman"/>
+ </policy>
+ <policy user="network_fw">
+ <allow own="net.connman"/>
+ <allow send_destination="net.connman"/>
+ </policy>
+ <policy context="default">
+ <deny own="net.connman"/>
+ <deny send_destination="net.connman"/>
+ <allow send_destination="net.connman" send_type="signal"/>
+ <allow send_destination="net.connman" send_interface="net.connman.Technology" send_member="GetScanState" />
+ <allow send_destination="net.connman" send_interface="net.connman.Technology" send_member="Get5GhzSupported" />
+ <allow send_destination="net.connman" send_interface="net.connman.Technology" send_member="Get6GHzSupported" />
+ <allow send_destination="net.connman" send_interface="net.connman.Technology" send_member="GetMaxScanSsid" />
+
+ <allow send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetTechnologies" />
+ <allow send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetProperties" />
+ <allow send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetServices" />
+ <allow send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetDefaultService" />
+ <allow send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetConnectedService" />
+ <allow send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetMeshPeers" />
+ <allow send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetConnectedMeshPeers" />
+ <allow send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetDisconnectedMeshPeers" />
+ <allow send_destination="net.connman" send_interface="net.connman.Manager" send_member="MeshAddPeer" />
+ <allow send_destination="net.connman" send_interface="net.connman.Manager" send_member="MeshRemovePeer" />
+ <allow send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetDhcpStatus" />
+ <allow send_destination="net.connman" send_interface="net.connman.Service" send_member="Connect" />
+ <allow send_destination="net.connman" send_interface="net.connman.Service" send_member="Disconnect" />
+ <allow send_destination="net.connman" send_interface="net.connman.Service" send_member="SetProperty" />
+ <allow send_destination="net.connman" send_interface="net.connman.Service" send_member="GetProperties" />
+ <allow send_destination="net.connman" send_interface="net.connman.Service" send_member="Remove" />
+ <allow send_destination="net.connman" send_interface="net.connman.Service" send_member="PropertyChanged" />
+ <allow send_destination="net.connman" send_interface="net.connman.Technology" send_member="Scan" />
+ <allow send_destination="net.connman" send_interface="net.connman.Technology" send_member="SpecificScan" />
+ <allow send_destination="net.connman" send_interface="net.connman.Technology" send_member="ScanDevice" />
+ <allow send_destination="net.connman" send_interface="net.connman.Technology" send_member="SetDevicePower" />
+ <allow send_destination="net.connman" send_interface="net.connman.Technology" send_member="SetBSSID" />
+ <allow send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetInterfaces" />
+ <allow send_destination="net.connman" send_interface="net.connman.Technology" send_member="MeshCommands" />
+ <allow send_destination="net.connman" send_interface="net.connman.Clock" send_member="GetProperties" />
+ </policy>
+</busconfig>
diff --git a/src/connman.conf b/src/connman.conf
index adff8fa4..7cc819e2 100644
--- a/src/connman.conf
+++ b/src/connman.conf
@@ -15,23 +15,29 @@
<allow send_destination="net.connman" send_type="signal"/>
<allow send_destination="net.connman" send_interface="net.connman.Technology" send_member="GetScanState" />
<allow send_destination="net.connman" send_interface="net.connman.Technology" send_member="Get5GhzSupported" />
+ <allow send_destination="net.connman" send_interface="net.connman.Technology" send_member="Get6GHzSupported" />
<allow send_destination="net.connman" send_interface="net.connman.Technology" send_member="GetMaxScanSsid" />
<check send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetTechnologies" privilege="http://tizen.org/privilege/network.get" />
+ <check send_destination="net.connman" send_interface="net.connman.Manager" send_member="SetProperty" privilege="http://tizen.org/privilege/network.set" />
<check send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetProperties" privilege="http://tizen.org/privilege/network.get" />
<check send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetServices" privilege="http://tizen.org/privilege/network.get" />
<check send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetDefaultService" privilege="http://tizen.org/privilege/network.get" />
+ <check send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetConnectedService" privilege="http://tizen.org/privilege/network.get" />
<check send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetMeshPeers" privilege="http://tizen.org/privilege/network.get" />
<check send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetConnectedMeshPeers" privilege="http://tizen.org/privilege/network.get" />
<check send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetDisconnectedMeshPeers" privilege="http://tizen.org/privilege/network.get" />
<check send_destination="net.connman" send_interface="net.connman.Manager" send_member="MeshAddPeer" privilege="http://tizen.org/privilege/network.set" />
<check send_destination="net.connman" send_interface="net.connman.Manager" send_member="MeshRemovePeer" privilege="http://tizen.org/privilege/network.set" />
+ <check send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetDhcpStatus" privilege="http://tizen.org/privilege/network.get" />
<check send_destination="net.connman" send_interface="net.connman.Service" send_member="Connect" privilege="http://tizen.org/privilege/network.set" />
<check send_destination="net.connman" send_interface="net.connman.Service" send_member="Disconnect" privilege="http://tizen.org/privilege/network.set" />
<check send_destination="net.connman" send_interface="net.connman.Service" send_member="SetProperty" privilege="http://tizen.org/privilege/network.profile" />
<check send_destination="net.connman" send_interface="net.connman.Service" send_member="GetProperties" privilege="http://tizen.org/privilege/network.get" />
<check send_destination="net.connman" send_interface="net.connman.Service" send_member="Remove" privilege="http://tizen.org/privilege/network.profile" />
<check send_destination="net.connman" send_interface="net.connman.Service" send_member="PropertyChanged" privilege="http://tizen.org/privilege/network.get" />
+ <check send_destination="net.connman" send_interface="net.connman.Technology" send_member="GetProperties" privilege="http://tizen.org/privilege/network.get" />
+ <check send_destination="net.connman" send_interface="net.connman.Technology" send_member="SetProperty" privilege="http://tizen.org/privilege/network.set" />
<check send_destination="net.connman" send_interface="net.connman.Technology" send_member="Scan" privilege="http://tizen.org/privilege/network.set" />
<check send_destination="net.connman" send_interface="net.connman.Technology" send_member="SpecificScan" privilege="http://tizen.org/privilege/network.set" />
<check send_destination="net.connman" send_interface="net.connman.Technology" send_member="ScanDevice" privilege="http://tizen.org/privilege/network.set" />
@@ -39,5 +45,6 @@
<check send_destination="net.connman" send_interface="net.connman.Technology" send_member="SetBSSID" privilege="http://tizen.org/privilege/network.set" />
<check send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetInterfaces" privilege="http://tizen.org/privilege/network.get" />
<check send_destination="net.connman" send_interface="net.connman.Technology" send_member="MeshCommands" privilege="http://tizen.org/privilege/network.set" />
+ <check send_destination="net.connman" send_interface="net.connman.Clock" send_member="GetProperties" privilege="http://tizen.org/privilege/network.get" />
</policy>
</busconfig>
diff --git a/src/connman.h b/src/connman.h
index 14ddcc2d..e6e16d11 100755
--- a/src/connman.h
+++ b/src/connman.h
@@ -63,6 +63,7 @@ DBusMessage *__connman_error_invalid_property(DBusMessage *msg);
DBusMessage *__connman_error_invalid_command(DBusMessage *msg);
DBusMessage *__connman_error_scan_abort_failed(DBusMessage *msg);
#endif
+DBusMessage *__connman_error_operation_canceled(DBusMessage *msg);
int __connman_manager_init(void);
void __connman_manager_cleanup(void);
@@ -78,6 +79,9 @@ int __connman_clock_init(void);
void __connman_clock_cleanup(void);
void __connman_clock_update_timezone(void);
+#if defined TIZEN_EXT
+void __connman_clock_set_time_updated(bool updated);
+#endif
int __connman_timezone_init(void);
void __connman_timezone_cleanup(void);
@@ -146,8 +150,6 @@ void __connman_log_enable(struct connman_debug_desc *start,
#include <connman/backtrace.h>
-#include <connman/option.h>
-
#include <connman/setting.h>
#include <connman/plugin.h>
@@ -167,7 +169,8 @@ int __connman_inet_modify_address(int cmd, int flags, int index, int family,
const char *address,
const char *peer,
unsigned char prefixlen,
- const char *broadcast);
+ const char *broadcast,
+ bool is_p2p);
int __connman_inet_get_interface_address(int index, int family, void *address);
int __connman_inet_get_interface_ll_address(int index, int family, void *address);
int __connman_inet_get_interface_mac_address(int index, uint8_t *mac_address);
@@ -288,7 +291,6 @@ int __connman_storage_save_ins(GKeyFile *keyfile);
GKeyFile *__connman_storage_load_config(const char *ident);
GKeyFile *__connman_storage_load_provider_config(const char *ident);
-GKeyFile *__connman_storage_open_service(const char *ident);
int __connman_storage_save_service(GKeyFile *keyfile, const char *ident);
GKeyFile *__connman_storage_load_provider(const char *identifier);
void __connman_storage_save_provider(GKeyFile *keyfile, const char *identifier);
@@ -318,6 +320,7 @@ struct connman_ipaddress {
char *peer;
char *broadcast;
char *gateway;
+ bool is_p2p; /* P2P connection or VPN, broadcast is excluded. */
};
struct connman_ipconfig_ops {
@@ -345,7 +348,6 @@ __connman_ipconfig_ref_debug(struct connman_ipconfig *ipconfig,
void __connman_ipconfig_unref_debug(struct connman_ipconfig *ipconfig,
const char *file, int line, const char *caller);
-void __connman_ipconfig_clear_address(struct connman_ipconfig *ipconfig);
void *__connman_ipconfig_get_data(struct connman_ipconfig *ipconfig);
void __connman_ipconfig_set_data(struct connman_ipconfig *ipconfig, void *data);
@@ -451,9 +453,9 @@ void __connman_ipconfig_set_dhcpv6_prefixes(struct connman_ipconfig *ipconfig,
char **prefixes);
char **__connman_ipconfig_get_dhcpv6_prefixes(struct connman_ipconfig *ipconfig);
-int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
+void __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
GKeyFile *keyfile, const char *identifier, const char *prefix);
-int __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
+void __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
GKeyFile *keyfile, const char *identifier, const char *prefix);
bool __connman_ipconfig_ipv6_privacy_enabled(struct connman_ipconfig *ipconfig);
int __connman_ipconfig_ipv6_reset_privacy(struct connman_ipconfig *ipconfig);
@@ -479,7 +481,11 @@ char **__connman_timeserver_system_get();
GSList *__connman_timeserver_add_list(GSList *server_list,
const char *timeserver);
GSList *__connman_timeserver_get_all(struct connman_service *service);
-int __connman_timeserver_sync(struct connman_service *service);
+void __connman_timeserver_sync(struct connman_service *service);
+void __connman_timeserver_conf_update(struct connman_service *service);
+
+bool __connman_timeserver_is_synced(void);
+void __connman_timeserver_set_synced(bool status);
enum __connman_dhcpv6_status {
CONNMAN_DHCPV6_STATUS_FAIL = 0,
@@ -537,6 +543,7 @@ int __connman_connection_gateway_add(struct connman_service *service,
void __connman_connection_gateway_remove(struct connman_service *service,
enum connman_ipconfig_type type);
int __connman_connection_get_vpn_index(int phy_index);
+int __connman_connection_get_vpn_phy_index(int vpn_index);
bool __connman_connection_update_gateway(void);
@@ -591,6 +598,13 @@ void __connman_technology_notify_regdom_by_device(struct connman_device *device,
int result, const char *alpha2);
#if defined TIZEN_EXT
+void __connman_technology_notify_mac_policy_by_device(struct connman_device *device,
+ int result, unsigned int policy);
+void __connman_technology_notify_preassoc_mac_policy_by_device(struct connman_device *device,
+ int result, unsigned int policy);
+void __connman_technology_notify_random_mac_lifetime_by_device(struct connman_device *device,
+ int result, unsigned int lifetime);
+
enum bssid_type {
CHECK_BSSID = 0,
GET_BSSID = 1,
@@ -646,6 +660,8 @@ int __connman_rfkill_block(enum connman_service_type type, bool block);
#if defined TIZEN_EXT
char *index2ident(int index, const char *prefix);
char *index2addr(int index);
+char *_get_wifi_ident(void);
+char *_get_wifi_addr(void);
#endif
#include <connman/network.h>
@@ -667,6 +683,13 @@ const char *__connman_network_get_type(struct connman_network *network);
const char *__connman_network_get_group(struct connman_network *network);
const char *__connman_network_get_ident(struct connman_network *network);
bool __connman_network_get_weakness(struct connman_network *network);
+bool __connman_network_native_autoconnect(struct connman_network *network);
+#if defined TIZEN_EXT
+char *__connman_network_get_dhcp_status(const char *ifname);
+dbus_bool_t __connman_network_notify_dhcp_changed(const char *key, const char *val);
+bool connman_network_get_psk_sha256(struct connman_network *network);
+void connman_network_set_psk_sha256(struct connman_network *network, bool is_psk_sha256);
+#endif
int __connman_config_init();
void __connman_config_cleanup(void);
@@ -714,6 +737,8 @@ void __connman_provider_list(DBusMessageIter *iter, void *user_data);
bool __connman_provider_is_immutable(struct connman_provider *provider);
int __connman_provider_create_and_connect(DBusMessage *msg);
const char * __connman_provider_get_ident(struct connman_provider *provider);
+const char * __connman_provider_get_transport_ident(
+ struct connman_provider *provider);
int __connman_provider_indicate_state(struct connman_provider *provider,
enum connman_provider_state state);
int __connman_provider_indicate_error(struct connman_provider *provider,
@@ -728,14 +753,14 @@ int __connman_provider_init(void);
int __connman_service_init(void);
void __connman_service_cleanup(void);
+int __connman_service_move(struct connman_service *service,
+ struct connman_service *target, bool before);
int __connman_service_load_modifiable(struct connman_service *service);
void __connman_service_list_struct(DBusMessageIter *iter);
-#if defined TIZEN_EXT_INS
+#if defined TIZEN_EXT
void __connman_ins_list_struct(DBusMessageIter *iter);
-#endif
-#if defined TIZEN_EXT
int connman_service_get_ipv6_dns_method(struct connman_service *service);
enum connman_dnsconfig_method {
CONNMAN_DNSCONFIG_METHOD_UNKNOWN = 0,
@@ -797,8 +822,9 @@ int __connman_service_set_mdns(struct connman_service *service,
void __connman_service_set_string(struct connman_service *service,
const char *key, const char *value);
-int __connman_service_online_check_failed(struct connman_service *service,
- enum connman_ipconfig_type type);
+void __connman_service_online_check(struct connman_service *service,
+ enum connman_ipconfig_type type,
+ bool success);
int __connman_service_ipconfig_indicate_state(struct connman_service *service,
enum connman_service_state new_state,
enum connman_ipconfig_type type);
@@ -818,7 +844,6 @@ int __connman_service_indicate_default(struct connman_service *service);
int __connman_service_connect(struct connman_service *service,
enum connman_service_connect_reason reason);
int __connman_service_disconnect(struct connman_service *service);
-int __connman_service_disconnect_all(void);
void __connman_service_set_active_session(bool enable, GSList *list);
void __connman_service_auto_connect(enum connman_service_connect_reason reason);
@@ -829,6 +854,7 @@ void __connman_service_set_auto_connect_mode(bool enable);
#if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
int __connman_service_get_use_eapol(struct connman_service *service);
+int __connman_service_get_connect_reason(struct connman_service *service);
#endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
bool __connman_service_remove(struct connman_service *service);
@@ -890,6 +916,9 @@ int check_passphrase_ext(struct connman_network *network,
bool __connman_service_is_hidden(struct connman_service *service);
bool __connman_service_is_split_routing(struct connman_service *service);
bool __connman_service_index_is_split_routing(int index);
+void __connman_service_set_split_routing(struct connman_service *service,
+ bool split_routing);
+void __connman_service_split_routing_changed(struct connman_service *service);
int __connman_service_get_index(struct connman_service *service);
void __connman_service_set_hidden(struct connman_service *service);
void __connman_service_set_hostname(struct connman_service *service,
@@ -1227,9 +1256,6 @@ int __connman_util_init(void);
void __connman_util_cleanup(void);
#ifdef TIZEN_EXT
-__attribute__ ((unused)) static bool dlog_logging = true;
-__attribute__ ((unused)) static bool file_logging = true;
-__attribute__ ((unused)) static bool simplified_log = true;
__attribute__ ((unused)) static int __tizentvextension = -1;
#define TIZEN_TV_EXT (__builtin_expect(__tizentvextension != -1, 1) ? \
__tizentvextension : \
diff --git a/src/dbus.c b/src/dbus.c
index d80a46ce..74b3157b 100755
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -246,9 +246,7 @@ dbus_bool_t connman_dbus_property_changed_basic(const char *path,
dbus_message_iter_init_append(signal, &iter);
connman_dbus_property_append_basic(&iter, key, type, val);
- g_dbus_send_message(connection, signal);
-
- return TRUE;
+ return g_dbus_send_message(connection, signal);
}
dbus_bool_t connman_dbus_property_changed_dict(const char *path,
@@ -268,9 +266,7 @@ dbus_bool_t connman_dbus_property_changed_dict(const char *path,
dbus_message_iter_init_append(signal, &iter);
connman_dbus_property_append_dict(&iter, key, function, user_data);
- g_dbus_send_message(connection, signal);
-
- return TRUE;
+ return g_dbus_send_message(connection, signal);
}
dbus_bool_t connman_dbus_property_changed_array(const char *path,
@@ -291,9 +287,7 @@ dbus_bool_t connman_dbus_property_changed_array(const char *path,
connman_dbus_property_append_array(&iter, key, type,
function, user_data);
- g_dbus_send_message(connection, signal);
-
- return TRUE;
+ return g_dbus_send_message(connection, signal);
}
dbus_bool_t connman_dbus_setting_changed_basic(const char *owner,
@@ -319,9 +313,7 @@ dbus_bool_t connman_dbus_setting_changed_basic(const char *owner,
connman_dbus_dict_close(&array, &dict);
- g_dbus_send_message(connection, msg);
-
- return TRUE;
+ return g_dbus_send_message(connection, msg);
}
dbus_bool_t connman_dbus_setting_changed_dict(const char *owner,
@@ -348,9 +340,7 @@ dbus_bool_t connman_dbus_setting_changed_dict(const char *owner,
connman_dbus_dict_close(&array, &dict);
- g_dbus_send_message(connection, msg);
-
- return TRUE;
+ return g_dbus_send_message(connection, msg);
}
dbus_bool_t connman_dbus_setting_changed_array(const char *owner,
@@ -377,9 +367,7 @@ dbus_bool_t connman_dbus_setting_changed_array(const char *owner,
connman_dbus_dict_close(&array, &dict);
- g_dbus_send_message(connection, msg);
-
- return TRUE;
+ return g_dbus_send_message(connection, msg);
}
dbus_bool_t __connman_dbus_append_objpath_dict_array(DBusMessage *msg,
@@ -699,7 +687,7 @@ int __connman_dbus_init(DBusConnection *conn)
connection = conn;
- return 0;
+ return g_dbus_attach_object_manager(conn);
}
void __connman_dbus_cleanup(void)
diff --git a/src/device.c b/src/device.c
index 801400f2..da86084f 100755
--- a/src/device.c
+++ b/src/device.c
@@ -76,18 +76,34 @@ struct connman_device {
time_t last_user_selection_time;
char *last_user_selection_ident;
char *last_connected_ident;
- DBusMessage *pending_reply;
+ GList *pending_reply_list; /* List of DBusMessage* for async reply to multiple
+ * device power dbus calls, which are made before
+ * connman_device_set_powered().
+ */
int max_scan_ssids;
bool is_5_0_ghz_supported;
+ bool is_6_0_ghz_supported;
+ unsigned int mac_policy;
+ unsigned int preassoc_mac_policy;
+ unsigned int random_mac_lifetime;
#endif
};
+#if defined TIZEN_EXT
+static void __clear_pending_trigger(gpointer data, gpointer user_data)
+{
+ DBusMessage *msg = (DBusMessage *)data;
+ dbus_message_unref(msg);
+}
+#endif
+
static void clear_pending_trigger(struct connman_device *device)
{
#if defined TIZEN_EXT
- if (device->pending_reply) {
- dbus_message_unref(device->pending_reply);
- device->pending_reply = NULL;
+ if (device->pending_reply_list) {
+ g_list_foreach(device->pending_reply_list, __clear_pending_trigger, NULL);
+ g_list_free(device->pending_reply_list);
+ device->pending_reply_list = NULL;
}
#endif
if (device->pending_timeout > 0) {
@@ -197,6 +213,20 @@ static bool device_has_service_type(struct connman_device *device,
return service_type == device_service_type;
}
+#if defined TIZEN_EXT
+static void __device_pending_reset(gpointer data, gpointer user_data)
+{
+ DBusMessage *msg = (DBusMessage *)data;
+ DBusMessage *reply;
+
+ reply = __connman_error_failed(msg, ETIMEDOUT);
+ if (reply)
+ g_dbus_send_message(connection, reply);
+
+ dbus_message_unref(msg);
+}
+#endif
+
static gboolean device_pending_reset(gpointer user_data)
{
struct connman_device *device = user_data;
@@ -204,16 +234,11 @@ static gboolean device_pending_reset(gpointer user_data)
DBG("device %p", device);
#if defined TIZEN_EXT
- DBusMessage *reply;
-
/* Power request timed out, send ETIMEDOUT. */
- if (device->pending_reply) {
- reply = __connman_error_failed(device->pending_reply, ETIMEDOUT);
- if (reply)
- g_dbus_send_message(connection, reply);
-
- dbus_message_unref(device->pending_reply);
- device->pending_reply = NULL;
+ if (device->pending_reply_list) {
+ g_list_foreach(device->pending_reply_list, __device_pending_reset, NULL);
+ g_list_free(device->pending_reply_list);
+ device->pending_reply_list = NULL;
}
#endif
/* Power request timedout, reset power pending state. */
@@ -263,6 +288,13 @@ int __connman_device_enable(struct connman_device *device)
if (err == -EALREADY) {
/* If device is already powered, but connman is not updated */
connman_device_set_powered(device, true);
+#ifdef TIZEN_EXT
+ if (device->type == CONNMAN_DEVICE_TYPE_WIFI) {
+ device->driver->set_mac_policy(device, device->mac_policy);
+ device->driver->set_preassoc_mac_policy(device, device->preassoc_mac_policy);
+ device->driver->set_random_mac_lifetime(device, device->random_mac_lifetime);
+ }
+#endif /* TIZEN_EXT */
goto done;
}
/*
@@ -356,6 +388,10 @@ static void remove_device(struct connman_device *device)
if (device->driver->remove)
device->driver->remove(device);
+#if defined TIZEN_EXT
+ __connman_technology_notify_device_detected_by_device(device, "", false);
+#endif
+
device->driver = NULL;
}
@@ -496,13 +532,19 @@ static void device_send_changed(const char *ifname, enum connman_service_type ty
dbus_message_unref(signal);
}
+static void __device_send_reply(gpointer data, gpointer user_data)
+{
+ DBusMessage *msg = (DBusMessage *)data;
+ g_dbus_send_reply(connection, msg, DBUS_TYPE_INVALID);
+ dbus_message_unref(msg);
+}
+
static void device_send_reply(struct connman_device *device)
{
- if (device->pending_reply) {
- g_dbus_send_reply(connection,
- device->pending_reply, DBUS_TYPE_INVALID);
- dbus_message_unref(device->pending_reply);
- device->pending_reply = NULL;
+ if (device->pending_reply_list) {
+ g_list_foreach(device->pending_reply_list, __device_send_reply, NULL);
+ g_list_free(device->pending_reply_list);
+ device->pending_reply_list = NULL;
}
}
#endif
@@ -654,6 +696,11 @@ void connman_device_set_interface(struct connman_device *device,
void connman_device_set_ident(struct connman_device *device,
const char *ident)
{
+#ifdef TIZEN_EXT
+ if (device->ident && device->powered)
+ return;
+ else
+#endif
g_free(device->ident);
device->ident = g_strdup(ident);
}
@@ -838,7 +885,9 @@ const char *connman_device_get_last_connected_ident(struct connman_device *devic
{
return device->last_connected_ident;
}
+#endif
+#if defined TIZEN_EXT
void connman_device_save_last_user_selection(struct connman_device *device)
{
GKeyFile *keyfile;
@@ -972,7 +1021,7 @@ void connman_device_load_last_connected(struct connman_device *device)
g_key_file_free(keyfile);
}
-#endif
+#endif /* defined TIZEN_EXT */
static void mark_network_available(gpointer key, gpointer value,
gpointer user_data)
@@ -1096,6 +1145,11 @@ int connman_device_set_string(struct connman_device *device,
DBG("device %p key %s value %s", device, key, value);
if (g_str_equal(key, "Address")) {
+#ifdef TIZEN_EXT
+ if (device->address && device->powered)
+ return 0;
+ else
+#endif
g_free(device->address);
device->address = g_strdup(value);
} else if (g_str_equal(key, "Name")) {
@@ -1200,7 +1254,7 @@ struct connman_network *connman_device_get_default_network(
void connman_device_set_pending_reply(struct connman_device *device,
DBusMessage *msg)
{
- device->pending_reply = dbus_message_ref(msg);
+ device->pending_reply_list = g_list_prepend(device->pending_reply_list, dbus_message_ref(msg));
}
void connman_device_send_connected_signal(struct connman_device *device,
@@ -1232,10 +1286,21 @@ void connman_device_set_wifi_5ghz_supported(struct connman_device *device,
device->is_5_0_ghz_supported = is_5_0_ghz_supported;
}
+void connman_device_set_wifi_6ghz_supported(struct connman_device *device,
+ bool is_6_0_ghz_supported)
+{
+ device->is_6_0_ghz_supported = is_6_0_ghz_supported;
+}
+
bool connman_device_get_wifi_5ghz_supported(struct connman_device *device)
{
return device->is_5_0_ghz_supported;
}
+
+bool connman_device_get_wifi_6ghz_supported(struct connman_device *device)
+{
+ return device->is_6_0_ghz_supported;
+}
#endif
/**
@@ -1758,6 +1823,87 @@ void __connman_device_stop_scan(enum connman_service_type type)
}
#if defined TIZEN_EXT
+#define WIFI_MAC "/opt/etc/.mac.info"
+#define MAC_ADDR_LEN 18
+
+char *_get_wifi_addr(void)
+{
+ FILE *fp = NULL;
+ char* rv = 0;
+ char wifi_mac[MAC_ADDR_LEN + 1];
+ char *str;
+
+ fp = fopen(WIFI_MAC, "r");
+ if (!fp){
+ connman_error("[%s] not present", WIFI_MAC);
+ return NULL;
+ }
+
+ rv = fgets(wifi_mac, MAC_ADDR_LEN, fp);
+ if (!rv) {
+ connman_error("Failed to get wifi mac address");
+ fclose(fp);
+ return NULL;
+ }
+
+ str = g_try_malloc0(MAC_ADDR_LEN);
+ if (!str) {
+ connman_error("memory allocation failed");
+ fclose(fp);
+ return NULL;
+ }
+
+ snprintf(str, MAC_ADDR_LEN, "%c%c:%c%c:%c%c:%c%c:%c%c:%c%c",
+ g_ascii_tolower(wifi_mac[0]), g_ascii_tolower(wifi_mac[1]),
+ g_ascii_tolower(wifi_mac[3]), g_ascii_tolower(wifi_mac[4]),
+ g_ascii_tolower(wifi_mac[6]), g_ascii_tolower(wifi_mac[7]),
+ g_ascii_tolower(wifi_mac[9]), g_ascii_tolower(wifi_mac[10]),
+ g_ascii_tolower(wifi_mac[12]), g_ascii_tolower(wifi_mac[13]),
+ g_ascii_tolower(wifi_mac[15]), g_ascii_tolower(wifi_mac[16]));
+ fclose(fp);
+ return str;
+}
+
+char *_get_wifi_ident(void)
+{
+ FILE *fp = NULL;
+ char* rv = 0;
+ char wifi_mac[MAC_ADDR_LEN + 1];
+ char *str;
+
+ fp = fopen(WIFI_MAC, "r");
+ if (!fp){
+ connman_error("[%s] not present", WIFI_MAC);
+ return NULL;
+ }
+
+ rv = fgets(wifi_mac, MAC_ADDR_LEN, fp);
+ if (!rv) {
+ connman_error("Failed to get wifi mac address");
+ fclose(fp);
+ return NULL;
+ }
+
+ str = g_try_malloc0(MAC_ADDR_LEN);
+ if (!str) {
+ connman_error("memory allocation failed");
+ fclose(fp);
+ return NULL;
+ }
+
+ snprintf(str, MAC_ADDR_LEN, "%c%c%c%c%c%c%c%c%c%c%c%c",
+ g_ascii_tolower(wifi_mac[0]), g_ascii_tolower(wifi_mac[1]),
+ g_ascii_tolower(wifi_mac[3]), g_ascii_tolower(wifi_mac[4]),
+ g_ascii_tolower(wifi_mac[6]), g_ascii_tolower(wifi_mac[7]),
+ g_ascii_tolower(wifi_mac[9]), g_ascii_tolower(wifi_mac[10]),
+ g_ascii_tolower(wifi_mac[12]), g_ascii_tolower(wifi_mac[13]),
+ g_ascii_tolower(wifi_mac[15]), g_ascii_tolower(wifi_mac[16]));
+ fclose(fp);
+ return str;
+}
+#endif
+
+#if defined TIZEN_EXT
char *index2ident(int index, const char *prefix)
#else
static char *index2ident(int index, const char *prefix)
@@ -1921,9 +2067,11 @@ struct connman_device *connman_device_create_from_index(int index)
connman_device_set_index(device, index);
connman_device_set_interface(device, devname);
#if defined TIZEN_EXT
- connman_device_load_last_connected(device);
- connman_device_load_last_user_selection(device);
-#endif
+ if (TIZEN_INS_ENABLED) {
+ connman_device_load_last_connected(device);
+ connman_device_load_last_user_selection(device);
+ }
+#endif /* defined TIZEN_EXT */
if (ident) {
connman_device_set_ident(device, ident);
@@ -2099,3 +2247,81 @@ void __connman_device_cleanup(void)
dbus_connection_unref(connection);
#endif
}
+
+#ifdef TIZEN_EXT
+void connman_device_mac_policy_notify(struct connman_device *device,
+ int result, unsigned int policy)
+{
+ device->mac_policy = policy;
+ __connman_technology_notify_mac_policy_by_device(device, result, policy);
+}
+
+int connman_device_set_mac_policy(struct connman_device *device,
+ unsigned int policy)
+{
+ int err = 0;
+
+ if (!device || !device->driver || !device->driver->set_mac_policy)
+ return -EOPNOTSUPP;
+
+ device->mac_policy = policy;
+ err = device->driver->set_mac_policy(device, policy);
+ return err;
+}
+
+unsigned int connman_device_get_mac_policy(struct connman_device *device)
+{
+ return device->mac_policy;
+}
+
+void connman_device_preassoc_mac_policy_notify(struct connman_device *device,
+ int result, unsigned int policy)
+{
+ device->preassoc_mac_policy = policy;
+ __connman_technology_notify_preassoc_mac_policy_by_device(device, result, policy);
+}
+
+int connman_device_set_preassoc_mac_policy(struct connman_device *device,
+ unsigned int policy)
+{
+ int err = 0;
+
+ if (!device || !device->driver || !device->driver->set_preassoc_mac_policy)
+ return -EOPNOTSUPP;
+
+ device->preassoc_mac_policy = policy;
+ err = device->driver->set_preassoc_mac_policy(device, policy);
+ return err;
+}
+
+unsigned int connman_device_get_preassoc_mac_policy(struct connman_device *device)
+{
+ return device->preassoc_mac_policy;
+}
+
+void connman_device_random_mac_lifetime_notify(struct connman_device *device,
+ int result, unsigned int lifetime)
+{
+ device->random_mac_lifetime = lifetime;
+ __connman_technology_notify_random_mac_lifetime_by_device(device, result, lifetime);
+}
+
+int connman_device_set_random_mac_lifetime(struct connman_device *device,
+ unsigned int lifetime)
+{
+ int err = 0;
+
+ if (!device || !device->driver || !device->driver->set_random_mac_lifetime)
+ return -EOPNOTSUPP;
+
+ device->random_mac_lifetime = lifetime;
+ err = device->driver->set_random_mac_lifetime(device, lifetime);
+ return err;
+}
+
+unsigned int connman_device_get_random_mac_lifetime(struct connman_device *device)
+{
+ return device->random_mac_lifetime;
+}
+
+#endif
diff --git a/src/dhcp.c b/src/dhcp.c
index 951836fd..5ad1efba 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -43,6 +43,12 @@
#define RATE_LIMIT_INTERVAL 60 /* delay between successive attempts */
+#if defined TIZEN_EXT
+#define DHCP_SUCCESS "DHCP_SUCCESS"
+#define DHCP_FAIL "DHCP_FAIL"
+#define DHCP_STARTED "DHCP_STARTED"
+#endif
+
struct connman_dhcp {
struct connman_ipconfig *ipconfig;
struct connman_network *network;
@@ -285,10 +291,26 @@ static void no_lease_cb(GDHCPClient *dhcp_client, gpointer user_data)
dhcp->ipv4ll_client);
#if defined TIZEN_EXT
+ if (dhcp->network &&
+ connman_network_get_bool(dhcp->network, "WiFi.RoamingDHCP")) {
+
+ connman_network_set_bool(dhcp->network, "WiFi.RoamingDHCP", false);
+ __connman_network_enable_ipconfig(dhcp->network, dhcp->ipconfig);
+ __connman_network_notify_dhcp_changed(DHCP_FAIL,
+ g_dhcp_client_get_interface(dhcp_client));
+
+ return;
+ }
+
if (connman_setting_get_bool("EnableAutoIp") == false) {
DBG("link-local address autoconfiguration is disabled.");
- if (dhcp->network)
- __connman_network_disconnect(dhcp->network);
+
+ if (dhcp->network) {
+ DBG("[DHCP-C] auto ip is not used, set dhcp-fail error and disconnect");
+ __connman_network_notify_dhcp_changed(DHCP_FAIL,
+ g_dhcp_client_get_interface(dhcp_client));
+ connman_network_set_error(dhcp->network, CONNMAN_NETWORK_ERROR_DHCP_FAIL);
+ }
return;
}
#endif
@@ -547,6 +569,8 @@ static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data)
#if defined TIZEN_EXT
__connman_ipconfig_set_dhcp_lease_duration(dhcp->ipconfig, dhcp_lease_duration);
+ __connman_network_notify_dhcp_changed(DHCP_SUCCESS,
+ g_dhcp_client_get_interface(dhcp_client));
#endif
/*
@@ -563,6 +587,17 @@ static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data)
__connman_service_notify_ipv4_configuration(service);
}
+#if defined TIZEN_EXT
+ if (connman_network_get_bool(dhcp->network, "WiFi.RoamingDHCP")) {
+
+ if (ip_change)
+ connman_service_notify_reconnection_roaming(
+ connman_service_lookup_from_network(dhcp->network));
+
+ connman_network_set_bool(dhcp->network, "WiFi.RoamingDHCP", false);
+ }
+#endif
+
if (ip_change) {
__connman_ipconfig_set_local(dhcp->ipconfig, address);
__connman_ipconfig_set_prefixlen(dhcp->ipconfig, prefixlen);
@@ -622,6 +657,11 @@ static void ipv4ll_available_cb(GDHCPClient *ipv4ll_client, gpointer user_data)
g_free(address);
g_free(netmask);
+
+#if defined TIZEN_EXT
+ __connman_network_notify_dhcp_changed(DHCP_FAIL,
+ g_dhcp_client_get_interface(ipv4ll_client));
+#endif
}
static int dhcp_initialize(struct connman_dhcp *dhcp)
@@ -684,7 +724,7 @@ static int dhcp_initialize(struct connman_dhcp *dhcp)
g_dhcp_client_set_request(dhcp_client, G_DHCP_ROUTER);
g_dhcp_client_set_request(dhcp_client, G_DHCP_SUBNET);
- vendor_class_id = connman_option_get_string("VendorClassID");
+ vendor_class_id = connman_setting_get_string("VendorClassID");
if (vendor_class_id)
g_dhcp_client_set_send(dhcp_client, G_DHCP_VENDOR_CLASS_ID,
vendor_class_id);
@@ -829,9 +869,18 @@ int __connman_dhcp_start(struct connman_ipconfig *ipconfig,
dhcp->user_data = user_data;
#if defined TIZEN_EXT
- DBG("Start DHCP with DHCPDISCOVER request");
+ __connman_network_notify_dhcp_changed(DHCP_STARTED,
+ g_dhcp_client_get_interface(dhcp->dhcp_client));
- return g_dhcp_client_start(dhcp->dhcp_client, NULL);
+ if (network && connman_network_get_bool(network, "WiFi.RoamingDHCP")) {
+ const char *last_addr = __connman_ipconfig_get_dhcp_address(ipconfig);
+
+ DBG("Start DHCP with last address request");
+ return g_dhcp_client_start(dhcp->dhcp_client, last_addr);
+ } else {
+ DBG("Start DHCP with DHCPDISCOVER request");
+ return g_dhcp_client_start(dhcp->dhcp_client, NULL);
+ }
#else
return g_dhcp_client_start(dhcp->dhcp_client, last_addr);
#endif
diff --git a/src/dhcpv6.c b/src/dhcpv6.c
index 4c07c769..ba54b892 100755
--- a/src/dhcpv6.c
+++ b/src/dhcpv6.c
@@ -1008,7 +1008,7 @@ static void do_dad(GDHCPClient *dhcp_client, struct connman_dhcpv6 *dhcp)
ref_own_address(user_data);
- if (inet_pton(AF_INET6, address, &addr) < 0) {
+ if (inet_pton(AF_INET6, address, &addr) != 1) {
DBG("Invalid IPv6 address %s %d/%s", address,
-errno, strerror(errno));
goto fail;
diff --git a/src/dns-systemd-resolved.c b/src/dns-systemd-resolved.c
index 5fe306c3..912ab3fe 100644
--- a/src/dns-systemd-resolved.c
+++ b/src/dns-systemd-resolved.c
@@ -106,7 +106,7 @@ static void setlinkdns_append(DBusMessageIter *iter, void *user_data)
if (type == AF_INET) {
result = inet_pton(type, server, ipv4_bytes);
- if (!result) {
+ if (result != 1) {
DBG("Failed to parse IPv4 address: %s",
server);
return;
@@ -128,7 +128,7 @@ static void setlinkdns_append(DBusMessageIter *iter, void *user_data)
&byte_array);
} else if (type == AF_INET6) {
result = inet_pton(type, server, ipv6_bytes);
- if (!result) {
+ if (result != 1) {
DBG("Failed to parse IPv6 address: %s", server);
return;
}
diff --git a/src/dnsproxy.c b/src/dnsproxy.c
index 178e98f7..8e3ce973 100755
--- a/src/dnsproxy.c
+++ b/src/dnsproxy.c
@@ -472,7 +472,7 @@ static void send_cached_response(int sk, unsigned char *buf, int len,
hdr->nscount = 0;
hdr->arcount = 0;
- /* if this is a negative reply, we are authorative */
+ /* if this is a negative reply, we are authoritative */
if (answers == 0)
hdr->aa = 1;
else
@@ -1819,6 +1819,7 @@ static char *uncompress(int16_t field_count, char *start, char *end,
char **uncompressed_ptr)
{
char *uptr = *uncompressed_ptr; /* position in result buffer */
+ char * const uncomp_end = uncompressed + uncomp_len - 1;
debug("count %d ptr %p end %p uptr %p", field_count, ptr, end, uptr);
@@ -1839,14 +1840,16 @@ static char *uncompress(int16_t field_count, char *start, char *end,
* tmp buffer.
*/
- ulen = strlen(name);
- strncpy(uptr, name, uncomp_len - (uptr - uncompressed));
+ ulen = strlen(name) + 1;
+ if ((uptr + ulen) > uncomp_end)
+ goto out;
+
+ memcpy(uptr, name, ulen);
debug("pos %d ulen %d left %d name %s", pos, ulen,
- (int)(uncomp_len - (uptr - uncompressed)), uptr);
+ (int)(uncomp_end - (uptr + ulen)), uptr);
uptr += ulen;
- *uptr++ = '\0';
ptr += pos;
@@ -1854,6 +1857,10 @@ static char *uncompress(int16_t field_count, char *start, char *end,
* We copy also the fixed portion of the result (type, class,
* ttl, address length and the address)
*/
+ if ((uptr + NS_RRFIXEDSZ) > uncomp_end) {
+ debug("uncompressed data too large for buffer");
+ goto out;
+ }
memcpy(uptr, ptr, NS_RRFIXEDSZ);
dns_type = uptr[0] << 8 | uptr[1];
@@ -1885,7 +1892,7 @@ static char *uncompress(int16_t field_count, char *start, char *end,
} else if (dns_type == ns_t_a || dns_type == ns_t_aaaa) {
dlen = uptr[-2] << 8 | uptr[-1];
- if (ptr + dlen > end) {
+ if ((ptr + dlen) > end || (uptr + dlen) > uncomp_end) {
debug("data len %d too long", dlen);
goto out;
}
@@ -1924,6 +1931,10 @@ static char *uncompress(int16_t field_count, char *start, char *end,
* refresh interval, retry interval, expiration
* limit and minimum ttl). They are 20 bytes long.
*/
+ if ((uptr + 20) > uncomp_end || (ptr + 20) > end) {
+ debug("soa record too long");
+ goto out;
+ }
memcpy(uptr, ptr, 20);
uptr += 20;
ptr += 20;
@@ -1993,6 +2004,12 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
if (offset < 0)
return offset;
+ if (reply_len < 0)
+ return -EINVAL;
+ if (reply_len < offset + 1)
+ return -EINVAL;
+ if ((size_t)reply_len < sizeof(struct domain_hdr))
+ return -EINVAL;
hdr = (void *)(reply + offset);
dns_id = reply[offset] | reply[offset + 1] << 8;
@@ -2028,23 +2045,31 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
*/
if (req->append_domain && ntohs(hdr->qdcount) == 1) {
uint16_t domain_len = 0;
- uint16_t header_len;
+ uint16_t header_len, payload_len;
uint16_t dns_type, dns_class;
uint8_t host_len, dns_type_pos;
char uncompressed[NS_MAXDNAME], *uptr;
char *ptr, *eom = (char *)reply + reply_len;
+ char *domain;
/*
* ptr points to the first char of the hostname.
* ->hostname.domain.net
*/
header_len = offset + sizeof(struct domain_hdr);
+ if (reply_len < header_len)
+ return -EINVAL;
+ payload_len = reply_len - header_len;
+
ptr = (char *)reply + header_len;
host_len = *ptr;
+ domain = ptr + 1 + host_len;
+ if (domain > eom)
+ return -EINVAL;
+
if (host_len > 0)
- domain_len = strnlen(ptr + 1 + host_len,
- reply_len - header_len);
+ domain_len = strnlen(domain, eom - domain);
/*
* If the query type is anything other than A or AAAA,
@@ -2053,6 +2078,8 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
*/
dns_type_pos = host_len + 1 + domain_len + 1;
+ if (ptr + (dns_type_pos + 3) > eom)
+ return -EINVAL;
dns_type = ptr[dns_type_pos] << 8 |
ptr[dns_type_pos + 1];
dns_class = ptr[dns_type_pos + 2] << 8 |
@@ -2082,6 +2109,8 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
int new_len, fixed_len;
char *answers;
+ if (len > payload_len)
+ return -EINVAL;
/*
* First copy host (without domain name) into
* tmp buffer.
@@ -2096,6 +2125,8 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
* Copy type and class fields of the question.
*/
ptr += len + domain_len + 1;
+ if (ptr + NS_QFIXEDSZ > eom)
+ return -EINVAL;
memcpy(uptr, ptr, NS_QFIXEDSZ);
/*
@@ -2105,6 +2136,8 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
uptr += NS_QFIXEDSZ;
answers = uptr;
fixed_len = answers - uncompressed;
+ if (ptr + offset > eom)
+ return -EINVAL;
/*
* We then uncompress the result to buffer
@@ -2215,6 +2248,9 @@ out:
err = sendto(sk, req->resp, req->resplen, 0,
&req->sa, req->sa_len);
} else {
+ uint16_t tcp_len = htons(req->resplen - 2);
+ /* correct TCP message length */
+ memcpy(req->resp, &tcp_len, sizeof(tcp_len));
sk = req->client_sk;
err = send(sk, req->resp, req->resplen, MSG_NOSIGNAL);
}
@@ -2303,14 +2339,15 @@ static gboolean udp_server_event(GIOChannel *channel, GIOCondition condition,
len = recv(sk, buf, sizeof(buf), 0);
- if (len >= 12)
- forward_dns_reply(buf, len, IPPROTO_UDP, data);
+ forward_dns_reply(buf, len, IPPROTO_UDP, data);
#if defined TIZEN_EXT
GSList *list;
- for (list = server_list_sec; list; list = list->next) {
+ list = server_list_sec;
+ while (list) {
struct server_data *new_data = list->data;
+ list = list->next;
if (new_data == data) {
destroy_server_sec(data);
@@ -2398,14 +2435,21 @@ hangup:
}
}
+ /*
+ * Remove the G_IO_OUT flag from the watch, otherwise we end
+ * up in a busy loop, because the socket is constantly writable.
+ *
+ * There seems to be no better way in g_io to do that than
+ * re-adding the watch.
+ */
+ g_source_remove(server->watch);
+ server->watch = g_io_add_watch(server->channel,
+ G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR,
+ tcp_server_event, server);
+
server->connected = true;
server_list = g_slist_append(server_list, server);
- if (server->timeout > 0) {
- g_source_remove(server->timeout);
- server->timeout = 0;
- }
-
for (list = request_list; list; ) {
struct request_data *req = list->data;
int status;
@@ -2683,8 +2727,10 @@ static void destroy_all_server_sec()
DBG("remove all dns server");
- for (list = server_list_sec; list; list = list->next) {
+ list = server_list_sec;
+ while (list) {
struct server_data *server = list->data;
+ list = list->next;
destroy_server_sec(server);
}
server_list_sec = NULL;
@@ -2940,7 +2986,7 @@ static void update_domain(int index, const char *domain, bool append)
for (list = server_list; list; list = list->next) {
struct server_data *data = list->data;
GList *dom_list;
- char *dom;
+ char *dom = NULL;
bool dom_found = false;
if (data->index < 0)
@@ -3124,6 +3170,7 @@ static void dnsproxy_default_changed(struct connman_service *service)
bool server_enabled = false;
GSList *list;
int index;
+ int vpn_index;
DBG("service %p", service);
@@ -3140,6 +3187,13 @@ static void dnsproxy_default_changed(struct connman_service *service)
if (index < 0)
return;
+ /*
+ * In case non-split-routed VPN is set as split routed the DNS servers
+ * the VPN must be enabled as well, when the transport becomes the
+ * default service.
+ */
+ vpn_index = __connman_connection_get_vpn_index(index);
+
for (list = server_list; list; list = list->next) {
struct server_data *data = list->data;
@@ -3147,6 +3201,9 @@ static void dnsproxy_default_changed(struct connman_service *service)
DBG("Enabling DNS server %s", data->server);
data->enabled = true;
server_enabled = true;
+ } else if (data->index == vpn_index) {
+ DBG("Enabling DNS server of VPN %s", data->server);
+ data->enabled = true;
} else {
DBG("Disabling DNS server %s", data->server);
data->enabled = false;
@@ -3159,10 +3216,46 @@ static void dnsproxy_default_changed(struct connman_service *service)
cache_refresh();
}
+static void dnsproxy_service_state_changed(struct connman_service *service,
+ enum connman_service_state state)
+{
+ GSList *list;
+ int index;
+
+ switch (state) {
+ case CONNMAN_SERVICE_STATE_DISCONNECT:
+ case CONNMAN_SERVICE_STATE_IDLE:
+ break;
+ case CONNMAN_SERVICE_STATE_ASSOCIATION:
+ case CONNMAN_SERVICE_STATE_CONFIGURATION:
+ case CONNMAN_SERVICE_STATE_FAILURE:
+ case CONNMAN_SERVICE_STATE_ONLINE:
+ case CONNMAN_SERVICE_STATE_READY:
+ case CONNMAN_SERVICE_STATE_UNKNOWN:
+ return;
+ }
+
+ index = __connman_service_get_index(service);
+ list = server_list;
+
+ while (list) {
+ struct server_data *data = list->data;
+
+ /* Get next before the list is changed by destroy_server() */
+ list = list->next;
+
+ if (data->index == index) {
+ DBG("removing server data of index %d", index);
+ destroy_server(data);
+ }
+ }
+}
+
static const struct connman_notifier dnsproxy_notifier = {
.name = "dnsproxy",
.default_changed = dnsproxy_default_changed,
.offline_mode = dnsproxy_offline_mode,
+ .service_state_changed = dnsproxy_service_state_changed,
};
static const unsigned char opt_edns0_type[2] = { 0x00, 0x29 };
@@ -3746,6 +3839,39 @@ static gboolean tcp6_listener_event(GIOChannel *channel, GIOCondition condition,
&ifdata->tcp6_listener_watch);
}
+#if defined TIZEN_EXT
+struct request_data * create_request(int sk, unsigned char *buf, size_t len,
+ const struct sockaddr *to, socklen_t tolen,
+ int protocol)
+{
+ struct request_data *req;
+ req = g_try_new0(struct request_data, 1);
+ if (!req)
+ return NULL;
+ memcpy(&req->sa, to, tolen);
+ req->sa_len = tolen;
+ req->client_sk = sk;
+ req->protocol = protocol;
+ req->request_len = len;
+ req->request = g_malloc(len);
+ memcpy(req->request, buf, len);
+ return req;
+
+}
+static gboolean send_response_timeout (gpointer user_data)
+{
+ struct request_data *req = user_data;
+
+ send_response(req->client_sk, req->request,(size_t) req->request_len, (const struct sockaddr *)&req->sa,
+ (socklen_t)req->sa_len, req->protocol);
+ g_free(req->request);
+ g_free(req);
+
+ return FALSE;
+
+}
+#endif
+
static bool udp_listener_event(GIOChannel *channel, GIOCondition condition,
struct listener_data *ifdata, int family,
guint *listener_watch)
@@ -3792,8 +3918,22 @@ static bool udp_listener_event(GIOChannel *channel, GIOCondition condition,
err = parse_request(buf, len, query, sizeof(query));
if (err < 0 || (g_slist_length(server_list) == 0)) {
+#if defined TIZEN_EXT
+ /** TEMP Fix
+ * Reason: In tizen6.0 same code working fine because it seems some delay in 6.0 platform
+ * where as in tizen6.5 this loop is continuously executing due to this unable to receive
+ * the response from telephony deamon and wpa_supplicant. To stop continuously execution
+ * of this code added 10ms delay.
+ */
+ req = create_request(sk, buf, len, client_addr,
+ *client_addr_len, IPPROTO_UDP);
+ if(!req)
+ return true;;
+ g_timeout_add(10, send_response_timeout, req);
+#else
send_response(sk, buf, len, client_addr,
*client_addr_len, IPPROTO_UDP);
+#endif
return true;
}
diff --git a/src/error.c b/src/error.c
index 1a059207..00791c37 100644
--- a/src/error.c
+++ b/src/error.c
@@ -39,6 +39,7 @@ DBusMessage *__connman_error_failed(DBusMessage *msg, int errnum)
return __connman_error_not_registered(msg);
case ENXIO:
return __connman_error_not_found(msg);
+ case EPERM:
case EACCES:
return __connman_error_permission_denied(msg);
case EEXIST:
@@ -67,6 +68,8 @@ DBusMessage *__connman_error_failed(DBusMessage *msg, int errnum)
return __connman_error_in_progress(msg);
case ENOKEY:
return __connman_error_passphrase_required(msg);
+ case ECANCELED:
+ return __connman_error_operation_canceled(msg);
}
return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
@@ -199,3 +202,9 @@ DBusMessage *__connman_error_scan_abort_failed(DBusMessage *msg)
".ScanAbortFailed", "Scan Abort Failed");
}
#endif
+
+DBusMessage *__connman_error_operation_canceled(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
+ ".OperationCanceled", "Operation canceled");
+}
diff --git a/src/firewall-nftables.c b/src/firewall-nftables.c
index 262b2a90..d73d661f 100644
--- a/src/firewall-nftables.c
+++ b/src/firewall-nftables.c
@@ -22,7 +22,7 @@
/*
* This file is based on the libnftnl examples:
* https://git.netfilter.org/libnftnl/tree/examples
- * by Pablo Neira Ayuso. and inspiration from systemd nft implemention
+ * by Pablo Neira Ayuso. and inspiration from systemd nft implementation
* https://github.com/zonque/systemd/blob/rfc-nftnl/src/shared/firewall-util.c
* by Daniel Mack.
*/
@@ -507,8 +507,8 @@ static int rule_delete(struct firewall_handle *handle)
if (!rule)
return -ENOMEM;
- nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
- nftnl_rule_set(rule, NFTNL_RULE_CHAIN, handle->chain);
+ nftnl_rule_set_str(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
+ nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN, handle->chain);
nftnl_rule_set_u64(rule, NFTNL_RULE_HANDLE, handle->handle);
err = socket_open_and_bind(&nl);
@@ -568,8 +568,8 @@ static int build_rule_nat(const char *address, unsigned char prefixlen,
if (!rule)
return -ENOMEM;
- nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
- nftnl_rule_set(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_NAT_POST);
+ nftnl_rule_set_str(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
+ nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_NAT_POST);
/* family ipv4 */
nftnl_rule_set_u32(rule, NFTNL_RULE_FAMILY, NFPROTO_IPV4);
@@ -673,8 +673,8 @@ static int build_rule_snat(int index, const char *address,
if (!rule)
return -ENOMEM;
- nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
- nftnl_rule_set(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_NAT_POST);
+ nftnl_rule_set_str(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
+ nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_NAT_POST);
/* OIF */
expr = nftnl_expr_alloc("meta");
@@ -770,8 +770,8 @@ static int build_rule_marking(uid_t uid, uint32_t mark, struct nftnl_rule **res)
if (!rule)
return -ENOMEM;
- nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
- nftnl_rule_set(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_ROUTE_OUTPUT);
+ nftnl_rule_set_str(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
+ nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_ROUTE_OUTPUT);
expr = nftnl_expr_alloc("meta");
if (!expr)
@@ -826,8 +826,8 @@ static int build_rule_src_ip(const char *src_ip, uint32_t mark, struct nftnl_rul
if (!rule)
return -ENOMEM;
- nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
- nftnl_rule_set(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_ROUTE_OUTPUT);
+ nftnl_rule_set_str(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
+ nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_ROUTE_OUTPUT);
/* family ipv4 */
nftnl_rule_set_u32(rule, NFTNL_RULE_FAMILY, NFPROTO_IPV4);
@@ -954,8 +954,8 @@ static struct nftnl_chain *build_chain(const char *name, const char *table,
if (!chain)
return NULL;
- nftnl_chain_set(chain, NFTNL_CHAIN_TABLE, table);
- nftnl_chain_set(chain, NFTNL_CHAIN_NAME, name);
+ nftnl_chain_set_str(chain, NFTNL_CHAIN_TABLE, table);
+ nftnl_chain_set_str(chain, NFTNL_CHAIN_NAME, name);
if (type)
nftnl_chain_set_str(chain, NFTNL_CHAIN_TYPE, type);
diff --git a/src/inet.c b/src/inet.c
index 08b1a25f..b1c55b88 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -79,7 +79,8 @@ int __connman_inet_modify_address(int cmd, int flags,
const char *address,
const char *peer,
unsigned char prefixlen,
- const char *broadcast)
+ const char *broadcast,
+ bool is_p2p)
{
uint8_t request[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
NLMSG_ALIGN(sizeof(struct ifaddrmsg)) +
@@ -94,8 +95,9 @@ int __connman_inet_modify_address(int cmd, int flags,
int sk, err;
DBG("cmd %#x flags %#x index %d family %d address %s peer %s "
- "prefixlen %hhu broadcast %s", cmd, flags, index, family,
- address, peer, prefixlen, broadcast);
+ "prefixlen %hhu broadcast %s p2p %s", cmd, flags, index,
+ family, address, peer, prefixlen, broadcast,
+ is_p2p ? "true" : "false");
if (!address)
return -EINVAL;
@@ -119,17 +121,11 @@ int __connman_inet_modify_address(int cmd, int flags,
ifaddrmsg->ifa_index = index;
if (family == AF_INET) {
- if (inet_pton(AF_INET, address, &ipv4_addr) < 1)
+ if (inet_pton(AF_INET, address, &ipv4_addr) != 1)
return -1;
- if (broadcast)
- inet_pton(AF_INET, broadcast, &ipv4_bcast);
- else
- ipv4_bcast.s_addr = ipv4_addr.s_addr |
- htonl(0xfffffffflu >> prefixlen);
-
if (peer) {
- if (inet_pton(AF_INET, peer, &ipv4_dest) < 1)
+ if (inet_pton(AF_INET, peer, &ipv4_dest) != 1)
return -1;
err = __connman_inet_rtnl_addattr_l(header,
@@ -149,16 +145,27 @@ int __connman_inet_modify_address(int cmd, int flags,
if (err < 0)
return err;
- err = __connman_inet_rtnl_addattr_l(header,
- sizeof(request),
- IFA_BROADCAST,
- &ipv4_bcast,
- sizeof(ipv4_bcast));
- if (err < 0)
- return err;
+ /*
+ * Broadcast address must not be added for P2P / VPN as
+ * getifaddrs() cannot interpret destination address.
+ */
+ if (!is_p2p) {
+ if (broadcast)
+ inet_pton(AF_INET, broadcast, &ipv4_bcast);
+ else
+ ipv4_bcast.s_addr = ipv4_addr.s_addr |
+ htonl(0xfffffffflu >> prefixlen);
+ err = __connman_inet_rtnl_addattr_l(header,
+ sizeof(request),
+ IFA_BROADCAST,
+ &ipv4_bcast,
+ sizeof(ipv4_bcast));
+ if (err < 0)
+ return err;
+ }
} else if (family == AF_INET6) {
- if (inet_pton(AF_INET6, address, &ipv6_addr) < 1)
+ if (inet_pton(AF_INET6, address, &ipv6_addr) != 1)
return -1;
err = __connman_inet_rtnl_addattr_l(header,
@@ -261,13 +268,46 @@ char *connman_inet_ifname2addr(const char *name)
}
#endif
+static bool is_addr_unspec(int family, struct sockaddr *addr)
+{
+ struct sockaddr_in *in4;
+ struct sockaddr_in6 *in6;
+
+ switch (family) {
+ case AF_INET:
+ in4 = (struct sockaddr_in*) addr;
+ return in4->sin_addr.s_addr == INADDR_ANY;
+ case AF_INET6:
+ in6 = (struct sockaddr_in6*) addr;
+ return IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr);
+ default:
+ return false;
+ }
+}
+
+static bool is_addr_ll(int family, struct sockaddr *addr)
+{
+ struct sockaddr_in *in4;
+ struct sockaddr_in6 *in6;
+
+ switch (family) {
+ case AF_INET:
+ in4 = (struct sockaddr_in*) addr;
+ return (in4->sin_addr.s_addr & IN_CLASSB_NET) ==
+ ((in_addr_t) htonl(0xa9fe0000));
+ case AF_INET6:
+ in6 = (struct sockaddr_in6*) addr;
+ return IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr);
+ default:
+ return false;
+ }
+}
+
bool __connman_inet_is_any_addr(const char *address, int family)
{
bool ret = false;
struct addrinfo hints;
struct addrinfo *result = NULL;
- struct sockaddr_in6 *in6 = NULL;
- struct sockaddr_in *in4 = NULL;
if (!address || !*address)
goto out;
@@ -280,14 +320,7 @@ bool __connman_inet_is_any_addr(const char *address, int family)
goto out;
if (result) {
- if (result->ai_family == AF_INET6) {
- in6 = (struct sockaddr_in6*)result->ai_addr;
- ret = IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr);
- } else if (result->ai_family == AF_INET) {
- in4 = (struct sockaddr_in*)result->ai_addr;
- ret = in4->sin_addr.s_addr == INADDR_ANY;
- }
-
+ ret = is_addr_unspec(result->ai_family, result->ai_addr);
freeaddrinfo(result);
}
@@ -521,18 +554,20 @@ int connman_inet_set_ipv6_address(int index,
int err;
unsigned char prefix_len;
const char *address;
+ bool is_p2p;
if (!ipaddress->local)
return 0;
prefix_len = ipaddress->prefixlen;
address = ipaddress->local;
+ is_p2p = ipaddress->is_p2p;
DBG("index %d address %s prefix_len %d", index, address, prefix_len);
err = __connman_inet_modify_address(RTM_NEWADDR,
NLM_F_REPLACE | NLM_F_ACK, index, AF_INET6,
- address, NULL, prefix_len, NULL);
+ address, NULL, prefix_len, NULL, is_p2p);
if (err < 0) {
connman_error("%s: %s", __func__, strerror(-err));
return err;
@@ -546,6 +581,7 @@ int connman_inet_set_address(int index, struct connman_ipaddress *ipaddress)
int err;
unsigned char prefix_len;
const char *address, *broadcast, *peer;
+ bool is_p2p;
if (!ipaddress->local)
return -1;
@@ -554,12 +590,13 @@ int connman_inet_set_address(int index, struct connman_ipaddress *ipaddress)
address = ipaddress->local;
broadcast = ipaddress->broadcast;
peer = ipaddress->peer;
+ is_p2p = ipaddress->is_p2p;
DBG("index %d address %s prefix_len %d", index, address, prefix_len);
err = __connman_inet_modify_address(RTM_NEWADDR,
NLM_F_REPLACE | NLM_F_ACK, index, AF_INET,
- address, peer, prefix_len, broadcast);
+ address, peer, prefix_len, broadcast, is_p2p);
if (err < 0) {
connman_error("%s: %s", __func__, strerror(-err));
return err;
@@ -568,10 +605,17 @@ int connman_inet_set_address(int index, struct connman_ipaddress *ipaddress)
return 0;
}
-int connman_inet_clear_ipv6_address(int index, const char *address,
- int prefix_len)
+int connman_inet_clear_ipv6_address(int index,
+ struct connman_ipaddress *ipaddress)
{
int err;
+ int prefix_len;
+ const char *address;
+ bool is_p2p;
+
+ address = ipaddress->local;
+ prefix_len = ipaddress->prefixlen;
+ is_p2p = ipaddress->is_p2p;
DBG("index %d address %s prefix_len %d", index, address, prefix_len);
@@ -579,7 +623,7 @@ int connman_inet_clear_ipv6_address(int index, const char *address,
return -EINVAL;
err = __connman_inet_modify_address(RTM_DELADDR, 0, index, AF_INET6,
- address, NULL, prefix_len, NULL);
+ address, NULL, prefix_len, NULL, is_p2p);
if (err < 0) {
connman_error("%s: %s", __func__, strerror(-err));
return err;
@@ -593,11 +637,13 @@ int connman_inet_clear_address(int index, struct connman_ipaddress *ipaddress)
int err;
unsigned char prefix_len;
const char *address, *broadcast, *peer;
+ bool is_p2p;
prefix_len = ipaddress->prefixlen;
address = ipaddress->local;
broadcast = ipaddress->broadcast;
peer = ipaddress->peer;
+ is_p2p = ipaddress->is_p2p;
DBG("index %d address %s prefix_len %d peer %s broadcast %s", index,
address, prefix_len, peer, broadcast);
@@ -606,7 +652,7 @@ int connman_inet_clear_address(int index, struct connman_ipaddress *ipaddress)
return -EINVAL;
err = __connman_inet_modify_address(RTM_DELADDR, 0, index, AF_INET,
- address, peer, prefix_len, broadcast);
+ address, peer, prefix_len, broadcast, is_p2p);
if (err < 0) {
connman_error("%s: %s", __func__, strerror(-err));
return err;
@@ -773,7 +819,7 @@ int connman_inet_del_ipv6_network_route(int index, const char *host,
rt.rtmsg_dst_len = prefix_len;
- if (inet_pton(AF_INET6, host, &rt.rtmsg_dst) < 0) {
+ if (inet_pton(AF_INET6, host, &rt.rtmsg_dst) != 1) {
err = -errno;
goto out;
}
@@ -823,7 +869,7 @@ int connman_inet_add_ipv6_network_route(int index, const char *host,
rt.rtmsg_dst_len = prefix_len;
- if (inet_pton(AF_INET6, host, &rt.rtmsg_dst) < 0) {
+ if (inet_pton(AF_INET6, host, &rt.rtmsg_dst) != 1) {
err = -errno;
goto out;
}
@@ -839,7 +885,7 @@ int connman_inet_add_ipv6_network_route(int index, const char *host,
*/
if (gateway && !__connman_inet_is_any_addr(gateway, AF_INET6) &&
- inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway) > 0)
+ inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway) == 1)
rt.rtmsg_flags |= RTF_GATEWAY;
rt.rtmsg_metric = 1;
@@ -882,7 +928,7 @@ int connman_inet_clear_ipv6_gateway_address(int index, const char *gateway)
memset(&rt, 0, sizeof(rt));
- if (inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway) < 0) {
+ if (inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway) != 1) {
err = -errno;
goto out;
}
@@ -1178,54 +1224,198 @@ out:
return err;
}
+#define ADDR_TYPE_MAX 4
+
+struct interface_address {
+ int index;
+ int family;
+ bool allow_unspec;
+ /* Applies only to ADDR_TYPE_IPADDR in ipaddrs */
+ bool require_ll;
+ /* Real types must be in_addr for AF_INET and in6_addr for AF_INET6 */
+ void *ipaddrs[ADDR_TYPE_MAX];
+};
+
+enum ipaddr_type {
+ ADDR_TYPE_IPADDR = 0,
+ ADDR_TYPE_NETMASK,
+ ADDR_TYPE_BRDADDR,
+ ADDR_TYPE_DSTADDR
+};
+
+static int get_interface_addresses(struct interface_address *if_addr)
+{
+ struct ifaddrs *ifaddr;
+ struct ifaddrs *ifa;
+ struct sockaddr *addrs[ADDR_TYPE_MAX] = { 0 };
+ struct sockaddr_in *addr_in;
+ struct sockaddr_in6 *addr_in6;
+ char name[IF_NAMESIZE] = { 0 };
+ size_t len;
+ int err = -ENOENT;
+ int i;
+
+ if (!if_addr)
+ return -EINVAL;
+
+ if (!if_indextoname(if_addr->index, name))
+ return -EINVAL;
+
+ DBG("index %d interface %s", if_addr->index, name);
+
+ if (getifaddrs(&ifaddr) < 0) {
+ connman_error("Cannot get addresses err %d/%s", errno,
+ strerror(errno));
+ return -errno;
+ }
+
+ for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
+ if (!ifa->ifa_addr)
+ continue;
+
+ if (g_strcmp0(ifa->ifa_name, name) ||
+ ifa->ifa_addr->sa_family !=
+ if_addr->family)
+ continue;
+
+
+ if (if_addr->ipaddrs[ADDR_TYPE_IPADDR]) {
+ if (!if_addr->allow_unspec && is_addr_unspec(
+ if_addr->family,
+ ifa->ifa_addr))
+ continue;
+
+ if (if_addr->require_ll && !is_addr_ll(if_addr->family,
+ ifa->ifa_addr))
+ continue;
+
+ addrs[ADDR_TYPE_IPADDR] = ifa->ifa_addr;
+ }
+
+ if (if_addr->ipaddrs[ADDR_TYPE_NETMASK]) {
+ if (!if_addr->allow_unspec && is_addr_unspec(
+ if_addr->family,
+ ifa->ifa_netmask))
+ continue;
+
+ addrs[ADDR_TYPE_NETMASK] = ifa->ifa_netmask;
+ }
+
+ if (if_addr->ipaddrs[ADDR_TYPE_BRDADDR] &&
+ (ifa->ifa_flags & IFF_BROADCAST)) {
+ if (!if_addr->allow_unspec && is_addr_unspec(
+ if_addr->family,
+ ifa->ifa_ifu.ifu_broadaddr))
+ continue;
+
+ addrs[ADDR_TYPE_BRDADDR] = ifa->ifa_ifu.ifu_broadaddr;
+ }
+
+ if (if_addr->ipaddrs[ADDR_TYPE_DSTADDR] &&
+ (ifa->ifa_flags & IFF_POINTOPOINT)) {
+ if (!if_addr->allow_unspec && is_addr_unspec(
+ if_addr->family,
+ ifa->ifa_ifu.ifu_dstaddr))
+ continue;
+
+ addrs[ADDR_TYPE_DSTADDR] = ifa->ifa_ifu.ifu_dstaddr;
+ }
+
+ err = 0;
+
+ break;
+ }
+
+ if (err)
+ goto out;
+
+ for (i = 0; i < ADDR_TYPE_MAX; i++) {
+ if (!addrs[i])
+ continue;
+
+ switch (if_addr->family) {
+ case AF_INET:
+ len = sizeof(struct in_addr);
+ addr_in = (struct sockaddr_in*) addrs[i];
+ memcpy(if_addr->ipaddrs[i], &addr_in->sin_addr, len);
+ break;
+ case AF_INET6:
+ len = sizeof(struct in6_addr);
+ addr_in6 = (struct sockaddr_in6*) addrs[i];
+ memcpy(if_addr->ipaddrs[i], &addr_in6->sin6_addr, len);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ }
+
+out:
+ freeifaddrs(ifaddr);
+ return err;
+}
+
bool connman_inet_compare_subnet(int index, const char *host)
{
- struct ifreq ifr;
- struct in_addr _host_addr;
- in_addr_t host_addr, netmask_addr, if_addr;
- struct sockaddr_in *netmask, *addr;
- int sk;
+ struct interface_address if_addr = { 0 };
+ struct in_addr iaddr = { 0 };
+ struct in_addr imask = { 0 };
+ struct in_addr haddr = { 0 };
DBG("host %s", host);
if (!host)
return false;
- if (inet_aton(host, &_host_addr) == 0)
+ if (inet_pton(AF_INET, host, &haddr) != 1)
return false;
- host_addr = _host_addr.s_addr;
- sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
- if (sk < 0)
+ if_addr.index = index;
+ if_addr.family = AF_INET;
+ if_addr.ipaddrs[ADDR_TYPE_IPADDR] = &iaddr;
+ if_addr.ipaddrs[ADDR_TYPE_NETMASK] = &imask;
+
+ if (get_interface_addresses(&if_addr))
return false;
- memset(&ifr, 0, sizeof(ifr));
- ifr.ifr_ifindex = index;
+ return (iaddr.s_addr & imask.s_addr) == (haddr.s_addr & imask.s_addr);
+}
- if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
- close(sk);
- return false;
- }
+static bool mem_mask_equal(const void *a, const void *b,
+ const void *mask, size_t n)
+{
+ const unsigned char *addr1 = a;
+ const unsigned char *addr2 = b;
+ const unsigned char *bitmask = mask;
+ size_t i;
- if (ioctl(sk, SIOCGIFNETMASK, &ifr) < 0) {
- close(sk);
- return false;
+ for (i = 0; i < n; i++) {
+ if ((addr1[i] ^ addr2[i]) & bitmask[i])
+ return false;
}
- netmask = (struct sockaddr_in *)&ifr.ifr_netmask;
- netmask_addr = netmask->sin_addr.s_addr;
+ return true;
+}
- if (ioctl(sk, SIOCGIFADDR, &ifr) < 0) {
- close(sk);
+bool connman_inet_compare_ipv6_subnet(int index, const char *host)
+{
+ struct interface_address addr = { 0 };
+ struct in6_addr iaddr = { 0 };
+ struct in6_addr imask = { 0 };
+ struct in6_addr haddr = { 0 };
+
+ if (inet_pton(AF_INET6, host, &haddr) != 1)
return false;
- }
- close(sk);
+ addr.index = index;
+ addr.family = AF_INET6;
+ addr.ipaddrs[ADDR_TYPE_IPADDR] = &iaddr;
+ addr.ipaddrs[ADDR_TYPE_NETMASK] = &imask;
- addr = (struct sockaddr_in *)&ifr.ifr_addr;
- if_addr = addr->sin_addr.s_addr;
+ if (get_interface_addresses(&addr))
+ return false;
- return ((if_addr & netmask_addr) == (host_addr & netmask_addr));
+ return mem_mask_equal(&iaddr, &haddr, &imask, sizeof(haddr));
}
int connman_inet_remove_from_bridge(int index, const char *bridge)
@@ -1794,13 +1984,6 @@ int __connman_inet_ipv6_send_rs(int index, int timeout,
return 0;
}
-static inline void ipv6_addr_advert_mult(const struct in6_addr *addr,
- struct in6_addr *advert)
-{
- ipv6_addr_set(advert, htonl(0xFF020000), 0, htonl(0x2),
- htonl(0xFF000000) | addr->s6_addr32[3]);
-}
-
#define MSG_SIZE_SEND 1452
static int inc_len(int len, int inc)
@@ -2234,98 +2417,156 @@ GSList *__connman_inet_ipv6_get_prefixes(struct nd_router_advert *hdr,
return prefixes;
}
-static int get_dest_addr(int family, int index, char *buf, int len)
+int connman_inet_get_dest_addr(int index, char **dest)
{
- struct ifreq ifr;
- void *addr;
- int sk;
+ struct interface_address if_addr = { 0 };
+ struct in_addr dstaddr = { 0 };
+ char buf[INET_ADDRSTRLEN] = { 0 };
+ int err;
- sk = socket(family, SOCK_DGRAM | SOCK_CLOEXEC, 0);
- if (sk < 0)
- return -errno;
+ if (!dest)
+ return -EINVAL;
- memset(&ifr, 0, sizeof(ifr));
- ifr.ifr_ifindex = index;
+ if_addr.index = index;
+ if_addr.family = AF_INET;
+ if_addr.allow_unspec = true;
+ if_addr.ipaddrs[ADDR_TYPE_DSTADDR] = &dstaddr;
- if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
- DBG("SIOCGIFNAME (%d/%s)", errno, strerror(errno));
- close(sk);
- return -errno;
- }
+ err = get_interface_addresses(&if_addr);
+ if (err)
+ return err;
- if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0) {
- DBG("SIOCGIFFLAGS (%d/%s)", errno, strerror(errno));
- close(sk);
- return -errno;
- }
+ if (inet_ntop(AF_INET, &dstaddr, buf, INET_ADDRSTRLEN))
+ *dest = g_strdup(buf);
- if ((ifr.ifr_flags & IFF_POINTOPOINT) == 0) {
- close(sk);
- errno = EINVAL;
- return -errno;
- }
+ DBG("destination %s", *dest);
- DBG("index %d %s", index, ifr.ifr_name);
+ return *dest && **dest ? 0 : -ENOENT;
+}
- if (ioctl(sk, SIOCGIFDSTADDR, &ifr) < 0) {
- connman_error("Get destination address failed (%s)",
- strerror(errno));
- close(sk);
- return -errno;
- }
+int connman_inet_ipv6_get_dest_addr(int index, char **dest)
+{
+ struct interface_address if_addr = { 0 };
+ struct in6_addr dstaddr = { 0 };
+ char buf[INET6_ADDRSTRLEN] = { 0 };
+ int err;
- close(sk);
+ if (!dest)
+ return -EINVAL;
- switch (family) {
- case AF_INET:
- addr = &((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_addr;
- break;
- case AF_INET6:
- addr = &((struct sockaddr_in6 *)&ifr.ifr_dstaddr)->sin6_addr;
- break;
- default:
- errno = EINVAL;
- return -errno;
- }
+ if_addr.index = index;
+ if_addr.family = AF_INET6;
+ if_addr.allow_unspec = true;
+ if_addr.ipaddrs[ADDR_TYPE_DSTADDR] = &dstaddr;
- if (!inet_ntop(family, addr, buf, len)) {
- DBG("error %d/%s", errno, strerror(errno));
- return -errno;
- }
+ err = get_interface_addresses(&if_addr);
+ if (err)
+ return err;
- return 0;
+ if (inet_ntop(AF_INET6, &dstaddr, buf, INET6_ADDRSTRLEN))
+ *dest = g_strdup(buf);
+
+ DBG("destination %s", *dest);
+
+ return *dest && **dest ? 0 : -ENOENT;
}
-int connman_inet_get_dest_addr(int index, char **dest)
+/* destination is optional */
+int connman_inet_get_route_addresses(int index, char **network, char **netmask,
+ char **destination)
{
- char addr[INET_ADDRSTRLEN];
- int ret;
+ struct interface_address if_addr = { 0 };
+ struct in_addr addr = { 0 };
+ struct in_addr mask = { 0 };
+ struct in_addr dest = { 0 };
+ struct in_addr nw_addr = { 0 };
+ char buf[INET_ADDRSTRLEN] = { 0 };
+ int err;
- ret = get_dest_addr(PF_INET, index, addr, INET_ADDRSTRLEN);
- if (ret < 0)
- return ret;
+ if (!network || !netmask)
+ return -EINVAL;
- *dest = g_strdup(addr);
+ if_addr.index = index;
+ if_addr.family = AF_INET;
+ if_addr.ipaddrs[ADDR_TYPE_IPADDR] = &addr;
+ if_addr.ipaddrs[ADDR_TYPE_NETMASK] = &mask;
+ if_addr.ipaddrs[ADDR_TYPE_DSTADDR] = &dest;
- DBG("destination %s", *dest);
+ err = get_interface_addresses(&if_addr);
+ if (err)
+ return err;
- return 0;
+ nw_addr.s_addr = (addr.s_addr & mask.s_addr);
+
+ if (inet_ntop(AF_INET, &nw_addr, buf, INET_ADDRSTRLEN))
+ *network = g_strdup(buf);
+
+ memset(&buf, 0, INET_ADDRSTRLEN);
+
+ if (inet_ntop(AF_INET, &mask, buf, INET_ADDRSTRLEN))
+ *netmask = g_strdup(buf);
+
+ if (destination) {
+ memset(&buf, 0, INET_ADDRSTRLEN);
+
+ if (inet_ntop(AF_INET, &dest, buf, INET_ADDRSTRLEN))
+ *destination = g_strdup(buf);
+ }
+
+ DBG("network %s netmask %s destination %s", *network, *netmask,
+ destination ? *destination : NULL);
+
+ return *network && **network && *netmask && **netmask ? 0 : -ENOENT;
}
-int connman_inet_ipv6_get_dest_addr(int index, char **dest)
+int connman_inet_ipv6_get_route_addresses(int index, char **network,
+ char **netmask, char **destination)
{
- char addr[INET6_ADDRSTRLEN];
- int ret;
+ struct interface_address if_addr = { 0 };
+ struct in6_addr addr = { 0 };
+ struct in6_addr mask = { 0 };
+ struct in6_addr dest = { 0 };
+ struct in6_addr nw_addr = { 0 };
+ char buf[INET6_ADDRSTRLEN] = { 0 };
+ int err;
- ret = get_dest_addr(PF_INET6, index, addr, INET6_ADDRSTRLEN);
- if (ret < 0)
- return ret;
+ if (!network)
+ return -EINVAL;
- *dest = g_strdup(addr);
+ if_addr.index = index;
+ if_addr.family = AF_INET6;
+ if_addr.ipaddrs[ADDR_TYPE_IPADDR] = &addr;
+ if_addr.ipaddrs[ADDR_TYPE_NETMASK] = &mask;
+ if_addr.ipaddrs[ADDR_TYPE_DSTADDR] = &dest;
- DBG("destination %s", *dest);
+ err = get_interface_addresses(&if_addr);
+ if (err)
+ return err;
- return 0;
+ ipv6_addr_set(&nw_addr, addr.s6_addr32[0] & mask.s6_addr32[0],
+ addr.s6_addr32[1] & mask.s6_addr32[1],
+ addr.s6_addr32[2] & mask.s6_addr32[2],
+ addr.s6_addr32[3] & mask.s6_addr32[3]);
+
+ if (inet_ntop(AF_INET6, &nw_addr, buf, INET6_ADDRSTRLEN))
+ *network = g_strdup(buf);
+
+ memset(&buf, 0, INET6_ADDRSTRLEN);
+
+ if (inet_ntop(AF_INET6, &mask, buf, INET6_ADDRSTRLEN))
+ *netmask = g_strdup(buf);
+
+ if (destination) {
+ memset(&buf, 0, INET6_ADDRSTRLEN);
+
+ if (inet_ntop(AF_INET6, &dest, buf, INET6_ADDRSTRLEN))
+ *destination = g_strdup(buf);
+ }
+
+ DBG("network %s netmask %s destination %s", *network, *netmask,
+ destination ? *destination : NULL);
+
+ return *network && **network && *netmask && **netmask ? 0 : -ENOENT;
}
int __connman_inet_rtnl_open(struct __connman_inet_rtnl_handle *rth)
@@ -2711,11 +2952,21 @@ int __connman_inet_get_route(const char *dest_address,
rth->req.u.r.rt.rtm_scope = 0;
rth->req.u.r.rt.rtm_type = 0;
rth->req.u.r.rt.rtm_src_len = 0;
- rth->req.u.r.rt.rtm_dst_len = rp->ai_addrlen << 3;
rth->req.u.r.rt.rtm_tos = 0;
- __connman_inet_rtnl_addattr_l(&rth->req.n, sizeof(rth->req), RTA_DST,
- &rp->ai_addr, rp->ai_addrlen);
+ if (rp->ai_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *)rp->ai_addr;
+
+ rth->req.u.r.rt.rtm_dst_len = 32;
+ __connman_inet_rtnl_addattr_l(&rth->req.n, sizeof(rth->req),
+ RTA_DST, &sin->sin_addr, sizeof(sin->sin_addr));
+ } else if (rp->ai_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rp->ai_addr;
+
+ rth->req.u.r.rt.rtm_dst_len = 128;
+ __connman_inet_rtnl_addattr_l(&rth->req.n, sizeof(rth->req),
+ RTA_DST, &sin6->sin6_addr, sizeof(sin6->sin6_addr));
+ }
freeaddrinfo(rp);
@@ -2912,58 +3163,30 @@ bool connman_inet_is_ipv6_supported()
return true;
}
-int __connman_inet_get_interface_address(int index, int family, void *address)
+/*
+ * Omits checking of the gateway matching the actual gateway IP since both
+ * connmand and vpnd use inet.c, getting the route is via ipconfig and ipconfig
+ * is different for both. Gateway is left here for possible future use.
+ *
+ * Gateway can be NULL and connection.c then assigns 0.0.0.0 address or ::,
+ * depending on IP family.
+ */
+bool connman_inet_is_default_route(int family, const char *host,
+ const char *gateway, const char *netmask)
{
- struct ifaddrs *ifaddr, *ifa;
- int err = -ENOENT;
- char name[IF_NAMESIZE];
-
- if (!if_indextoname(index, name))
- return -EINVAL;
-
- DBG("index %d interface %s", index, name);
-
- if (getifaddrs(&ifaddr) < 0) {
- err = -errno;
- DBG("Cannot get addresses err %d/%s", err, strerror(-err));
- return err;
- }
-
- for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
- if (!ifa->ifa_addr)
- continue;
-
- if (strncmp(ifa->ifa_name, name, IF_NAMESIZE) == 0 &&
- ifa->ifa_addr->sa_family == family) {
- if (family == AF_INET) {
- struct sockaddr_in *in4 = (struct sockaddr_in *)
- ifa->ifa_addr;
- if (in4->sin_addr.s_addr == INADDR_ANY)
- continue;
- memcpy(address, &in4->sin_addr,
- sizeof(struct in_addr));
- } else if (family == AF_INET6) {
- struct sockaddr_in6 *in6 =
- (struct sockaddr_in6 *)ifa->ifa_addr;
- if (memcmp(&in6->sin6_addr, &in6addr_any,
- sizeof(struct in6_addr)) == 0)
- continue;
- memcpy(address, &in6->sin6_addr,
- sizeof(struct in6_addr));
+ return __connman_inet_is_any_addr(host, family) &&
+ __connman_inet_is_any_addr(netmask, family);
+}
- } else {
- err = -EINVAL;
- goto out;
- }
+int __connman_inet_get_interface_address(int index, int family, void *address)
+{
+ struct interface_address if_addr = { 0 };
- err = 0;
- break;
- }
- }
+ if_addr.index = index;
+ if_addr.family = family;
+ if_addr.ipaddrs[ADDR_TYPE_IPADDR] = address;
-out:
- freeifaddrs(ifaddr);
- return err;
+ return get_interface_addresses(&if_addr);
}
int __connman_inet_get_interface_mac_address(int index, uint8_t *mac_address)
@@ -3097,7 +3320,7 @@ static int iproute_default_modify(int cmd, uint32_t table_id, int ifindex,
ret = inet_pton(family, dst ? dst : gateway, buf);
g_free(dst);
- if (ret <= 0)
+ if (ret != 1)
return -EINVAL;
memset(&rth, 0, sizeof(rth));
@@ -3172,61 +3395,14 @@ int __connman_inet_del_subnet_from_table(uint32_t table_id, int ifindex,
int __connman_inet_get_interface_ll_address(int index, int family,
void *address)
{
- struct ifaddrs *ifaddr, *ifa;
- int err = -ENOENT;
- char name[IF_NAMESIZE];
-
- if (!if_indextoname(index, name))
- return -EINVAL;
-
- DBG("index %d interface %s", index, name);
-
- if (getifaddrs(&ifaddr) < 0) {
- err = -errno;
- DBG("Cannot get addresses err %d/%s", err, strerror(-err));
- return err;
- }
+ struct interface_address if_addr = { 0 };
- for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
- if (!ifa->ifa_addr)
- continue;
+ if_addr.index = index;
+ if_addr.family = family;
+ if_addr.require_ll = true;
+ if_addr.ipaddrs[ADDR_TYPE_IPADDR] = address;
- if (strncmp(ifa->ifa_name, name, IF_NAMESIZE) == 0 &&
- ifa->ifa_addr->sa_family == family) {
- if (family == AF_INET) {
- struct sockaddr_in *in4 = (struct sockaddr_in *)
- ifa->ifa_addr;
- if (in4->sin_addr.s_addr == INADDR_ANY)
- continue;
- if ((in4->sin_addr.s_addr & IN_CLASSB_NET) !=
- ((in_addr_t) 0xa9fe0000))
- continue;
- memcpy(address, &in4->sin_addr,
- sizeof(struct in_addr));
- } else if (family == AF_INET6) {
- struct sockaddr_in6 *in6 =
- (struct sockaddr_in6 *)ifa->ifa_addr;
- if (memcmp(&in6->sin6_addr, &in6addr_any,
- sizeof(struct in6_addr)) == 0)
- continue;
- if (!IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr))
- continue;
-
- memcpy(address, &in6->sin6_addr,
- sizeof(struct in6_addr));
- } else {
- err = -EINVAL;
- goto out;
- }
-
- err = 0;
- break;
- }
- }
-
-out:
- freeifaddrs(ifaddr);
- return err;
+ return get_interface_addresses(&if_addr);
}
int __connman_inet_get_address_netmask(int ifindex,
@@ -3313,7 +3489,7 @@ static int get_nfs_server_ip(const char *cmdline_file, const char *pnp_file,
if (cmdline[len - 1] == '\n')
cmdline[--len] = '\0';
- /* split in arguments (seperated by space) */
+ /* split in arguments (separated by space) */
args = g_strsplit(cmdline, " ", 0);
if (!args) {
connman_error("%s: Cannot split cmdline \"%s\"\n", __func__,
@@ -3333,6 +3509,10 @@ static int get_nfs_server_ip(const char *cmdline_file, const char *pnp_file,
for (pp = args; *pp; pp++) {
if (!strcmp(*pp, "root=/dev/nfs"))
break;
+ if (!strncmp(*pp, "root=/dev/nbd", strlen("root=/dev/nbd")))
+ break;
+ if (!strncmp(*pp, "nbddev=", strlen("nbddev=")))
+ break;
}
/* no rootnfs found */
if (!*pp)
@@ -3342,6 +3522,8 @@ static int get_nfs_server_ip(const char *cmdline_file, const char *pnp_file,
for (pp = args; *pp; pp++) {
if (!strncmp(*pp, "nfsroot=", strlen("nfsroot=")))
break;
+ if (!strncmp(*pp, "nbdroot=", strlen("nbdroot=")))
+ break;
}
/* no nfsroot argument found */
if (!*pp)
@@ -3380,7 +3562,7 @@ static int get_nfs_server_ip(const char *cmdline_file, const char *pnp_file,
addrstr[len] = '\0';
err = inet_pton(AF_INET, addrstr, addr);
- if (err <= 0) {
+ if (err != 1) {
connman_error("%s: Cannot convert to numeric addr \"%s\"\n",
__func__, addrstr);
err = -1;
@@ -3516,7 +3698,7 @@ char **__connman_inet_get_pnp_nameservers(const char *pnp_file)
}
/*
- * Perform two passes to retreive a char ** array of
+ * Perform two passes to retrieve a char ** array of
* nameservers that are not 0.0.0.0
*
* The first pass counts them, the second fills in the
diff --git a/src/ipaddress.c b/src/ipaddress.c
index d63d95c3..201d8345 100755
--- a/src/ipaddress.c
+++ b/src/ipaddress.c
@@ -70,10 +70,19 @@ struct connman_ipaddress *connman_ipaddress_alloc(int family)
ipaddress->peer = NULL;
ipaddress->broadcast = NULL;
ipaddress->gateway = NULL;
+ ipaddress->is_p2p = false;
return ipaddress;
}
+void connman_ipaddress_set_p2p(struct connman_ipaddress *ipaddress, bool value)
+{
+ if (!ipaddress)
+ return;
+
+ ipaddress->is_p2p = value;
+}
+
void connman_ipaddress_free(struct connman_ipaddress *ipaddress)
{
if (!ipaddress)
@@ -95,7 +104,7 @@ static bool check_ipv6_address(const char *address)
return false;
err = inet_pton(AF_INET6, address, buf);
- if (err > 0)
+ if (err == 1)
return true;
return false;
@@ -223,6 +232,7 @@ connman_ipaddress_copy(struct connman_ipaddress *ipaddress)
copy->peer = g_strdup(ipaddress->peer);
copy->broadcast = g_strdup(ipaddress->broadcast);
copy->gateway = g_strdup(ipaddress->gateway);
+ copy->is_p2p = ipaddress->is_p2p;
return copy;
}
diff --git a/src/ipconfig.c b/src/ipconfig.c
index 6d8ba05a..9765ca14 100755
--- a/src/ipconfig.c
+++ b/src/ipconfig.c
@@ -89,16 +89,101 @@ struct connman_ipdevice {
int ipv6_privacy;
};
+struct ipconfig_store {
+ GKeyFile *file;
+ const char *group;
+ const char *prefix;
+};
+
static GHashTable *ipdevice_hash = NULL;
static GList *ipconfig_list = NULL;
static bool is_ipv6_supported = false;
-void __connman_ipconfig_clear_address(struct connman_ipconfig *ipconfig)
+static void store_set_str(struct ipconfig_store *store,
+ const char *key, const char *val)
+
{
- if (!ipconfig)
+ char *pk;
+
+ if (!val || strlen(val) == 0)
+ return;
+
+ pk = g_strdup_printf("%s%s", store->prefix, key);
+ g_key_file_set_string(store->file, store->group, pk, val);
+ g_free(pk);
+}
+
+static char *store_get_str(struct ipconfig_store *store, const char *key)
+{
+ char *pk, *val;
+
+ pk = g_strdup_printf("%s%s", store->prefix, key);
+ val = g_key_file_get_string(store->file, store->group, pk, NULL);
+ g_free(pk);
+
+ return val;
+}
+
+static void store_set_strs(struct ipconfig_store *store,
+ const char *key, char **val)
+{
+ guint len;
+ char *pk;
+
+ if (!val)
+ return;
+
+ len = g_strv_length(val);
+ if (len == 0)
return;
- connman_ipaddress_clear(ipconfig->address);
+ pk = g_strdup_printf("%s%s", store->prefix, key);
+ g_key_file_set_string_list(store->file, store->group,
+ pk, (const gchar **)val, len);
+ g_free(pk);
+}
+
+static char **store_get_strs(struct ipconfig_store *store, const char *key)
+{
+ gsize len;
+ char *pk, **val;
+
+ pk = g_strdup_printf("%s%s", store->prefix, key);
+ val = g_key_file_get_string_list(store->file, store->group,
+ pk, &len, NULL);
+ g_free(pk);
+
+ if (val && len == 0) {
+ g_free(val);
+ return NULL;
+ }
+
+ return val;
+}
+
+static void store_set_int(struct ipconfig_store *store,
+ const char *key, int val)
+{
+ char *pk;
+
+ if (val == 0)
+ return;
+
+ pk = g_strdup_printf("%s%s", store->prefix, key);
+ g_key_file_set_integer(store->file, store->group, pk, val);
+ g_free(pk);
+}
+
+static int store_get_int(struct ipconfig_store *store, const char *key)
+{
+ int val;
+ char *pk;
+
+ pk = g_strdup_printf("%s%s", store->prefix, key);
+ val = g_key_file_get_integer(store->file, store->group, pk, 0);
+ g_free(pk);
+
+ return val;
}
static void free_address_list(struct connman_ipdevice *ipdevice)
@@ -177,153 +262,165 @@ static const char *scope2str(unsigned char scope)
return "";
}
-static bool get_ipv6_state(gchar *ifname)
+#define PROC_IPV4_CONF_PREFIX "/proc/sys/net/ipv4/conf"
+#define PROC_IPV6_CONF_PREFIX "/proc/sys/net/ipv6/conf"
+
+static int read_conf_value(const char *prefix, const char *ifname,
+ const char *suffix, int *value)
{
- int disabled;
gchar *path;
FILE *f;
- bool enabled = false;
-
- if (!ifname)
- path = g_strdup("/proc/sys/net/ipv6/conf/all/disable_ipv6");
- else
- path = g_strdup_printf(
- "/proc/sys/net/ipv6/conf/%s/disable_ipv6", ifname);
+ int err;
+ path = g_build_filename(prefix, ifname ? ifname : "all", suffix, NULL);
if (!path)
- return enabled;
+ return -ENOMEM;
+ errno = 0;
f = fopen(path, "r");
+ if (!f) {
+ err = -errno;
+ } else {
+ errno = 0; /* Avoid stale errno values with fscanf */
- g_free(path);
+ err = fscanf(f, "%d", value);
+ if (err <= 0 && errno)
+ err = -errno;
- if (f) {
- if (fscanf(f, "%d", &disabled) > 0)
- enabled = !disabled;
fclose(f);
}
- return enabled;
+ if (err <= 0)
+ connman_error("failed to read %s", path);
+
+ g_free(path);
+
+ return err;
+}
+
+static int read_ipv4_conf_value(const char *ifname, const char *suffix,
+ int *value)
+{
+ return read_conf_value(PROC_IPV4_CONF_PREFIX, ifname, suffix, value);
}
-static void set_ipv6_state(gchar *ifname, bool enable)
+static int read_ipv6_conf_value(const char *ifname, const char *suffix,
+ int *value)
{
+ return read_conf_value(PROC_IPV6_CONF_PREFIX, ifname, suffix, value);
+}
+
+static int write_conf_value(const char *prefix, const char *ifname,
+ const char *suffix, int value) {
gchar *path;
FILE *f;
+ int rval;
- if (!ifname)
- path = g_strdup("/proc/sys/net/ipv6/conf/all/disable_ipv6");
- else
- path = g_strdup_printf(
- "/proc/sys/net/ipv6/conf/%s/disable_ipv6", ifname);
-
+ path = g_build_filename(prefix, ifname ? ifname : "all", suffix, NULL);
if (!path)
- return;
+ return -ENOMEM;
f = fopen(path, "r+");
+ if (!f) {
+ rval = -errno;
+ } else {
+ rval = fprintf(f, "%d", value);
+ fclose(f);
+ }
+
+ if (rval <= 0)
+ connman_error("failed to set %s value %d", path, value);
g_free(path);
- if (!f)
- return;
+ return rval;
+}
- if (!enable)
- fprintf(f, "1");
- else
- fprintf(f, "0");
+static int write_ipv4_conf_value(const char *ifname, const char *suffix,
+ int value)
+{
+ return write_conf_value(PROC_IPV4_CONF_PREFIX, ifname, suffix, value);
+}
- fclose(f);
+static int write_ipv6_conf_value(const char *ifname, const char *suffix,
+ int value)
+{
+ return write_conf_value(PROC_IPV6_CONF_PREFIX, ifname, suffix, value);
}
-static int get_ipv6_privacy(gchar *ifname)
+static bool get_ipv6_state(gchar *ifname)
{
- gchar *path;
- FILE *f;
- int value;
+ int disabled;
+ bool enabled = false;
- if (!ifname)
- return 0;
+ if (read_ipv6_conf_value(ifname, "disable_ipv6", &disabled) > 0)
+ enabled = !disabled;
- path = g_strdup_printf("/proc/sys/net/ipv6/conf/%s/use_tempaddr",
- ifname);
+ return enabled;
+}
- if (!path)
- return 0;
+static int set_ipv6_state(gchar *ifname, bool enable)
+{
+ int disabled = enable ? 0 : 1;
- f = fopen(path, "r");
+ DBG("%s %d", ifname, disabled);
- g_free(path);
+ return write_ipv6_conf_value(ifname, "disable_ipv6", disabled);
+}
- if (!f)
+static int get_ipv6_privacy(gchar *ifname)
+{
+ int value;
+
+ if (!ifname)
return 0;
- if (fscanf(f, "%d", &value) <= 0)
+ if (read_ipv6_conf_value(ifname, "use_tempaddr", &value) < 0)
value = 0;
- fclose(f);
-
return value;
}
/* Enable the IPv6 privacy extension for stateless address autoconfiguration.
* The privacy extension is described in RFC 3041 and RFC 4941
*/
-static void set_ipv6_privacy(gchar *ifname, int value)
+static int set_ipv6_privacy(gchar *ifname, int value)
{
- gchar *path;
- FILE *f;
-
if (!ifname)
- return;
-
- path = g_strdup_printf("/proc/sys/net/ipv6/conf/%s/use_tempaddr",
- ifname);
-
- if (!path)
- return;
+ return -EINVAL;
if (value < 0)
value = 0;
- f = fopen(path, "r+");
-
- g_free(path);
-
- if (!f)
- return;
-
- fprintf(f, "%d", value);
- fclose(f);
+ return write_ipv6_conf_value(ifname, "use_tempaddr", value);
}
static int get_rp_filter(void)
{
- FILE *f;
- int value = -EINVAL, tmp;
-
- f = fopen("/proc/sys/net/ipv4/conf/all/rp_filter", "r");
+ int value;
- if (f) {
- if (fscanf(f, "%d", &tmp) == 1)
- value = tmp;
- fclose(f);
- }
+ if (read_ipv4_conf_value(NULL, "rp_filter", &value) < 0)
+ value = -EINVAL;
return value;
}
-static void set_rp_filter(int value)
+static int set_rp_filter(int value)
{
- FILE *f;
-
- f = fopen("/proc/sys/net/ipv4/conf/all/rp_filter", "r+");
-
- if (!f)
- return;
-
- fprintf(f, "%d", value);
+ /* 0 = no validation, 1 = strict mode, 2 = loose mode */
+ switch (value) {
+ case -1:
+ value = 0;
+ /* fall through */
+ case 0:
+ case 1:
+ case 2:
+ break;
+ default:
+ return -EINVAL;
+ }
- fclose(f);
+ return write_ipv4_conf_value(NULL, "rp_filter", value);
}
int __connman_ipconfig_set_rp_filter()
@@ -625,6 +722,25 @@ static inline gint check_duplicate_address(gconstpointer a, gconstpointer b)
return g_strcmp0(addr1->local, addr2->local);
}
+static bool is_index_p2p_service(int index)
+{
+ struct connman_service *service;
+ enum connman_service_type type;
+
+ service = __connman_service_lookup_from_index(index);
+ if (!service)
+ return false;
+
+ type = connman_service_get_type(service);
+ switch (type) {
+ case CONNMAN_SERVICE_TYPE_P2P:
+ case CONNMAN_SERVICE_TYPE_VPN:
+ return true;
+ default:
+ return false;
+ }
+}
+
int __connman_ipconfig_newaddr(int index, int family, const char *label,
unsigned char prefixlen, const char *address)
{
@@ -647,6 +763,9 @@ int __connman_ipconfig_newaddr(int index, int family, const char *label,
ipaddress->prefixlen = prefixlen;
ipaddress->local = g_strdup(address);
+ if (is_index_p2p_service(index))
+ connman_ipaddress_set_p2p(ipaddress, true);
+
if (g_slist_find_custom(ipdevice->address_list, ipaddress,
check_duplicate_address)) {
connman_ipaddress_free(ipaddress);
@@ -1131,6 +1250,15 @@ void __connman_ipconfig_set_prefixlen(struct connman_ipconfig *ipconfig,
ipconfig->address->prefixlen = prefixlen;
}
+static void ipconfig_set_p2p(int index, struct connman_ipconfig *ipconfig)
+{
+ if (!is_index_p2p_service(index))
+ return;
+
+ connman_ipaddress_set_p2p(ipconfig->address, true);
+ connman_ipaddress_set_p2p(ipconfig->system, true);
+}
+
static struct connman_ipconfig *create_ipv6config(int index)
{
struct connman_ipconfig *ipv6config;
@@ -1166,6 +1294,8 @@ static struct connman_ipconfig *create_ipv6config(int index)
ipv6config->system = connman_ipaddress_alloc(AF_INET6);
+ ipconfig_set_p2p(index, ipv6config);
+
DBG("ipconfig %p index %d method %s", ipv6config, index,
__connman_ipconfig_method2string(ipv6config->method));
@@ -1203,6 +1333,9 @@ struct connman_ipconfig *__connman_ipconfig_create(int index,
}
ipconfig->system = connman_ipaddress_alloc(AF_INET);
+
+ ipconfig_set_p2p(index, ipconfig);
+
#if defined TIZEN_EXT
if (!simplified_log)
#endif
@@ -1372,13 +1505,14 @@ int __connman_ipconfig_address_remove(struct connman_ipconfig *ipconfig)
case CONNMAN_IPCONFIG_METHOD_OFF:
break;
case CONNMAN_IPCONFIG_METHOD_AUTO:
- case CONNMAN_IPCONFIG_METHOD_FIXED:
case CONNMAN_IPCONFIG_METHOD_DHCP:
- case CONNMAN_IPCONFIG_METHOD_MANUAL:
err = __connman_ipconfig_address_unset(ipconfig);
connman_ipaddress_clear(ipconfig->address);
return err;
+ case CONNMAN_IPCONFIG_METHOD_FIXED:
+ case CONNMAN_IPCONFIG_METHOD_MANUAL:
+ return __connman_ipconfig_address_unset(ipconfig);
}
return 0;
@@ -1409,10 +1543,8 @@ int __connman_ipconfig_address_unset(struct connman_ipconfig *ipconfig)
err = connman_inet_clear_address(ipconfig->index,
ipconfig->address);
else if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6)
- err = connman_inet_clear_ipv6_address(
- ipconfig->index,
- ipconfig->address->local,
- ipconfig->address->prefixlen);
+ err = connman_inet_clear_ipv6_address(ipconfig->index,
+ ipconfig->address);
else
err = -EINVAL;
@@ -1506,6 +1638,9 @@ static void disable_ipv6(struct connman_ipconfig *ipconfig)
ifname = connman_inet_ifname(ipconfig->index);
+ if (!ifname)
+ return;
+
set_ipv6_state(ifname, false);
g_free(ifname);
@@ -1525,6 +1660,9 @@ static void enable_ipv6(struct connman_ipconfig *ipconfig)
ifname = connman_inet_ifname(ipconfig->index);
+ if (!ifname)
+ return;
+
if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_AUTO)
set_ipv6_privacy(ifname, ipconfig->ipv6_privacy_config);
@@ -1605,6 +1743,9 @@ int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig)
connman_ipaddress_clear(ipdevice->config_ipv4->system);
__connman_ipconfig_unref(ipdevice->config_ipv4);
+
+ g_free(ipdevice->ipv4_gateway);
+ ipdevice->ipv4_gateway = NULL;
}
if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
@@ -1615,6 +1756,9 @@ int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig)
connman_ipaddress_clear(ipdevice->config_ipv6->system);
__connman_ipconfig_unref(ipdevice->config_ipv6);
+
+ g_free(ipdevice->ipv6_gateway);
+ ipdevice->ipv6_gateway = NULL;
}
if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
@@ -1679,6 +1823,10 @@ int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig)
connman_ipaddress_clear(ipdevice->config_ipv4->system);
__connman_ipconfig_unref(ipdevice->config_ipv4);
ipdevice->config_ipv4 = NULL;
+
+ g_free(ipdevice->ipv4_gateway);
+ ipdevice->ipv4_gateway = NULL;
+
return 0;
}
@@ -1687,12 +1835,18 @@ int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig)
#if defined TIZEN_EXT
if (ipdevice->config_ipv6->method ==
- CONNMAN_IPCONFIG_METHOD_AUTO)
+ CONNMAN_IPCONFIG_METHOD_AUTO) {
disable_ipv6(ipdevice->config_ipv6);
+ enable_ipv6(ipdevice->config_ipv6);
+ }
#endif
connman_ipaddress_clear(ipdevice->config_ipv6->system);
__connman_ipconfig_unref(ipdevice->config_ipv6);
ipdevice->config_ipv6 = NULL;
+
+ g_free(ipdevice->ipv6_gateway);
+ ipdevice->ipv6_gateway = NULL;
+
return 0;
}
@@ -2206,65 +2360,56 @@ void __connman_ipconfig_append_ethernet(struct connman_ipconfig *ipconfig,
DBUS_TYPE_UINT16, &ipdevice->mtu);
}
-int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
+void __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
GKeyFile *keyfile, const char *identifier, const char *prefix)
{
char *method;
- char *key;
char *str;
+ struct ipconfig_store is = { .file = keyfile,
+ .group = identifier,
+ .prefix = prefix };
DBG("ipconfig %p identifier %s", ipconfig, identifier);
- key = g_strdup_printf("%smethod", prefix);
- method = g_key_file_get_string(keyfile, identifier, key, NULL);
+ method = store_get_str(&is, "method");
if (!method) {
switch (ipconfig->type) {
case CONNMAN_IPCONFIG_TYPE_IPV4:
ipconfig->method = CONNMAN_IPCONFIG_METHOD_DHCP;
break;
+
case CONNMAN_IPCONFIG_TYPE_IPV6:
ipconfig->method = CONNMAN_IPCONFIG_METHOD_AUTO;
break;
+
case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
case CONNMAN_IPCONFIG_TYPE_ALL:
ipconfig->method = CONNMAN_IPCONFIG_METHOD_OFF;
break;
}
- } else
+ } else {
ipconfig->method = __connman_ipconfig_string2method(method);
+ g_free(method);
+ }
if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_UNKNOWN)
ipconfig->method = CONNMAN_IPCONFIG_METHOD_OFF;
if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6) {
- gsize length;
- char *pprefix;
-
if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_AUTO ||
- ipconfig->method == CONNMAN_IPCONFIG_METHOD_MANUAL) {
+ ipconfig->method == CONNMAN_IPCONFIG_METHOD_MANUAL) {
char *privacy;
- pprefix = g_strdup_printf("%sprivacy", prefix);
- privacy = g_key_file_get_string(keyfile, identifier,
- pprefix, NULL);
+ privacy = store_get_str(&is, "privacy");
ipconfig->ipv6_privacy_config = string2privacy(privacy);
- g_free(pprefix);
g_free(privacy);
}
- pprefix = g_strdup_printf("%sDHCP.LastPrefixes", prefix);
+ g_strfreev(ipconfig->last_dhcpv6_prefixes);
ipconfig->last_dhcpv6_prefixes =
- g_key_file_get_string_list(keyfile, identifier, pprefix,
- &length, NULL);
- if (ipconfig->last_dhcpv6_prefixes && length == 0) {
- g_free(ipconfig->last_dhcpv6_prefixes);
- ipconfig->last_dhcpv6_prefixes = NULL;
- }
- g_free(pprefix);
+ store_get_strs(&is, "DHCP.LastPrefixes");
}
- g_free(method);
- g_free(key);
switch (ipconfig->method) {
case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
@@ -2273,39 +2418,27 @@ int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
case CONNMAN_IPCONFIG_METHOD_FIXED:
case CONNMAN_IPCONFIG_METHOD_MANUAL:
+ ipconfig->address->prefixlen =
+ store_get_int(&is, "netmask_prefixlen");
- key = g_strdup_printf("%snetmask_prefixlen", prefix);
- ipconfig->address->prefixlen = g_key_file_get_integer(
- keyfile, identifier, key, NULL);
- g_free(key);
-
- key = g_strdup_printf("%slocal_address", prefix);
g_free(ipconfig->address->local);
- ipconfig->address->local = g_key_file_get_string(
- keyfile, identifier, key, NULL);
- g_free(key);
+ ipconfig->address->local =
+ store_get_str(&is, "local_address");
- key = g_strdup_printf("%speer_address", prefix);
g_free(ipconfig->address->peer);
- ipconfig->address->peer = g_key_file_get_string(
- keyfile, identifier, key, NULL);
- g_free(key);
+ ipconfig->address->peer =
+ store_get_str(&is, "peer_address");
- key = g_strdup_printf("%sbroadcast_address", prefix);
g_free(ipconfig->address->broadcast);
- ipconfig->address->broadcast = g_key_file_get_string(
- keyfile, identifier, key, NULL);
- g_free(key);
+ ipconfig->address->broadcast =
+ store_get_str(&is, "broadcast_address");
- key = g_strdup_printf("%sgateway", prefix);
g_free(ipconfig->address->gateway);
- ipconfig->address->gateway = g_key_file_get_string(
- keyfile, identifier, key, NULL);
- g_free(key);
+ ipconfig->address->gateway =
+ store_get_str(&is, "gateway");
break;
case CONNMAN_IPCONFIG_METHOD_AUTO:
-
if (ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV4)
break;
@@ -2319,120 +2452,61 @@ int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
/* fall through */
case CONNMAN_IPCONFIG_METHOD_DHCP:
-
- key = g_strdup_printf("%sDHCP.LastAddress", prefix);
- str = g_key_file_get_string(keyfile, identifier, key, NULL);
+ str = store_get_str(&is, "DHCP.LastAddress");
if (str) {
g_free(ipconfig->last_dhcp_address);
ipconfig->last_dhcp_address = str;
}
- g_free(key);
break;
}
-
- return 0;
}
-int __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
+void __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
GKeyFile *keyfile, const char *identifier, const char *prefix)
{
const char *method;
- char *key;
+ struct ipconfig_store is = { .file = keyfile,
+ .group = identifier,
+ .prefix = prefix };
method = __connman_ipconfig_method2string(ipconfig->method);
-
DBG("ipconfig %p identifier %s method %s", ipconfig, identifier,
method);
- if (method) {
- key = g_strdup_printf("%smethod", prefix);
- g_key_file_set_string(keyfile, identifier, key, method);
- g_free(key);
- }
+ store_set_str(&is, "method", method);
if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6) {
- const char *privacy;
- privacy = privacy2string(ipconfig->ipv6_privacy_config);
- key = g_strdup_printf("%sprivacy", prefix);
- g_key_file_set_string(keyfile, identifier, key, privacy);
- g_free(key);
-
- key = g_strdup_printf("%sDHCP.LastAddress", prefix);
- if (ipconfig->last_dhcp_address &&
- strlen(ipconfig->last_dhcp_address) > 0)
- g_key_file_set_string(keyfile, identifier, key,
- ipconfig->last_dhcp_address);
- else
- g_key_file_remove_key(keyfile, identifier, key, NULL);
- g_free(key);
-
- key = g_strdup_printf("%sDHCP.LastPrefixes", prefix);
- if (ipconfig->last_dhcpv6_prefixes &&
- ipconfig->last_dhcpv6_prefixes[0]) {
- guint len =
- g_strv_length(ipconfig->last_dhcpv6_prefixes);
-
- g_key_file_set_string_list(keyfile, identifier, key,
- (const gchar **)ipconfig->last_dhcpv6_prefixes,
- len);
- } else
- g_key_file_remove_key(keyfile, identifier, key, NULL);
- g_free(key);
+ store_set_str(&is, "privacy",
+ privacy2string(ipconfig->ipv6_privacy_config));
+
+ store_set_str(&is, "DHCP.LastAddress",
+ ipconfig->last_dhcp_address);
+
+ store_set_strs(&is, "DHCP.LastPrefixes",
+ ipconfig->last_dhcpv6_prefixes);
}
switch (ipconfig->method) {
case CONNMAN_IPCONFIG_METHOD_FIXED:
case CONNMAN_IPCONFIG_METHOD_MANUAL:
break;
+
case CONNMAN_IPCONFIG_METHOD_DHCP:
- key = g_strdup_printf("%sDHCP.LastAddress", prefix);
- if (ipconfig->last_dhcp_address &&
- strlen(ipconfig->last_dhcp_address) > 0)
- g_key_file_set_string(keyfile, identifier, key,
- ipconfig->last_dhcp_address);
- else
- g_key_file_remove_key(keyfile, identifier, key, NULL);
- g_free(key);
+ store_set_str(&is, "DHCP.LastAddress",
+ ipconfig->last_dhcp_address);
/* fall through */
+
case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
case CONNMAN_IPCONFIG_METHOD_OFF:
case CONNMAN_IPCONFIG_METHOD_AUTO:
- return 0;
+ return;
}
- key = g_strdup_printf("%snetmask_prefixlen", prefix);
- if (ipconfig->address->prefixlen != 0)
- g_key_file_set_integer(keyfile, identifier,
- key, ipconfig->address->prefixlen);
- g_free(key);
-
- key = g_strdup_printf("%slocal_address", prefix);
- if (ipconfig->address->local)
- g_key_file_set_string(keyfile, identifier,
- key, ipconfig->address->local);
- g_free(key);
-
- key = g_strdup_printf("%speer_address", prefix);
- if (ipconfig->address->peer)
- g_key_file_set_string(keyfile, identifier,
- key, ipconfig->address->peer);
- g_free(key);
-
- key = g_strdup_printf("%sbroadcast_address", prefix);
- if (ipconfig->address->broadcast)
- g_key_file_set_string(keyfile, identifier,
- key, ipconfig->address->broadcast);
- g_free(key);
-
- key = g_strdup_printf("%sgateway", prefix);
- if (ipconfig->address->gateway)
- g_key_file_set_string(keyfile, identifier,
- key, ipconfig->address->gateway);
- else
- g_key_file_remove_key(keyfile, identifier, key, NULL);
- g_free(key);
-
- return 0;
+ store_set_int(&is, "netmask_prefixlen", ipconfig->address->prefixlen);
+ store_set_str(&is, "local_address", ipconfig->address->local);
+ store_set_str(&is, "peer_address", ipconfig->address->peer);
+ store_set_str(&is, "broadcast_address", ipconfig->address->broadcast);
+ store_set_str(&is, "gateway", ipconfig->address->gateway);
}
int __connman_ipconfig_init(void)
diff --git a/src/iptables.c b/src/iptables.c
index beb14df7..90a296e2 100755
--- a/src/iptables.c
+++ b/src/iptables.c
@@ -62,7 +62,7 @@
* - ipt_entry->target_offset = Size of ipt_entry + matches
* - ipt_entry->next_offset = Size of ipt_entry + matches + target
* - IPT_SO_SET_REPLACE is used to write a table (contains the complete
- * - hook_entry and overflow mark the begining and the end of a chain, e.g
+ * - hook_entry and overflow mark the beginning and the end of a chain, e.g
* entry hook: pre/in/fwd/out/post -1/0/352/504/-1
* underflow: pre/in/fwd/out/post -1/200/352/904/-1
* means that INPUT starts at offset 0 and ends at 200 (the start offset to
@@ -868,7 +868,7 @@ static int iptables_add_entry(struct connman_iptables *table,
entry_before = before->data;
/*
- * We've just appended/insterted a new entry. All references
+ * We've just appended/inserted a new entry. All references
* should be bumped accordingly.
*/
update_targets_reference(table, entry_before, e, false);
@@ -2947,7 +2947,7 @@ static int parse_ip_and_mask(const char *str, struct in_addr *ip,
if (!tokens)
return -1;
- if (!inet_pton(AF_INET, tokens[0], ip)) {
+ if (inet_pton(AF_INET, tokens[0], ip) != 1) {
err = -1;
goto out;
}
@@ -2988,7 +2988,7 @@ static int parse_ipv6_and_mask(const char *str, struct in6_addr *ip,
if (!tokens)
return -1;
- if (!inet_pton(AF_INET6, tokens[0], ip)) {
+ if (inet_pton(AF_INET6, tokens[0], ip) != 1) {
err = -1;
goto out;
}
@@ -3247,7 +3247,7 @@ static int parse_rule_spec(struct connman_iptables *table,
* - if '!' is found, set the invert flag to true and
* removes the '!' from the optarg string and jumps
* back to getopt to reparse the current optarg string.
- * After reparsing the invert flag is reseted to false.
+ * After reparsing the invert flag is reset to false.
* - If 'm' or 'j' is found then call either
* prepare_matches() or prepare_target(). Those function
* will modify (extend) the longopts for getopt_long.
@@ -3399,7 +3399,7 @@ static int parse_rule_spec(struct connman_iptables *table,
break;
if (invert)
- ctx->ip->invflags |= IP6T_INV_DSTIP;
+ ctx->ipv6->invflags |= IP6T_INV_DSTIP;
}
break;
@@ -3515,7 +3515,7 @@ static int parse_rule_spec(struct connman_iptables *table,
optarg[0] = '\0';
/*
- * And recall getopt_long without reseting
+ * And recall getopt_long without resetting
* invert.
*/
continue;
diff --git a/src/log.c b/src/log.c
index 8dbbb04b..e821f54e 100755
--- a/src/log.c
+++ b/src/log.c
@@ -40,6 +40,7 @@ static const char *program_path;
#if defined TIZEN_EXT
#include <sys/stat.h>
#include <sys/time.h>
+#include <stdbool.h>
#include <dlog.h>
#undef LOG_TAG
@@ -55,6 +56,29 @@ static const char *program_path;
#define syslog __connman_log_s
static FILE *log_file = NULL;
+static bool dlog_logging = true;
+static bool file_logging = true;
+static bool simple_log = true;
+
+bool get_simple_log_option(void)
+{
+ return simple_log;
+}
+
+void set_simple_log_option(bool option)
+{
+ simple_log = option;
+}
+
+void set_dlog_logging_option(bool option)
+{
+ dlog_logging = option;
+}
+
+void set_file_logging_option(bool option)
+{
+ file_logging = option;
+}
void __connman_log_open(const char *ident, int option, int facility)
{
@@ -175,6 +199,9 @@ void __connman_log_s(int log_priority, const char *format, ...)
if (dlog_logging)
dlog_vprint(DLOG_DEBUG, LOG_TAG, format, ap);
+ va_end(ap);
+ va_start(ap, format);
+
if (file_logging)
vsyslog(LOG_DEBUG, format, ap);
@@ -201,6 +228,9 @@ void connman_info(const char *format, ...)
if (dlog_logging)
dlog_vprint(DLOG_INFO, LOG_TAG, format, ap);
+ va_end(ap);
+ va_start(ap, format);
+
if (file_logging)
#endif
vsyslog(LOG_INFO, format, ap);
@@ -224,6 +254,9 @@ void connman_warn(const char *format, ...)
if (dlog_logging)
dlog_vprint(DLOG_WARN, LOG_TAG, format, ap);
+ va_end(ap);
+ va_start(ap, format);
+
if (file_logging)
#endif
vsyslog(LOG_WARNING, format, ap);
@@ -247,6 +280,9 @@ void connman_error(const char *format, ...)
if (dlog_logging)
dlog_vprint(DLOG_ERROR, LOG_TAG, format, ap);
+ va_end(ap);
+ va_start(ap, format);
+
if (file_logging)
#endif
vsyslog(LOG_ERR, format, ap);
@@ -270,6 +306,9 @@ void connman_debug(const char *format, ...)
if (dlog_logging)
dlog_vprint(DLOG_DEBUG, LOG_TAG, format, ap);
+ va_end(ap);
+ va_start(ap, format);
+
if (file_logging)
#endif
vsyslog(LOG_DEBUG, format, ap);
diff --git a/src/main.c b/src/main.c
index 0821c45b..8b0a995c 100755
--- a/src/main.c
+++ b/src/main.c
@@ -46,8 +46,20 @@
#define DEFAULT_INPUT_REQUEST_TIMEOUT (120 * 1000)
#define DEFAULT_BROWSER_LAUNCH_TIMEOUT (300 * 1000)
+#define DEFAULT_ONLINE_CHECK_IPV4_URL "http://ipv4.connman.net/online/status.html"
+#define DEFAULT_ONLINE_CHECK_IPV6_URL "http://ipv6.connman.net/online/status.html"
+
+/*
+ * We set the integer to 1 sec so that we have a chance to get
+ * necessary IPv6 router advertisement messages that might have
+ * DNS data etc.
+ */
+#define DEFAULT_ONLINE_CHECK_INITIAL_INTERVAL 1
+#define DEFAULT_ONLINE_CHECK_MAX_INTERVAL 12
+
#if defined TIZEN_EXT
#define DEFAULT_WIFI_INTERFACE "wlan0"
+#define CONTAINER_FILE "/run/systemd/container"
#endif
#define MAINFILE "main.conf"
@@ -94,6 +106,11 @@ static struct {
bool enable_6to4;
char *vendor_class_id;
bool enable_online_check;
+ bool enable_online_to_ready_transition;
+ char *online_check_ipv4_url;
+ char *online_check_ipv6_url;
+ unsigned int online_check_initial_interval;
+ unsigned int online_check_max_interval;
bool auto_connect_roaming_services;
bool acd;
bool use_gateways_as_timeservers;
@@ -106,7 +123,14 @@ static struct {
char *def_wifi_ifname;
bool file_log;
bool dlog_log;
- bool simplified_log;
+ bool simple_log;
+ bool wifi_roam_scan;
+ bool wifi_roam;
+ int wifi_roam_min_snr;
+ int wifi_roam_min_rssi_2_4GHz;
+ int wifi_roam_min_rssi_5GHz;
+ int wifi_roam_min_rssi_6GHz;
+ int wifi_ap_selection_method;
#endif
} connman_settings = {
.bg_scan = true,
@@ -127,6 +151,11 @@ static struct {
.enable_6to4 = false,
.vendor_class_id = NULL,
.enable_online_check = true,
+ .enable_online_to_ready_transition = false,
+ .online_check_ipv4_url = NULL,
+ .online_check_ipv6_url = NULL,
+ .online_check_initial_interval = DEFAULT_ONLINE_CHECK_INITIAL_INTERVAL,
+ .online_check_max_interval = DEFAULT_ONLINE_CHECK_MAX_INTERVAL,
.auto_connect_roaming_services = false,
.acd = false,
.use_gateways_as_timeservers = false,
@@ -139,7 +168,14 @@ static struct {
.def_wifi_ifname = DEFAULT_WIFI_INTERFACE,
.file_log = true,
.dlog_log = true,
- .simplified_log = true,
+ .simple_log = true,
+ .wifi_roam_scan = false,
+ .wifi_roam = false,
+ .wifi_roam_min_snr = 0,
+ .wifi_roam_min_rssi_2_4GHz = 0,
+ .wifi_roam_min_rssi_5GHz = 0,
+ .wifi_roam_min_rssi_6GHz = 0,
+ .wifi_ap_selection_method = AP_SELECTION_METHOD_NORMAL,
#endif
};
@@ -217,6 +253,11 @@ static struct {
#define CONF_ENABLE_6TO4 "Enable6to4"
#define CONF_VENDOR_CLASS_ID "VendorClassID"
#define CONF_ENABLE_ONLINE_CHECK "EnableOnlineCheck"
+#define CONF_ENABLE_ONLINE_TO_READY_TRANSITION "EnableOnlineToReadyTransition"
+#define CONF_ONLINE_CHECK_IPV4_URL "OnlineCheckIPv4URL"
+#define CONF_ONLINE_CHECK_IPV6_URL "OnlineCheckIPv6URL"
+#define CONF_ONLINE_CHECK_INITIAL_INTERVAL "OnlineCheckInitialInterval"
+#define CONF_ONLINE_CHECK_MAX_INTERVAL "OnlineCheckMaxInterval"
#define CONF_AUTO_CONNECT_ROAMING_SERVICES "AutoConnectRoamingServices"
#define CONF_ACD "AddressConflictDetection"
#define CONF_USE_GATEWAYS_AS_TIMESERVERS "UseGatewaysAsTimeservers"
@@ -225,11 +266,18 @@ static struct {
#define CONF_TIZEN_TV_EXT "TizenTVExtension"
#define CONF_ENABLE_AUTO_IP "EnableAutoIp"
#define CONF_GLOBAL_NAMESERVER "GlobalNameserver"
-#define CONF_CONNMAN_SUPPLICANT_DEBUG "ConnmanSupplicantDebug"
-#define CONF_CONNMAN_WIFI_DEF_IFNAME "DefaultWifiInterface"
-#define CONF_CONNMAN_FILE_LOG "FileLogging"
-#define CONF_CONNMAN_DLOG_LOG "DlogLogging"
-#define CONF_CONNMAN_SIMPLIFIED_LOG "SimplifiedLog"
+#define CONF_SUPPLICANT_DEBUG "ConnmanSupplicantDebug"
+#define CONF_WIFI_DEF_IFNAME "DefaultWifiInterface"
+#define CONF_FILE_LOG "FileLogging"
+#define CONF_DLOG_LOG "DlogLogging"
+#define CONF_SIMPLIFIED_LOG "SimplifiedLog"
+#define CONF_WIFI_ROAM_SCAN "WifiRoamingScan"
+#define CONF_WIFI_ROAM "WifiRoaming"
+#define CONF_WIFI_ROAM_MIN_SNR "WifiRoamingMinSNR"
+#define CONF_WIFI_ROAM_MIN_RSSI_2_4 "WifiRoamingMinRSSI_2_4GHz"
+#define CONF_WIFI_ROAM_MIN_RSSI_5 "WifiRoamingMinRSSI_5GHz"
+#define CONF_WIFI_ROAM_MIN_RSSI_6 "WifiRoamingMinRSSI_6GHz"
+#define CONF_WIFI_AP_SELECTION_METHOD "ApSelectionMethod"
#endif
#if defined TIZEN_EXT
@@ -257,13 +305,14 @@ static struct {
#define CONF_INS_INTERNET_SCORE "INSInternetScore"
/* Common */
#define CONF_INS_SIGNAL_LEVEL3_5GHZ "INSSignalLevel3_5GHz"
-#define CONF_INS_SIGNAL_LEVEL3_24GHZ "INSSignalLevel3_24GHz"
+#define CONF_INS_SIGNAL_LEVEL3_2_4GHZ "INSSignalLevel3_2_4GHz"
#endif
static const char *supported_options[] = {
CONF_BG_SCAN,
CONF_PREF_TIMESERVERS,
CONF_AUTO_CONNECT_TECHS,
+ CONF_FAVORITE_TECHS,
CONF_ALWAYS_CONNECTED_TECHS,
CONF_PREFERRED_TECHS,
CONF_FALLBACK_NAMESERVERS,
@@ -278,6 +327,11 @@ static const char *supported_options[] = {
CONF_ENABLE_6TO4,
CONF_VENDOR_CLASS_ID,
CONF_ENABLE_ONLINE_CHECK,
+ CONF_ENABLE_ONLINE_TO_READY_TRANSITION,
+ CONF_ONLINE_CHECK_IPV4_URL,
+ CONF_ONLINE_CHECK_IPV6_URL,
+ CONF_ONLINE_CHECK_INITIAL_INTERVAL,
+ CONF_ONLINE_CHECK_MAX_INTERVAL,
CONF_AUTO_CONNECT_ROAMING_SERVICES,
CONF_ACD,
CONF_USE_GATEWAYS_AS_TIMESERVERS,
@@ -286,11 +340,18 @@ static const char *supported_options[] = {
CONF_TIZEN_TV_EXT,
CONF_ENABLE_AUTO_IP,
CONF_GLOBAL_NAMESERVER,
- CONF_CONNMAN_SUPPLICANT_DEBUG,
- CONF_CONNMAN_WIFI_DEF_IFNAME,
- CONF_CONNMAN_FILE_LOG,
- CONF_CONNMAN_DLOG_LOG,
- CONF_CONNMAN_SIMPLIFIED_LOG,
+ CONF_SUPPLICANT_DEBUG,
+ CONF_WIFI_DEF_IFNAME,
+ CONF_FILE_LOG,
+ CONF_DLOG_LOG,
+ CONF_SIMPLIFIED_LOG,
+ CONF_WIFI_ROAM_SCAN,
+ CONF_WIFI_ROAM,
+ CONF_WIFI_ROAM_MIN_SNR,
+ CONF_WIFI_ROAM_MIN_RSSI_2_4,
+ CONF_WIFI_ROAM_MIN_RSSI_5,
+ CONF_WIFI_ROAM_MIN_RSSI_6,
+ CONF_WIFI_AP_SELECTION_METHOD,
#endif
NULL
};
@@ -321,7 +382,7 @@ static const char *supported_ins_options[] = {
CONF_INS_INTERNET_SCORE,
/* Common */
CONF_INS_SIGNAL_LEVEL3_5GHZ,
- CONF_INS_SIGNAL_LEVEL3_24GHZ,
+ CONF_INS_SIGNAL_LEVEL3_2_4GHZ,
NULL
};
#endif
@@ -465,7 +526,7 @@ static void check_config(GKeyFile *config)
}
#if defined TIZEN_EXT
-static void check_Tizen_INS_configuration(GKeyFile *config)
+static void check_tizen_ins_configuration(GKeyFile *config)
{
GError *error = NULL;
char *ins_preferred_freq_bssid;
@@ -619,20 +680,21 @@ static void check_Tizen_INS_configuration(GKeyFile *config)
g_clear_error(&error);
integer = g_key_file_get_integer(config, "INS",
- CONF_INS_SIGNAL_LEVEL3_24GHZ, &error);
+ CONF_INS_SIGNAL_LEVEL3_2_4GHZ, &error);
if (!error)
connman_ins_settings.ins_signal_level3_24ghz = integer;
g_clear_error(&error);
}
-static void check_Tizen_configuration(GKeyFile *config)
+static void check_tizen_configuration(GKeyFile *config)
{
GError *error = NULL;
char **cellular_interfaces;
char *global_nameserver;
char *default_wifi_ifname;
bool boolean;
+ int integer;
gsize len;
cellular_interfaces = g_key_file_get_string_list(config, "General",
@@ -665,41 +727,90 @@ static void check_Tizen_configuration(GKeyFile *config)
g_clear_error(&error);
boolean = __connman_config_get_bool(config, "General",
- CONF_CONNMAN_SUPPLICANT_DEBUG, &error);
+ CONF_SUPPLICANT_DEBUG, &error);
if (!error)
connman_settings.supplicant_debug = boolean;
g_clear_error(&error);
default_wifi_ifname = __connman_config_get_string(config, "General",
- CONF_CONNMAN_WIFI_DEF_IFNAME, &error);
+ CONF_WIFI_DEF_IFNAME, &error);
if (!error)
connman_settings.def_wifi_ifname = default_wifi_ifname;
g_clear_error(&error);
boolean = __connman_config_get_bool(config, "General",
- CONF_CONNMAN_FILE_LOG, &error);
+ CONF_FILE_LOG, &error);
if (!error)
connman_settings.file_log = boolean;
g_clear_error(&error);
boolean = __connman_config_get_bool(config, "General",
- CONF_CONNMAN_DLOG_LOG, &error);
+ CONF_DLOG_LOG, &error);
if (!error)
connman_settings.dlog_log = boolean;
g_clear_error(&error);
boolean = __connman_config_get_bool(config, "General",
- CONF_CONNMAN_SIMPLIFIED_LOG, &error);
+ CONF_SIMPLIFIED_LOG, &error);
+ if (!error)
+ connman_settings.simple_log = boolean;
+
+ g_clear_error(&error);
+
+ boolean = __connman_config_get_bool(config, "General",
+ CONF_WIFI_ROAM_SCAN, &error);
+ if (!error)
+ connman_settings.wifi_roam_scan = boolean;
+
+ g_clear_error(&error);
+
+ boolean = __connman_config_get_bool(config, "General",
+ CONF_WIFI_ROAM, &error);
+ if (!error)
+ connman_settings.wifi_roam = boolean;
+
+ g_clear_error(&error);
+
+ integer = g_key_file_get_integer(config, "General",
+ CONF_WIFI_ROAM_MIN_SNR, &error);
+ if (!error && integer >= 0)
+ connman_settings.wifi_roam_min_snr = integer;
+
+ g_clear_error(&error);
+
+ integer = g_key_file_get_integer(config, "General",
+ CONF_WIFI_ROAM_MIN_RSSI_2_4, &error);
+ if (!error)
+ connman_settings.wifi_roam_min_rssi_2_4GHz = integer;
+
+ g_clear_error(&error);
+
+ integer = g_key_file_get_integer(config, "General",
+ CONF_WIFI_ROAM_MIN_RSSI_5, &error);
+ if (!error)
+ connman_settings.wifi_roam_min_rssi_5GHz = integer;
+
+ g_clear_error(&error);
+
+ integer = g_key_file_get_integer(config, "General",
+ CONF_WIFI_ROAM_MIN_RSSI_6, &error);
+ if (!error)
+ connman_settings.wifi_roam_min_rssi_6GHz = integer;
+
+ g_clear_error(&error);
+
+ integer = g_key_file_get_integer(config, "General",
+ CONF_WIFI_AP_SELECTION_METHOD, &error);
if (!error)
- connman_settings.simplified_log = boolean;
+ connman_settings.wifi_ap_selection_method = integer;
g_clear_error(&error);
- check_Tizen_INS_configuration(config);
+ check_tizen_ins_configuration(config);
}
static void set_nofile_inc(void)
@@ -726,9 +837,9 @@ static void parse_config(GKeyFile *config)
char **interfaces;
char **str_list;
char **tethering;
- char *vendor_class_id;
+ char *string;
gsize len;
- int timeout;
+ int integer;
if (!config) {
connman_settings.auto_connect =
@@ -766,6 +877,8 @@ static void parse_config(GKeyFile *config)
connman_settings.auto_connect =
parse_service_types(default_auto_connect, CONF_ARRAY_SIZE(default_auto_connect));
+ g_strfreev(str_list);
+
g_clear_error(&error);
str_list = __connman_config_get_string_list(config, "General",
@@ -815,17 +928,17 @@ static void parse_config(GKeyFile *config)
g_clear_error(&error);
- timeout = g_key_file_get_integer(config, "General",
+ integer = g_key_file_get_integer(config, "General",
CONF_TIMEOUT_INPUTREQ, &error);
- if (!error && timeout >= 0)
- connman_settings.timeout_inputreq = timeout * 1000;
+ if (!error && integer >= 0)
+ connman_settings.timeout_inputreq = integer * 1000;
g_clear_error(&error);
- timeout = g_key_file_get_integer(config, "General",
+ integer = g_key_file_get_integer(config, "General",
CONF_TIMEOUT_BROWSERLAUNCH, &error);
- if (!error && timeout >= 0)
- connman_settings.timeout_browserlaunch = timeout * 1000;
+ if (!error && integer >= 0)
+ connman_settings.timeout_browserlaunch = integer * 1000;
g_clear_error(&error);
@@ -886,10 +999,10 @@ static void parse_config(GKeyFile *config)
g_clear_error(&error);
- vendor_class_id = __connman_config_get_string(config, "General",
+ string = __connman_config_get_string(config, "General",
CONF_VENDOR_CLASS_ID, &error);
if (!error)
- connman_settings.vendor_class_id = vendor_class_id;
+ connman_settings.vendor_class_id = string;
g_clear_error(&error);
@@ -904,6 +1017,61 @@ static void parse_config(GKeyFile *config)
g_clear_error(&error);
boolean = __connman_config_get_bool(config, "General",
+ CONF_ENABLE_ONLINE_TO_READY_TRANSITION, &error);
+ if (!error) {
+ connman_settings.enable_online_to_ready_transition = boolean;
+ }
+
+ g_clear_error(&error);
+
+ string = __connman_config_get_string(config, "General",
+ CONF_ONLINE_CHECK_IPV4_URL, &error);
+ if (!error)
+ connman_settings.online_check_ipv4_url = string;
+ else
+ connman_settings.online_check_ipv4_url =
+ g_strdup(DEFAULT_ONLINE_CHECK_IPV4_URL);
+
+ g_clear_error(&error);
+
+ string = __connman_config_get_string(config, "General",
+ CONF_ONLINE_CHECK_IPV6_URL, &error);
+ if (!error)
+ connman_settings.online_check_ipv6_url = string;
+ else
+ connman_settings.online_check_ipv6_url =
+ g_strdup(DEFAULT_ONLINE_CHECK_IPV6_URL);
+
+
+ g_clear_error(&error);
+
+ integer = g_key_file_get_integer(config, "General",
+ CONF_ONLINE_CHECK_INITIAL_INTERVAL, &error);
+ if (!error && integer >= 0)
+ connman_settings.online_check_initial_interval = integer;
+
+ g_clear_error(&error);
+
+ integer = g_key_file_get_integer(config, "General",
+ CONF_ONLINE_CHECK_MAX_INTERVAL, &error);
+ if (!error && integer >= 0)
+ connman_settings.online_check_max_interval = integer;
+
+ g_clear_error(&error);
+
+ if (connman_settings.online_check_initial_interval < 1 ||
+ connman_settings.online_check_initial_interval >
+ connman_settings.online_check_max_interval) {
+ connman_warn("Incorrect online check intervals [%u, %u]",
+ connman_settings.online_check_initial_interval,
+ connman_settings.online_check_max_interval);
+ connman_settings.online_check_initial_interval =
+ DEFAULT_ONLINE_CHECK_INITIAL_INTERVAL;
+ connman_settings.online_check_max_interval =
+ DEFAULT_ONLINE_CHECK_MAX_INTERVAL;
+ }
+
+ boolean = __connman_config_get_bool(config, "General",
CONF_AUTO_CONNECT_ROAMING_SERVICES, &error);
if (!error)
connman_settings.auto_connect_roaming_services = boolean;
@@ -924,7 +1092,7 @@ static void parse_config(GKeyFile *config)
g_clear_error(&error);
#if defined TIZEN_EXT
- check_Tizen_configuration(config);
+ check_tizen_configuration(config);
#endif
}
@@ -940,10 +1108,11 @@ static int config_init(const char *file)
parse_config(config);
if (config)
g_key_file_free(config);
+
#if defined TIZEN_EXT
- dlog_logging = connman_settings.dlog_log;
- file_logging = connman_settings.file_log;
- simplified_log = connman_settings.simplified_log;
+ set_simple_log_option(connman_settings.simple_log);
+ set_dlog_logging_option(connman_settings.dlog_log);
+ set_file_logging_option(connman_settings.file_log);
#endif
return 0;
}
@@ -1105,11 +1274,17 @@ static GOptionEntry options[] = {
{ NULL },
};
-const char *connman_option_get_string(const char *key)
+char *connman_setting_get_string(const char *key)
{
if (g_str_equal(key, CONF_VENDOR_CLASS_ID))
return connman_settings.vendor_class_id;
+ if (g_str_equal(key, CONF_ONLINE_CHECK_IPV4_URL))
+ return connman_settings.online_check_ipv4_url;
+
+ if (g_str_equal(key, CONF_ONLINE_CHECK_IPV6_URL))
+ return connman_settings.online_check_ipv6_url;
+
if (g_strcmp0(key, "wifi") == 0) {
if (!option_wifi)
return "nl80211,wext";
@@ -1127,7 +1302,7 @@ const char *connman_option_get_string(const char *key)
if (g_str_equal(key, CONF_INS_PREFERRED_FREQ))
return connman_ins_settings.ins_preferred_freq;
- if (g_str_equal(key, CONF_CONNMAN_WIFI_DEF_IFNAME))
+ if (g_str_equal(key, CONF_WIFI_DEF_IFNAME))
return connman_settings.def_wifi_ifname;
#endif
return NULL;
@@ -1156,6 +1331,9 @@ bool connman_setting_get_bool(const char *key)
if (g_str_equal(key, CONF_ENABLE_ONLINE_CHECK))
return connman_settings.enable_online_check;
+ if (g_str_equal(key, CONF_ENABLE_ONLINE_TO_READY_TRANSITION))
+ return connman_settings.enable_online_to_ready_transition;
+
if (g_str_equal(key, CONF_AUTO_CONNECT_ROAMING_SERVICES))
return connman_settings.auto_connect_roaming_services;
@@ -1169,20 +1347,24 @@ bool connman_setting_get_bool(const char *key)
if (g_str_equal(key, CONF_ENABLE_AUTO_IP))
return connman_settings.auto_ip;
- if (g_str_equal(key, CONF_CONNMAN_SUPPLICANT_DEBUG))
+ if (g_str_equal(key, CONF_SUPPLICANT_DEBUG))
return connman_settings.supplicant_debug;
- if (g_str_equal(key, CONF_CONNMAN_FILE_LOG))
+ if (g_str_equal(key, CONF_FILE_LOG))
return connman_settings.file_log;
- if (g_str_equal(key, CONF_CONNMAN_DLOG_LOG))
+ if (g_str_equal(key, CONF_DLOG_LOG))
return connman_settings.dlog_log;
- if (g_str_equal(key, CONF_CONNMAN_SIMPLIFIED_LOG))
- return connman_settings.simplified_log;
-#endif
+ if (g_str_equal(key, CONF_SIMPLIFIED_LOG))
+ return connman_settings.simple_log;
+
+ if (g_str_equal(key, CONF_WIFI_ROAM_SCAN))
+ return connman_settings.wifi_roam_scan;
+
+ if (g_str_equal(key, CONF_WIFI_ROAM))
+ return connman_settings.wifi_roam;
-#if defined TIZEN_EXT
if (g_str_equal(key, CONF_INS_LAST_CONNECTED_BSSID))
return connman_ins_settings.ins_last_connected_bssid;
@@ -1208,9 +1390,15 @@ bool connman_setting_get_bool(const char *key)
return false;
}
-#if defined TIZEN_EXT
unsigned int connman_setting_get_uint(const char *key)
{
+ if (g_str_equal(key, CONF_ONLINE_CHECK_INITIAL_INTERVAL))
+ return connman_settings.online_check_initial_interval;
+
+ if (g_str_equal(key, CONF_ONLINE_CHECK_MAX_INTERVAL))
+ return connman_settings.online_check_max_interval;
+
+#if defined TIZEN_EXT
if (g_str_equal(key, CONF_INS_PREFERRED_FREQ_BSSID_SCORE))
return connman_ins_settings.ins_preferred_freq_bssid_score;
@@ -1240,18 +1428,34 @@ unsigned int connman_setting_get_uint(const char *key)
if (g_str_equal(key, CONF_INS_INTERNET_SCORE))
return connman_ins_settings.ins_internet_score;
-
+#endif
return 0;
}
+#if defined TIZEN_EXT
int connman_setting_get_int(const char *key)
{
+ if (g_str_equal(key, CONF_WIFI_AP_SELECTION_METHOD))
+ return connman_settings.wifi_ap_selection_method;
+
if (g_str_equal(key, CONF_INS_SIGNAL_LEVEL3_5GHZ))
return connman_ins_settings.ins_signal_level3_5ghz;
- if (g_str_equal(key, CONF_INS_SIGNAL_LEVEL3_24GHZ))
+ if (g_str_equal(key, CONF_INS_SIGNAL_LEVEL3_2_4GHZ))
return connman_ins_settings.ins_signal_level3_24ghz;
+ if (g_str_equal(key, CONF_WIFI_ROAM_MIN_SNR))
+ return connman_settings.wifi_roam_min_snr;
+
+ if (g_str_equal(key, CONF_WIFI_ROAM_MIN_RSSI_2_4))
+ return connman_settings.wifi_roam_min_rssi_2_4GHz;
+
+ if (g_str_equal(key, CONF_WIFI_ROAM_MIN_RSSI_5))
+ return connman_settings.wifi_roam_min_rssi_5GHz;
+
+ if (g_str_equal(key, CONF_WIFI_ROAM_MIN_RSSI_6))
+ return connman_settings.wifi_roam_min_rssi_6GHz;
+
return 0;
}
#endif
@@ -1375,6 +1579,21 @@ int main(int argc, char *argv[])
__connman_dbus_init(conn);
+#if defined TIZEN_EXT
+ if (access(CONTAINER_FILE, F_OK) == 0) {
+ g_main_loop_run(main_loop);
+
+ g_source_remove(signal);
+ dbus_connection_unref(conn);
+ g_main_loop_unref(main_loop);
+
+ __connman_dbus_cleanup();
+ __connman_log_cleanup(option_backtrace);
+
+ return 0;
+ }
+#endif
+
if (!option_config)
config_init(CONFIGMAINFILE);
else
@@ -1501,6 +1720,9 @@ int main(int argc, char *argv[])
g_strfreev(connman_settings.fallback_nameservers);
g_strfreev(connman_settings.blacklisted_interfaces);
g_strfreev(connman_settings.tethering_technologies);
+ g_free(connman_settings.vendor_class_id);
+ g_free(connman_settings.online_check_ipv4_url);
+ g_free(connman_settings.online_check_ipv6_url);
#if defined TIZEN_EXT
g_free(connman_ins_settings.ins_preferred_freq_bssid);
diff --git a/src/main.conf b/src/main.conf
index 555225f0..9905e3e2 100755
--- a/src/main.conf
+++ b/src/main.conf
@@ -130,6 +130,31 @@ SingleConnectedTechnology = true
# Default value is true.
# EnableOnlineCheck = false
+# Urls (IPv4 and IPv6 respectively) used during the online status check.
+# Please refer to the README for more detailed information.
+# Default values are http://ipv4.connman.net/online/status.html and
+# http://ipv6.connman.net/online/status.html respectively.
+# OnlineCheckIPv4URL= http://ipv4.connman.net/online/status.html
+# OnlineCheckIPv6URL= http://ipv6.connman.net/online/status.html
+
+# Range of intervals between two online check requests.
+# Please refer to the README for more detailed information.
+# Default values are 1 and 12 respectively.
+# OnlineCheckInitialInterval = 1
+# OnlineCheckMaxInterval = 12
+
+# WARNING: Experimental feature!!!
+# In addition to EnableOnlineCheck setting, enable or disable use of HTTP GET
+# to detect the loss of end-to-end connectivity.
+# If this setting is false, when the default service transitions to ONLINE
+# state, the HTTP GET request is no more called until next cycle, initiated
+# by a transition of the default service to DISCONNECT state.
+# If this setting is true, the HTTP GET request keeps beeing called to guarantee
+# that end-to-end connectivity is still successful. If not, the default service
+# will transition to READY state, enabling another service to become the
+# default one, in replacement.
+# EnableOnlineToReadyTransition = false
+
# List of technologies with AutoConnect = true which are always connected
# regardless of PreferredTechnologies setting. Default value is empty and
# will connect a technology only if it is at a higher preference than any
@@ -185,6 +210,30 @@ SimplifiedLog = true
# Default value is wlan0.
DefaultWifiInterface = wlan0
+# Allow ConnMan to start scan for wifi roaming when SNR and signal are weakened
+# Default value is false.
+# WifiRoamingScan = true
+
+# Allow ConnMan to start wifi roaming when SNR and signal are weakened
+# and there is another BSS in better condition.
+# Default value is false.
+# WifiRoaming = true
+
+# Determine if the SNR and signal have weakened
+# based on the following conditions.
+# - SNR is less than WifiRoamingMinSNR or RSSI is less than
+# WifiRoamingMinRSSI_2_4GHz, WifiRoamingMinRSSI_5GHz or WifiRoamingMinRSSI_6GHz.
+# - If the WifiRoamingMinSNR value is 0, the SNR check will be skipped.
+WifiRoamingMinSNR = 20
+WifiRoamingMinRSSI_2_4GHz = -75
+WifiRoamingMinRSSI_5GHz = -77
+WifiRoamingMinRSSI_6GHz = -78
+
+# This value indicates which AP selection method to be used.
+# 0: Normal(Signal strength)
+# 1: INS
+ApSelectionMethod = 0
+
[INS]
# INS(Intelligent Network Selection) configuration: BSSID Selection.
INSPreferredFreqBSSID = 5GHz
@@ -214,4 +263,4 @@ INSInternetScore = 30
# INS(Intelligent Network Selection) configuration: Common.
INSSignalLevel3_5GHz = -76
-INSSignalLevel3_24GHz = -74
+INSSignalLevel3_2_4GHz = -74
diff --git a/src/main_robot.conf b/src/main_robot.conf
new file mode 100755
index 00000000..5b72cd98
--- /dev/null
+++ b/src/main_robot.conf
@@ -0,0 +1,262 @@
+[General]
+
+# Set input request timeout. Default is 120 seconds
+# The request for inputs like passphrase will timeout
+# after certain amount of time. Use this setting to
+# increase the value in case of different user
+# interface designs.
+# InputRequestTimeout = 120
+
+# Set browser launch timeout. Default is 300 seconds
+# The request for launching a browser for portal pages
+# will timeout after certain amount of time. Use this
+# setting to increase the value in case of different
+# user interface designs.
+# BrowserLaunchTimeout = 300
+
+# If wifi is disconnected, the background scanning will follow a simple
+# backoff mechanism from 3s up to 5 minutes. Then, it will stay in 5
+# minutes unless user specifically asks for scanning through a D-Bus
+# call. If so, the mechanism will start again from 3s. This feature
+# activates also the background scanning while being connected, which
+# is required for roaming on wifi.
+# When BackgroundScanning is false, ConnMan will not perform any scan
+# regardless of wifi is connected or not, unless it is requested by
+# the user through a D-Bus call.
+# BackgroundScanning = true
+BackgroundScanning = false
+
+# Assume that service gateways also function as timeservers.
+# UseGatewaysAsTimeservers = false
+
+# List of Fallback timeservers separated by ",".
+# These timeservers are used for NTP sync when there are
+# no timeservers set by the user or by the service, and
+# when UseGatewaysAsTimeservers = false. These can contain
+# mixed combination of fully qualified domain names, IPv4
+# and IPv6 addresses.
+# FallbackTimeservers =
+#FallbackTimeservers = pool.ntp.org
+
+# List of fallback nameservers separated by "," used if no
+# nameservers are otherwise provided by the service. The
+# nameserver entries must be in numeric format, host
+# names are ignored.
+# FallbackNameservers =
+
+# List of technologies that are marked autoconnectable
+# by default, separated by commas ",". The default value
+# for this entry when empty is ethernet,wifi,cellular.
+# Services that are automatically connected must have been
+# set up and saved to storage beforehand.
+# DefaultAutoConnectTechnologies =
+
+# List of preferred technologies from the most preferred
+# one to the least preferred one separated by commas ",".
+# Services of the listed technology type will be tried one
+# by one in the order given, until one of them gets connected
+# or they are all tried. A service of a preferred technology
+# type in state 'ready' will get the default route when
+# compared to another preferred type further down the list
+# with state 'ready' or with a non-preferred type; a service
+# of a preferred technology type in state 'online' will get
+# the default route when compared to either a non-preferred
+# type or a preferred type further down in the list.
+# PreferredTechnologies =
+PreferredTechnologies = wifi, ethernet
+
+# List of blacklisted network interfaces separated by ",".
+# Found interfaces will be compared to the list and will
+# not be handled by ConnMan, if their first characters
+# match any of the list entries. Default value is
+# vmnet,vboxnet,virbr,ifb,ve-,vb-.
+# NetworkInterfaceBlacklist = vmnet,vboxnet,virbr,ifb,ve-,vb-
+NetworkInterfaceBlacklist = veth,vmnet,vboxnet,virbr,usb,rndis,rmnet,rev_rmnet,dummy,seth_td,seth_w
+
+# Allow ConnMan to change the system hostname. This can
+# happen for example if we receive DHCP hostname option.
+# Default value is true.
+# AllowHostnameUpdates = true
+
+# Allow ConnMan to change the system domainname. This can
+# happen for example if we receive DHCP domainname option.
+# Default value is true.
+# AllowDomainnameUpdates = true
+
+# Keep only a single connected technology at any time. When a new
+# service is connected by the user or a better one is found according
+# to PreferredTechnologies, the new service is kept connected and all
+# the other previously connected services are disconnected. With this
+# setting it does not matter whether the previously connected services
+# are in 'online' or 'ready' states, the newly connected service is
+# the only one that will be kept connected. A service connected by the
+# user will be used until going out of network coverage. With this
+# setting enabled applications will notice more network breaks than
+# normal. Default value is false.
+# SingleConnectedTechnology = false
+SingleConnectedTechnology = false
+
+# List of technologies for which tethering is allowed separated by ",".
+# The default value is wifi,bluetooth,gadget. Only those technologies
+# listed here are used for tethering. If ethernet tethering is desired,
+# then ethernet should be added to the list. The technologies listed here
+# have to support tethering, currently tethering is implemented for wifi,
+# bluetooth, gadget and ethernet.
+# NOTE that if ethernet tethering is enabled, then a DHCP server is
+# started on all ethernet interfaces. Tethered ethernet should
+# never be connected to corporate or home network as it will disrupt
+# normal operation of these networks. Due to this ethernet is not
+# tethered by default. Do not activate ethernet tethering unless you
+# really know what you are doing.
+# TetheringTechnologies = wifi,bluetooth,gadget
+
+# Restore earlier tethering status when returning from offline mode,
+# re-enabling a technology, and after restarts and reboots.
+# Default value is false.
+# PersistentTetheringMode = false
+
+# Automatically enable Anycast 6to4 if possible. This is not recommended, as
+# the use of 6to4 will generally lead to a severe degradation of connection
+# quality. See RFC6343. Default value is false (as recommended by RFC6343
+# section 4.1).
+# Enable6to4 = false
+
+# Enable use of http get as on online status check.
+# When a service is in a READY state, and is selected as default,
+# ConnMan will issue an HTTP GET request to verify that end-to-end
+# connectivity is successful. Only then the service will be
+# transitioned to ONLINE state.
+# If this setting is false, the default service will remain in READY state.
+# Default value is true.
+# EnableOnlineCheck = false
+
+# Range of intervals between two online check requests.
+# When an online check request fails, another one is triggered after a
+# longer interval. The intervals follow the power of two series of numbers
+# between OnlineCheckInitialInterval and OnlineCheckMaxInterval.
+# Default range is [1, 12], corresponding to the following intervals, in
+# seconds: 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121 and 144.
+# OnlineCheckInitialInterval = 1
+# OnlineCheckMaxInterval = 12
+
+# WARNING: Experimental feature!!!
+# In addition to EnableOnlineCheck setting, enable or disable use of HTTP GET
+# to detect the loss of end-to-end connectivity.
+# If this setting is false, when the default service transitions to ONLINE
+# state, the HTTP GET request is no more called until next cycle, initiated
+# by a transition of the default service to DISCONNECT state.
+# If this setting is true, the HTTP GET request keeps beeing called to guarantee
+# that end-to-end connectivity is still successful. If not, the default service
+# will transition to READY state, enabling another service to become the
+# default one, in replacement.
+# EnableOnlineToReadyTransition = false
+
+# List of technologies with AutoConnect = true which are always connected
+# regardless of PreferredTechnologies setting. Default value is empty and
+# will connect a technology only if it is at a higher preference than any
+# other which is already connected.
+# This setting has no effect if SingleConnectedTechnologies is enabled.
+# AlwaysConnectedTechnologies =
+
+# Allow connman to add service gateway to the time server list.
+# Default value is false.
+# UseGatewaysAsTimeservers = false
+
+# Enable auto connection of services in roaming.
+# If this setting is false, roaming services are not auto-connected by ConnMan.
+# Default value is false.
+# AutoConnectRoamingServices = false
+
+# Enable address conflict detection
+# If this setting is true, ConnMan will send probe ARP packets to see
+# if an IPv4 address is already in use before assigning the address
+# to an interface (in accordance with RFC 5227).
+# Default value is false.
+# AddressConflictDetection = false
+
+NetworkCellularInterfaceList = pdp,rmnet,seth_td,seth_w
+
+# Enable use of link-local address for auto-configuration.
+# When a device fails to get IP address from DHCP server,
+# ConnMan will start link-local address autoconfiguration and
+# assign a link-local IP address to device.
+# If this setting is false and device fails to get IP address
+# from DHCP server then device state will be set to disconnected.
+# Default value is true.
+# EnableAutoIp = false
+
+# Allow connman to set additional global nameserver and it will be used
+# if all nameservers are failed to resolve DNS query. The nameserver
+# entries must be in numeric format.
+# GlobalNameserver = 8.8.8.8
+
+# Enable supplicant debugging log
+ConnmanSupplicantDebug = false
+
+# Save ConnMan log to file
+FileLogging = false
+
+# Use dlog for ConnMan logging
+DlogLogging = true
+
+# Some logs of low importance are omitted to reduce the amount of logs
+SimplifiedLog = true
+
+# This value specifies which will be the default when there are multiple wifi interfaces.
+# Default value is wlan0.
+DefaultWifiInterface = wlan0
+
+# Allow ConnMan to start scan for wifi roaming when SNR and signal are weakened
+# Default value is false.
+# WifiRoamingScan = true
+
+# Allow ConnMan to start wifi roaming when SNR and signal are weakened
+# and there is another BSS in better condition.
+# Default value is false.
+# WifiRoaming = true
+
+# Determine if the SNR and signal have weakened
+# based on the following conditions.
+# - SNR is less than WifiRoamingMinSNR or RSSI is less than
+# WifiRoamingMinRSSI_2_4GHz, WifiRoamingMinRSSI_5GHz or WifiRoamingMinRSSI_6GHz.
+# - If the WifiRoamingMinSNR value is 0, the SNR check will be skipped.
+WifiRoamingMinSNR = 20
+WifiRoamingMinRSSI_2_4GHz = -75
+WifiRoamingMinRSSI_5GHz = -77
+WifiRoamingMinRSSI_6GHz = -78
+
+# This value indicates which AP selection method to be used.
+# 0: Normal(Signal strength)
+# 1: INS
+ApSelectionMethod = 0
+
+[INS]
+# INS(Intelligent Network Selection) configuration: BSSID Selection.
+INSPreferredFreqBSSID = 5GHz
+INSPreferredFreqBSSIDScore = 20
+INSLastConnectedBSSID = true
+INSLastConnectedBSSIDScore = 20
+INSAssocReject = true
+INSAssocRejectScore = 10
+INSSignalBSSID = true
+
+# INS(Intelligent Network Selection) configuration: SSID Selection.
+INSLastUserSelection = true
+INSLastUserSelectionTime = 480
+INSLastUserSelectionScore = 30
+# (INSLastUserSelectionTime - selection time diff) / (INSLastUserSelectionTime / INSLastUserSelectionScore)
+# This means '(480 - selection time) / x) <= 30'
+INSLastConnected = true
+INSLastConnectedScore = 30
+INSPreferredFreq = 5GHz
+INSPreferredFreqScore = 60
+INSSecurityPriority = SAE,RSN
+INSSecurityPriorityScore = 5
+# In this case, SAE(10 score), RSN(5 score)
+INSSignal = true
+INSInternet = true
+INSInternetScore = 30
+
+# INS(Intelligent Network Selection) configuration: Common.
+INSSignalLevel3_5GHz = -76
+INSSignalLevel3_2_4GHz = -74
diff --git a/src/main_tv.conf b/src/main_tv.conf
index c7b8e112..b40394c0 100755
--- a/src/main_tv.conf
+++ b/src/main_tv.conf
@@ -120,6 +120,11 @@ TizenTVExtension = true
# Default value is wlan0.
DefaultWifiInterface = wlan0
+# This value indicates which AP selection method to be used.
+# 0: Normal(Signal strength)
+# 1: INS
+ApSelectionMethod = 0
+
[INS]
# INS(Intelligent Network Selection) configuration: BSSID Selection.
INSPreferredFreqBSSID = 5GHz
@@ -149,4 +154,4 @@ INSInternetScore = 30
# INS(Intelligent Network Selection) configuration: Common.
INSSignalLevel3_5GHz = -76
-INSSignalLevel3_24GHz = -74
+INSSignalLevel3_2_4GHz = -74
diff --git a/src/manager.c b/src/manager.c
index 19f62c65..9fea4e0e 100755
--- a/src/manager.c
+++ b/src/manager.c
@@ -221,7 +221,7 @@ static DBusMessage *get_interfaces(DBusConnection *conn, DBusMessage *msg, void
{
DBusMessage *reply;
DBusMessageIter iter, array;
- const char *default_interface = connman_option_get_string("DefaultWifiInterface");
+ const char *default_interface = connman_setting_get_string("DefaultWifiInterface");
DBG("DefaultWifiInterface %s", default_interface);
@@ -249,11 +249,47 @@ static DBusMessage *get_default_service(DBusConnection *conn,
struct connman_service *service = connman_service_get_default_connection();
DBG("service %p", service);
- return connman_service_get_defaut_info(msg, service);
+ return connman_service_create_dbus_service_reply(msg, service);
+}
+
+static DBusMessage *get_connected_service(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *ifname;
+ struct connman_service *service;
+
+ dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &ifname,
+ DBUS_TYPE_INVALID);
+
+ service = connman_service_get_connected_service(ifname);
+ DBG("Interface Name %s, service %p", ifname, service);
+
+ return connman_service_create_dbus_service_reply(msg, service);
+}
+
+static DBusMessage *get_dhcp_status(DBusConnection *conn, DBusMessage *msg, void *data)
+{
+ const char *ifname;
+ const char *dhcp_status;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+
+ dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &ifname, DBUS_TYPE_INVALID);
+ dhcp_status = __connman_network_get_dhcp_status(ifname);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ if (!dhcp_status)
+ dhcp_status = "Unknown";
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &dhcp_status);
+
+ return reply;
}
-#endif
-#if defined TIZEN_EXT_INS
static void append_ins_structs(DBusMessageIter *iter, void *user_data)
{
__connman_ins_list_struct(iter);
@@ -268,8 +304,9 @@ static DBusMessage *get_ins(DBusConnection *conn,
if (!reply)
return NULL;
- __connman_dbus_append_objpath_dict_array(reply,
- append_ins_structs, NULL);
+ if (TIZEN_INS_ENABLED)
+ __connman_dbus_append_objpath_dict_array(reply,
+ append_ins_structs, NULL);
return reply;
}
@@ -732,8 +769,14 @@ static const GDBusMethodTable manager_methods[] = {
{ GDBUS_METHOD("GetDefaultService",
NULL, GDBUS_ARGS({ "service", "oa{sv}" }),
get_default_service) },
-#endif
-#if defined TIZEN_EXT_INS
+ { GDBUS_METHOD("GetConnectedService",
+ GDBUS_ARGS({ "ifname", "s" }),
+ GDBUS_ARGS({ "service", "oa{sv}" }),
+ get_connected_service) },
+ { GDBUS_METHOD("GetDhcpStatus",
+ GDBUS_ARGS({ "ifname", "s" }),
+ GDBUS_ARGS({ "status", "s" }),
+ get_dhcp_status) },
{ GDBUS_METHOD("GetINS",
NULL, GDBUS_ARGS({ "services", "a(oa{sv})" }),
get_ins) },
@@ -816,6 +859,9 @@ static const GDBusSignalTable manager_signals[] = {
{ GDBUS_SIGNAL("PeersChanged",
GDBUS_ARGS({ "changed", "a(oa{sv})" },
{ "removed", "ao" })) },
+ { GDBUS_SIGNAL("TetheringClientsChanged",
+ GDBUS_ARGS({ "registered", "as" },
+ { "removed", "as" })) },
{ },
};
diff --git a/src/mesh.c b/src/mesh.c
index b9029343..e0e6d2f3 100644
--- a/src/mesh.c
+++ b/src/mesh.c
@@ -757,7 +757,7 @@ static int mesh_save(struct connman_mesh *mesh)
{
GKeyFile *keyfile;
- keyfile = __connman_storage_open_service(mesh->identifier);
+ keyfile = g_key_file_new();
if (!keyfile)
return -EIO;
diff --git a/src/network.c b/src/network.c
index 281d0204..69816999 100755
--- a/src/network.c
+++ b/src/network.c
@@ -30,6 +30,12 @@
#include <connman/acd.h>
#include "src/shared/arp.h"
+#if defined TIZEN_EXT
+#include <gdbus.h>
+
+static DBusConnection *connection;
+#endif
+
/*
* How many times to send RS with the purpose of
* refreshing RDNSS entries before they actually expire.
@@ -56,6 +62,8 @@
static unsigned char invalid_bssid[WIFI_BSSID_LEN_MAX] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
+
+static GHashTable *dhcp_status_list = NULL;
#endif
static GSList *network_list = NULL;
@@ -122,6 +130,7 @@ struct connman_network {
unsigned int keymgmt;
char *keymgmt_type;
bool rsn_mode;
+ bool pmf_required;
int disconnect_reason;
int assoc_status_code;
GSList *vsie_list;
@@ -131,25 +140,34 @@ struct connman_network {
char *phase1;
unsigned char country_code[WIFI_COUNTRY_CODE_LEN];
GSList *bssid_list;
+ GSList *sec_list;
ieee80211_modes_e phy_mode;
connection_mode_e connection_mode;
char *connector;
char *c_sign_key;
char *net_access_key;
-#endif
-#if defined TIZEN_EXT
+
unsigned char last_connected_bssid[WIFI_BSSID_LEN_MAX];
GHashTable *assoc_reject_table;
bool owe_transition_mode;
void *transition_mode_ssid;
int transition_mode_ssid_len;
unsigned char transition_mode_bssid[WIFI_BSSID_LEN_MAX];
+ bool roaming_progress;
+ bool roaming_dhcp;
+ char *roaming_cur_bssid;
+ char *roaming_dst_bssid;
+ __time_t roam_scan_time;
+ unsigned int max_bssid_count;
+ int snr;
+ unsigned int est_throughput;
#endif
} wifi;
#if defined TIZEN_EXT
/* Multiple APN services and a default APN which a user selected */
bool default_internet;
+ bool is_psk_sha256;
#endif
};
@@ -554,6 +572,10 @@ static int set_connected_manual(struct connman_network *network)
ipconfig = __connman_service_get_ip4config(service);
__connman_ipconfig_enable(ipconfig);
+#if defined TIZEN_EXT
+ if (!service || !ipconfig)
+ return -EINVAL;
+#endif
if (!__connman_ipconfig_get_local(ipconfig))
__connman_service_read_ip4config(service);
@@ -589,7 +611,11 @@ static void remove_dhcp_timeout(struct connman_network *network)
}
}
+#if defined TIZEN_EXT
+int set_connected_dhcp(struct connman_network *network)
+#else
static int set_connected_dhcp(struct connman_network *network)
+#endif
{
struct connman_service *service;
struct connman_ipconfig *ipconfig_ipv4;
@@ -1339,6 +1365,9 @@ static void network_destruct(struct connman_network *network)
#if defined TIZEN_EXT
g_slist_free_full(network->wifi.vsie_list, g_free);
g_slist_free_full(network->wifi.bssid_list, g_free);
+
+ if (TIZEN_INS_ENABLED)
+ g_hash_table_destroy(network->wifi.assoc_reject_table);
#endif
g_free(network->path);
g_free(network->group);
@@ -1354,7 +1383,7 @@ static void network_destruct(struct connman_network *network)
/**
* connman_network_create:
- * @identifier: network identifier (for example an unqiue name)
+ * @identifier: network identifier (for example an unique name)
*
* Allocate a new network and assign the #identifier to it.
*
@@ -1403,6 +1432,9 @@ struct connman_network *
connman_network_ref_debug(struct connman_network *network,
const char *file, int line, const char *caller)
{
+#if defined TIZEN_EXT
+ if (!simplified_log)
+#endif
DBG("%p name %s ref %d by %s:%d:%s()", network, network->name,
network->refcount + 1, file, line, caller);
@@ -1420,6 +1452,9 @@ connman_network_ref_debug(struct connman_network *network,
void connman_network_unref_debug(struct connman_network *network,
const char *file, int line, const char *caller)
{
+#if defined TIZEN_EXT
+ if (!simplified_log)
+#endif
DBG("%p name %s ref %d by %s:%d:%s()", network, network->name,
network->refcount - 1, file, line, caller);
@@ -1787,6 +1822,26 @@ int connman_network_set_associating(struct connman_network *network,
return 0;
}
+#if defined TIZEN_EXT
+static void set_authenticate_error(struct connman_network *network)
+{
+ struct connman_service *service;
+
+ service = connman_service_lookup_from_network(network);
+
+ if (!service)
+ return;
+
+ if (connman_service_get_favorite(service)) {
+ __connman_service_set_ignore(service, true);
+ }
+
+ __connman_service_indicate_error(service,
+ CONNMAN_SERVICE_ERROR_AUTH_FAILED);
+}
+#endif
+
+
static void set_associate_error(struct connman_network *network)
{
struct connman_service *service;
@@ -1794,8 +1849,14 @@ static void set_associate_error(struct connman_network *network)
service = connman_service_lookup_from_network(network);
#if defined TIZEN_EXT
+ if (!service)
+ return;
+
+ if (connman_service_get_favorite(service))
+ __connman_service_set_ignore(service, true);
+
__connman_service_indicate_error(service,
- CONNMAN_SERVICE_ERROR_AUTH_FAILED);
+ CONNMAN_SERVICE_ERROR_ASSOC_FAILED);
#else
__connman_service_indicate_error(service,
CONNMAN_SERVICE_ERROR_CONNECT_FAILED);
@@ -1917,6 +1978,9 @@ void connman_network_set_error(struct connman_network *network,
set_connect_error(network);
break;
#if defined TIZEN_EXT
+ case CONNMAN_NETWORK_ERROR_AUTHENTICATE_FAIL:
+ set_authenticate_error(network);
+ break;
case CONNMAN_NETWORK_ERROR_DHCP_FAIL:
set_dhcp_error(network);
break;
@@ -1973,6 +2037,18 @@ bool connman_network_get_connected(struct connman_network *network)
return network->connected;
}
+#if defined TIZEN_EXT
+bool connman_network_get_psk_sha256(struct connman_network *network)
+{
+ return network->is_psk_sha256;
+}
+
+void connman_network_set_psk_sha256(struct connman_network *network, bool is_psk_sha256)
+{
+ network->is_psk_sha256 = is_psk_sha256;
+}
+#endif
+
/**
* connman_network_get_associating:
* @network: network structure
@@ -2035,6 +2111,63 @@ out:
return err;
}
+#if defined TIZEN_EXT
+char *__connman_network_get_dhcp_status(const char *ifname)
+{
+ char *status = NULL;
+
+ if (!ifname)
+ return NULL;
+
+ status = g_hash_table_lookup(dhcp_status_list, ifname);
+ DBG("ifname: %s, DHCP status: %s", ifname, status);
+
+ return status;
+}
+
+static void __connman_network_update_dhcp_status(
+ const char *ifname, const char *status)
+{
+ if (!ifname || !status)
+ return;
+
+ g_hash_table_replace(dhcp_status_list, g_strdup(ifname), g_strdup(status));
+}
+
+dbus_bool_t __connman_network_notify_dhcp_changed(const char *key, const char *val)
+{
+ DBusMessage *signal;
+ DBusMessageIter iter;
+ dbus_bool_t result = FALSE;
+
+ if (val)
+ DBG("key %s, val %s", key, val);
+ else
+ DBG("key %s, val NULL", key);
+
+ signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
+ CONNMAN_MANAGER_INTERFACE, "DhcpChanged");
+
+ if (!signal)
+ return result;
+
+ dbus_message_iter_init_append(signal, &iter);
+ connman_dbus_property_append_basic(&iter, key, DBUS_TYPE_STRING, &val);
+
+ result = dbus_connection_send(connection, signal, NULL);
+ if (result)
+ DBG("Successfuly sent signal");
+ else
+ DBG("Fail to send signal");
+
+ dbus_message_unref(signal);
+
+ __connman_network_update_dhcp_status(val, key);
+
+ return result;
+}
+#endif
+
/**
* __connman_network_connect:
* @network: network structure
@@ -2345,12 +2478,11 @@ int connman_network_set_bssid(struct connman_network *network,
if (bssid == NULL)
return -EINVAL;
-#if defined TIZEN_EXT
+
if (!simplified_log)
-#endif
- DBG("network %p bssid %02x:%02x:%02x:%02x:%02x:%02x", network,
- bssid[0], bssid[1], bssid[2],
- bssid[3], bssid[4], bssid[5]);
+ DBG("network %p bssid %02x:%02x:%02x:%02x:%02x:%02x", network,
+ bssid[0], bssid[1], bssid[2],
+ bssid[3], bssid[4], bssid[5]);
for (;i < WIFI_BSSID_LEN_MAX;i++)
network->wifi.bssid[i] = bssid[i];
@@ -2416,6 +2548,20 @@ int connman_network_get_maxspeed(struct connman_network *network)
return 0;
}
+int connman_network_set_sec_list(struct connman_network *network,
+ GSList *sec_list)
+{
+ g_slist_free(network->wifi.sec_list);
+ network->wifi.sec_list = sec_list;
+
+ return 0;
+}
+
+void *connman_network_get_sec_list(struct connman_network *network)
+{
+ return network->wifi.sec_list;
+}
+
int connman_network_set_maxrate(struct connman_network *network,
unsigned int maxrate)
{
@@ -2439,10 +2585,8 @@ int connman_network_set_enc_mode(struct connman_network *network,
if (encryption_mode == NULL)
return -EINVAL;
-#if defined TIZEN_EXT
if (!simplified_log)
-#endif
- DBG("network %p encryption mode %s", network, encryption_mode);
+ DBG("network %p encryption mode %s", network, encryption_mode);
g_strlcpy(network->wifi.encryption_mode, encryption_mode,
WIFI_ENCYPTION_MODE_LEN_MAX);
@@ -2535,11 +2679,9 @@ int connman_network_set_countrycode(struct connman_network *network,
if (country_code == NULL)
return -EINVAL;
-#if defined TIZEN_EXT
if (!simplified_log)
-#endif
- DBG("network %p Country Code %02x:%02x",network,
- country_code[0],country_code[1]);
+ DBG("network %p Country Code %02x:%02x",network,
+ country_code[0],country_code[1]);
for (; i < WIFI_COUNTRY_CODE_LEN; i++)
network->wifi.country_code[i] = country_code[i];
@@ -2555,19 +2697,23 @@ unsigned char *connman_network_get_countrycode(struct connman_network *network)
int connman_network_set_bssid_list(struct connman_network *network,
GSList *bssids)
{
+ unsigned int max_bssid_count;
+
g_slist_free_full(network->wifi.bssid_list, g_free);
network->wifi.bssid_list = bssids;
+ max_bssid_count = g_slist_length(bssids);
+ if (network->wifi.max_bssid_count < max_bssid_count)
+ network->wifi.max_bssid_count = max_bssid_count;
+
return 0;
}
int connman_network_set_phy_mode(struct connman_network *network,
ieee80211_modes_e mode)
{
-#if defined TIZEN_EXT
if (!simplified_log)
-#endif
- DBG("network %p phy mode %d", network, mode);
+ DBG("network %p phy mode %d", network, mode);
network->wifi.phy_mode = mode;
return 0;
@@ -2597,6 +2743,11 @@ void *connman_network_get_bssid_list(struct connman_network *network)
return network->wifi.bssid_list;
}
+unsigned int connman_network_get_max_bssid_count(struct connman_network *network)
+{
+ return network->wifi.max_bssid_count;
+}
+
int connman_network_set_last_connected_bssid(struct connman_network *network,
const unsigned char *bssid)
{
@@ -2625,6 +2776,8 @@ void connman_network_set_assoc_reject_table(struct connman_network *network,
if (!assoc_reject_table)
return;
+ g_hash_table_destroy(network->wifi.assoc_reject_table);
+
network->wifi.assoc_reject_table = assoc_reject_table;
}
@@ -2635,6 +2788,38 @@ GHashTable *connman_network_get_assoc_reject_table(struct connman_network *netwo
return network->wifi.assoc_reject_table;
}
+
+__time_t connman_network_get_roam_scan_time(struct connman_network *network)
+{
+ return network->wifi.roam_scan_time;
+}
+
+void connman_network_set_roam_scan_time(struct connman_network *network,
+ __time_t roam_scan_time)
+{
+ network->wifi.roam_scan_time = roam_scan_time;
+}
+
+int connman_network_get_snr(struct connman_network *network)
+{
+ return network->wifi.snr;
+}
+
+void connman_network_set_snr(struct connman_network *network, int snr)
+{
+ network->wifi.snr = snr;
+}
+
+unsigned int connman_network_get_est_throughput(struct connman_network *network)
+{
+ return network->wifi.est_throughput;
+}
+
+void connman_network_set_est_throughput(struct connman_network *network,
+ unsigned int est_throughput)
+{
+ network->wifi.est_throughput = est_throughput;
+}
#endif
int connman_network_set_nameservers(struct connman_network *network,
@@ -2755,6 +2940,21 @@ int connman_network_set_wifi_channel(struct connman_network *network,
return 0;
}
+int connman_network_set_autoconnect(struct connman_network *network,
+ bool autoconnect)
+{
+ if (!network->driver || !network->driver->set_autoconnect)
+ return 0;
+ return network->driver->set_autoconnect(network, autoconnect);
+}
+
+bool __connman_network_native_autoconnect(struct connman_network *network)
+{
+ if (!network->driver || !network->driver->set_autoconnect)
+ return false;
+ return true;
+}
+
uint16_t connman_network_get_wifi_channel(struct connman_network *network)
{
return network->wifi.channel;
@@ -2844,6 +3044,12 @@ int connman_network_set_string(struct connman_network *network,
} else if (g_str_equal(key, "WiFi.NetAccessKey")) {
g_free(network->wifi.net_access_key);
network->wifi.net_access_key = g_strdup(value);
+ } else if (g_str_equal(key, "WiFi.RoamingCurBSSID")) {
+ g_free(network->wifi.roaming_cur_bssid);
+ network->wifi.roaming_cur_bssid = g_strdup(value);
+ } else if (g_str_equal(key, "WiFi.RoamingDstBSSID")) {
+ g_free(network->wifi.roaming_dst_bssid);
+ network->wifi.roaming_dst_bssid = g_strdup(value);
#endif
} else {
return -EINVAL;
@@ -2871,15 +3077,7 @@ const char *connman_network_get_string(struct connman_network *network,
else if (g_str_equal(key, "WiFi.Mode"))
return network->wifi.mode;
else if (g_str_equal(key, "WiFi.Security"))
-#if defined TIZEN_EXT
- if (network->wifi.rsn_mode != true ||
- g_str_equal(network->wifi.security, "ieee8021x"))
- return network->wifi.security;
- else
- return "rsn";
-#else
return network->wifi.security;
-#endif
else if (g_str_equal(key, "WiFi.Passphrase"))
return network->wifi.passphrase;
else if (g_str_equal(key, "WiFi.EAP"))
@@ -2917,6 +3115,10 @@ const char *connman_network_get_string(struct connman_network *network,
return network->wifi.c_sign_key;
else if (g_str_equal(key, "WiFi.NetAccessKey"))
return network->wifi.net_access_key;
+ else if (g_str_equal(key, "WiFi.RoamingCurBSSID"))
+ return network->wifi.roaming_cur_bssid;
+ else if (g_str_equal(key, "WiFi.RoamingDstBSSID"))
+ return network->wifi.roaming_dst_bssid;
#endif
return NULL;
@@ -2948,6 +3150,12 @@ int connman_network_set_bool(struct connman_network *network,
network->wifi.isHS20AP = value;
else if (g_strcmp0(key, "WiFi.TRANSITION_MODE") == 0)
network->wifi.owe_transition_mode = value;
+ else if (g_strcmp0(key, "WiFi.Roaming") == 0)
+ network->wifi.roaming_progress = value;
+ else if (g_strcmp0(key, "WiFi.RoamingDHCP") == 0)
+ network->wifi.roaming_dhcp = value;
+ else if (g_strcmp0(key, "WiFi.PMFRequired") == 0)
+ network->wifi.pmf_required = value;
#endif
return -EINVAL;
@@ -2976,8 +3184,14 @@ bool connman_network_get_bool(struct connman_network *network,
return network->default_internet;
else if (g_str_equal(key, "WiFi.HS20AP"))
return network->wifi.isHS20AP;
- else if (g_strcmp0(key, "WiFi.TRANSITION_MODE"))
+ else if (g_str_equal(key, "WiFi.TRANSITION_MODE"))
return network->wifi.owe_transition_mode;
+ else if (g_str_equal(key, "WiFi.Roaming"))
+ return network->wifi.roaming_progress;
+ else if (g_str_equal(key, "WiFi.RoamingDHCP"))
+ return network->wifi.roaming_dhcp;
+ else if (g_str_equal(key, "WiFi.PMFRequired"))
+ return network->wifi.pmf_required;
#endif
return false;
@@ -3068,6 +3282,7 @@ const void *connman_network_get_blob(struct connman_network *network,
return network->wifi.transition_mode_ssid;
#endif
}
+
return NULL;
}
@@ -3142,6 +3357,11 @@ void connman_network_update(struct connman_network *network)
int __connman_network_init(void)
{
DBG("");
+#if defined TIZEN_EXT
+ connection = connman_dbus_get_connection();
+ dhcp_status_list = g_hash_table_new_full(g_str_hash,
+ g_str_equal, g_free, g_free);
+#endif
return 0;
}
@@ -3149,4 +3369,9 @@ int __connman_network_init(void)
void __connman_network_cleanup(void)
{
DBG("");
+#if defined TIZEN_EXT
+ dbus_connection_unref(connection);
+ if (dhcp_status_list)
+ g_hash_table_destroy(dhcp_status_list);
+#endif
}
diff --git a/src/notifier.c b/src/notifier.c
index d1be47f6..2c271ee3 100644
--- a/src/notifier.c
+++ b/src/notifier.c
@@ -247,7 +247,7 @@ void __connman_notifier_service_remove(struct connman_service *service)
if (g_hash_table_lookup(service_hash, service)) {
/*
- * This is a tempory check for consistency. It can be
+ * This is a temporary check for consistency. It can be
* removed when there are no reports for the following
* error message.
*/
diff --git a/src/ntp.c b/src/ntp.c
index ccea3ea5..81b6835a 100755
--- a/src/ntp.c
+++ b/src/ntp.c
@@ -370,6 +370,7 @@ static void decode_msg(struct ntp_data *nd, void *base, size_t len,
connection = connman_dbus_get_connection();
if(!connection){
DBG("dbus connection does not exist");
+ nd->cb(false, nd->user_data);
return;
}
@@ -397,6 +398,7 @@ static void decode_msg(struct ntp_data *nd, void *base, size_t len,
}
dbus_connection_unref(connection);
dbus_message_unref(msg);
+ nd->cb(false, nd->user_data);
return;
}
@@ -407,6 +409,9 @@ static void decode_msg(struct ntp_data *nd, void *base, size_t len,
DBG("%lu cur seconds, %lu cur nsecs, %lu req seconds, %lu req nsecs",
cur.tv_sec, cur.tv_nsec, req.tv_sec, req.tv_nsec);
DBG("setting time");
+
+ __connman_clock_set_time_updated(true);
+ nd->cb(true, nd->user_data);
}
#else
if (offset < STEPTIME_MIN_OFFSET && offset > -STEPTIME_MIN_OFFSET) {
@@ -525,6 +530,13 @@ static gboolean received_data(GIOChannel *channel, GIOCondition condition,
}
}
+#if defined TIZEN_EXT
+ if (__connman_clock_timeupdates() == TIME_UPDATES_MANUAL) {
+ DBG("Skip time update.");
+ return TRUE;
+ }
+#endif
+
decode_msg(nd, iov.iov_base, iov.iov_len, tv, &mrx_time);
return TRUE;
diff --git a/src/peer.c b/src/peer.c
index 2102f119..bad5c841 100755
--- a/src/peer.c
+++ b/src/peer.c
@@ -154,7 +154,7 @@ static int start_dhcp_server(struct connman_peer *peer)
err = __connman_inet_modify_address(RTM_NEWADDR,
NLM_F_REPLACE | NLM_F_ACK, index, AF_INET,
- gateway, NULL, prefixlen, broadcast);
+ gateway, NULL, prefixlen, broadcast, true);
if (err < 0)
goto error;
@@ -983,7 +983,10 @@ void connman_peer_add_service(struct connman_peer *peer,
service = g_malloc0(sizeof(struct _peer_service));
service->type = type;
- service->data = g_memdup(data, data_length * sizeof(unsigned char));
+ if (data_length > 0) {
+ service->data = g_malloc(data_length * sizeof(unsigned char));
+ memcpy(service->data, data, data_length * sizeof(unsigned char));
+ }
service->length = data_length;
peer->services = g_slist_prepend(peer->services, service);
diff --git a/src/provider.c b/src/provider.c
index f1e4a067..195ae226 100755
--- a/src/provider.c
+++ b/src/provider.c
@@ -53,6 +53,7 @@ void __connman_provider_append_properties(struct connman_provider *provider,
DBusMessageIter *iter)
{
const char *host, *domain, *type;
+ dbus_bool_t split_routing;
if (!provider->driver || !provider->driver->get_property)
return;
@@ -72,6 +73,12 @@ void __connman_provider_append_properties(struct connman_provider *provider,
if (type)
connman_dbus_dict_append_basic(iter, "Type", DBUS_TYPE_STRING,
&type);
+
+ if (provider->vpn_service) {
+ split_routing = connman_provider_is_split_routing(provider);
+ connman_dbus_dict_append_basic(iter, "SplitRouting",
+ DBUS_TYPE_BOOLEAN, &split_routing);
+ }
}
struct connman_provider *
@@ -176,17 +183,24 @@ int __connman_provider_connect(struct connman_provider *provider,
else
return -EOPNOTSUPP;
- if (err < 0) {
- if (err != -EINPROGRESS)
- return err;
+ switch (err) {
+ case 0:
+ return 0;
+ case -EINPROGRESS:
provider_indicate_state(provider,
CONNMAN_SERVICE_STATE_ASSOCIATION);
-
+ /* fall through */
+ /*
+ * Return EINPROGRESS also for when there is an existing pending call.
+ * The state should not be indicated again but the real state is
+ * still in progress for the provider.
+ */
+ case -EALREADY:
return -EINPROGRESS;
}
- return 0;
+ return err;
}
int __connman_provider_remove_by_path(const char *path)
@@ -432,6 +446,15 @@ const char *__connman_provider_get_ident(struct connman_provider *provider)
return provider->identifier;
}
+const char * __connman_provider_get_transport_ident(
+ struct connman_provider *provider)
+{
+ if (provider && provider && provider->driver && provider->driver->get_property)
+ return provider->driver->get_property(provider, "Transport");
+
+ return NULL;
+}
+
int connman_provider_set_string(struct connman_provider *provider,
const char *key, const char *value)
{
@@ -489,7 +512,7 @@ void connman_provider_set_index(struct connman_provider *provider, int index)
ipconfig = __connman_service_get_ip4config(service);
if (!ipconfig) {
- DBG("Couldnt create ipconfig");
+ DBG("Couldn't create ipconfig");
goto done;
}
}
@@ -504,7 +527,7 @@ void connman_provider_set_index(struct connman_provider *provider, int index)
ipconfig = __connman_service_get_ip6config(service);
if (!ipconfig) {
- DBG("Couldnt create ipconfig for IPv6");
+ DBG("Couldn't create ipconfig for IPv6");
goto done;
}
}
@@ -589,6 +612,111 @@ int connman_provider_set_nameservers(struct connman_provider *provider,
return 0;
}
+void connman_provider_set_autoconnect(struct connman_provider *provider,
+ bool flag)
+{
+ if (!provider || !provider->vpn_service)
+ return;
+
+ /* Save VPN service if autoconnect value changes */
+ if (connman_service_set_autoconnect(provider->vpn_service, flag))
+ __connman_service_save(provider->vpn_service);
+}
+
+bool connman_provider_is_split_routing(struct connman_provider *provider)
+{
+ if (!provider || !provider->vpn_service)
+ return false;
+
+ return __connman_service_is_split_routing(provider->vpn_service);
+}
+
+int connman_provider_set_split_routing(struct connman_provider *provider,
+ bool split_routing)
+{
+ struct connman_service *service;
+ enum connman_ipconfig_type type;
+ int service_index;
+ int vpn_index;
+ bool service_split_routing;
+ int err = 0;
+
+ DBG("");
+
+ if (!provider || !provider->vpn_service)
+ return -EINVAL;
+
+ service_split_routing = __connman_service_is_split_routing(
+ provider->vpn_service);
+
+ if (service_split_routing == split_routing) {
+ DBG("split_routing already set %s",
+ split_routing ? "true" : "false");
+ return -EALREADY;
+ }
+
+ switch (provider->family) {
+ case AF_INET:
+ type = CONNMAN_IPCONFIG_TYPE_IPV4;
+ break;
+ case AF_INET6:
+ type = CONNMAN_IPCONFIG_TYPE_IPV6;
+ break;
+ case AF_UNSPEC:
+ type = CONNMAN_IPCONFIG_TYPE_ALL;
+ break;
+ default:
+ type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
+ }
+
+ if (!__connman_service_is_connected_state(provider->vpn_service,
+ type)) {
+ DBG("%p VPN not connected", provider->vpn_service);
+ goto save;
+ }
+
+ vpn_index = __connman_service_get_index(provider->vpn_service);
+ service_index = __connman_connection_get_vpn_phy_index(vpn_index);
+ service = __connman_service_lookup_from_index(service_index);
+ if (!service)
+ goto save;
+
+ if (split_routing)
+ err = __connman_service_move(service, provider->vpn_service,
+ true);
+ else
+ err = __connman_service_move(provider->vpn_service, service,
+ true);
+
+ if (err) {
+ connman_warn("cannot move service %p and VPN %p error %d",
+ service, provider->vpn_service, err);
+
+ /*
+ * In case of error notify vpnd about the current split routing
+ * state.
+ */
+ __connman_service_split_routing_changed(provider->vpn_service);
+ goto out;
+ }
+
+save:
+ __connman_service_set_split_routing(provider->vpn_service,
+ split_routing);
+ __connman_service_save(provider->vpn_service);
+
+out:
+ return err;
+}
+
+int connman_provider_get_family(struct connman_provider *provider)
+{
+ if (!provider)
+ return AF_UNSPEC;
+
+ return provider->family;
+}
+
static void unregister_provider(gpointer data)
{
struct connman_provider *provider = data;
diff --git a/src/resolver.c b/src/resolver.c
index 7ec2150b..8bfea3ce 100755
--- a/src/resolver.c
+++ b/src/resolver.c
@@ -93,9 +93,22 @@ static void resolvfile_remove_entries(GList *entries)
g_list_free(entries);
}
-static int resolvfile_export(void)
+static bool already_exported(GList *export_list, const char *str)
{
GList *list;
+
+ for (list = export_list; list; list = g_list_next(list)) {
+ const char *str0 = list->data;
+ if (g_strcmp0(str0, str) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+static int resolvfile_export(void)
+{
+ GList *list, *export_list;
GString *content;
int fd, err;
unsigned int count;
@@ -109,6 +122,7 @@ static int resolvfile_export(void)
* MAXDNSRCH/MAXNS entries are used.
*/
+ export_list = NULL;
for (count = 0, list = g_list_first(resolvfile_list);
list && (count < MAXDNSRCH);
list = g_list_next(list)) {
@@ -117,16 +131,25 @@ static int resolvfile_export(void)
if (!entry->domain)
continue;
+ if (already_exported(export_list, entry->domain))
+ continue;
+
if (count == 0)
g_string_append_printf(content, "search ");
g_string_append_printf(content, "%s ", entry->domain);
+
+ export_list = g_list_append(export_list, entry->domain);
+
count++;
}
+ g_list_free(export_list);
+
if (count)
g_string_append_printf(content, "\n");
+ export_list = NULL;
for (count = 0, list = g_list_first(resolvfile_list);
list && (count < MAXNS);
list = g_list_next(list)) {
@@ -135,10 +158,16 @@ static int resolvfile_export(void)
if (!entry->server)
continue;
- g_string_append_printf(content, "nameserver %s\n",
- entry->server);
+ if (already_exported(export_list, entry->server))
+ continue;
+
+ g_string_append_printf(content, "nameserver %s\n", entry->server);
+
+ export_list = g_list_append(export_list, entry->server);
+
count++;
}
+ g_list_free(export_list);
old_umask = umask(022);
@@ -182,7 +211,7 @@ int __connman_resolvfile_append(int index, const char *domain,
{
struct resolvfile_entry *entry;
- DBG("index %d server %s", index, server);
+ DBG("index %d domain %s server %s", index, domain, server);
if (index < 0)
return -ENOENT;
@@ -205,7 +234,7 @@ int __connman_resolvfile_remove(int index, const char *domain,
{
GList *list, *matches = NULL;
- DBG("index %d server %s", index, server);
+ DBG("index %d domain %s server %s", index, domain, server);
for (list = resolvfile_list; list; list = g_list_next(list)) {
struct resolvfile_entry *entry = list->data;
diff --git a/src/rtnl.c b/src/rtnl.c
index 7da55fa5..6a47a8c1 100644
--- a/src/rtnl.c
+++ b/src/rtnl.c
@@ -217,6 +217,9 @@ static void read_uevent(struct interface_data *interface)
} else if (strcmp(line + 8, "bond") == 0) {
interface->service_type = CONNMAN_SERVICE_TYPE_ETHERNET;
interface->device_type = CONNMAN_DEVICE_TYPE_ETHERNET;
+ } else if (strcmp(line + 8, "dsa") == 0) {
+ interface->service_type = CONNMAN_SERVICE_TYPE_ETHERNET;
+ interface->device_type = CONNMAN_DEVICE_TYPE_ETHERNET;
} else {
interface->service_type = CONNMAN_SERVICE_TYPE_UNKNOWN;
interface->device_type = CONNMAN_DEVICE_TYPE_UNKNOWN;
@@ -591,14 +594,15 @@ static void process_newlink(unsigned short type, int index, unsigned flags,
__connman_technology_add_interface(interface->service_type,
interface->index, interface->ident);
- for (list = watch_list; list; list = list->next) {
+ list = watch_list;
+ while (list) {
+ GSList *next = list->next;
struct watch_data *watch = list->data;
- if (watch->index != index)
- continue;
-
- if (watch->newlink)
+ if (watch->index == index && watch->newlink)
watch->newlink(flags, change, watch->user_data);
+
+ list = next;
}
}
@@ -1452,75 +1456,71 @@ static const char *type2string(uint16_t type)
static GIOChannel *channel = NULL;
static guint channel_watch = 0;
-struct rtnl_request {
- struct nlmsghdr hdr;
- struct rtgenmsg msg;
-};
-#define RTNL_REQUEST_SIZE (sizeof(struct nlmsghdr) + sizeof(struct rtgenmsg))
+#define RTNL_REQUEST_SIZE (NLMSG_HDRLEN + NLMSG_ALIGN(sizeof(struct rtgenmsg)))
static GSList *request_list = NULL;
static guint32 request_seq = 0;
-static struct rtnl_request *find_request(guint32 seq)
+static struct nlmsghdr *find_request(guint32 seq)
{
GSList *list;
for (list = request_list; list; list = list->next) {
- struct rtnl_request *req = list->data;
+ struct nlmsghdr *hdr = list->data;
- if (req->hdr.nlmsg_seq == seq)
- return req;
+ if (hdr->nlmsg_seq == seq)
+ return hdr;
}
return NULL;
}
-static int send_request(struct rtnl_request *req)
+static int send_request(struct nlmsghdr *hdr)
{
struct sockaddr_nl addr;
int sk;
DBG("%s len %d type %d flags 0x%04x seq %d",
- type2string(req->hdr.nlmsg_type),
- req->hdr.nlmsg_len, req->hdr.nlmsg_type,
- req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
+ type2string(hdr->nlmsg_type),
+ hdr->nlmsg_len, hdr->nlmsg_type,
+ hdr->nlmsg_flags, hdr->nlmsg_seq);
sk = g_io_channel_unix_get_fd(channel);
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
- return sendto(sk, req, req->hdr.nlmsg_len, 0,
+ return sendto(sk, hdr, hdr->nlmsg_len, 0,
(struct sockaddr *) &addr, sizeof(addr));
}
-static int queue_request(struct rtnl_request *req)
+static int queue_request(struct nlmsghdr *hdr)
{
- request_list = g_slist_append(request_list, req);
+ request_list = g_slist_append(request_list, hdr);
if (g_slist_length(request_list) > 1)
return 0;
- return send_request(req);
+ return send_request(hdr);
}
static int process_response(guint32 seq)
{
- struct rtnl_request *req;
+ struct nlmsghdr *hdr;
DBG("seq %d", seq);
- req = find_request(seq);
- if (req) {
- request_list = g_slist_remove(request_list, req);
- g_free(req);
+ hdr = find_request(seq);
+ if (hdr) {
+ request_list = g_slist_remove(request_list, hdr);
+ g_free(hdr);
}
- req = g_slist_nth_data(request_list, 0);
- if (!req)
+ hdr = g_slist_nth_data(request_list, 0);
+ if (!hdr)
return 0;
- return send_request(req);
+ return send_request(hdr);
}
static void rtnl_message(void *buf, size_t len)
@@ -1635,62 +1635,65 @@ static gboolean netlink_event(GIOChannel *chan, GIOCondition cond, gpointer data
static int send_getlink(void)
{
- struct rtnl_request *req;
+ struct nlmsghdr *hdr;
+ struct rtgenmsg *msg;
DBG("");
- req = g_try_malloc0(RTNL_REQUEST_SIZE);
- if (!req)
- return -ENOMEM;
+ hdr = g_malloc0(RTNL_REQUEST_SIZE);
+
+ hdr->nlmsg_len = RTNL_REQUEST_SIZE;
+ hdr->nlmsg_type = RTM_GETLINK;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ hdr->nlmsg_pid = 0;
+ hdr->nlmsg_seq = request_seq++;
- req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
- req->hdr.nlmsg_type = RTM_GETLINK;
- req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
- req->hdr.nlmsg_pid = 0;
- req->hdr.nlmsg_seq = request_seq++;
- req->msg.rtgen_family = AF_INET;
+ msg = (struct rtgenmsg *) NLMSG_DATA(hdr);
+ msg->rtgen_family = AF_INET;
- return queue_request(req);
+ return queue_request(hdr);
}
static int send_getaddr(void)
{
- struct rtnl_request *req;
+ struct nlmsghdr *hdr;
+ struct rtgenmsg *msg;
DBG("");
- req = g_try_malloc0(RTNL_REQUEST_SIZE);
- if (!req)
- return -ENOMEM;
+ hdr = g_malloc0(RTNL_REQUEST_SIZE);
- req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
- req->hdr.nlmsg_type = RTM_GETADDR;
- req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
- req->hdr.nlmsg_pid = 0;
- req->hdr.nlmsg_seq = request_seq++;
- req->msg.rtgen_family = AF_INET;
+ hdr->nlmsg_len = RTNL_REQUEST_SIZE;
+ hdr->nlmsg_type = RTM_GETADDR;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ hdr->nlmsg_pid = 0;
+ hdr->nlmsg_seq = request_seq++;
- return queue_request(req);
+ msg = (struct rtgenmsg *) NLMSG_DATA(hdr);
+ msg->rtgen_family = AF_INET;
+
+ return queue_request(hdr);
}
static int send_getroute(void)
{
- struct rtnl_request *req;
+ struct nlmsghdr *hdr;
+ struct rtgenmsg *msg;
DBG("");
- req = g_try_malloc0(RTNL_REQUEST_SIZE);
- if (!req)
- return -ENOMEM;
+ hdr = g_malloc0(RTNL_REQUEST_SIZE);
+
+ hdr->nlmsg_len = RTNL_REQUEST_SIZE;
+ hdr->nlmsg_type = RTM_GETROUTE;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ hdr->nlmsg_pid = 0;
+ hdr->nlmsg_seq = request_seq++;
- req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
- req->hdr.nlmsg_type = RTM_GETROUTE;
- req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
- req->hdr.nlmsg_pid = 0;
- req->hdr.nlmsg_seq = request_seq++;
- req->msg.rtgen_family = AF_INET;
+ msg = (struct rtgenmsg *) NLMSG_DATA(hdr);
+ msg->rtgen_family = AF_INET;
- return queue_request(req);
+ return queue_request(hdr);
}
static gboolean update_timeout_cb(gpointer user_data)
@@ -1853,14 +1856,14 @@ void __connman_rtnl_cleanup(void)
update_list = NULL;
for (list = request_list; list; list = list->next) {
- struct rtnl_request *req = list->data;
+ struct nlmsghdr *hdr= list->data;
DBG("%s len %d type %d flags 0x%04x seq %d",
- type2string(req->hdr.nlmsg_type),
- req->hdr.nlmsg_len, req->hdr.nlmsg_type,
- req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
+ type2string(hdr->nlmsg_type),
+ hdr->nlmsg_len, hdr->nlmsg_type,
+ hdr->nlmsg_flags, hdr->nlmsg_seq);
- g_free(req);
+ g_free(hdr);
list->data = NULL;
}
diff --git a/src/service.c b/src/service.c
index 90ff7e5e..2ac5a04f 100755
--- a/src/service.c
+++ b/src/service.c
@@ -31,10 +31,16 @@
#include <ctype.h>
#include <stdint.h>
+#if defined TIZEN_EXT
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
#include <connman/storage.h>
#include <connman/setting.h>
#include <connman/agent.h>
+#include "src/shared/util.h"
+
#include "connman.h"
#define CONNECT_TIMEOUT 120
@@ -42,9 +48,7 @@
#if defined TIZEN_EXT
#define WIFI_BSSID_STR_LEN 18
#define MAX_WIFI_PROFILES 200
-#endif
-#if defined TIZEN_EXT
#define FREQ_RANGE_24GHZ_CHANNEL_1 2412
#define FREQ_RANGE_24GHZ_CHANNEL_14 2484
#define FREQ_RANGE_5GHZ_CHANNEL_32 5160
@@ -53,16 +57,23 @@
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
#endif
+#define VPN_AUTOCONNECT_TIMEOUT_DEFAULT 1
+#define VPN_AUTOCONNECT_TIMEOUT_STEP 30
+#define VPN_AUTOCONNECT_TIMEOUT_ATTEMPTS_THRESHOLD 270
static DBusConnection *connection = NULL;
static GList *service_list = NULL;
static GHashTable *service_hash = NULL;
+static GHashTable *passphrase_requested = NULL;
static GSList *counter_list = NULL;
static unsigned int autoconnect_id = 0;
static unsigned int vpn_autoconnect_id = 0;
static struct connman_service *current_default = NULL;
static bool services_dirty = false;
+static bool enable_online_to_ready_transition = false;
+static unsigned int online_check_initial_interval = 0;
+static unsigned int online_check_max_interval = 0;
#if defined TIZEN_EXT
static bool auto_connect_mode = TRUE;
@@ -72,9 +83,10 @@ struct saved_profiles {
gchar *profile_name;
};
-#endif
+static unsigned char invalid_bssid[WIFI_BSSID_LEN_MAX] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
-#if defined TIZEN_EXT
enum connman_ins_preferred_freq {
CONNMAN_INS_PREFERRED_FREQ_UNKNOWN,
CONNMAN_INS_PREFERRED_FREQ_24GHZ,
@@ -100,11 +112,7 @@ struct connman_ins_settings {
};
static struct connman_ins_settings ins_settings;
-
-static unsigned char invalid_bssid[WIFI_BSSID_LEN_MAX] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-#endif
+#endif /* defined TIZEN_EXT */
struct connman_stats {
bool valid;
@@ -137,7 +145,7 @@ struct connman_service {
bool hidden;
bool ignore;
bool autoconnect;
- GTimeVal modified;
+ struct timeval modified;
unsigned int order;
char *name;
char *passphrase;
@@ -185,8 +193,8 @@ struct connman_service {
bool wps;
bool wps_advertizing;
guint online_timeout;
- int online_check_interval_ipv4;
- int online_check_interval_ipv6;
+ unsigned int online_check_interval_ipv4;
+ unsigned int online_check_interval_ipv6;
bool do_split_routing;
bool new_service;
bool hidden_service;
@@ -226,24 +234,19 @@ struct connman_service {
enum connman_dnsconfig_method dns_config_method_ipv4;
enum connman_dnsconfig_method dns_config_method_ipv6;
-#endif
-#if defined TIZEN_EXT
+
char *connector;
char *c_sign_key;
char *net_access_key;
-#endif
-#if defined TIZEN_EXT
unsigned char last_connected_bssid[WIFI_BSSID_LEN_MAX];
bool is_internet_connection;
int assoc_reject_count;
-#if defined TIZEN_EXT_INS
int score_last_user_selection;
int score_last_connected;
int score_frequency;
int score_security_priority;
int score_internet_connection;
int score_strength;
-#endif
int ins_score;
#endif
#if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
@@ -261,6 +264,7 @@ static struct connman_ipconfig *create_ip4config(struct connman_service *service
static struct connman_ipconfig *create_ip6config(struct connman_service *service,
int index);
static void dns_changed(struct connman_service *service);
+static void vpn_auto_connect(void);
struct find_data {
const char *path;
@@ -272,9 +276,7 @@ struct assoc_reject_data {
char *bssid;
GSList *reject_time_list;
};
-#endif
-#if defined TIZEN_EXT
/*
* Public APIs to use user_pdn_connection_refcount
*/
@@ -353,6 +355,8 @@ static const char *reason2string(enum connman_service_connect_reason reason)
return "auto";
case CONNMAN_SERVICE_CONNECT_REASON_SESSION:
return "session";
+ case CONNMAN_SERVICE_CONNECT_REASON_NATIVE:
+ return "native";
}
return "unknown";
@@ -471,6 +475,10 @@ static const char *security2string(enum connman_service_security security)
#endif
case CONNMAN_SERVICE_SECURITY_8021X:
return "ieee8021x";
+#if defined TIZEN_EXT
+ default:
+ break;
+#endif
}
return NULL;
@@ -517,6 +525,10 @@ static const char *error2string(enum connman_service_error error)
return "login-failed";
case CONNMAN_SERVICE_ERROR_AUTH_FAILED:
return "auth-failed";
+#ifdef TIZEN_EXT
+ case CONNMAN_SERVICE_ERROR_ASSOC_FAILED:
+ return "assoc-failed";
+#endif
case CONNMAN_SERVICE_ERROR_INVALID_KEY:
return "invalid-key";
case CONNMAN_SERVICE_ERROR_BLOCKED:
@@ -581,7 +593,26 @@ static enum connman_dnsconfig_method __connman_dnsconfig_string2method(
}
#endif
-static void set_split_routing(struct connman_service *service, bool value)
+void __connman_service_split_routing_changed(struct connman_service *service)
+{
+ dbus_bool_t split_routing;
+
+ if (!service->path)
+ return;
+
+ if (!allow_property_changed(service))
+ return;
+
+ split_routing = service->do_split_routing;
+ if (!connman_dbus_property_changed_basic(service->path,
+ CONNMAN_SERVICE_INTERFACE, "SplitRouting",
+ DBUS_TYPE_BOOLEAN, &split_routing))
+ connman_warn("cannot send SplitRouting property change on %s",
+ service->identifier);
+}
+
+void __connman_service_set_split_routing(struct connman_service *service,
+ bool value)
{
if (service->type != CONNMAN_SERVICE_TYPE_VPN)
return;
@@ -592,6 +623,12 @@ static void set_split_routing(struct connman_service *service, bool value)
service->order = 0;
else
service->order = 10;
+
+ /*
+ * In order to make sure the value is propagated also when loading the
+ * VPN service signal the value regardless of the value change.
+ */
+ __connman_service_split_routing_changed(service);
}
int __connman_service_load_modifiable(struct connman_service *service)
@@ -617,9 +654,10 @@ int __connman_service_load_modifiable(struct connman_service *service)
#endif
break;
case CONNMAN_SERVICE_TYPE_VPN:
- set_split_routing(service, g_key_file_get_boolean(keyfile,
- service->identifier,
- "SplitRouting", NULL));
+ __connman_service_set_split_routing(service,
+ g_key_file_get_boolean(keyfile,
+ service->identifier,
+ "SplitRouting", NULL));
/* fall through */
case CONNMAN_SERVICE_TYPE_WIFI:
@@ -638,7 +676,7 @@ int __connman_service_load_modifiable(struct connman_service *service)
str = g_key_file_get_string(keyfile,
service->identifier, "Modified", NULL);
if (str) {
- g_time_val_from_iso8601(str, &service->modified);
+ util_iso8601_to_timeval(str, &service->modified);
g_free(str);
}
@@ -794,6 +832,9 @@ static void save_assoc_reject(gpointer key, gpointer value, gpointer user_data)
GSList *list;
char *val_str;
+ if (!assoc_rd)
+ return;
+
if (g_slist_length(assoc_rd->reject_time_list) < 1)
return;
@@ -816,7 +857,8 @@ static void count_assoc_reject(gpointer key, gpointer value, gpointer user_data)
struct assoc_reject_data *assoc_data = value;
int *assoc_reject_count = user_data;
- *assoc_reject_count += g_slist_length(assoc_data->reject_time_list);
+ if (assoc_data)
+ *assoc_reject_count += g_slist_length(assoc_data->reject_time_list);
}
static bool update_assoc_reject(struct connman_service *service)
@@ -831,10 +873,10 @@ static bool update_assoc_reject(struct connman_service *service)
if (assoc_reject_table) {
assoc_reject_count = 0;
g_hash_table_foreach(assoc_reject_table, count_assoc_reject, &assoc_reject_count);
-#if defined TIZEN_EXT_INS
+
DBG("assoc reject count [%d -> %d]",
service->assoc_reject_count, assoc_reject_count);
-#endif
+
if (service->assoc_reject_count != assoc_reject_count) {
service->assoc_reject_count = assoc_reject_count;
return true;
@@ -860,10 +902,8 @@ static int service_ext_load(struct connman_service *service)
int i;
int err = 0;
-#if defined TIZEN_EXT
if (!simplified_log)
-#endif
- DBG("service %p", service);
+ DBG("service %p", service);
if (!service->network)
return -EINVAL;
@@ -923,9 +963,7 @@ static int service_ext_load(struct connman_service *service)
reject_data->reject_time_list = g_slist_append(reject_data->reject_time_list,
GINT_TO_POINTER(reject_time));
-#if defined TIZEN_EXT_INS
DBG("assoc reject [%s_%ld]", bssid, reject_time);
-#endif
g_strfreev(bssid_time);
}
@@ -954,7 +992,8 @@ static int service_ext_save(struct connman_service *service)
if (service->type != CONNMAN_SERVICE_TYPE_WIFI)
return -EINVAL;
- keyfile = __connman_storage_open_service(service->identifier);
+ keyfile = connman_storage_load_service(service->identifier);
+
if (!keyfile)
return -EIO;
@@ -980,9 +1019,7 @@ static int service_ext_save(struct connman_service *service)
g_key_file_set_string(keyfile, identifier,
"LastConnectedBSSID", bssid_str->str);
-#if defined TIZEN_EXT_INS
DBG("last connected bssid[%s]", bssid_str->str);
-#endif
g_string_free(bssid_str, TRUE);
}
@@ -1006,9 +1043,7 @@ next:
g_key_file_set_string_list(keyfile, service->identifier,
"AssocReject", (const gchar **)reject_list, reject_len);
-#if defined TIZEN_EXT_INS
DBG("assoc reject table [%d]", reject_len);
-#endif
g_strfreev(reject_list);
g_string_free(reject_str, TRUE);
@@ -1022,7 +1057,7 @@ done:
g_key_file_free(keyfile);
return err;
}
-#endif
+#endif /* defined TIZEN_EXT */
static int service_load(struct connman_service *service)
{
@@ -1061,9 +1096,10 @@ static int service_load(struct connman_service *service)
#endif
break;
case CONNMAN_SERVICE_TYPE_VPN:
- set_split_routing(service, g_key_file_get_boolean(keyfile,
- service->identifier,
- "SplitRouting", NULL));
+ __connman_service_set_split_routing(service,
+ g_key_file_get_boolean(keyfile,
+ service->identifier,
+ "SplitRouting", NULL));
autoconnect = g_key_file_get_boolean(keyfile,
service->identifier, "AutoConnect", &error);
@@ -1123,44 +1159,46 @@ static int service_load(struct connman_service *service)
}
#if defined TIZEN_EXT
- /* Last connected BSSID */
- if (service->network) {
- gchar *bssid_str;
- unsigned char last_connected_bssid[WIFI_BSSID_LEN_MAX];
- char **str_list;
- unsigned int i;
+ if (TIZEN_INS_ENABLED) {
+ /* Last connected BSSID */
+ if (service->network) {
+ gchar *bssid_str;
+ unsigned char last_connected_bssid[WIFI_BSSID_LEN_MAX];
+ char **str_list;
+ unsigned int i;
- bssid_str = g_key_file_get_string(keyfile,
- service->identifier, "LastConnectedBSSID", NULL);
+ bssid_str = g_key_file_get_string(keyfile,
+ service->identifier, "LastConnectedBSSID", NULL);
- if (bssid_str) {
- str_list = g_strsplit(bssid_str, ":", 0);
+ if (bssid_str) {
+ str_list = g_strsplit(bssid_str, ":", 0);
- if (str_list) {
- for (i = 0; i < WIFI_BSSID_LEN_MAX; i++)
- last_connected_bssid[i] = strtol(str_list[i], NULL, 16);
+ if (str_list) {
+ for (i = 0; i < WIFI_BSSID_LEN_MAX; i++)
+ last_connected_bssid[i] = strtol(str_list[i], NULL, 16);
- memcpy(service->last_connected_bssid,
- last_connected_bssid, WIFI_BSSID_LEN_MAX);
+ memcpy(service->last_connected_bssid,
+ last_connected_bssid, WIFI_BSSID_LEN_MAX);
- connman_network_set_last_connected_bssid(service->network,
- last_connected_bssid);
+ connman_network_set_last_connected_bssid(service->network,
+ last_connected_bssid);
- g_strfreev(str_list);
- }
+ g_strfreev(str_list);
+ }
- g_free(bssid_str);
+ g_free(bssid_str);
+ }
}
- }
- /* Internet connection */
- internet_connection = g_key_file_get_boolean(keyfile,
- service->identifier, "InternetConnection", &error);
- if (!error)
- service->is_internet_connection = internet_connection;
+ /* Internet connection */
+ internet_connection = g_key_file_get_boolean(keyfile,
+ service->identifier, "InternetConnection", &error);
+ if (!error)
+ service->is_internet_connection = internet_connection;
- g_clear_error(&error);
-#endif
+ g_clear_error(&error);
+ }
+#endif /* defined TIZEN_EXT */
/* fall through */
case CONNMAN_SERVICE_TYPE_GADGET:
@@ -1191,15 +1229,17 @@ static int service_load(struct connman_service *service)
str = g_key_file_get_string(keyfile,
service->identifier, "Modified", NULL);
if (str) {
- g_time_val_from_iso8601(str, &service->modified);
+ util_iso8601_to_timeval(str, &service->modified);
g_free(str);
}
str = g_key_file_get_string(keyfile,
service->identifier, "Passphrase", NULL);
if (str) {
+ char *dec = g_strcompress(str);
+ g_free(str);
g_free(service->passphrase);
- service->passphrase = str;
+ service->passphrase = dec;
}
if (service->ipconfig_ipv4)
@@ -1407,7 +1447,7 @@ static int service_save(struct connman_service *service)
if (service->new_service)
return -ESRCH;
- keyfile = __connman_storage_open_service(service->identifier);
+ keyfile = g_key_file_new();
if (!keyfile)
return -EIO;
@@ -1468,72 +1508,69 @@ static int service_save(struct connman_service *service)
"Frequency", freq);
#if defined TIZEN_EXT
- /* Last connected BSSID */
- if (memcmp(service->last_connected_bssid, invalid_bssid, WIFI_BSSID_LEN_MAX)) {
- char *identifier = service->identifier;
- GString *bssid_str;
- unsigned int i;
+ if (TIZEN_INS_ENABLED) {
+ /* Last connected BSSID */
+ if (memcmp(service->last_connected_bssid, invalid_bssid, WIFI_BSSID_LEN_MAX)) {
+ char *identifier = service->identifier;
+ GString *bssid_str;
+ unsigned int i;
- bssid_str = g_string_sized_new(18);
- if (!bssid_str) {
- err = -ENOMEM;
- goto done;
- }
+ bssid_str = g_string_sized_new(18);
+ if (!bssid_str) {
+ err = -ENOMEM;
+ goto done;
+ }
- for (i = 0; i < WIFI_BSSID_LEN_MAX; i++) {
- g_string_append_printf(bssid_str,
- "%02x", service->last_connected_bssid[i]);
- if (i < WIFI_BSSID_LEN_MAX - 1)
- g_string_append(bssid_str, ":");
- }
+ for (i = 0; i < WIFI_BSSID_LEN_MAX; i++) {
+ g_string_append_printf(bssid_str,
+ "%02x", service->last_connected_bssid[i]);
+ if (i < WIFI_BSSID_LEN_MAX - 1)
+ g_string_append(bssid_str, ":");
+ }
- g_key_file_set_string(keyfile, identifier,
+ g_key_file_set_string(keyfile, identifier,
"LastConnectedBSSID", bssid_str->str);
-#if defined TIZEN_EXT_INS
- DBG("last connected bssid[%s]", bssid_str->str);
-#endif
+ DBG("last connected bssid[%s]", bssid_str->str);
- g_string_free(bssid_str, TRUE);
- }
+ g_string_free(bssid_str, TRUE);
+ }
- /* Assoc reject */
- assoc_reject_table = connman_network_get_assoc_reject_table(service->network);
- if (assoc_reject_table && g_hash_table_size(assoc_reject_table) > 0) {
- GString *assoc_reject_str;
- char **assoc_reject_list;
- guint assoc_reject_len;
+ /* Assoc reject */
+ assoc_reject_table = connman_network_get_assoc_reject_table(service->network);
+ if (assoc_reject_table && g_hash_table_size(assoc_reject_table) > 0) {
+ GString *assoc_reject_str;
+ char **assoc_reject_list;
+ guint assoc_reject_len;
- assoc_reject_str = g_string_new(NULL);
- if (!assoc_reject_str) {
- err = -ENOMEM;
- goto done;
- }
+ assoc_reject_str = g_string_new(NULL);
+ if (!assoc_reject_str) {
+ err = -ENOMEM;
+ goto done;
+ }
- g_hash_table_foreach(assoc_reject_table, save_assoc_reject, assoc_reject_str);
+ g_hash_table_foreach(assoc_reject_table, save_assoc_reject, assoc_reject_str);
- assoc_reject_list = g_strsplit_set(assoc_reject_str->str, " ", 0);
- assoc_reject_len = g_strv_length(assoc_reject_list);
+ assoc_reject_list = g_strsplit_set(assoc_reject_str->str, " ", 0);
+ assoc_reject_len = g_strv_length(assoc_reject_list);
- g_key_file_set_string_list(keyfile, service->identifier,
- "AssocReject", (const gchar **)assoc_reject_list, assoc_reject_len);
+ g_key_file_set_string_list(keyfile, service->identifier,
+ "AssocReject", (const gchar **)assoc_reject_list, assoc_reject_len);
-#if defined TIZEN_EXT_INS
- DBG("assoc reject table [%d]", assoc_reject_len);
-#endif
+ DBG("assoc reject table [%d]", assoc_reject_len);
- g_strfreev(assoc_reject_list);
- g_string_free(assoc_reject_str, TRUE);
- } else
- g_key_file_remove_key(keyfile, service->identifier, "AssocReject", NULL);
+ g_strfreev(assoc_reject_list);
+ g_string_free(assoc_reject_str, TRUE);
+ } else
+ g_key_file_remove_key(keyfile, service->identifier, "AssocReject", NULL);
- /* Internet connection */
- g_key_file_set_boolean(keyfile, service->identifier,
- "InternetConnection", service->is_internet_connection);
-#if defined TIZEN_EXT_INS
- DBG("internet connection [%s]", service->is_internet_connection ? "true" : "false");
-#endif
-#endif
+ /* Internet connection */
+ g_key_file_set_boolean(keyfile, service->identifier,
+ "InternetConnection", service->is_internet_connection);
+
+ DBG("internet connection [%s]", service->is_internet_connection ? "true" : "false");
+ }
+#endif /* defined TIZEN_EXT */
}
/* fall through */
@@ -1543,9 +1580,6 @@ static int service_save(struct connman_service *service)
g_key_file_set_boolean(keyfile, service->identifier,
"Favorite", service->favorite);
- g_key_file_remove_key(keyfile, service->identifier,
- "Failure", NULL);
-
/* fall through */
case CONNMAN_SERVICE_TYPE_ETHERNET:
@@ -1559,37 +1593,35 @@ static int service_save(struct connman_service *service)
break;
}
- str = g_time_val_to_iso8601(&service->modified);
+ str = util_timeval_to_iso8601(&service->modified);
if (str) {
g_key_file_set_string(keyfile, service->identifier,
- "Modified", str);
+ "Modified", str);
g_free(str);
}
- if (service->passphrase && strlen(service->passphrase) > 0)
+ if (service->passphrase && strlen(service->passphrase) > 0) {
+ char *enc = g_strescape(service->passphrase, NULL);
g_key_file_set_string(keyfile, service->identifier,
- "Passphrase", service->passphrase);
- else
- g_key_file_remove_key(keyfile, service->identifier,
- "Passphrase", NULL);
+ "Passphrase", enc);
+ g_free(enc);
+ }
if (service->ipconfig_ipv4)
__connman_ipconfig_save(service->ipconfig_ipv4, keyfile,
- service->identifier, "IPv4.");
+ service->identifier, "IPv4.");
if (service->ipconfig_ipv6)
__connman_ipconfig_save(service->ipconfig_ipv6, keyfile,
- service->identifier, "IPv6.");
+ service->identifier, "IPv6.");
if (service->nameservers_config) {
guint len = g_strv_length(service->nameservers_config);
g_key_file_set_string_list(keyfile, service->identifier,
- "Nameservers",
+ "Nameservers",
(const gchar **) service->nameservers_config, len);
- } else
- g_key_file_remove_key(keyfile, service->identifier,
- "Nameservers", NULL);
+ }
#if defined TIZEN_EXT
if(service->dns_config_method_ipv4 != 0) {
@@ -1617,21 +1649,17 @@ static int service_save(struct connman_service *service)
guint len = g_strv_length(service->timeservers_config);
g_key_file_set_string_list(keyfile, service->identifier,
- "Timeservers",
+ "Timeservers",
(const gchar **) service->timeservers_config, len);
- } else
- g_key_file_remove_key(keyfile, service->identifier,
- "Timeservers", NULL);
+ }
if (service->domains) {
guint len = g_strv_length(service->domains);
g_key_file_set_string_list(keyfile, service->identifier,
- "Domains",
+ "Domains",
(const gchar **) service->domains, len);
- } else
- g_key_file_remove_key(keyfile, service->identifier,
- "Domains", NULL);
+ }
cst_str = proxymethod2string(service->proxy_config);
if (cst_str)
@@ -1644,9 +1672,7 @@ static int service_save(struct connman_service *service)
g_key_file_set_string_list(keyfile, service->identifier,
"Proxy.Servers",
(const gchar **) service->proxies, len);
- } else
- g_key_file_remove_key(keyfile, service->identifier,
- "Proxy.Servers", NULL);
+ }
if (service->excludes) {
guint len = g_strv_length(service->excludes);
@@ -1654,34 +1680,25 @@ static int service_save(struct connman_service *service)
g_key_file_set_string_list(keyfile, service->identifier,
"Proxy.Excludes",
(const gchar **) service->excludes, len);
- } else
- g_key_file_remove_key(keyfile, service->identifier,
- "Proxy.Excludes", NULL);
+ }
if (service->pac && strlen(service->pac) > 0)
g_key_file_set_string(keyfile, service->identifier,
- "Proxy.URL", service->pac);
- else
- g_key_file_remove_key(keyfile, service->identifier,
- "Proxy.URL", NULL);
+ "Proxy.URL", service->pac);
if (service->mdns_config)
g_key_file_set_boolean(keyfile, service->identifier,
- "mDNS", TRUE);
- else
- g_key_file_remove_key(keyfile, service->identifier,
- "mDNS", NULL);
+ "mDNS", TRUE);
if (service->hidden_service)
- g_key_file_set_boolean(keyfile, service->identifier, "Hidden",
- TRUE);
+ g_key_file_set_boolean(keyfile, service->identifier,
+ "Hidden", TRUE);
if (service->config_file && strlen(service->config_file) > 0)
g_key_file_set_string(keyfile, service->identifier,
"Config.file", service->config_file);
- if (service->config_entry &&
- strlen(service->config_entry) > 0)
+ if (service->config_entry && strlen(service->config_entry) > 0)
g_key_file_set_string(keyfile, service->identifier,
"Config.ident", service->config_entry);
@@ -1859,6 +1876,7 @@ static void __connman_manage_saved_profiles()
if (!entry) {
g_sequence_free(profile_list);
g_key_file_free(keyfile);
+ g_strfreev(services);
return;
}
@@ -1882,6 +1900,7 @@ static void __connman_manage_saved_profiles()
}
g_sequence_free(profile_list);
+ g_strfreev(services);
}
#endif
@@ -2285,7 +2304,7 @@ static int nameserver_add_all(struct connman_service *service,
__connman_resolver_append_fallback_nameservers();
#if defined TIZEN_EXT
- const char *global_dns = connman_option_get_string("GlobalNameserver");
+ const char *global_dns = connman_setting_get_string("GlobalNameserver");
if (global_dns)
nameserver_add(service, type, global_dns);
#endif
@@ -2460,7 +2479,7 @@ static int nameserver_remove_all(struct connman_service *service,
}
#if defined TIZEN_EXT
- const char *global_dns = connman_option_get_string("GlobalNameserver");
+ const char *global_dns = connman_setting_get_string("GlobalNameserver");
if (global_dns)
nameserver_remove(service, type, global_dns);
#endif
@@ -2496,18 +2515,15 @@ int __connman_service_nameserver_append(struct connman_service *service,
else
nameservers = service->nameservers;
- for (i = 0; nameservers && nameservers[i]; i++)
+ if (nameservers) {
+ for (i = 0; nameservers[i]; i++) {
#if defined TIZEN_EXT
- {
- DBG("nameservers[%d] %s, nameserver %s", i, nameservers[i], nameserver);
-#endif
- if (g_strcmp0(nameservers[i], nameserver) == 0)
- return -EEXIST;
-#if defined TIZEN_EXT
- }
+ DBG("nameservers[%d] %s, nameserver %s", i, nameservers[i], nameserver);
#endif
+ if (g_strcmp0(nameservers[i], nameserver) == 0)
+ return -EEXIST;
+ }
- if (nameservers) {
len = g_strv_length(nameservers);
nameservers = g_try_renew(char *, nameservers, len + 2);
} else {
@@ -2743,6 +2759,62 @@ void __connman_service_nameserver_del_routes(struct connman_service *service,
nameserver_del_routes(index, service->nameservers, type);
}
+static bool check_proxy_setup(struct connman_service *service)
+{
+ /*
+ * We start WPAD if we haven't got a PAC URL from DHCP and
+ * if our proxy manual configuration is either empty or set
+ * to AUTO with an empty URL.
+ */
+
+ if (service->proxy != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN)
+ return true;
+
+ if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN &&
+ (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_AUTO ||
+ service->pac))
+ return true;
+
+ if (__connman_wpad_start(service) < 0) {
+ service->proxy = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
+ __connman_notifier_proxy_changed(service);
+ return true;
+ }
+
+ return false;
+}
+
+static void cancel_online_check(struct connman_service *service)
+{
+ if (service->online_timeout == 0)
+ return;
+
+ g_source_remove(service->online_timeout);
+ service->online_timeout = 0;
+ connman_service_unref(service);
+}
+
+static void start_online_check(struct connman_service *service,
+ enum connman_ipconfig_type type)
+{
+ if (!connman_setting_get_bool("EnableOnlineCheck")) {
+ connman_info("Online check disabled. "
+ "Default service remains in READY state.");
+ return;
+ }
+ enable_online_to_ready_transition =
+ connman_setting_get_bool("EnableOnlineToReadyTransition");
+ online_check_initial_interval =
+ connman_setting_get_uint("OnlineCheckInitialInterval");
+ online_check_max_interval =
+ connman_setting_get_uint("OnlineCheckMaxInterval");
+
+ if (type != CONNMAN_IPCONFIG_TYPE_IPV4 || check_proxy_setup(service)) {
+ cancel_online_check(service);
+ __connman_service_wispr_start(service, type);
+ }
+}
+
static void address_updated(struct connman_service *service,
enum connman_ipconfig_type type)
{
@@ -2750,6 +2822,7 @@ static void address_updated(struct connman_service *service,
service == connman_service_get_default()) {
nameserver_remove_all(service, type);
nameserver_add_all(service, type);
+ start_online_check(service, type);
__connman_timeserver_sync(service);
}
@@ -2898,6 +2971,31 @@ struct connman_service *connman_service_get_default_connection(void)
return default_service;
}
+
+struct connman_service *connman_service_get_connected_service(const char *ifname)
+{
+ GList *list;
+ const char *svc_ifname;
+ struct connman_service *service;
+
+ if (!ifname)
+ return NULL;
+
+ for (list = service_list; list; list = list->next) {
+ service = list->data;
+
+ if (!is_connected(service->state))
+ continue;
+
+ svc_ifname = connman_device_get_string(
+ connman_network_get_device(service->network), "Interface");
+
+ if (svc_ifname && g_strcmp0(svc_ifname, ifname) == 0)
+ return service;
+ }
+
+ return NULL;
+}
#endif
struct connman_service *connman_service_get_default(void)
@@ -2931,6 +3029,25 @@ bool __connman_service_index_is_default(int index)
return __connman_service_get_index(service) == index;
}
+static void start_wispr_when_connected(struct connman_service *service)
+{
+ if (!connman_setting_get_bool("EnableOnlineCheck")) {
+ connman_info("Online check disabled. "
+ "Default service remains in READY state.");
+ return;
+ }
+
+ if (__connman_service_is_connected_state(service,
+ CONNMAN_IPCONFIG_TYPE_IPV4))
+ __connman_service_wispr_start(service,
+ CONNMAN_IPCONFIG_TYPE_IPV4);
+
+ if (__connman_service_is_connected_state(service,
+ CONNMAN_IPCONFIG_TYPE_IPV6))
+ __connman_service_wispr_start(service,
+ CONNMAN_IPCONFIG_TYPE_IPV6);
+}
+
static void default_changed(void)
{
#if defined TIZEN_EXT
@@ -2964,11 +3081,48 @@ static void default_changed(void)
if (service->domainname &&
connman_setting_get_bool("AllowDomainnameUpdates"))
__connman_utsname_set_domainname(service->domainname);
+
+ start_wispr_when_connected(service);
+
+ /*
+ * Connect VPN automatically when new default service
+ * is set and connected, unless new default is VPN
+ */
+ if (is_connected(service->state) &&
+ service->type != CONNMAN_SERVICE_TYPE_VPN) {
+ DBG("running vpn_auto_connect");
+ vpn_auto_connect();
+ }
}
__connman_notifier_default_changed(service);
}
+#if defined TIZEN_EXT
+static void append_struct(gpointer value, gpointer user_data);
+
+static void emit_state_changed_with_properties(struct connman_service *service)
+{
+ DBusMessage *signal;
+ DBusMessageIter iter;
+
+ if (!service)
+ return;
+
+ signal = dbus_message_new_signal(service->path, CONNMAN_SERVICE_INTERFACE,
+ "StateChangedProperties");
+ if (!signal)
+ return;
+
+ dbus_message_iter_init_append(signal, &iter);
+ append_struct(service, &iter);
+
+ g_dbus_send_message(connection, signal);
+
+ return;
+}
+#endif
+
static void state_changed(struct connman_service *service)
{
const char *str;
@@ -2982,14 +3136,17 @@ static void state_changed(struct connman_service *service)
#if !defined TIZEN_EXT
if (!allow_property_changed(service))
return;
-
-#endif
-#if defined TIZEN_EXT
+#else
DBG(" %s, %s", str, service->path);
#endif
+
connman_dbus_property_changed_basic(service->path,
CONNMAN_SERVICE_INTERFACE, "State",
DBUS_TYPE_STRING, &str);
+
+#if defined TIZEN_EXT
+ emit_state_changed_with_properties(service);
+#endif
}
#if defined TIZEN_EXT
@@ -3003,28 +3160,30 @@ static void connect_reason_changed(struct connman_service *service)
if (!allow_property_changed(service))
return;
- if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
- device = connman_network_get_device(service->network);
- if (device) {
- bool need_save = false;
+ if (TIZEN_INS_ENABLED) {
+ if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
+ device = connman_network_get_device(service->network);
+ if (device) {
+ bool need_save = false;
- need_save |= connman_device_set_last_user_selection_ident(device, service->identifier);
- need_save |= connman_device_set_last_user_selection_time(device, time(NULL));
+ need_save |= connman_device_set_last_user_selection_ident(device, service->identifier);
+ need_save |= connman_device_set_last_user_selection_time(device, time(NULL));
- DBG("last user selection ident[%s] time[%ld]",
- connman_device_get_last_user_selection_ident(device),
- connman_device_get_last_user_selection_time(device));
+ DBG("last user selection ident[%s] time[%ld]",
+ connman_device_get_last_user_selection_ident(device),
+ connman_device_get_last_user_selection_time(device));
- if (need_save)
- connman_device_save_last_user_selection(device);
+ if (need_save)
+ connman_device_save_last_user_selection(device);
+ }
}
}
connman_dbus_property_changed_basic(service->path,
- CONNMAN_SERVICE_INTERFACE,
- "ConnectReason",
- DBUS_TYPE_INT32,
- &service->connect_reason);
+ CONNMAN_SERVICE_INTERFACE,
+ "ConnectReason",
+ DBUS_TYPE_INT32,
+ &service->connect_reason);
}
static void disconnection_requested_changed(struct connman_service *service)
@@ -3046,7 +3205,7 @@ static void disconnection_requested_changed(struct connman_service *service)
}
void connman_service_set_disconnection_requested(struct connman_service *service,
- bool disconnection_requested)
+ bool disconnection_requested)
{
if (service == NULL)
return;
@@ -3054,6 +3213,47 @@ void connman_service_set_disconnection_requested(struct connman_service *service
service->disconnection_requested = disconnection_requested;
disconnection_requested_changed(service);
}
+
+static void connman_service_emit_state(struct connman_service *service,
+ enum connman_service_state state)
+{
+ const char *str;
+ enum connman_service_state cur_state = service->state;
+
+ if (service->state != state)
+ service->state = state;
+
+ str = state2string(service->state);
+ if (!str) {
+ service->state = cur_state;
+ return;
+ }
+
+ DBG(" %s, %s", str, service->path);
+
+ connman_dbus_property_changed_basic(service->path,
+ CONNMAN_SERVICE_INTERFACE, "State",
+ DBUS_TYPE_STRING, &str);
+
+ emit_state_changed_with_properties(service);
+ service->state = cur_state;
+}
+
+void connman_service_notify_reconnection_roaming(struct connman_service *service)
+{
+ if (!service)
+ return;
+
+ if (service->state != CONNMAN_SERVICE_STATE_READY &&
+ service->state != CONNMAN_SERVICE_STATE_ONLINE)
+ return;
+
+ connman_service_emit_state(service, CONNMAN_SERVICE_STATE_CONFIGURATION);
+ connman_service_emit_state(service, CONNMAN_SERVICE_STATE_READY);
+
+ if (service->state == CONNMAN_SERVICE_STATE_ONLINE)
+ connman_service_emit_state(service, CONNMAN_SERVICE_STATE_ONLINE);
+}
#endif
static void strength_changed(struct connman_service *service)
@@ -3154,6 +3354,20 @@ static void autoconnect_changed(struct connman_service *service)
DBUS_TYPE_BOOLEAN, &autoconnect);
}
+bool connman_service_set_autoconnect(struct connman_service *service,
+ bool autoconnect)
+{
+ if (service->autoconnect == autoconnect)
+ return false;
+
+ service->autoconnect = autoconnect;
+ autoconnect_changed(service);
+
+ connman_network_set_autoconnect(service->network, autoconnect);
+
+ return true;
+}
+
static void append_security(DBusMessageIter *iter, void *user_data)
{
struct connman_service *service = user_data;
@@ -3183,12 +3397,17 @@ static void append_security(DBusMessageIter *iter, void *user_data)
break;
#if defined TIZEN_EXT
case CONNMAN_SERVICE_SECURITY_OWE:
+ case CONNMAN_SERVICE_SECURITY_DPP:
#endif
case CONNMAN_SERVICE_SECURITY_UNKNOWN:
case CONNMAN_SERVICE_SECURITY_NONE:
case CONNMAN_SERVICE_SECURITY_WEP:
case CONNMAN_SERVICE_SECURITY_8021X:
break;
+#if defined TIZEN_EXT
+ default:
+ break;
+#endif
}
if (service->wps_advertizing) {
@@ -4147,6 +4366,22 @@ int connman_service_iterate_services(connman_service_iterate_cb cb,
}
#if defined TIZEN_EXT
+static void append_security_list(DBusMessageIter *iter, void *user_data)
+{
+ GSList *sec_list = (GSList *)user_data;
+ const char *sec_str;
+
+ if (sec_list) {
+ GSList *list;
+ for (list = sec_list; list; list = list->next) {
+ sec_str = (const char *)list->data;
+
+ dbus_message_iter_append_basic(iter,
+ DBUS_TYPE_STRING, &sec_str);
+ }
+ }
+}
+
static void append_wifi_ext_info(DBusMessageIter *dict,
struct connman_network *network)
{
@@ -4162,10 +4397,12 @@ static void append_wifi_ext_info(DBusMessageIter *dict,
const char *enc_mode;
const char *str;
gboolean passpoint;
+ gboolean pmf_required;
char country_code_buff[WIFI_COUNTRY_CODE_LEN + 1] = {0,};
char *country_code_str = country_code_buff;
unsigned char *country_code;
uint16_t connection_mode;
+ GSList *sec_list = NULL;
ssid = connman_network_get_blob(network, "WiFi.SSID", &ssid_len);
bssid = connman_network_get_bssid(network);
@@ -4175,14 +4412,19 @@ static void append_wifi_ext_info(DBusMessageIter *dict,
enc_mode = connman_network_get_enc_mode(network);
passpoint = connman_network_get_bool(network, "WiFi.HS20AP");
keymgmt = connman_network_get_keymgmt(network);
+ pmf_required = connman_network_get_bool(network, "WiFi.PMFRequired");
country_code = connman_network_get_countrycode(network);
connection_mode = connman_network_get_connection_mode(network);
+ sec_list = (GSList *)connman_network_get_sec_list(network);
snprintf(bssid_str, WIFI_BSSID_STR_LEN, MACSTR, MAC2STR(bssid));
snprintf(country_code_str, (WIFI_COUNTRY_CODE_LEN + 1), "%c%c",
country_code[0], country_code[1]);
+ connman_dbus_dict_append_array(dict, "SecurityList",
+ DBUS_TYPE_STRING,
+ append_security_list, sec_list);
connman_dbus_dict_append_fixed_array(dict, "SSID",
DBUS_TYPE_BYTE, &ssid, ssid_len);
@@ -4200,6 +4442,8 @@ static void append_wifi_ext_info(DBusMessageIter *dict,
DBUS_TYPE_BOOLEAN, &passpoint);
connman_dbus_dict_append_basic(dict, "Keymgmt",
DBUS_TYPE_UINT32, &keymgmt);
+ connman_dbus_dict_append_basic(dict, "PmfReq",
+ DBUS_TYPE_BOOLEAN, &pmf_required);
connman_dbus_dict_append_basic(dict, "Country", DBUS_TYPE_STRING,
&country_code_str);
connman_dbus_dict_append_basic(dict, "ConnMode",
@@ -4461,7 +4705,7 @@ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited,
connman_network_append_acddbus(dict, service->network);
}
-#if defined TIZEN_EXT_INS
+#if defined TIZEN_EXT
static void append_ins_bssid_info(DBusMessageIter *iter, void *user_data)
{
GSList *bssid_list = NULL;
@@ -4552,7 +4796,7 @@ static void append_ins_properties(DBusMessageIter *dict,
append_ins_bssid_info, service->network);
}
}
-#endif
+#endif /* defined TIZEN_EXT */
static void append_struct_service(DBusMessageIter *iter,
connman_dbus_append_cb_t function,
@@ -4591,12 +4835,7 @@ static void append_struct(gpointer value, gpointer user_data)
append_struct_service(iter, append_dict_properties, service);
}
-void __connman_service_list_struct(DBusMessageIter *iter)
-{
- g_list_foreach(service_list, append_struct, iter);
-}
-
-#if defined TIZEN_EXT_INS
+#if defined TIZEN_EXT
static void append_dict_ins_properties(DBusMessageIter *dict, void *user_data)
{
struct connman_service *service = user_data;
@@ -4622,7 +4861,12 @@ void __connman_ins_list_struct(DBusMessageIter *iter)
{
g_list_foreach(service_list, append_ins_struct, iter);
}
-#endif
+#endif /* defined TIZEN_EXT */
+
+void __connman_service_list_struct(DBusMessageIter *iter)
+{
+ g_list_foreach(service_list, append_struct, iter);
+}
bool __connman_service_is_hidden(struct connman_service *service)
{
@@ -4882,7 +5126,7 @@ void connman_service_set_internet_connection(struct connman_service *service,
if (service->is_internet_connection != internet_connection) {
service->is_internet_connection = internet_connection;
- g_get_current_time(&service->modified);
+ g_get_current_time((GTimeVal *)&service->modified);
service_save(service);
}
}
@@ -4895,7 +5139,7 @@ bool connman_service_get_internet_connection(struct connman_service *service)
return service->is_internet_connection;
}
-DBusMessage *connman_service_get_defaut_info(DBusMessage *msg,
+DBusMessage *connman_service_create_dbus_service_reply(DBusMessage *msg,
struct connman_service *service)
{
DBusMessage *reply;
@@ -5276,6 +5520,7 @@ int __connman_service_check_passphrase(enum connman_service_security security,
#if defined TIZEN_EXT
case CONNMAN_SERVICE_SECURITY_OWE:
case CONNMAN_SERVICE_SECURITY_DPP:
+ default:
#endif
break;
}
@@ -5341,6 +5586,16 @@ int __connman_service_get_use_eapol(struct connman_service *service)
return service->use_eapol;
}
+
+int __connman_service_get_connect_reason(struct connman_service *service)
+{
+ if (!service) {
+ DBG("Service is NULL");
+ return -1;
+ }
+
+ return service->connect_reason;
+}
#endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
static DBusMessage *get_properties(DBusConnection *conn,
@@ -5557,6 +5812,44 @@ error:
return -EINVAL;
}
+static void do_auto_connect(struct connman_service *service,
+ enum connman_service_connect_reason reason)
+{
+ /*
+ * CONNMAN_SERVICE_CONNECT_REASON_NONE must be ignored for VPNs. VPNs
+ * always have reason CONNMAN_SERVICE_CONNECT_REASON_USER/AUTO.
+ */
+ if (!service || (service->type == CONNMAN_SERVICE_TYPE_VPN &&
+ reason == CONNMAN_SERVICE_CONNECT_REASON_NONE))
+ return;
+
+ /*
+ * Only user interaction should get VPN or WIFI connected in failure
+ * state.
+ */
+ if (service->state == CONNMAN_SERVICE_STATE_FAILURE &&
+ reason != CONNMAN_SERVICE_CONNECT_REASON_USER &&
+ (service->type == CONNMAN_SERVICE_TYPE_VPN ||
+ service->type == CONNMAN_SERVICE_TYPE_WIFI))
+ return;
+
+ /*
+ * Do not use the builtin auto connect, instead rely on the
+ * native auto connect feature of the service.
+ */
+ if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_NATIVE)
+ return;
+
+ /*
+ * Run service auto connect for other than VPN services. Afterwards
+ * start also VPN auto connect process.
+ */
+ if (service->type != CONNMAN_SERVICE_TYPE_VPN)
+ __connman_service_auto_connect(reason);
+
+ vpn_auto_connect();
+}
+
int __connman_service_reset_ipconfig(struct connman_service *service,
enum connman_ipconfig_type type, DBusMessageIter *array,
enum connman_service_state *new_state)
@@ -5621,7 +5914,7 @@ int __connman_service_reset_ipconfig(struct connman_service *service,
settings_changed(service, new_ipconfig);
address_updated(service, type);
- __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
+ do_auto_connect(service, CONNMAN_SERVICE_CONNECT_REASON_AUTO);
}
DBG("err %d ipconfig %p type %d method %d state %s", err,
@@ -5631,14 +5924,6 @@ int __connman_service_reset_ipconfig(struct connman_service *service,
return err;
}
-/*
- * We set the timeout to 1 sec so that we have a chance to get
- * necessary IPv6 router advertisement messages that might have
- * DNS data etc.
- */
-#define ONLINE_CHECK_INITIAL_INTERVAL 1
-#define ONLINE_CHECK_MAX_INTERVAL 12
-
void __connman_service_wispr_start(struct connman_service *service,
enum connman_ipconfig_type type)
{
@@ -5646,14 +5931,17 @@ void __connman_service_wispr_start(struct connman_service *service,
if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
service->online_check_interval_ipv4 =
- ONLINE_CHECK_INITIAL_INTERVAL;
+ online_check_initial_interval;
else
service->online_check_interval_ipv6 =
- ONLINE_CHECK_INITIAL_INTERVAL;
+ online_check_initial_interval;
__connman_wispr_start(service, type);
}
+static void set_error(struct connman_service *service,
+ enum connman_service_error error);
+
static DBusMessage *set_property(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
@@ -5691,17 +5979,26 @@ static DBusMessage *set_property(DBusConnection *conn,
dbus_message_iter_get_basic(&value, &autoconnect);
- if (service->autoconnect == autoconnect)
- return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-
- service->autoconnect = autoconnect;
-
- autoconnect_changed(service);
+ if (autoconnect && service->type == CONNMAN_SERVICE_TYPE_VPN) {
+ /*
+ * Changing the autoconnect flag on VPN to "on" should
+ * have the same effect as user connecting the VPN =
+ * clear previous error and change state to idle.
+ */
+ set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
- if (autoconnect)
- __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
+ if (service->state == CONNMAN_SERVICE_STATE_FAILURE) {
+ service->state = CONNMAN_SERVICE_STATE_IDLE;
+ state_changed(service);
+ }
+ }
- service_save(service);
+ if (connman_service_set_autoconnect(service, autoconnect)) {
+ service_save(service);
+ if (autoconnect)
+ do_auto_connect(service,
+ CONNMAN_SERVICE_CONNECT_REASON_AUTO);
+ }
} else if (g_str_equal(name, "Nameservers.Configuration")) {
DBusMessageIter entry;
GString *str;
@@ -5840,13 +6137,7 @@ static DBusMessage *set_property(DBusConnection *conn,
#endif
dns_configuration_changed(service);
- if (__connman_service_is_connected_state(service,
- CONNMAN_IPCONFIG_TYPE_IPV4))
- __connman_service_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
-
- if (__connman_service_is_connected_state(service,
- CONNMAN_IPCONFIG_TYPE_IPV6))
- __connman_service_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV6);
+ start_wispr_when_connected(service);
service_save(service);
} else if (g_str_equal(name, "Timeservers.Configuration")) {
@@ -5892,9 +6183,7 @@ static DBusMessage *set_property(DBusConnection *conn,
service_save(service);
timeservers_configuration_changed(service);
-
- if (service == connman_service_get_default())
- __connman_timeserver_sync(service);
+ __connman_timeserver_conf_update(service);
} else if (g_str_equal(name, "Domains.Configuration")) {
DBusMessageIter entry;
@@ -6054,6 +6343,7 @@ static DBusMessage *set_property(DBusConnection *conn,
if (err < 0)
return __connman_error_failed(msg, -err);
+ service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_USER;
service_save(service);
#endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
} else
@@ -6067,8 +6357,10 @@ static void set_error(struct connman_service *service,
{
const char *str;
+#if !defined TIZEN_EXT
if (service->error == error)
return;
+#endif
service->error = error;
@@ -6119,9 +6411,9 @@ static void service_complete(struct connman_service *service)
reply_pending(service, EIO);
if (service->connect_reason != CONNMAN_SERVICE_CONNECT_REASON_USER)
- __connman_service_auto_connect(service->connect_reason);
+ do_auto_connect(service, service->connect_reason);
- g_get_current_time(&service->modified);
+ gettimeofday(&service->modified, NULL);
service_save(service);
}
@@ -6328,6 +6620,7 @@ static void set_always_connecting_technologies()
always_connect[always_connected_techs[i]] = 1;
}
+#if !defined TIZEN_EXT
static bool autoconnect_no_session_active(struct connman_service *service)
{
/*
@@ -6340,6 +6633,7 @@ static bool autoconnect_no_session_active(struct connman_service *service)
return false;
}
+#endif
static bool autoconnect_already_connecting(struct connman_service *service,
bool autoconnecting)
@@ -6356,6 +6650,8 @@ static bool autoconnect_already_connecting(struct connman_service *service,
return false;
}
+static int service_indicate_state(struct connman_service *service);
+
static bool auto_connect_service(GList *services,
enum connman_service_connect_reason reason,
bool preferred)
@@ -6367,6 +6663,7 @@ static bool auto_connect_service(GList *services,
#if defined TIZEN_EXT
GSList *wifi_ignore = NULL;
#endif
+ int index;
DBG("preferred %d sessions %d reason %s", preferred, active_count,
reason2string(reason));
@@ -6409,6 +6706,17 @@ static bool auto_connect_service(GList *services,
continue;
#endif
+ if (service->connect_reason ==
+ CONNMAN_SERVICE_CONNECT_REASON_NATIVE) {
+ DBG("service %p uses native autonnect, skip", service);
+ continue;
+ }
+
+ index = __connman_service_get_index(service);
+ if (g_hash_table_lookup(passphrase_requested,
+ GINT_TO_POINTER(index)))
+ return true;
+
if (service->pending ||
is_connecting(service->state) ||
is_connected(service->state)) {
@@ -6468,11 +6776,22 @@ static bool auto_connect_service(GList *services,
DBG("service %p %s %s", service, service->name,
(preferred) ? "preferred" : reason2string(reason));
+#if defined TIZEN_EXT
__connman_service_connect(service, reason);
-#if !defined TIZEN_EXT
+#else
+ if (__connman_service_connect(service, reason) == 0)
+ service_indicate_state(service);
+
if (autoconnect_no_session_active(service))
return true;
#endif
+#if defined TIZEN_EXT
+ if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
+ int index = connman_network_get_index(service->network);
+ wifi_ignore = g_slist_prepend(wifi_ignore, GINT_TO_POINTER(index));
+ autoconnecting = true;
+ }
+#endif
ignore[service->type] = true;
}
#if defined TIZEN_EXT
@@ -6559,8 +6878,28 @@ void __connman_service_auto_connect(enum connman_service_connect_reason reason)
static gboolean run_vpn_auto_connect(gpointer data) {
GList *list;
bool need_split = false;
+ bool autoconnectable_vpns = false;
+ int attempts = 0;
+ int timeout = VPN_AUTOCONNECT_TIMEOUT_DEFAULT;
+ struct connman_service *def_service;
- vpn_autoconnect_id = 0;
+ attempts = GPOINTER_TO_INT(data);
+ def_service = connman_service_get_default();
+
+ /*
+ * Stop auto connecting VPN if there is no transport service or the
+ * transport service is not connected or if the current default service
+ * is a connected VPN (in ready state).
+ */
+ if (!def_service || !is_connected(def_service->state) ||
+ (def_service->type == CONNMAN_SERVICE_TYPE_VPN &&
+ is_connected(def_service->state))) {
+
+ DBG("stopped, default service %s connected %d",
+ def_service ? def_service->identifier : "NULL",
+ def_service ? is_connected(def_service->state) : -1);
+ goto out;
+ }
for (list = service_list; list; list = list->next) {
struct connman_service *service = list->data;
@@ -6570,9 +6909,17 @@ static gboolean run_vpn_auto_connect(gpointer data) {
continue;
if (is_connected(service->state) ||
- is_connecting(service->state)) {
+ is_connecting(service->state)) {
if (!service->do_split_routing)
need_split = true;
+
+ /*
+ * If the service is connecting it must be accounted
+ * for to keep the autoconnection in main loop.
+ */
+ if (is_connecting(service->state))
+ autoconnectable_vpns = true;
+
continue;
}
@@ -6590,20 +6937,64 @@ static gboolean run_vpn_auto_connect(gpointer data) {
res = __connman_service_connect(service,
CONNMAN_SERVICE_CONNECT_REASON_AUTO);
- if (res < 0 && res != -EINPROGRESS)
+
+ switch (res) {
+ case 0:
+ service_indicate_state(service);
+ /* fall through */
+ case -EINPROGRESS:
+ autoconnectable_vpns = true;
+ break;
+ default:
continue;
+ }
if (!service->do_split_routing)
need_split = true;
}
- return FALSE;
+ /* Stop if there is no VPN to automatically connect.*/
+ if (!autoconnectable_vpns) {
+ DBG("stopping, no autoconnectable VPNs found");
+ goto out;
+ }
+
+ /* Increase the attempt count up to the threshold.*/
+ if (attempts < VPN_AUTOCONNECT_TIMEOUT_ATTEMPTS_THRESHOLD)
+ attempts++;
+
+ /*
+ * Timeout increases with 1s after VPN_AUTOCONNECT_TIMEOUT_STEP amount
+ * of attempts made. After VPN_AUTOCONNECT_TIMEOUT_ATTEMPTS_THRESHOLD is
+ * reached the delay does not increase.
+ */
+ timeout = timeout + (int)(attempts / VPN_AUTOCONNECT_TIMEOUT_STEP);
+
+ /* Re add this to main loop */
+ vpn_autoconnect_id =
+ g_timeout_add_seconds(timeout, run_vpn_auto_connect,
+ GINT_TO_POINTER(attempts));
+
+ DBG("re-added to main loop, next VPN autoconnect in %d seconds (#%d)",
+ timeout, attempts);
+
+ return G_SOURCE_REMOVE;
+
+out:
+ vpn_autoconnect_id = 0;
+ return G_SOURCE_REMOVE;
}
static void vpn_auto_connect(void)
{
- if (vpn_autoconnect_id)
- return;
+ /*
+ * Remove existing autoconnect from main loop to reset the attempt
+ * counter in order to get VPN connected when there is a network change.
+ */
+ if (vpn_autoconnect_id) {
+ if (!g_source_remove(vpn_autoconnect_id))
+ return;
+ }
vpn_autoconnect_id =
g_idle_add(run_vpn_auto_connect, NULL);
@@ -6706,7 +7097,7 @@ static gboolean connect_timeout(gpointer user_data)
if (autoconnect &&
service->connect_reason !=
CONNMAN_SERVICE_CONNECT_REASON_USER)
- __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
+ do_auto_connect(service, CONNMAN_SERVICE_CONNECT_REASON_AUTO);
return FALSE;
}
@@ -6755,7 +7146,7 @@ static DBusMessage *connect_service(DBusConnection *conn,
break;
#endif
if (!is_connecting(temp->state) && !is_connected(temp->state))
- break;
+ continue;
if (service == temp)
continue;
@@ -6953,13 +7344,90 @@ bool __connman_service_remove(struct connman_service *service)
return true;
}
+#if defined TIZEN_EXT
+static char *__connman_service_get_wpa_id_to_remove(struct connman_service *service)
+{
+ char *identifier;
+ char *ptr;
+
+ if (service->type != CONNMAN_SERVICE_TYPE_WIFI)
+ return NULL;
+
+ if (service->security != CONNMAN_SERVICE_SECURITY_SAE &&
+ service->security != CONNMAN_SERVICE_SECURITY_PSK)
+ return NULL;
+
+ identifier = g_strdup(service->identifier);
+ if (!identifier)
+ return NULL;
+
+ if (service->security == CONNMAN_SERVICE_SECURITY_SAE) {
+ ptr = strstr(identifier, "_sae");
+ if (!ptr) {
+ g_free(identifier);
+ return NULL;
+ }
+
+ memcpy(ptr, "_psk", strlen("_psk"));
+ } else if (service->security == CONNMAN_SERVICE_SECURITY_PSK) {
+ ptr = strstr(identifier, "_psk");
+ if (!ptr) {
+ g_free(identifier);
+ return NULL;
+ }
+
+ memcpy(ptr, "_sae", strlen("_sae"));
+ }
+
+ return identifier;
+}
+
+
+static void __connman_service_remove_wpa_service(struct connman_service *service)
+{
+ gchar *dir;
+ GList *list;
+ char *identifier = __connman_service_get_wpa_id_to_remove(service);
+
+ if (!identifier)
+ return;
+
+ dir = g_strdup_printf("%s/%s", STORAGEDIR, identifier);
+ if (!dir)
+ goto done;
+
+ if (g_file_test(dir, G_FILE_TEST_EXISTS) != TRUE)
+ goto done;
+
+ for (list = service_list; list; list = list->next) {
+ struct connman_service *dst_service = list->data;
+
+ if (dst_service->type != CONNMAN_SERVICE_TYPE_WIFI)
+ continue;
+
+ if (g_strcmp0(dst_service->identifier, identifier) == 0) {
+ __connman_service_remove(dst_service);
+ goto done;
+ }
+ }
+
+ __connman_storage_remove_service(identifier);
+
+done:
+ g_free(identifier);
+ g_free(dir);
+}
+#endif
+
static DBusMessage *remove_service(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
struct connman_service *service = user_data;
DBG("service %p", service);
-
+#if defined TIZEN_EXT
+ __connman_service_remove_wpa_service(service);
+#endif
if (!__connman_service_remove(service))
return __connman_error_not_supported(msg);
@@ -7006,15 +7474,11 @@ static void apply_relevant_default_downgrade(struct connman_service *service)
struct connman_service *def_service;
def_service = connman_service_get_default();
- if (!def_service)
+ if (!def_service || def_service != service ||
+ def_service->state != CONNMAN_SERVICE_STATE_ONLINE)
return;
- if (def_service == service &&
- def_service->state == CONNMAN_SERVICE_STATE_ONLINE) {
- def_service->state = CONNMAN_SERVICE_STATE_READY;
- __connman_notifier_leave_online(def_service->type);
- state_changed(def_service);
- }
+ downgrade_state(def_service);
}
static void switch_default_service(struct connman_service *default_service,
@@ -7124,27 +7588,22 @@ static void service_schedule_changed(void)
services_notify->id = g_timeout_add(100, service_send_changed, NULL);
}
-static DBusMessage *move_service(DBusConnection *conn,
- DBusMessage *msg, void *user_data,
- bool before)
+int __connman_service_move(struct connman_service *service,
+ struct connman_service *target, bool before)
{
- struct connman_service *service = user_data;
- struct connman_service *target;
- const char *path;
enum connman_ipconfig_method target4, target6;
enum connman_ipconfig_method service4, service6;
DBG("service %p", service);
- dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID);
+ if (!service)
+ return -EINVAL;
if (!service->favorite)
- return __connman_error_not_supported(msg);
+ return -EOPNOTSUPP;
- target = find_service(path);
if (!target || !target->favorite || target == service)
- return __connman_error_invalid_service(msg);
+ return -EINVAL;
if (target->type == CONNMAN_SERVICE_TYPE_VPN) {
/*
@@ -7155,14 +7614,14 @@ static DBusMessage *move_service(DBusConnection *conn,
connman_info("Cannot move service. "
"No routes defined for provider %s",
__connman_provider_get_ident(target->provider));
- return __connman_error_invalid_service(msg);
+ return -EINVAL;
}
- set_split_routing(target, true);
+ __connman_service_set_split_routing(target, true);
} else
- set_split_routing(target, false);
+ __connman_service_set_split_routing(target, false);
- set_split_routing(service, false);
+ __connman_service_set_split_routing(service, false);
target4 = __connman_ipconfig_get_method(target->ipconfig_ipv4);
target6 = __connman_ipconfig_get_method(target->ipconfig_ipv6);
@@ -7185,7 +7644,7 @@ static DBusMessage *move_service(DBusConnection *conn,
if (service6 != CONNMAN_IPCONFIG_METHOD_OFF) {
if (!check_suitable_state(target->state_ipv6,
service->state_ipv6))
- return __connman_error_invalid_service(msg);
+ return -EINVAL;
}
}
@@ -7193,7 +7652,7 @@ static DBusMessage *move_service(DBusConnection *conn,
if (service4 != CONNMAN_IPCONFIG_METHOD_OFF) {
if (!check_suitable_state(target->state_ipv4,
service->state_ipv4))
- return __connman_error_invalid_service(msg);
+ return -EINVAL;
}
}
@@ -7201,7 +7660,7 @@ static DBusMessage *move_service(DBusConnection *conn,
if (target6 != CONNMAN_IPCONFIG_METHOD_OFF) {
if (!check_suitable_state(target->state_ipv6,
service->state_ipv6))
- return __connman_error_invalid_service(msg);
+ return -EINVAL;
}
}
@@ -7209,11 +7668,11 @@ static DBusMessage *move_service(DBusConnection *conn,
if (target4 != CONNMAN_IPCONFIG_METHOD_OFF) {
if (!check_suitable_state(target->state_ipv4,
service->state_ipv4))
- return __connman_error_invalid_service(msg);
+ return -EINVAL;
}
}
- g_get_current_time(&service->modified);
+ gettimeofday(&service->modified, NULL);
service_save(service);
service_save(target);
@@ -7232,6 +7691,39 @@ static DBusMessage *move_service(DBusConnection *conn,
service_schedule_changed();
+ return 0;
+}
+
+static DBusMessage *move_service(DBusConnection *conn,
+ DBusMessage *msg, void *user_data,
+ bool before)
+{
+ struct connman_service *service = user_data;
+ struct connman_service *target;
+ const char *path;
+ int err;
+
+ DBG("service %p", service);
+
+ dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+
+ target = find_service(path);
+
+ err = __connman_service_move(service, target, before);
+ switch (err) {
+ case 0:
+ break;
+ case -EINVAL:
+ return __connman_error_invalid_service(msg);
+ case -EOPNOTSUPP:
+ return __connman_error_not_supported(msg);
+ default:
+ connman_warn("unsupported error code %d in move_service()",
+ err);
+ break;
+ }
+
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
@@ -7257,7 +7749,27 @@ static DBusMessage *reset_counters(DBusConnection *conn,
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
-#if defined TIZEN_MAINTAIN_ONLINE
+#if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
+static DBusMessage *is_eapol_enabled(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct connman_service *service = user_data;
+ DBG("service: %p path: %s UseEapol: %d", service, service->path, service->use_eapol);
+
+ dbus_bool_t eapol_status = service->use_eapol;
+
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ DBG("Failed to initialize reply");
+ return NULL;
+ }
+
+ dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &eapol_status, DBUS_TYPE_INVALID);
+ return reply;
+}
+#endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
+
+#if defined TIZEN_EXT
static DBusMessage *downgrade_service(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
@@ -7265,6 +7777,7 @@ static DBusMessage *downgrade_service(DBusConnection *conn,
downgrade_state(service);
__connman_connection_update_gateway();
+ start_online_check(service, CONNMAN_IPCONFIG_TYPE_IPV4);
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
@@ -7334,7 +7847,10 @@ static const GDBusMethodTable service_methods[] = {
GDBUS_ARGS({ "service", "o" }), NULL,
move_after) },
{ GDBUS_METHOD("ResetCounters", NULL, NULL, reset_counters) },
-#if defined TIZEN_MAINTAIN_ONLINE
+#if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
+ { GDBUS_METHOD("IsEapolEnabled", NULL, GDBUS_ARGS({ "eapol", "b" }), is_eapol_enabled) },
+#endif
+#if defined TIZEN_EXT
{ GDBUS_METHOD("Downgrade", NULL, NULL, downgrade_service) },
#endif
{ },
@@ -7343,6 +7859,10 @@ static const GDBusMethodTable service_methods[] = {
static const GDBusSignalTable service_signals[] = {
{ GDBUS_SIGNAL("PropertyChanged",
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+#if defined TIZEN_EXT
+ { GDBUS_SIGNAL("StateChangedProperties",
+ GDBUS_ARGS({ "properties", "a{sv}" })) },
+#endif
{ },
};
@@ -7504,8 +8024,6 @@ static void service_initialize(struct connman_service *service)
memset(service->last_connected_bssid, 0, WIFI_BSSID_LEN_MAX);
service->is_internet_connection = false;
service->assoc_reject_count = 0;
-#endif
-#if defined TIZEN_EXT
service->disconnection_requested = false;
service->storage_reload = false;
/*
@@ -7618,6 +8136,9 @@ static int calculate_score_last_user_selection(struct connman_service *service)
struct tm* ref_timeinfo;
device = connman_network_get_device(service->network);
+ if (!device)
+ return 0;
+
last_user_selection_time = connman_device_get_last_user_selection_time(device);
last_user_selection_ident = connman_device_get_last_user_selection_ident(device);
frequency = connman_network_get_frequency(service->network);
@@ -7661,17 +8182,22 @@ static int calculate_score_last_connected(struct connman_service *service)
unsigned int frequency;
device = connman_network_get_device(service->network);
+ if (!device)
+ return 0;
+
last_connected_ident = connman_device_get_last_connected_ident(device);
frequency = connman_network_get_frequency(service->network);
- if (g_strcmp0(last_connected_ident, service->identifier) == 0 &&
- (((frequency >= FREQ_RANGE_24GHZ_CHANNEL_1 &&
- frequency <= FREQ_RANGE_24GHZ_CHANNEL_14) &&
- service->strength >= ins_settings.signal_level3_24ghz) ||
- ((frequency >= FREQ_RANGE_5GHZ_CHANNEL_32 &&
- frequency <= FREQ_RANGE_5GHZ_CHANNEL_165) &&
- service->strength >= ins_settings.signal_level3_5ghz))) {
- score += ins_settings.last_connected_score;
+ if (ins_settings.last_connected) {
+ if (g_strcmp0(last_connected_ident, service->identifier) == 0 &&
+ (((frequency >= FREQ_RANGE_24GHZ_CHANNEL_1 &&
+ frequency <= FREQ_RANGE_24GHZ_CHANNEL_14) &&
+ service->strength >= ins_settings.signal_level3_24ghz) ||
+ ((frequency >= FREQ_RANGE_5GHZ_CHANNEL_32 &&
+ frequency <= FREQ_RANGE_5GHZ_CHANNEL_165) &&
+ service->strength >= ins_settings.signal_level3_5ghz))) {
+ score += ins_settings.last_connected_score;
+ }
}
return score;
@@ -7686,7 +8212,7 @@ static int calculate_score_frequency(struct connman_service *service)
switch (ins_settings.preferred_freq) {
case CONNMAN_INS_PREFERRED_FREQ_24GHZ:
- if ((frequency >= FREQ_RANGE_24GHZ_CHANNEL_14 &&
+ if ((frequency >= FREQ_RANGE_24GHZ_CHANNEL_1 &&
frequency <= FREQ_RANGE_24GHZ_CHANNEL_14) &&
(service->strength >= ins_settings.signal_level3_24ghz))
score += ins_settings.preferred_freq_score;
@@ -7765,19 +8291,70 @@ static int calculate_score(struct connman_service *service)
score_frequency + score_security_priority +
score_internet_connection + score_strength;
-#if defined TIZEN_EXT_INS
service->score_last_user_selection = score_last_user_selection;
service->score_last_connected = score_last_connected;
service->score_frequency = score_frequency;
service->score_security_priority = score_security_priority;
service->score_internet_connection = score_internet_connection;
service->score_strength = score_strength;
-#endif
service->ins_score = score;
return score;
}
-#endif
+#endif /* defined TIZEN_EXT */
+
+static gint service_compare(gconstpointer a, gconstpointer b);
+
+static gint service_compare_vpn(struct connman_service *a,
+ struct connman_service *b)
+{
+ struct connman_provider *provider;
+ struct connman_service *service;
+ struct connman_service *transport;
+ const char *ident;
+ bool reverse;
+
+ if (a->provider) {
+ provider = a->provider;
+ service = b;
+ reverse = false;
+ } else if (b->provider) {
+ provider = b->provider;
+ service = a;
+ reverse = true;
+ } else {
+ return 0;
+ }
+
+ ident = __connman_provider_get_transport_ident(provider);
+ transport = connman_service_lookup_from_identifier(ident);
+ if (!transport)
+ return 0;
+
+ if (reverse)
+ return service_compare(service, transport);
+
+ return service_compare(transport, service);
+}
+
+static gint service_compare_preferred(struct connman_service *service_a,
+ struct connman_service *service_b)
+{
+ unsigned int *tech_array;
+ int i;
+
+ tech_array = connman_setting_get_uint_list("PreferredTechnologies");
+ if (tech_array) {
+ for (i = 0; tech_array[i]; i++) {
+ if (tech_array[i] == service_a->type)
+ return -1;
+
+ if (tech_array[i] == service_b->type)
+ return 1;
+ }
+ }
+ return 0;
+}
static gint service_compare(gconstpointer a, gconstpointer b)
{
@@ -7788,9 +8365,10 @@ static gint service_compare(gconstpointer a, gconstpointer b)
#if defined TIZEN_EXT
int score_a;
int score_b;
-#else
+ gint strength = 0;
+#else /* defined TIZEN_EXT */
gint strength;
-#endif
+#endif /* defined TIZEN_EXT */
state_a = service_a->state;
state_b = service_b->state;
@@ -7803,7 +8381,7 @@ static gint service_compare(gconstpointer a, gconstpointer b)
service_a->type == CONNMAN_SERVICE_TYPE_WIFI &&
service_b->type == CONNMAN_SERVICE_TYPE_WIFI) {
const char *default_interface =
- connman_option_get_string("DefaultWifiInterface");
+ connman_setting_get_string("DefaultWifiInterface");
const char *ifname_a = connman_device_get_string(
connman_network_get_device(service_a->network), "Interface");
const char *ifname_b = connman_device_get_string(
@@ -7817,11 +8395,26 @@ static gint service_compare(gconstpointer a, gconstpointer b)
#endif
if (a_connected && b_connected) {
+ int rval;
+
+ /* Compare the VPN transport and the service */
+ if ((service_a->type == CONNMAN_SERVICE_TYPE_VPN ||
+ service_b->type == CONNMAN_SERVICE_TYPE_VPN) &&
+ service_b->type != service_a->type) {
+ rval = service_compare_vpn(service_a, service_b);
+ if (rval)
+ return rval;
+ }
+
if (service_a->order > service_b->order)
return -1;
if (service_a->order < service_b->order)
return 1;
+
+ rval = service_compare_preferred(service_a, service_b);
+ if (rval)
+ return rval;
}
if (state_a != state_b) {
@@ -7852,20 +8445,11 @@ static gint service_compare(gconstpointer a, gconstpointer b)
return 1;
if (service_a->type != service_b->type) {
- unsigned int *tech_array;
- int i;
+ int rval;
- tech_array = connman_setting_get_uint_list(
- "PreferredTechnologies");
- if (tech_array) {
- for (i = 0; tech_array[i]; i++) {
- if (tech_array[i] == service_a->type)
- return -1;
-
- if (tech_array[i] == service_b->type)
- return 1;
- }
- }
+ rval = service_compare_preferred(service_a, service_b);
+ if (rval)
+ return rval;
if (service_a->type == CONNMAN_SERVICE_TYPE_ETHERNET)
return -1;
@@ -7899,43 +8483,31 @@ static gint service_compare(gconstpointer a, gconstpointer b)
}
#if defined TIZEN_EXT
- score_a = calculate_score(service_a);
- score_b = calculate_score(service_b);
- if (score_b != score_a)
- return score_b - score_a;
-#else
+ if (TIZEN_INS_ENABLED) {
+ score_a = calculate_score(service_a);
+ score_b = calculate_score(service_b);
+
+ if (score_b != score_a)
+ return score_b - score_a;
+ else if (score_b == score_a) {
+ strength = (gint) service_b->strength - (gint) service_a->strength;
+ if (strength)
+ return strength;
+ }
+ }
+#else /* defined TIZEN_EXT */
strength = (gint) service_b->strength - (gint) service_a->strength;
if (strength)
return strength;
-#endif
+#endif /* defined TIZEN_EXT */
return g_strcmp0(service_a->name, service_b->name);
}
-#if defined TIZEN_EXT_INS
-static void print_service_sort(gpointer data, gpointer user_data)
-{
- struct connman_service *service = data;
-
- if (service->type != CONNMAN_SERVICE_TYPE_WIFI)
- return;
-
- DBG("name[%-20s] total[%2d] last_usr[%2d] last_conn[%2d] "
- "freq[%2d] sec[%2d] internet[%2d] strength[%2d]",
- service->name, service->ins_score, service->score_last_user_selection,
- service->score_last_connected, service->score_frequency,
- service->score_security_priority, service->score_internet_connection,
- service->score_strength);
-}
-#endif
-
static void service_list_sort(void)
{
if (service_list && service_list->next) {
service_list = g_list_sort(service_list, service_compare);
-#if defined TIZEN_EXT_INS
- g_list_foreach(service_list, print_service_sort, NULL);
-#endif
service_schedule_changed();
}
}
@@ -8312,10 +8884,12 @@ static void report_error_cb(void *user_context, bool retry,
service->state_ipv4 = service->state_ipv6 =
CONNMAN_SERVICE_STATE_IDLE;
- if (service->error != CONNMAN_SERVICE_ERROR_AUTH_FAILED)
+ if (service->error != CONNMAN_SERVICE_ERROR_AUTH_FAILED &&
+ service->error != CONNMAN_SERVICE_ERROR_ASSOC_FAILED)
set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
#endif
service_complete(service);
+ service_list_sort();
__connman_connection_update_gateway();
}
}
@@ -8362,6 +8936,7 @@ static void request_input_cb(struct connman_service *service,
struct connman_device *device;
const char *security;
int err = 0;
+ int index;
DBG("RequestInput return, %p", service);
@@ -8376,22 +8951,29 @@ static void request_input_cb(struct connman_service *service,
__connman_service_return_error(service,
ECONNABORTED,
user_data);
- goto done;
} else {
+ err = -ETIMEDOUT;
+
if (service->hidden)
__connman_service_return_error(service,
ETIMEDOUT, user_data);
}
+
+ goto done;
}
- if (service->hidden && name_len > 0 && name_len <= 32) {
- device = connman_network_get_device(service->network);
- security = connman_network_get_string(service->network,
- "WiFi.Security");
- err = __connman_device_request_hidden_scan(device,
- name, name_len,
- identity, passphrase,
- security, user_data);
+ if (service->hidden) {
+ if (name_len > 0 && name_len <= 32) {
+ device = connman_network_get_device(service->network);
+ security = connman_network_get_string(service->network,
+ "WiFi.Security");
+ err = __connman_device_request_hidden_scan(device,
+ name, name_len,
+ identity, passphrase,
+ security, user_data);
+ } else {
+ err = -EINVAL;
+ }
if (err < 0)
__connman_service_return_error(service, -err,
user_data);
@@ -8417,6 +8999,10 @@ static void request_input_cb(struct connman_service *service,
err = __connman_service_set_passphrase(service, passphrase);
done:
+ index = __connman_service_get_index(service);
+ g_hash_table_remove(passphrase_requested,
+ GINT_TO_POINTER(index));
+
if (err >= 0) {
/* We forget any previous error. */
set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
@@ -8470,27 +9056,14 @@ static int service_update_preferred_order(struct connman_service *default_servic
struct connman_service *new_service,
enum connman_service_state new_state)
{
- unsigned int *tech_array;
- int i;
-
- if (!default_service || default_service == new_service ||
- default_service->state != new_state)
+ if (!default_service || default_service == new_service)
return 0;
- tech_array = connman_setting_get_uint_list("PreferredTechnologies");
- if (tech_array) {
-
- for (i = 0; tech_array[i] != 0; i += 1) {
- if (default_service->type == tech_array[i])
- return -EALREADY;
-
- if (new_service->type == tech_array[i]) {
- switch_default_service(default_service,
- new_service);
- __connman_connection_update_gateway();
- return 0;
- }
- }
+ if (service_compare_preferred(default_service, new_service) > 0) {
+ switch_default_service(default_service,
+ new_service);
+ __connman_connection_update_gateway();
+ return 0;
}
return -EALREADY;
@@ -8513,12 +9086,15 @@ static struct connman_device *default_connecting_device = NULL;
static void __connman_service_disconnect_default(struct connman_service *service)
{
struct connman_device *default_device = NULL;
+ struct connman_network *network = __connman_service_get_network(service);
+
+ if (!network)
+ return;
if (default_connecting_device == NULL)
return;
- default_device = connman_network_get_device(
- __connman_service_get_network(service));
+ default_device = connman_network_get_device(network);
DBG("Disconnecting service %p %s", service, service->path);
DBG("Disconnecting device %p %p %s",
@@ -8696,6 +9272,50 @@ static void set_priority_connected_service(void)
#endif
}
}
+
+static void emit_wifi_roaming_failure(struct connman_service *service,
+ enum connman_service_state new_state)
+{
+ if (connman_setting_get_bool("WifiRoaming") &&
+ connman_network_get_bool(service->network, "WiFi.Roaming")) {
+ const char *cur_bssid;
+ const char *dst_bssid;
+ const char *ifname;
+ struct connman_device *device;
+
+ device = connman_network_get_device(service->network);
+ if (device) {
+ ifname = connman_device_get_string(device, "Interface");
+ cur_bssid = connman_network_get_string(service->network,
+ "WiFi.RoamingCurBSSID");
+ dst_bssid = connman_network_get_string(service->network,
+ "WiFi.RoamingDstBSSID");
+ }
+
+ if (device && ifname && cur_bssid && dst_bssid) {
+ switch(new_state) {
+ case CONNMAN_SERVICE_STATE_UNKNOWN:
+ case CONNMAN_SERVICE_STATE_ASSOCIATION:
+ case CONNMAN_SERVICE_STATE_CONFIGURATION:
+ case CONNMAN_SERVICE_STATE_READY:
+ case CONNMAN_SERVICE_STATE_ONLINE:
+ break;
+ case CONNMAN_SERVICE_STATE_DISCONNECT:
+ case CONNMAN_SERVICE_STATE_FAILURE:
+ case CONNMAN_SERVICE_STATE_IDLE:
+ __connman_technology_notify_roaming_state(ifname,
+ "failure", cur_bssid, dst_bssid);
+ connman_network_set_bool(service->network,
+ "WiFi.Roaming", false);
+ connman_network_set_string(service->network,
+ "WiFi.RoamingCurBSSID", NULL);
+ connman_network_set_string(service->network,
+ "WiFi.RoamingDstBSSID", NULL);
+ break;
+ }
+ }
+ }
+}
#endif
static const char *get_dbus_sender(struct connman_service *service)
@@ -8764,6 +9384,15 @@ static int service_indicate_state(struct connman_service *service)
break;
case CONNMAN_SERVICE_STATE_IDLE:
+ if (old_state == CONNMAN_SERVICE_STATE_FAILURE &&
+ service->connect_reason ==
+ CONNMAN_SERVICE_CONNECT_REASON_NATIVE &&
+ service->error ==
+ CONNMAN_SERVICE_ERROR_INVALID_KEY) {
+ __connman_service_clear_error(service);
+ service_complete(service);
+ }
+
if (old_state != CONNMAN_SERVICE_STATE_DISCONNECT)
__connman_service_disconnect(service);
@@ -8806,12 +9435,12 @@ static int service_indicate_state(struct connman_service *service)
service->new_service = false;
- default_changed();
-
def_service = connman_service_get_default();
service_update_preferred_order(def_service, service, new_state);
+ default_changed();
+
__connman_service_set_favorite(service, true);
reply_pending(service, 0);
@@ -8830,7 +9459,7 @@ static int service_indicate_state(struct connman_service *service)
"WiFi.UseWPS", false);
}
- g_get_current_time(&service->modified);
+ gettimeofday(&service->modified, NULL);
service_save(service);
domain_changed(service);
@@ -8873,7 +9502,7 @@ static int service_indicate_state(struct connman_service *service)
#endif
#if defined TIZEN_EXT
- if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
+ if (TIZEN_INS_ENABLED && service->type == CONNMAN_SERVICE_TYPE_WIFI)
connman_service_set_internet_connection(service, true);
#endif
break;
@@ -8902,6 +9531,8 @@ static int service_indicate_state(struct connman_service *service)
proxy_changed(service);
#if defined TIZEN_EXT
}
+
+ emit_wifi_roaming_failure(service, new_state);
#endif
/*
@@ -8911,7 +9542,7 @@ static int service_indicate_state(struct connman_service *service)
*/
downgrade_connected_services();
- __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
+ do_auto_connect(service, CONNMAN_SERVICE_CONNECT_REASON_AUTO);
break;
case CONNMAN_SERVICE_STATE_FAILURE:
@@ -8920,12 +9551,16 @@ static int service_indicate_state(struct connman_service *service)
service->order = 5;
__connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
#endif
- if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
+ if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER ||
+ service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_NATIVE) {
connman_agent_report_error(service, service->path,
error2string(service->error),
report_error_cb,
get_dbus_sender(service),
NULL);
+#if !defined TIZEN_EXT
+ goto notifier;
+#endif
}
service_complete(service);
break;
@@ -8939,10 +9574,14 @@ static int service_indicate_state(struct connman_service *service)
#else
__connman_service_connect_default(service);
#endif
+ emit_wifi_roaming_failure(service, new_state);
#endif
__connman_connection_update_gateway();
+#if !defined TIZEN_EXT
+notifier:
+#endif
if ((old_state == CONNMAN_SERVICE_STATE_ONLINE &&
new_state != CONNMAN_SERVICE_STATE_READY) ||
(old_state == CONNMAN_SERVICE_STATE_READY &&
@@ -8969,6 +9608,20 @@ int __connman_service_indicate_error(struct connman_service *service,
if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
return -EALREADY;
+#if defined TIZEN_EXT
+ /*
+ * change connman_service_error type
+ * from CONNMAN_SERVICE_ERROR_AUTH_FAILED to CONNMAN_SERVICE_ERROR_INVALID_KEY
+ * in case of SAE security type.
+ */
+ if (error == CONNMAN_SERVICE_ERROR_AUTH_FAILED &&
+ service->security == CONNMAN_SERVICE_SECURITY_SAE) {
+ DBG("SAE security auth failed, set error to invalid-key and ignore the service");
+ error = CONNMAN_SERVICE_ERROR_INVALID_KEY;
+ __connman_service_set_ignore(service, true);
+ }
+#endif
+
set_error(service, error);
/* default internet service: fix not cleared if pdp activation*/
@@ -9062,34 +9715,6 @@ enum connman_service_state __connman_service_ipconfig_get_state(
return CONNMAN_SERVICE_STATE_UNKNOWN;
}
-static void check_proxy_setup(struct connman_service *service)
-{
- /*
- * We start WPAD if we haven't got a PAC URL from DHCP and
- * if our proxy manual configuration is either empty or set
- * to AUTO with an empty URL.
- */
-
- if (service->proxy != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN)
- goto done;
-
- if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN &&
- (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_AUTO ||
- service->pac))
- goto done;
-
- if (__connman_wpad_start(service) < 0) {
- service->proxy = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
- __connman_notifier_proxy_changed(service);
- goto done;
- }
-
- return;
-
-done:
- __connman_service_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
-}
-
#if defined TIZEN_EXT
void connman_check_proxy_setup_and_wispr_start(struct connman_service *service){
@@ -9169,7 +9794,13 @@ static gboolean redo_wispr_ipv4(gpointer user_data)
{
struct connman_service *service = user_data;
+#if defined TIZEN_MAINTAIN_ONLINE
+ DBG("");
+
+ __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
+#else
redo_wispr(service, CONNMAN_IPCONFIG_TYPE_IPV4);
+#endif
return FALSE;
}
@@ -9183,24 +9814,13 @@ static gboolean redo_wispr_ipv6(gpointer user_data)
return FALSE;
}
-#if defined TIZEN_MAINTAIN_ONLINE
-static gboolean redo_wispr_ipv4(gpointer user_data)
-{
- struct connman_service *service = user_data;
-
- DBG("");
-
- __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
-
- return FALSE;
-}
-#endif
-
-int __connman_service_online_check_failed(struct connman_service *service,
- enum connman_ipconfig_type type)
+void __connman_service_online_check(struct connman_service *service,
+ enum connman_ipconfig_type type,
+ bool success)
{
GSourceFunc redo_func;
- int *interval;
+ unsigned int *interval;
+ enum connman_service_state current_state;
if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
interval = &service->online_check_interval_ipv4;
@@ -9210,6 +9830,22 @@ int __connman_service_online_check_failed(struct connman_service *service,
redo_func = redo_wispr_ipv6;
}
+ if(!enable_online_to_ready_transition)
+ goto redo_func;
+
+ if (success) {
+ *interval = online_check_max_interval;
+ } else {
+ current_state = service->state;
+ downgrade_state(service);
+ if (current_state != service->state)
+ *interval = online_check_initial_interval;
+ if (service != connman_service_get_default()) {
+ return;
+ }
+ }
+
+redo_func:
DBG("service %p type %s interval %d", service,
__connman_ipconfig_type2string(type), *interval);
@@ -9217,22 +9853,10 @@ int __connman_service_online_check_failed(struct connman_service *service,
redo_func, connman_service_ref(service));
/* Increment the interval for the next time, set a maximum timeout of
- * ONLINE_CHECK_MAX_INTERVAL * ONLINE_CHECK_MAX_INTERVAL seconds.
+ * online_check_max_interval seconds * online_check_max_interval seconds.
*/
- if (*interval < ONLINE_CHECK_MAX_INTERVAL)
+ if (*interval < online_check_max_interval)
(*interval)++;
-
- return EAGAIN;
-}
-
-static void cancel_online_check(struct connman_service *service)
-{
- if (service->online_timeout == 0)
- return;
-
- g_source_remove(service->online_timeout);
- service->online_timeout = 0;
- connman_service_unref(service);
}
int __connman_service_ipconfig_indicate_state(struct connman_service *service,
@@ -9493,8 +10117,8 @@ static void prepare_8021x(struct connman_service *service)
service->phase1);
#endif
}
-#if defined TIZEN_EXT
+#if defined TIZEN_EXT
static bool has_valid_configuration_object(struct connman_service *service)
{
return service->connector && service->c_sign_key && service->net_access_key;
@@ -9647,6 +10271,10 @@ static int service_connect(struct connman_service *service)
return -ENOKEY;
break;
+#if defined TIZEN_EXT
+ default:
+ break;
+#endif
}
break;
}
@@ -9673,6 +10301,10 @@ static int service_connect(struct connman_service *service)
case CONNMAN_SERVICE_SECURITY_8021X:
prepare_8021x(service);
break;
+#if defined TIZEN_EXT
+ default:
+ break;
+#endif
}
if (__connman_stats_service_register(service) == 0) {
@@ -9708,6 +10340,7 @@ static int service_connect(struct connman_service *service)
int __connman_service_connect(struct connman_service *service,
enum connman_service_connect_reason reason)
{
+ int index;
int err;
DBG("service %p state %s connect reason %s -> %s",
@@ -9745,6 +10378,12 @@ int __connman_service_connect(struct connman_service *service,
__connman_service_clear_error(service);
+ if (service->network && service->autoconnect &&
+ __connman_network_native_autoconnect(service->network)) {
+ DBG("service %p switch connecting reason to native", service);
+ reason = CONNMAN_SERVICE_CONNECT_REASON_NATIVE;
+ }
+
err = service_connect(service);
DBG("service %p err %d", service, err);
@@ -9771,7 +10410,8 @@ int __connman_service_connect(struct connman_service *service,
service->provider)
connman_provider_disconnect(service->provider);
- if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
+ if (reason == CONNMAN_SERVICE_CONNECT_REASON_USER ||
+ reason == CONNMAN_SERVICE_CONNECT_REASON_NATIVE) {
if (err == -ENOKEY || err == -EPERM) {
DBusMessage *pending = NULL;
const char *dbus_sender = get_dbus_sender(service);
@@ -9794,6 +10434,13 @@ int __connman_service_connect(struct connman_service *service,
if (service->hidden && err != -EINPROGRESS)
service->pending = pending;
+ if (err == -EINPROGRESS) {
+ index = __connman_service_get_index(service);
+ g_hash_table_replace(passphrase_requested,
+ GINT_TO_POINTER(index),
+ GINT_TO_POINTER(true));
+ }
+
return err;
}
}
@@ -9992,6 +10639,65 @@ static struct connman_service *service_get(const char *identifier)
return service;
}
+#if defined TIZEN_EXT
+static void service_load_wpa_passphrase(struct connman_service *service)
+{
+ char *identifier;
+ char *ptr;
+ GKeyFile *keyfile;
+ bool favorite;
+ bool autoconnect;
+ char *passphrase;
+
+ if (service->security != CONNMAN_SERVICE_SECURITY_SAE)
+ return;
+
+ if (service->passphrase)
+ return;
+
+ if (!service->identifier)
+ return;
+
+ identifier = g_strdup(service->identifier);
+ if (!identifier)
+ return;
+
+ ptr = strstr(identifier, "_sae");
+ if (!ptr) {
+ g_free(identifier);
+ return;
+ }
+
+ memcpy(ptr, "_psk", strlen("_psk"));
+
+ keyfile = connman_storage_load_service(identifier);
+ if (!keyfile) {
+ g_free(identifier);
+ return;
+ }
+
+ favorite = g_key_file_get_boolean(keyfile, identifier, "Favorite", NULL);
+ autoconnect = g_key_file_get_boolean(keyfile, identifier, "AutoConnect", NULL);
+
+ if (!favorite || !autoconnect) {
+ g_free(identifier);
+ g_key_file_free(keyfile);
+ return;
+ }
+
+ passphrase = g_key_file_get_string(keyfile, identifier, "Passphrase", NULL);
+ if (passphrase) {
+ service->passphrase = g_strdup(passphrase);
+ service->favorite = favorite;
+ service->autoconnect = autoconnect;
+ }
+
+ g_free(identifier);
+ g_free(passphrase);
+ g_key_file_free(keyfile);
+}
+#endif
+
static int service_register(struct connman_service *service)
{
#if defined TIZEN_EXT
@@ -10010,22 +10716,30 @@ static int service_register(struct connman_service *service)
#if defined TIZEN_EXT
int ret;
service_load(service);
- ret = service_ext_load(service);
- if (ret == -ERANGE)
- service_ext_save(service);
+ service_load_wpa_passphrase(service);
+
+ if (TIZEN_INS_ENABLED) {
+ ret = service_ext_load(service);
+ if (ret == -ERANGE)
+ service_ext_save(service);
+ }
+
ret = __connman_config_provision_service(service);
- if (ret < 0 && simplified_log)
+ if (ret < 0 && !simplified_log)
DBG("Failed to provision service");
#else
if (__connman_config_provision_service(service) < 0)
service_load(service);
-#endif
+#endif /* defined TIZEN_EXT */
g_dbus_register_interface(connection, service->path,
CONNMAN_SERVICE_INTERFACE,
service_methods, service_signals,
NULL, service, NULL);
+ if (__connman_config_provision_service(service) < 0)
+ service_load(service);
+
service_list_sort();
__connman_connection_update_gateway();
@@ -10468,6 +11182,75 @@ static void update_from_network(struct connman_service *service,
service_list_sort();
}
+static void trigger_autoconnect(struct connman_service *service)
+{
+ struct connman_device *device;
+ bool native;
+
+ if (!service->favorite)
+ return;
+
+ native = __connman_network_native_autoconnect(service->network);
+ if (native && service->autoconnect) {
+ DBG("trigger native autoconnect");
+ connman_network_set_autoconnect(service->network, true);
+ return;
+ }
+
+ device = connman_network_get_device(service->network);
+ if (device && connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_UNKNOWN))
+ return;
+
+ switch (service->type) {
+ case CONNMAN_SERVICE_TYPE_UNKNOWN:
+ case CONNMAN_SERVICE_TYPE_SYSTEM:
+ case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
+ break;
+
+ case CONNMAN_SERVICE_TYPE_GADGET:
+ case CONNMAN_SERVICE_TYPE_ETHERNET:
+ if (service->autoconnect) {
+ __connman_service_connect(service,
+ CONNMAN_SERVICE_CONNECT_REASON_AUTO);
+ break;
+ }
+
+ /* fall through */
+ case CONNMAN_SERVICE_TYPE_BLUETOOTH:
+ case CONNMAN_SERVICE_TYPE_GPS:
+ case CONNMAN_SERVICE_TYPE_VPN:
+ case CONNMAN_SERVICE_TYPE_WIFI:
+ case CONNMAN_SERVICE_TYPE_CELLULAR:
+ do_auto_connect(service, CONNMAN_SERVICE_CONNECT_REASON_AUTO);
+ break;
+ }
+
+#if defined TIZEN_EXT
+ /* TIZEN synchronizes below information when the service creates */
+ if (service->eap != NULL)
+ connman_network_set_string(service->network, "WiFi.EAP",
+ service->eap);
+ if (service->identity != NULL)
+ connman_network_set_string(service->network, "WiFi.Identity",
+ service->identity);
+ if (service->phase2 != NULL)
+ connman_network_set_string(service->network, "WiFi.Phase2",
+ service->phase2);
+ if (service->eap != NULL)
+ connman_network_set_string(service->network, "WiFi.Connector",
+ service->connector);
+ if (service->identity != NULL)
+ connman_network_set_string(service->network, "WiFi.CSignKey",
+ service->c_sign_key);
+ if (service->phase2 != NULL)
+ connman_network_set_string(service->network, "WiFi.NetAccessKey",
+ service->net_access_key);
+#endif
+}
+
/**
* __connman_service_create_from_network:
* @network: network structure
@@ -10477,7 +11260,6 @@ static void update_from_network(struct connman_service *service,
struct connman_service * __connman_service_create_from_network(struct connman_network *network)
{
struct connman_service *service;
- struct connman_device *device;
const char *ident, *group;
char *name;
unsigned int *auto_connect_types, *favorite_types;
@@ -10507,8 +11289,19 @@ struct connman_service * __connman_service_create_from_network(struct connman_ne
if (__connman_network_get_weakness(network))
return service;
+ index = connman_network_get_index(network);
+
if (service->path) {
update_from_network(service, network);
+
+ if (service->ipconfig_ipv4)
+ __connman_ipconfig_set_index(service->ipconfig_ipv4,
+ index);
+
+ if (service->ipconfig_ipv6)
+ __connman_ipconfig_set_index(service->ipconfig_ipv6,
+ index);
+
__connman_connection_update_gateway();
return service;
}
@@ -10539,73 +11332,21 @@ struct connman_service * __connman_service_create_from_network(struct connman_ne
update_from_network(service, network);
- index = connman_network_get_index(network);
-
if (!service->ipconfig_ipv4)
service->ipconfig_ipv4 = create_ip4config(service, index,
CONNMAN_IPCONFIG_METHOD_DHCP);
+ else
+ __connman_ipconfig_set_index(service->ipconfig_ipv4, index);
if (!service->ipconfig_ipv6)
service->ipconfig_ipv6 = create_ip6config(service, index);
+ else
+ __connman_ipconfig_set_index(service->ipconfig_ipv6, index);
service_register(service);
service_schedule_added(service);
- if (service->favorite) {
- device = connman_network_get_device(service->network);
- if (device && !connman_device_get_scanning(device,
- CONNMAN_SERVICE_TYPE_UNKNOWN)) {
-
- switch (service->type) {
- case CONNMAN_SERVICE_TYPE_UNKNOWN:
- case CONNMAN_SERVICE_TYPE_SYSTEM:
- case CONNMAN_SERVICE_TYPE_P2P:
-#if defined TIZEN_EXT_WIFI_MESH
- case CONNMAN_SERVICE_TYPE_MESH:
-#endif
- break;
-
- case CONNMAN_SERVICE_TYPE_GADGET:
- case CONNMAN_SERVICE_TYPE_ETHERNET:
- if (service->autoconnect) {
- __connman_service_connect(service,
- CONNMAN_SERVICE_CONNECT_REASON_AUTO);
- break;
- }
-
- /* fall through */
- case CONNMAN_SERVICE_TYPE_BLUETOOTH:
- case CONNMAN_SERVICE_TYPE_GPS:
- case CONNMAN_SERVICE_TYPE_VPN:
- case CONNMAN_SERVICE_TYPE_WIFI:
- case CONNMAN_SERVICE_TYPE_CELLULAR:
- __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
- break;
- }
- }
-
-#if defined TIZEN_EXT
- /* TIZEN synchronizes below information when the service creates */
- if (service->eap != NULL)
- connman_network_set_string(service->network, "WiFi.EAP",
- service->eap);
- if (service->identity != NULL)
- connman_network_set_string(service->network, "WiFi.Identity",
- service->identity);
- if (service->phase2 != NULL)
- connman_network_set_string(service->network, "WiFi.Phase2",
- service->phase2);
- if (service->eap != NULL)
- connman_network_set_string(service->network, "WiFi.Connector",
- service->connector);
- if (service->identity != NULL)
- connman_network_set_string(service->network, "WiFi.CSignKey",
- service->c_sign_key);
- if (service->phase2 != NULL)
- connman_network_set_string(service->network, "WiFi.NetAccessKey",
- service->net_access_key);
-#endif
- }
+ trigger_autoconnect(service);
__connman_notifier_service_add(service, service->name);
@@ -10645,9 +11386,6 @@ void __connman_service_update_from_network(struct connman_network *network)
bool roaming;
const char *name;
bool stats_enable;
-#if defined TIZEN_EXT
- bool need_save = false;
-#endif
service = connman_service_lookup_from_network(network);
if (!service)
@@ -10705,12 +11443,17 @@ roaming:
sorting:
#if defined TIZEN_EXT
- need_save |= update_last_connected_bssid(service);
- need_save |= update_assoc_reject(service);
- if (need_save) {
- g_get_current_time(&service->modified);
- service_ext_save(service);
- need_sort = true;
+ if (TIZEN_INS_ENABLED) {
+ bool need_save = false;
+
+ need_save |= update_last_connected_bssid(service);
+ need_save |= update_assoc_reject(service);
+
+ if (need_save) {
+ g_get_current_time((GTimeVal *)&service->modified);
+ service_ext_save(service);
+ need_sort = true;
+ }
}
#endif
@@ -10908,7 +11651,7 @@ static void ins_setting_init(void)
ins_settings.last_user_selection_time = connman_setting_get_uint("INSLastUserSelectionTime");
ins_settings.last_connected = connman_setting_get_bool("INSLastConnected");
- string = connman_option_get_string("INSPreferredFreq");
+ string = connman_setting_get_string("INSPreferredFreq");
if (g_strcmp0(string, "5GHz") == 0)
ins_settings.preferred_freq = CONNMAN_INS_PREFERRED_FREQ_5GHZ;
else if (g_strcmp0(string, "2.4GHz") == 0)
@@ -10953,8 +11696,13 @@ static void ins_setting_init(void)
ins_settings.preferred_freq_score = connman_setting_get_uint("INSPreferredFreqScore");
ins_settings.internet_score = connman_setting_get_uint("INSInternetScore");
- ins_settings.signal_level3_5ghz = connman_setting_get_int("INSSignalLevel3_5GHz");
- ins_settings.signal_level3_24ghz = connman_setting_get_int("INSSignalLevel3_24GHz");
+ /*
+ * In ConnMan, signal strength is used after being converted
+ * to positive value(signal strength + 120).
+ * So the value for comparison should also be converted to the same.
+ */
+ ins_settings.signal_level3_5ghz = connman_setting_get_int("INSSignalLevel3_5GHz") + 120;
+ ins_settings.signal_level3_24ghz = connman_setting_get_int("INSSignalLevel3_2_4GHz") + 120;
DBG("last_user_selection [%s]", ins_settings.last_user_selection ? "true" : "false");
DBG("last_user_selection_time [%d]", ins_settings.last_user_selection_time);
@@ -10982,7 +11730,7 @@ static void ins_setting_init(void)
DBG("signal_level3_5ghz [%d]", ins_settings.signal_level3_5ghz);
DBG("signal_level3_24ghz [%d]", ins_settings.signal_level3_24ghz);
}
-#endif
+#endif /* defined TIZEN_EXT */
int __connman_service_init(void)
{
@@ -11004,6 +11752,8 @@ int __connman_service_init(void)
service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, service_free);
+ passphrase_requested = g_hash_table_new(g_direct_hash, g_direct_equal);
+
services_notify = g_new0(struct _services_notify, 1);
services_notify->remove = g_hash_table_new_full(g_str_hash,
g_str_equal, g_free, NULL);
@@ -11012,8 +11762,9 @@ int __connman_service_init(void)
remove_unprovisioned_services();
#if defined TIZEN_EXT
- ins_setting_init();
-#endif
+ if (TIZEN_INS_ENABLED)
+ ins_setting_init();
+#endif /* defined TIZEN_EXT */
return 0;
}
@@ -11040,6 +11791,9 @@ void __connman_service_cleanup(void)
g_hash_table_destroy(service_hash);
service_hash = NULL;
+ g_hash_table_destroy(passphrase_requested);
+ passphrase_requested = NULL;
+
g_slist_free(counter_list);
counter_list = NULL;
diff --git a/src/session.c b/src/session.c
index 6000b6d9..69adba9c 100644
--- a/src/session.c
+++ b/src/session.c
@@ -1815,7 +1815,7 @@ static void session_activate(struct connman_session *session)
struct connman_service *service;
struct connman_service_info *info;
GSList *service_list = NULL;
- enum connman_service_state state = CONNMAN_SESSION_STATE_DISCONNECTED;
+ enum connman_service_state state = CONNMAN_SERVICE_STATE_DISCONNECT;
g_hash_table_iter_init(&iter, service_hash);
diff --git a/src/shared/mnlg.c b/src/shared/mnlg.c
new file mode 100644
index 00000000..1399ce40
--- /dev/null
+++ b/src/shared/mnlg.c
@@ -0,0 +1,331 @@
+/*
+ * mnlg.c Generic Netlink helpers for libmnl
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Jiri Pirko <jiri@mellanox.com>
+ */
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <libmnl/libmnl.h>
+#include <linux/genetlink.h>
+
+#include "mnlg.h"
+
+#ifndef MNL_ARRAY_SIZE
+#define MNL_ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
+#endif
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
+#endif
+
+#ifndef NETLINK_CAP_ACK
+#define NETLINK_CAP_ACK 10
+#endif
+#ifndef NETLINK_EXT_ACK
+#define NETLINK_EXT_ACK 11
+#endif
+
+struct mnlg_socket {
+ struct mnl_socket *nl;
+ char *buf;
+ uint32_t id;
+ uint8_t version;
+ unsigned int seq;
+ unsigned int portid;
+};
+
+static struct nlmsghdr *__mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd,
+ uint16_t flags, uint32_t id,
+ uint8_t version)
+{
+ struct nlmsghdr *nlh;
+ struct genlmsghdr *genl;
+
+ nlh = mnl_nlmsg_put_header(nlg->buf);
+ nlh->nlmsg_type = id;
+ nlh->nlmsg_flags = flags;
+ nlg->seq = time(NULL);
+ nlh->nlmsg_seq = nlg->seq;
+
+ genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
+ genl->cmd = cmd;
+ genl->version = version;
+
+ return nlh;
+}
+
+struct nlmsghdr *mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd,
+ uint16_t flags)
+{
+ return __mnlg_msg_prepare(nlg, cmd, flags, nlg->id, nlg->version);
+}
+
+int mnlg_socket_send(struct mnlg_socket *nlg, const struct nlmsghdr *nlh)
+{
+ return mnl_socket_sendto(nlg->nl, nlh, nlh->nlmsg_len);
+}
+
+static int mnlg_cb_noop(const struct nlmsghdr *nlh, void *data)
+{
+ return MNL_CB_OK;
+}
+
+static int mnlg_cb_error(const struct nlmsghdr *nlh, void *data)
+{
+ const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
+
+ /* Netlink subsystems returns the errno value with different signess */
+ if (err->error < 0)
+ errno = -err->error;
+ else
+ errno = err->error;
+
+ return err->error == 0 ? MNL_CB_STOP : MNL_CB_ERROR;
+}
+
+static int mnlg_cb_stop(const struct nlmsghdr *nlh, void *data)
+{
+ int len = *(int *)NLMSG_DATA(nlh);
+
+ if (len < 0) {
+ errno = -len;
+ return MNL_CB_ERROR;
+ }
+ return MNL_CB_STOP;
+}
+
+static mnl_cb_t mnlg_cb_array[NLMSG_MIN_TYPE] = {
+ [NLMSG_NOOP] = mnlg_cb_noop,
+ [NLMSG_ERROR] = mnlg_cb_error,
+ [NLMSG_DONE] = mnlg_cb_stop,
+ [NLMSG_OVERRUN] = mnlg_cb_noop,
+};
+
+int mnlg_socket_recv_run(struct mnlg_socket *nlg, mnl_cb_t data_cb, void *data)
+{
+ int err;
+
+ do {
+ err = mnl_socket_recvfrom(nlg->nl, nlg->buf,
+ MNL_SOCKET_BUFFER_SIZE);
+ if (err <= 0)
+ break;
+ err = mnl_cb_run2(nlg->buf, err, nlg->seq, nlg->portid,
+ data_cb, data, mnlg_cb_array,
+ ARRAY_SIZE(mnlg_cb_array));
+ } while (err > 0);
+
+ return err;
+}
+
+struct group_info {
+ bool found;
+ uint32_t id;
+ const char *name;
+};
+
+static int parse_mc_grps_cb(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+ int type = mnl_attr_get_type(attr);
+
+ if (mnl_attr_type_valid(attr, CTRL_ATTR_MCAST_GRP_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch (type) {
+ case CTRL_ATTR_MCAST_GRP_ID:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+ return MNL_CB_ERROR;
+ break;
+ case CTRL_ATTR_MCAST_GRP_NAME:
+ if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
+ return MNL_CB_ERROR;
+ break;
+ }
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static void parse_genl_mc_grps(struct nlattr *nested,
+ struct group_info *group_info)
+{
+ struct nlattr *pos;
+ const char *name;
+
+ mnl_attr_for_each_nested(pos, nested) {
+ struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1] = {};
+
+ mnl_attr_parse_nested(pos, parse_mc_grps_cb, tb);
+ if (!tb[CTRL_ATTR_MCAST_GRP_NAME] ||
+ !tb[CTRL_ATTR_MCAST_GRP_ID])
+ continue;
+
+ name = mnl_attr_get_str(tb[CTRL_ATTR_MCAST_GRP_NAME]);
+ if (strcmp(name, group_info->name) != 0)
+ continue;
+
+ group_info->id = mnl_attr_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]);
+ group_info->found = true;
+ }
+}
+
+static int get_group_id_attr_cb(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+ int type = mnl_attr_get_type(attr);
+
+ if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0)
+ return MNL_CB_ERROR;
+
+ if (type == CTRL_ATTR_MCAST_GROUPS &&
+ mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
+ return MNL_CB_ERROR;
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int get_group_id_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct group_info *group_info = data;
+ struct nlattr *tb[CTRL_ATTR_MAX + 1] = {};
+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+
+ mnl_attr_parse(nlh, sizeof(*genl), get_group_id_attr_cb, tb);
+ if (!tb[CTRL_ATTR_MCAST_GROUPS])
+ return MNL_CB_ERROR;
+ parse_genl_mc_grps(tb[CTRL_ATTR_MCAST_GROUPS], group_info);
+ return MNL_CB_OK;
+}
+
+int mnlg_socket_group_add(struct mnlg_socket *nlg, const char *group_name)
+{
+ struct nlmsghdr *nlh;
+ struct group_info group_info;
+ int err;
+
+ nlh = __mnlg_msg_prepare(nlg, CTRL_CMD_GETFAMILY,
+ NLM_F_REQUEST | NLM_F_ACK, GENL_ID_CTRL, 1);
+ mnl_attr_put_u16(nlh, CTRL_ATTR_FAMILY_ID, nlg->id);
+
+ err = mnlg_socket_send(nlg, nlh);
+ if (err < 0)
+ return err;
+
+ group_info.found = false;
+ group_info.name = group_name;
+ err = mnlg_socket_recv_run(nlg, get_group_id_cb, &group_info);
+ if (err < 0)
+ return err;
+
+ if (!group_info.found) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ err = mnl_socket_setsockopt(nlg->nl, NETLINK_ADD_MEMBERSHIP,
+ &group_info.id, sizeof(group_info.id));
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int get_family_id_attr_cb(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+ int type = mnl_attr_get_type(attr);
+
+ if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0)
+ return MNL_CB_ERROR;
+
+ if (type == CTRL_ATTR_FAMILY_ID &&
+ mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
+ return MNL_CB_ERROR;
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int get_family_id_cb(const struct nlmsghdr *nlh, void *data)
+{
+ uint32_t *p_id = data;
+ struct nlattr *tb[CTRL_ATTR_MAX + 1] = {};
+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+
+ mnl_attr_parse(nlh, sizeof(*genl), get_family_id_attr_cb, tb);
+ if (!tb[CTRL_ATTR_FAMILY_ID])
+ return MNL_CB_ERROR;
+ *p_id = mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
+ return MNL_CB_OK;
+}
+
+struct mnlg_socket *mnlg_socket_open(const char *family_name, uint8_t version)
+{
+ struct mnlg_socket *nlg;
+ struct nlmsghdr *nlh;
+ int one = 1;
+ int err;
+
+ nlg = malloc(sizeof(*nlg));
+ if (!nlg)
+ return NULL;
+
+ nlg->buf = malloc(MNL_SOCKET_BUFFER_SIZE);
+ if (!nlg->buf)
+ goto err_buf_alloc;
+
+ nlg->nl = mnl_socket_open(NETLINK_GENERIC);
+ if (!nlg->nl)
+ goto err_mnl_socket_open;
+
+ /* Older kernels may no support capped/extended ACK reporting */
+ mnl_socket_setsockopt(nlg->nl, NETLINK_CAP_ACK, &one, sizeof(one));
+ mnl_socket_setsockopt(nlg->nl, NETLINK_EXT_ACK, &one, sizeof(one));
+
+ err = mnl_socket_bind(nlg->nl, 0, MNL_SOCKET_AUTOPID);
+ if (err < 0)
+ goto err_mnl_socket_bind;
+
+ nlg->portid = mnl_socket_get_portid(nlg->nl);
+
+ nlh = __mnlg_msg_prepare(nlg, CTRL_CMD_GETFAMILY,
+ NLM_F_REQUEST | NLM_F_ACK, GENL_ID_CTRL, 1);
+ mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, family_name);
+
+ err = mnlg_socket_send(nlg, nlh);
+ if (err < 0)
+ goto err_mnlg_socket_send;
+
+ err = mnlg_socket_recv_run(nlg, get_family_id_cb, &nlg->id);
+ if (err < 0)
+ goto err_mnlg_socket_recv_run;
+
+ nlg->version = version;
+ return nlg;
+
+err_mnlg_socket_recv_run:
+err_mnlg_socket_send:
+err_mnl_socket_bind:
+ mnl_socket_close(nlg->nl);
+err_mnl_socket_open:
+ free(nlg->buf);
+err_buf_alloc:
+ free(nlg);
+ return NULL;
+}
+
+void mnlg_socket_close(struct mnlg_socket *nlg)
+{
+ mnl_socket_close(nlg->nl);
+ free(nlg->buf);
+ free(nlg);
+}
diff --git a/src/shared/mnlg.h b/src/shared/mnlg.h
new file mode 100644
index 00000000..4d1babf3
--- /dev/null
+++ b/src/shared/mnlg.h
@@ -0,0 +1,27 @@
+/*
+ * mnlg.h Generic Netlink helpers for libmnl
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Jiri Pirko <jiri@mellanox.com>
+ */
+
+#ifndef _MNLG_H_
+#define _MNLG_H_
+
+#include <libmnl/libmnl.h>
+
+struct mnlg_socket;
+
+struct nlmsghdr *mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd,
+ uint16_t flags);
+int mnlg_socket_send(struct mnlg_socket *nlg, const struct nlmsghdr *nlh);
+int mnlg_socket_recv_run(struct mnlg_socket *nlg, mnl_cb_t data_cb, void *data);
+int mnlg_socket_group_add(struct mnlg_socket *nlg, const char *group_name);
+struct mnlg_socket *mnlg_socket_open(const char *family_name, uint8_t version);
+void mnlg_socket_close(struct mnlg_socket *nlg);
+
+#endif /* _MNLG_H_ */
diff --git a/src/shared/netlink.c b/src/shared/netlink.c
deleted file mode 100755
index b32ab854..00000000
--- a/src/shared/netlink.c
+++ /dev/null
@@ -1,666 +0,0 @@
-/*
- *
- * Connection Manager
- *
- * Copyright (C) 2011-2012 Intel Corporation. All rights reserved.
- * Copyright (C) 2013-2014 BMW Car IT GmbH.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-/*
- * This file is a copy from ELL which has been ported to use GLib's
- * data structures.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <linux/netlink.h>
-
-#include <gdbus.h>
-
-#include "src/shared/util.h"
-#include "src/shared/netlink.h"
-
-#ifndef SOL_NETLINK
-#define SOL_NETLINK 270
-#endif
-
-struct command {
- unsigned int id;
- uint32_t seq;
- uint32_t len;
- netlink_command_func_t handler;
- netlink_destroy_func_t destroy;
- void *user_data;
-};
-
-struct notify {
- uint32_t group;
- netlink_notify_func_t handler;
- netlink_destroy_func_t destroy;
- void *user_data;
-};
-
-struct netlink_info {
- uint32_t pid;
- GIOChannel *channel;
- uint32_t next_seq;
- GQueue *command_queue;
- GHashTable *command_pending;
- GHashTable *command_lookup;
- unsigned int next_command_id;
- GHashTable *notify_groups;
- GHashTable *notify_lookup;
- unsigned int next_notify_id;
- netlink_debug_func_t debug_handler;
- netlink_destroy_func_t debug_destroy;
- void *debug_data;
-};
-
-
-static void destroy_command(struct command *command)
-{
- if (command->destroy)
- command->destroy(command->user_data);
-
- g_free(command);
-}
-
-static void destroy_notify(struct notify *notify)
-{
- if (notify->destroy)
- notify->destroy(notify->user_data);
-
- g_free(notify);
-}
-
-static gboolean can_write_data(GIOChannel *chan,
- GIOCondition cond, gpointer user_data)
-{
- struct netlink_info *netlink = user_data;
- struct command *command;
- struct sockaddr_nl addr;
- const void *data;
- ssize_t written;
- int sk;
-
- command = g_queue_pop_head(netlink->command_queue);
- if (!command)
- return FALSE;
-
- sk = g_io_channel_unix_get_fd(chan);
-
- memset(&addr, 0, sizeof(addr));
- addr.nl_family = AF_NETLINK;
- addr.nl_pid = 0;
-
- data = ((void *) command) + NLMSG_ALIGN(sizeof(struct command));
-
- written = sendto(sk, data, command->len, 0,
- (struct sockaddr *) &addr, sizeof(addr));
- if (written < 0 || (uint32_t) written != command->len) {
- g_hash_table_remove(netlink->command_lookup,
- GUINT_TO_POINTER(command->id));
- destroy_command(command);
- return FALSE;
- }
-
- util_hexdump('<', data, command->len,
- netlink->debug_handler, netlink->debug_data);
-
- g_hash_table_replace(netlink->command_pending,
- GUINT_TO_POINTER(command->seq), command);
-
- return g_queue_get_length(netlink->command_queue) > 0;
-}
-
-static void do_notify(gpointer key, gpointer value, gpointer user_data)
-{
- struct nlmsghdr *nlmsg = user_data;
- struct notify *notify = value;
-
- if (notify->handler) {
- notify->handler(nlmsg->nlmsg_type, NLMSG_DATA(nlmsg),
- nlmsg->nlmsg_len - NLMSG_HDRLEN, notify->user_data);
- }
-}
-
-static void process_broadcast(struct netlink_info *netlink, uint32_t group,
- struct nlmsghdr *nlmsg)
-{
- GHashTable *notify_list;
-
- notify_list = g_hash_table_lookup(netlink->notify_groups,
- GUINT_TO_POINTER(group));
- if (!notify_list)
- return;
-
- g_hash_table_foreach(notify_list, do_notify, nlmsg);
-}
-
-static void process_message(struct netlink_info *netlink,
- struct nlmsghdr *nlmsg)
-{
- const void *data = nlmsg;
- struct command *command;
-
- command = g_hash_table_lookup(netlink->command_pending,
- GUINT_TO_POINTER(nlmsg->nlmsg_seq));
- if (!command)
- return;
-
- g_hash_table_remove(netlink->command_pending,
- GUINT_TO_POINTER(nlmsg->nlmsg_seq));
-
- if (!command->handler)
- goto done;
-
- if (nlmsg->nlmsg_type < NLMSG_MIN_TYPE) {
- const struct nlmsgerr *err;
-
- switch (nlmsg->nlmsg_type) {
- case NLMSG_ERROR:
- err = data + NLMSG_HDRLEN;
-
- command->handler(-err->error, 0, NULL, 0,
- command->user_data);
- break;
- }
- } else {
- command->handler(0, nlmsg->nlmsg_type, data + NLMSG_HDRLEN,
- nlmsg->nlmsg_len - NLMSG_HDRLEN,
- command->user_data);
- }
-
-done:
- g_hash_table_remove(netlink->command_lookup,
- GUINT_TO_POINTER(command->id));
-
- destroy_command(command);
-}
-
-static void process_multi(struct netlink_info *netlink, struct nlmsghdr *nlmsg)
-{
- const void *data = nlmsg;
- struct command *command;
-
- command = g_hash_table_lookup(netlink->command_pending,
- GUINT_TO_POINTER(nlmsg->nlmsg_seq));
- if (!command)
- return;
-
- if (!command->handler)
- goto done;
-
- if (nlmsg->nlmsg_type < NLMSG_MIN_TYPE) {
- const struct nlmsgerr *err;
-
- switch (nlmsg->nlmsg_type) {
- case NLMSG_DONE:
- case NLMSG_ERROR:
- err = data + NLMSG_HDRLEN;
-
- command->handler(-err->error, 0, NULL, 0,
- command->user_data);
- break;
- }
- } else {
- command->handler(0, nlmsg->nlmsg_type, data + NLMSG_HDRLEN,
- nlmsg->nlmsg_len - NLMSG_HDRLEN,
- command->user_data);
- return;
- }
-
-done:
- g_hash_table_remove(netlink->command_pending,
- GUINT_TO_POINTER(nlmsg->nlmsg_seq));
-
- g_hash_table_remove(netlink->command_lookup,
- GUINT_TO_POINTER(command->id));
-
- destroy_command(command);
-}
-
-static gboolean can_read_data(GIOChannel *chan,
- GIOCondition cond, gpointer data)
-{
- struct netlink_info *netlink = data;
- struct cmsghdr *cmsg;
- struct msghdr msg;
- struct iovec iov;
- struct nlmsghdr *nlmsg;
- unsigned char buffer[4096];
- unsigned char control[32];
- uint32_t group = 0;
- ssize_t len;
- int sk;
-
- sk = g_io_channel_unix_get_fd(chan);
-
- iov.iov_base = buffer;
- iov.iov_len = sizeof(buffer);
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = control;
- msg.msg_controllen = sizeof(control);
-
- len = recvmsg(sk, &msg, 0);
- if (len < 0)
- return FALSE;
-
- util_hexdump('>', buffer, len, netlink->debug_handler,
- netlink->debug_data);
-
- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
- cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- struct nl_pktinfo *pktinfo;
-
- if (cmsg->cmsg_level != SOL_NETLINK)
- continue;
-
- if (cmsg->cmsg_type != NETLINK_PKTINFO)
- continue;
-
- pktinfo = (void *) CMSG_DATA(cmsg);
-
- group = pktinfo->group;
- }
-
- for (nlmsg = iov.iov_base; NLMSG_OK(nlmsg, (uint32_t) len);
- nlmsg = NLMSG_NEXT(nlmsg, len)) {
- if (group > 0 && nlmsg->nlmsg_seq == 0) {
- process_broadcast(netlink, group, nlmsg);
- continue;
- }
-
- if (nlmsg->nlmsg_pid != netlink->pid)
- continue;
-
- if (nlmsg->nlmsg_flags & NLM_F_MULTI)
- process_multi(netlink, nlmsg);
- else
- process_message(netlink, nlmsg);
- }
-
- return TRUE;
-}
-
-static gboolean netlink_event(GIOChannel *chan,
- GIOCondition cond, gpointer data)
-{
- if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
- return FALSE;
-
- return TRUE;
-}
-
-static int create_netlink_socket(int protocol, uint32_t *pid)
-{
- struct sockaddr_nl addr;
- socklen_t addrlen = sizeof(addr);
- int sk, pktinfo = 1;
-
- sk = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
- protocol);
- if (sk < 0)
- return -1;
-
- memset(&addr, 0, sizeof(addr));
- addr.nl_family = AF_NETLINK;
-
- if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- close(sk);
- return -1;
- }
-
- if (getsockname(sk, (struct sockaddr *) &addr, &addrlen) < 0) {
- close(sk);
- return -1;
- }
-
- if (setsockopt(sk, SOL_NETLINK, NETLINK_PKTINFO,
- &pktinfo, sizeof(pktinfo)) < 0) {
- close(sk);
- return -1;
- }
-
- if (pid)
- *pid = addr.nl_pid;
-
- return sk;
-}
-
-struct netlink_info *netlink_new(int protocol)
-{
- struct netlink_info *netlink;
- int sk;
-
- netlink = g_try_new0(struct netlink_info, 1);
- if (!netlink)
- return NULL;
-
- netlink->next_seq = 1;
- netlink->next_command_id = 1;
- netlink->next_notify_id = 1;
-
- sk = create_netlink_socket(protocol, &netlink->pid);
- if (sk < 0) {
- g_free(netlink);
- return NULL;
- }
-
- netlink->channel = g_io_channel_unix_new(sk);
- g_io_channel_set_close_on_unref(netlink->channel, TRUE);
-
- g_io_channel_set_encoding(netlink->channel, NULL, NULL);
- g_io_channel_set_buffered(netlink->channel, FALSE);
-
- g_io_add_watch(netlink->channel, G_IO_IN, can_read_data, netlink);
- g_io_add_watch(netlink->channel, G_IO_NVAL | G_IO_HUP | G_IO_ERR,
- netlink_event, netlink);
-
- netlink->command_queue = g_queue_new();
- netlink->command_pending = g_hash_table_new(g_direct_hash,
- g_direct_equal);
- netlink->command_lookup = g_hash_table_new(g_direct_hash,
- g_direct_equal);
-
- netlink->notify_groups = g_hash_table_new(g_direct_hash,
- g_direct_equal);
- netlink->notify_lookup = g_hash_table_new(g_direct_hash,
- g_direct_equal);
-
- return netlink;
-}
-
-static gboolean cleanup_notify(gpointer key, gpointer value, gpointer user_data)
-{
- struct notify *notify = value;
-
- destroy_notify(notify);
-
- return TRUE;
-
-}
-
-static gboolean cleanup_notify_group(gpointer key, gpointer value,
- gpointer user_data)
-{
- GHashTable *notify_list = value;
-
- g_hash_table_foreach_remove(notify_list, cleanup_notify, user_data);
- g_hash_table_destroy(notify_list);
-
- return TRUE;
-}
-
-static gboolean cleanup_command(gpointer key, gpointer value,
- gpointer user_data)
-{
- struct command *command = value;
-
- destroy_command(command);
-
- return TRUE;
-}
-
-void netlink_destroy(struct netlink_info *netlink)
-{
- g_hash_table_destroy(netlink->notify_lookup);
-
- g_hash_table_foreach_remove(netlink->notify_groups,
- cleanup_notify_group, NULL);
- g_hash_table_destroy(netlink->notify_groups);
-
- g_queue_free(netlink->command_queue);
-
- g_hash_table_destroy(netlink->command_pending);
-
- g_hash_table_foreach_remove(netlink->command_lookup,
- cleanup_command, NULL);
- g_hash_table_destroy(netlink->command_lookup);
-
- g_io_channel_shutdown(netlink->channel, TRUE, NULL);
- g_io_channel_unref(netlink->channel);
-
- g_free(netlink);
-}
-
-unsigned int netlink_send(struct netlink_info *netlink,
- uint16_t type, uint16_t flags, const void *data,
- uint32_t len, netlink_command_func_t function,
- void *user_data, netlink_destroy_func_t destroy)
-{
- struct command *command;
- struct nlmsghdr *nlmsg;
- size_t size;
-
- if (!netlink)
- return 0;
-
- if (!netlink->command_queue ||
- !netlink->command_pending ||
- !netlink->command_lookup)
- return 0;
-
- size = NLMSG_ALIGN(sizeof(struct command)) +
- NLMSG_HDRLEN + NLMSG_ALIGN(len);
-
- command = g_try_malloc0(size);
- if (!command)
- return 0;
-
- command->handler = function;
- command->destroy = destroy;
- command->user_data = user_data;
-
- command->id = netlink->next_command_id;
-
- g_hash_table_replace(netlink->command_lookup,
- GUINT_TO_POINTER(command->id), command);
-
- command->seq = netlink->next_seq++;
- command->len = NLMSG_HDRLEN + NLMSG_ALIGN(len);
-
- nlmsg = ((void *) command) + NLMSG_ALIGN(sizeof(struct command));
-
- nlmsg->nlmsg_len = command->len;
- nlmsg->nlmsg_type = type;
- nlmsg->nlmsg_flags = NLM_F_REQUEST | flags;
- nlmsg->nlmsg_seq = command->seq;
- nlmsg->nlmsg_pid = netlink->pid;
-
- if (data && len > 0)
- memcpy(((void *) nlmsg) + NLMSG_HDRLEN, data, len);
-
- g_queue_push_tail(netlink->command_queue, command);
-
- netlink->next_command_id++;
-
- /* Arm IOChannel to call can_write_data in case it is not armed yet. */
- if (g_queue_get_length(netlink->command_queue) == 1)
- g_io_add_watch(netlink->channel, G_IO_OUT, can_write_data,
- netlink);
-
- return command->id;
-}
-
-bool netlink_cancel(struct netlink_info *netlink, unsigned int id)
-{
- struct command *command;
-
- if (!netlink || id == 0)
- return false;
-
- if (!netlink->command_queue ||
- !netlink->command_pending ||
- !netlink->command_lookup)
- return false;
-
- command = g_hash_table_lookup(netlink->command_lookup,
- GUINT_TO_POINTER(id));
- if (!command)
- return false;
-
- g_hash_table_remove(netlink->command_lookup, GUINT_TO_POINTER(id));
-
- if (!g_queue_remove(netlink->command_queue, command)) {
- g_hash_table_remove(netlink->command_pending,
- GUINT_TO_POINTER(command->seq));
- }
-
- destroy_command(command);
-
- return true;
-}
-
-static bool add_membership(struct netlink_info *netlink, uint32_t group)
-{
- int sk, value = group;
-
- sk = g_io_channel_unix_get_fd(netlink->channel);
-
- if (setsockopt(sk, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
- &value, sizeof(value)) < 0)
- return false;
-
- return true;
-}
-
-static bool drop_membership(struct netlink_info *netlink, uint32_t group)
-{
- int sk, value = group;
-
- sk = g_io_channel_unix_get_fd(netlink->channel);
-
- if (setsockopt(sk, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
- &value, sizeof(value)) < 0)
- return false;
-
- return true;
-}
-
-unsigned int netlink_register(struct netlink_info *netlink,
- uint32_t group, netlink_notify_func_t function,
- void *user_data, netlink_destroy_func_t destroy)
-{
- GHashTable *notify_list;
- struct notify *notify;
- unsigned int id;
-
- if (!netlink)
- return 0;
-
- if (!netlink->notify_groups || !netlink->notify_lookup)
- return 0;
-
- notify_list = g_hash_table_lookup(netlink->notify_groups,
- GUINT_TO_POINTER(group));
- if (!notify_list) {
- notify_list = g_hash_table_new(g_direct_hash, g_direct_equal);
- if (!notify_list)
- return 0;
-
- g_hash_table_replace(netlink->notify_groups,
- GUINT_TO_POINTER(group), notify_list);
- }
-
- notify = g_new(struct notify, 1);
-
- notify->group = group;
- notify->handler = function;
- notify->destroy = destroy;
- notify->user_data = user_data;
-
- id = netlink->next_notify_id;
-
- g_hash_table_replace(netlink->notify_lookup,
- GUINT_TO_POINTER(id), notify_list);
- g_hash_table_replace(notify_list, GUINT_TO_POINTER(id), notify);
-
- if (g_hash_table_size(notify_list) == 1) {
- if (add_membership(netlink, notify->group) == false)
- goto remove_notify;
- }
-
- netlink->next_notify_id++;
-
- return id;
-
-remove_notify:
- g_hash_table_remove(notify_list, GUINT_TO_POINTER(id));
- g_hash_table_remove(netlink->notify_lookup, GUINT_TO_POINTER(id));
- g_free(notify);
-
- return 0;
-}
-
-bool netlink_unregister(struct netlink_info *netlink, unsigned int id)
-{
- GHashTable *notify_list;
- struct notify *notify;
-
- if (!netlink || id == 0)
- return false;
-
- if (!netlink->notify_groups || !netlink->notify_lookup)
- return false;
-
- notify_list = g_hash_table_lookup(netlink->notify_lookup,
- GUINT_TO_POINTER(id));
-
- if (!notify_list)
- return false;
-
- g_hash_table_remove(netlink->notify_lookup, GUINT_TO_POINTER(id));
-
- notify = g_hash_table_lookup(notify_list, GUINT_TO_POINTER(id));
- if (!notify)
- return false;
-
- g_hash_table_remove(notify_list, GUINT_TO_POINTER(id));
-
- if (g_hash_table_size(notify_list) == 0)
- drop_membership(netlink, notify->group);
-
- destroy_notify(notify);
-
- return true;
-}
-
-bool netlink_set_debug(struct netlink_info *netlink,
- netlink_debug_func_t function,
- void *user_data, netlink_destroy_func_t destroy)
-{
- if (!netlink)
- return false;
-
- if (netlink->debug_destroy)
- netlink->debug_destroy(netlink->debug_data);
-
- netlink->debug_handler = function;
- netlink->debug_destroy = destroy;
- netlink->debug_data = user_data;
-
- return true;
-}
diff --git a/src/shared/netlink.h b/src/shared/netlink.h
deleted file mode 100755
index 62bb3e01..00000000
--- a/src/shared/netlink.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- *
- * Connection Manager
- *
- * Copyright (C) 2011-2012 Intel Corporation. All rights reserved.
- * Copyright (C) 2013 BMW Car IT GbmH.
- *
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-
-typedef void (*netlink_debug_func_t) (const char *str, void *user_data);
-typedef void (*netlink_command_func_t) (unsigned int error,
- uint16_t type, const void *data,
- uint32_t len, void *user_data);
-typedef void (*netlink_notify_func_t) (uint16_t type, const void *data,
- uint32_t len, void *user_data);
-typedef void (*netlink_destroy_func_t) (void *user_data);
-
-struct netlink_info;
-
-struct netlink_info *netlink_new(int protocol);
-void netlink_destroy(struct netlink_info *netlink);
-
-unsigned int netlink_send(struct netlink_info *netlink,
- uint16_t type, uint16_t flags, const void *data,
- uint32_t len, netlink_command_func_t function,
- void *user_data, netlink_destroy_func_t destroy);
-bool netlink_cancel(struct netlink_info *netlink, unsigned int id);
-
-unsigned int netlink_register(struct netlink_info *netlink,
- uint32_t group, netlink_notify_func_t function,
- void *user_data, netlink_destroy_func_t destroy);
-bool netlink_unregister(struct netlink_info *netlink, unsigned int id);
-
-bool netlink_set_debug(struct netlink_info *netlink,
- netlink_debug_func_t function,
- void *user_data, netlink_destroy_func_t destroy);
diff --git a/src/shared/util.c b/src/shared/util.c
index df045c5b..bda2d2b3 100755
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -28,6 +28,7 @@
#include <stdio.h>
#include <ctype.h>
#include <stdarg.h>
+#include <string.h>
#include "src/shared/util.h"
@@ -88,3 +89,42 @@ void util_hexdump(const char dir, const unsigned char *buf, size_t len,
function(str, user_data);
}
}
+
+void util_iso8601_to_timeval(char *str, struct timeval *time)
+{
+ struct tm tm;
+ time_t t;
+ char *p;
+
+ p = strptime(str, "%FT%T", &tm);
+ if (!p)
+ return;
+
+ if (*p != 'Z') {
+ /* backwards compatibility */
+ if (*p != '.' || p[strlen(p) - 1] != 'Z')
+ return;
+ }
+
+ t = mktime(&tm);
+ if (t < 0)
+ return;
+
+ time->tv_sec = t;
+ time->tv_usec = 0;
+}
+
+char *util_timeval_to_iso8601(struct timeval *time)
+{
+ char buf[255];
+ struct tm tm;
+ time_t t;
+
+ t = time->tv_sec;
+ if (!localtime_r(&t, &tm))
+ return NULL;
+ if (!strftime(buf, sizeof(buf), "%FT%TZ", &tm))
+ return NULL;
+
+ return g_strdup(buf);
+}
diff --git a/src/shared/util.h b/src/shared/util.h
index 293fb3a4..430b821f 100755
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -21,6 +21,8 @@
*
*/
+#include <sys/time.h>
+
#include <glib.h>
typedef void (*util_debug_func_t)(const char *str, void *user_data);
@@ -48,3 +50,6 @@ static inline struct cb_data *cb_data_new(void *cb, void *user_data)
return ret;
}
+
+void util_iso8601_to_timeval(char *str, struct timeval *time);
+char *util_timeval_to_iso8601(struct timeval *time);
diff --git a/src/stats.c b/src/stats.c
index 6f7ce208..1df41f14 100755
--- a/src/stats.c
+++ b/src/stats.c
@@ -53,7 +53,7 @@
*
* File properties:
* The ring buffer is mmap to a file
- * Initialy only the smallest possible amount of disk space is allocated
+ * Initially only the smallest possible amount of disk space is allocated
* The files grow to the configured maximal size
* The grows by _SC_PAGESIZE step size
* For each service a file is created
@@ -80,8 +80,8 @@
*
* History file:
* Same format as the ring buffer file
- * For a period of at least 2 months dayly records are keept
- * If older, then only a monthly record is keept
+ * For a period of at least 2 months daily records are kept
+ * If older, then only a monthly record is kept
*/
@@ -348,7 +348,7 @@ static int stats_open_temp(struct stats_file *file)
STORAGEDIR);
file->fd = g_mkstemp_full(file->name, O_RDWR | O_CREAT, 0644);
if (file->fd < 0) {
- connman_error("create tempory file error %s for %s",
+ connman_error("create temporary file error %s for %s",
strerror(errno), file->name);
g_free(file->name);
file->name = NULL;
diff --git a/src/storage.c b/src/storage.c
index 277e5f53..67f6036b 100755
--- a/src/storage.c
+++ b/src/storage.c
@@ -37,7 +37,7 @@
#define DEFAULT "default.profile"
#if defined TIZEN_EXT
#define INS_SETTINGS "settings.ins"
-#endif
+#endif /* defined TIZEN_EXT */
#define MODE (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | \
S_IXGRP | S_IROTH | S_IXOTH)
@@ -165,7 +165,7 @@ int __connman_storage_save_ins(GKeyFile *keyfile)
return ret;
}
-#endif
+#endif /* defined TIZEN_EXT */
void __connman_storage_delete_global(void)
{
@@ -212,28 +212,6 @@ GKeyFile *__connman_storage_load_provider_config(const char *ident)
return keyfile;
}
-GKeyFile *__connman_storage_open_service(const char *service_id)
-{
- gchar *pathname;
- GKeyFile *keyfile = NULL;
-
- pathname = g_strdup_printf("%s/%s/%s", STORAGEDIR, service_id, SETTINGS);
- if (!pathname)
- return NULL;
-
- keyfile = storage_load(pathname);
- if (keyfile) {
- g_free(pathname);
- return keyfile;
- }
-
- g_free(pathname);
-
- keyfile = g_key_file_new();
-
- return keyfile;
-}
-
gchar **connman_storage_get_services(void)
{
struct dirent *d;
diff --git a/src/task.c b/src/task.c
index 953cc409..280b5e4c 100755
--- a/src/task.c
+++ b/src/task.c
@@ -45,8 +45,10 @@ struct connman_task {
GPtrArray *argv;
GPtrArray *envp;
connman_task_exit_t exit_func;
+ connman_task_setup_t setup_func;
void *exit_data;
GHashTable *notify;
+ void *setup_data;
};
static GHashTable *task_hash = NULL;
@@ -93,7 +95,9 @@ static void free_task(gpointer data)
*
* Returns: a newly-allocated #connman_task structure
*/
-struct connman_task *connman_task_create(const char *program)
+struct connman_task *connman_task_create(const char *program,
+ connman_task_setup_t custom_task_setup,
+ void *setup_data)
{
struct connman_task *task;
gint counter;
@@ -116,9 +120,13 @@ struct connman_task *connman_task_create(const char *program)
str = g_strdup(program);
g_ptr_array_add(task->argv, str);
+ task->setup_func = custom_task_setup;
+
task->notify = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, g_free);
+ task->setup_data = setup_data;
+
DBG("task %p", task);
g_hash_table_insert(task_hash, task->path, task);
@@ -130,7 +138,7 @@ struct connman_task *connman_task_create(const char *program)
* connman_task_destory:
* @task: task structure
*
- * Remove and destory #task
+ * Remove and destroy #task
*/
void connman_task_destroy(struct connman_task *task)
{
@@ -220,7 +228,7 @@ int connman_task_add_variable(struct connman_task *task,
/**
* connman_task_set_notify:
* @task: task structure
- * @member: notifcation method name
+ * @member: notification method name
* @function: notification callback
* @user_data: optional notification user data
*
@@ -277,6 +285,9 @@ static void task_setup(gpointer user_data)
sigemptyset(&mask);
if (sigprocmask(SIG_SETMASK, &mask, NULL) < 0)
connman_error("Failed to clean signal mask");
+
+ if (task->setup_func)
+ task->setup_func(task->setup_data);
}
/**
diff --git a/src/technology.c b/src/technology.c
index 39b0cfaa..d21d790f 100644
--- a/src/technology.c
+++ b/src/technology.c
@@ -84,6 +84,7 @@ struct connman_technology {
*/
char *tethering_ident;
char *tethering_passphrase;
+ int tethering_freq;
bool enable_persistent; /* Save the tech state */
@@ -100,6 +101,9 @@ struct connman_technology {
bool dbus_registered;
#if defined TIZEN_EXT
char **enabled_devices;
+ unsigned int mac_policy;
+ unsigned int preassoc_mac_policy;
+ unsigned int random_mac_lifetime;
#endif
#if defined TIZEN_EXT_WIFI_MESH
DBusMessage *mesh_dbus_msg;
@@ -213,10 +217,31 @@ static void technology_save(struct connman_technology *technology)
"Tethering.Identifier",
technology->tethering_ident);
- if (technology->tethering_passphrase)
+ if (technology->tethering_passphrase) {
+ char *enc = g_strescape(technology->tethering_passphrase, NULL);
g_key_file_set_string(keyfile, identifier,
- "Tethering.Passphrase",
- technology->tethering_passphrase);
+ "Tethering.Passphrase", enc);
+ g_free(enc);
+ }
+
+#ifdef TIZEN_EXT
+ if (technology->type == CONNMAN_SERVICE_TYPE_WIFI) {
+ g_key_file_set_uint64(keyfile, identifier, "MacPolicy",
+ technology->mac_policy);
+
+ g_key_file_set_uint64(keyfile, identifier, "PreassocMacPolicy",
+ technology->preassoc_mac_policy);
+
+ g_key_file_set_uint64(keyfile, identifier, "RandomMacLifetime",
+ technology->random_mac_lifetime);
+ }
+#endif /* TIZEN_EXT */
+ if (technology->tethering_freq == 0)
+ technology->tethering_freq = 2412;
+
+ g_key_file_set_integer(keyfile, identifier,
+ "Tethering.Freq",
+ technology->tethering_freq);
done:
g_free(identifier);
@@ -290,8 +315,7 @@ static int set_tethering(struct connman_technology *technology,
if (!driver || !driver->set_tethering)
continue;
- err = driver->set_tethering(technology, ident, passphrase,
- bridge, enabled);
+ err = driver->set_tethering(technology, bridge, enabled);
if (result == -EINPROGRESS)
continue;
@@ -382,25 +406,32 @@ enum connman_service_type connman_technology_get_type
return technology->type;
}
-bool connman_technology_get_wifi_tethering(const char **ssid,
- const char **psk)
+bool connman_technology_get_wifi_tethering(const struct connman_technology *technology,
+ const char **ssid, const char **psk,
+ int *freq)
{
- struct connman_technology *technology;
+ bool force = true;
if (!ssid || !psk)
return false;
*ssid = *psk = NULL;
- technology = technology_find(CONNMAN_SERVICE_TYPE_WIFI);
+ /* Workaround for the neard plugin */
+ if (!technology) {
+ technology = technology_find(CONNMAN_SERVICE_TYPE_WIFI);
+ force = false;
+ }
+
if (!technology)
return false;
- if (!technology->tethering)
+ if (!force && !technology->tethering)
return false;
*ssid = technology->tethering_ident;
*psk = technology->tethering_passphrase;
+ *freq = technology->tethering_freq;
return true;
}
@@ -430,6 +461,11 @@ static void technology_load(struct connman_technology *technology)
gchar *identifier;
GError *error = NULL;
bool enable, need_saving = false;
+#ifdef TIZEN_EXT
+ char *enc = NULL;
+#else
+ char *enc;
+#endif
DBG("technology %p", technology);
@@ -486,11 +522,46 @@ static void technology_load(struct connman_technology *technology)
technology->tethering_ident = g_key_file_get_string(keyfile,
identifier, "Tethering.Identifier", NULL);
- technology->tethering_passphrase = g_key_file_get_string(keyfile,
+ enc = g_key_file_get_string(keyfile,
identifier, "Tethering.Passphrase", NULL);
+ if (enc)
+ technology->tethering_passphrase = g_strcompress(enc);
+#ifdef TIZEN_EXT
+ if (technology->type == CONNMAN_SERVICE_TYPE_WIFI) {
+ unsigned int val = 0;
+
+ val = g_key_file_get_uint64(keyfile,
+ identifier, "MacPolicy", NULL);
+ if (val <= 2)
+ technology->mac_policy = val;
+ else
+ technology->mac_policy = 0;
+
+ val = g_key_file_get_uint64(keyfile,
+ identifier, "PreassocMacPolicy", NULL);
+ if (val <= 2)
+ technology->preassoc_mac_policy = val;
+ else
+ technology->preassoc_mac_policy = 0;
+
+ val = g_key_file_get_uint64(keyfile,
+ identifier, "RandomMacLifetime", NULL);
+ if (val > 0)
+ technology->random_mac_lifetime = val;
+ else
+ technology->random_mac_lifetime = 60;
+ }
+#endif /* TIZEN_EXT */
+
+ technology->tethering_freq = g_key_file_get_integer(keyfile,
+ identifier, "Tethering.Freq", NULL);
+
done:
g_free(identifier);
+#ifdef TIZEN_EXT
+ g_free(enc);
+#endif
g_key_file_free(keyfile);
}
@@ -666,11 +737,31 @@ static void append_properties(DBusMessageIter *iter,
connman_dbus_dict_append_basic(&dict, "TetheringPassphrase",
DBUS_TYPE_STRING,
&technology->tethering_passphrase);
+
#if defined TIZEN_EXT
+ connman_dbus_dict_append_basic(&dict, "MacPolicy",
+ DBUS_TYPE_UINT32,
+ &(technology->mac_policy));
+
+ connman_dbus_dict_append_basic(&dict, "PreassocMacPolicy",
+ DBUS_TYPE_UINT32,
+ &(technology->preassoc_mac_policy));
+
+ connman_dbus_dict_append_basic(&dict, "RandomMacLifetime",
+ DBUS_TYPE_UINT32,
+ &(technology->random_mac_lifetime));
+
if (technology->type == CONNMAN_SERVICE_TYPE_WIFI)
connman_dbus_dict_append_dict(&dict, "Device.List",
append_devices, technology);
+ if (technology->regdom)
+ connman_dbus_dict_append_basic(&dict, "CountryCode",
+ DBUS_TYPE_STRING,
+ &technology->regdom);
#endif
+ connman_dbus_dict_append_basic(&dict, "TetheringFreq",
+ DBUS_TYPE_INT32,
+ &technology->tethering_freq);
connman_dbus_dict_close(iter, &dict);
}
@@ -1078,6 +1169,190 @@ int set_connman_bssid(enum bssid_type mode, char *bssid, const char *ifname)
return bssid_len;
}
+
+void connman_technology_mac_policy_notify(struct connman_technology *technology,
+ unsigned int policy)
+{
+ DBG("Mac polict set to %u", policy);
+
+ technology->mac_policy = policy;
+ technology_save(technology);
+}
+
+void __connman_technology_notify_mac_policy_by_device(struct connman_device *device,
+ int result, unsigned int policy)
+{
+ struct connman_technology *technology;
+ enum connman_service_type type;
+
+ type = __connman_device_get_service_type(device);
+ technology = technology_find(type);
+
+ if (!technology)
+ return;
+
+ connman_technology_mac_policy_notify(technology, policy);
+}
+
+static DBusMessage *set_mac_policy(struct connman_technology *technology,
+ DBusMessage *msg, unsigned int policy)
+{
+ DBusMessage *reply = NULL;
+ int err = 0;
+ unsigned int last_policy = technology->mac_policy;
+
+ if (technology->rfkill_driven && technology->hardblocked) {
+ err = -EACCES;
+ goto make_reply;
+ }
+
+ for (GSList *list = technology->device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+
+ err = connman_device_set_mac_policy(device, policy);
+ if (err < 0)
+ break;
+ }
+
+make_reply:
+ if (err < 0) {
+ if (err != -EACCES && err != -EOPNOTSUPP) {
+ for (GSList *list = technology->device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+
+ connman_device_set_mac_policy(device, last_policy);
+ }
+ }
+
+ reply = __connman_error_failed(msg, -err);
+ } else {
+ reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ }
+
+ return reply;
+}
+
+void connman_technology_preassoc_mac_policy_notify(struct connman_technology *technology,
+ unsigned int policy)
+{
+ DBG("Preassoc mac polict set to %u", policy);
+
+ technology->preassoc_mac_policy = policy;
+ technology_save(technology);
+}
+
+void __connman_technology_notify_preassoc_mac_policy_by_device(struct connman_device *device,
+ int result, unsigned int policy)
+{
+ struct connman_technology *technology;
+ enum connman_service_type type;
+
+ type = __connman_device_get_service_type(device);
+ technology = technology_find(type);
+
+ if (!technology)
+ return;
+
+ connman_technology_preassoc_mac_policy_notify(technology, policy);
+}
+
+static DBusMessage *set_preassoc_mac_policy(struct connman_technology *technology,
+ DBusMessage *msg, unsigned int policy)
+{
+ DBusMessage *reply = NULL;
+ int err = 0;
+ unsigned int last_policy = technology->preassoc_mac_policy;
+
+ if (technology->rfkill_driven && technology->hardblocked) {
+ err = -EACCES;
+ goto make_reply;
+ }
+
+ for (GSList *list = technology->device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+
+ err = connman_device_set_preassoc_mac_policy(device, policy);
+ if (err < 0)
+ break;
+ }
+
+make_reply:
+ if (err < 0) {
+ if (err != -EACCES && err != -EOPNOTSUPP) {
+ for (GSList *list = technology->device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+
+ connman_device_set_preassoc_mac_policy(device, last_policy);
+ }
+ }
+
+ reply = __connman_error_failed(msg, -err);
+ } else {
+ reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ }
+
+ return reply;
+}
+
+void connman_technology_random_mac_lifetime_notify(struct connman_technology *technology,
+ unsigned int lifetime)
+{
+ DBG("Random mac lifetime set to %u", lifetime);
+
+ technology->random_mac_lifetime = lifetime;
+ technology_save(technology);
+}
+
+void __connman_technology_notify_random_mac_lifetime_by_device(struct connman_device *device,
+ int result, unsigned int lifetime)
+{
+ struct connman_technology *technology;
+ enum connman_service_type type;
+
+ type = __connman_device_get_service_type(device);
+ technology = technology_find(type);
+
+ if (!technology)
+ return;
+
+ connman_technology_random_mac_lifetime_notify(technology, lifetime);
+}
+
+static DBusMessage *set_random_mac_lifetime(struct connman_technology *technology,
+ DBusMessage *msg, unsigned int lifetime)
+{
+ DBusMessage *reply = NULL;
+ int err = 0;
+ unsigned int last_lifetime = technology->random_mac_lifetime;
+
+ if (technology->rfkill_driven && technology->hardblocked) {
+ err = -EACCES;
+ goto make_reply;
+ }
+
+ for (GSList *list = technology->device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+
+ err = connman_device_set_random_mac_lifetime(device, lifetime);
+ }
+
+make_reply:
+ if (err < 0) {
+ if (err != -EACCES && err != -EOPNOTSUPP) {
+ for (GSList *list = technology->device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+
+ connman_device_set_random_mac_lifetime(device, last_lifetime);
+ }
+ }
+
+ reply = __connman_error_failed(msg, -err);
+ } else {
+ reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ }
+
+ return reply;
+}
#endif
static DBusMessage *set_property(DBusConnection *conn,
@@ -1184,6 +1459,27 @@ static DBusMessage *set_property(DBusConnection *conn,
DBUS_TYPE_STRING,
&technology->tethering_passphrase);
}
+ } else if (g_str_equal(name, "TetheringFreq")) {
+ dbus_int32_t freq;
+
+ if (type != DBUS_TYPE_INT32)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value, &freq);
+
+ if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
+ return __connman_error_not_supported(msg);
+
+ if (freq >= 0) {
+ technology->tethering_freq = freq;
+ technology_save(technology);
+
+ connman_dbus_property_changed_basic(technology->path,
+ CONNMAN_TECHNOLOGY_INTERFACE,
+ "TetheringFreq",
+ DBUS_TYPE_INT32,
+ &technology->tethering_freq);
+ }
} else if (g_str_equal(name, "Powered")) {
dbus_bool_t enable;
@@ -1203,6 +1499,60 @@ static DBusMessage *set_property(DBusConnection *conn,
dbus_message_iter_get_basic(&value, &key);
DBG("BSSID %s", key);
set_connman_bssid(SET_BSSID, key, NULL);
+ } else if (g_str_equal(name, "MacPolicy")) {
+ dbus_uint32_t mac_policy;
+
+ if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
+ return __connman_error_not_supported(msg);
+
+ if (type != DBUS_TYPE_UINT32)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value, &mac_policy);
+
+ if (mac_policy <= 2)
+ return set_mac_policy(technology, msg, mac_policy);
+ else
+ return __connman_error_invalid_arguments(msg);
+
+ } else if (g_str_equal(name, "PreassocMacPolicy")) {
+ dbus_uint32_t preassoc_mac_policy;
+
+ if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
+ return __connman_error_not_supported(msg);
+
+ if (type != DBUS_TYPE_UINT32)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value, &preassoc_mac_policy);
+
+ if (preassoc_mac_policy <= 2)
+ return set_preassoc_mac_policy(technology, msg, preassoc_mac_policy);
+ else
+ return __connman_error_invalid_arguments(msg);
+
+ } else if (g_str_equal(name, "RandomMacLifetime")) {
+ dbus_uint32_t random_mac_lifetime;
+
+ if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
+ return __connman_error_not_supported(msg);
+
+ if (type != DBUS_TYPE_UINT32)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value, &random_mac_lifetime);
+
+ if (random_mac_lifetime > 0)
+ return set_random_mac_lifetime(technology, msg, random_mac_lifetime);
+ else
+ return __connman_error_invalid_arguments(msg);
+
+ } else if (g_str_equal(name, "CountryCode")) {
+ const char *str;
+
+ dbus_message_iter_get_basic(&value, &str);
+ DBG("country code %s", str);
+ connman_technology_set_regdom(str);
#endif
} else
return __connman_error_invalid_property(msg);
@@ -1364,6 +1714,56 @@ static void __connman_technology_notify_device_detected(
DBG("Successfuly sent DeviceDetected signal");
}
+
+void __connman_technology_notify_device_detected_by_device(
+ struct connman_device *device, const char *ifname, bool val)
+{
+ struct connman_technology *technology;
+ enum connman_service_type type;
+
+ type = __connman_device_get_service_type(device);
+
+ technology = technology_find(type);
+ if (technology)
+ __connman_technology_notify_device_detected(technology, ifname, val);
+}
+
+void __connman_technology_notify_roaming_state(const char *ifname,
+ const char *state, const char *cur_bssid, const char *dst_bssid)
+{
+ DBG("");
+ DBusMessage *signal;
+ DBusMessageIter array, dict;
+
+ signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
+ CONNMAN_MANAGER_INTERFACE, "RoamingStateChanged");
+ if (!signal)
+ return;
+
+ dbus_message_iter_init_append(signal, &array);
+
+ connman_dbus_dict_open(&array, &dict);
+
+ if (ifname)
+ connman_dbus_dict_append_basic(&dict, "Interface",
+ DBUS_TYPE_STRING, &ifname);
+ if (state)
+ connman_dbus_dict_append_basic(&dict, "State",
+ DBUS_TYPE_STRING, &state);
+ if (cur_bssid)
+ connman_dbus_dict_append_basic(&dict, "ConnectedBSSID",
+ DBUS_TYPE_STRING, &cur_bssid);
+ if (dst_bssid)
+ connman_dbus_dict_append_basic(&dict, "TargetBSSID",
+ DBUS_TYPE_STRING, &dst_bssid);
+
+ connman_dbus_dict_close(&array, &dict);
+
+ dbus_connection_send(connection, signal, NULL);
+ dbus_message_unref(signal);
+
+ DBG("Successfully sent Roaming State Changed signal");
+}
#endif
void __connman_technology_scan_started(struct connman_device *device)
@@ -1406,9 +1806,10 @@ void __connman_technology_scan_stopped(struct connman_device *device,
reply_scan_pending_device(technology, ifname, count);
return;
-#endif
+#else
if (count == 0)
reply_scan_pending(technology, 0);
+#endif
}
void __connman_technology_notify_regdom_by_device(struct connman_device *device,
@@ -1716,6 +2117,41 @@ static DBusMessage *get_5ghz_supported(DBusConnection *conn, DBusMessage *msg, v
return reply;
}
+static DBusMessage *get_6ghz_supported(DBusConnection *conn, DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter, dict;
+ GSList *list;
+ struct connman_technology *technology = data;
+ dbus_bool_t supported = false;
+ const char *ifname = NULL;
+
+ DBG("technology %p", technology);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+ connman_dbus_dict_open(&iter, &dict);
+
+ for (list = technology->device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+
+ supported = connman_device_get_wifi_6ghz_supported(device);
+ ifname = connman_device_get_string(device, "Interface");
+
+ DBG("ifname %s supported : %d", ifname, supported);
+ connman_dbus_dict_append_basic(&dict, ifname,
+ DBUS_TYPE_BOOLEAN,
+ &supported);
+ }
+
+ connman_dbus_dict_close(&iter, &dict);
+
+ return reply;
+}
+
static DBusMessage *get_scan_state(DBusConnection *conn, DBusMessage *msg, void *data)
{
DBusMessage *reply;
@@ -1915,10 +2351,17 @@ void technology_save_device(struct connman_device *device)
enum connman_service_type type;
type = __connman_device_get_service_type(device);
+
+ if (type != CONNMAN_SERVICE_TYPE_WIFI)
+ return;
+
technology = technology_get(type);
if (!technology)
return;
+ if (!g_slist_find(technology->device_list, device))
+ return;
+
GKeyFile *keyfile;
gchar *identifier;
const char *name = get_name(technology->type);
@@ -1940,7 +2383,7 @@ void technology_save_device(struct connman_device *device)
gchar **ifname_list = NULL;
guint dev_count = g_slist_length(technology->device_list);
- if (dev_count > 1) {
+ if (dev_count >= 1) {
GString *ifname_str = g_string_new(NULL);
if (ifname_str) {
@@ -2487,6 +2930,8 @@ static const GDBusMethodTable technology_methods[] = {
get_scan_state) },
{ GDBUS_METHOD("Get5GhzSupported", NULL, GDBUS_ARGS({ "supported", "a{sv}" }),
get_5ghz_supported) },
+ { GDBUS_METHOD("Get6GHzSupported", NULL, GDBUS_ARGS({ "supported", "a{sv}" }),
+ get_6ghz_supported) },
{ GDBUS_METHOD("GetMaxScanSsid", NULL, GDBUS_ARGS({ "maxscanssid", "a{sv}" }),
get_max_scan_ssid) },
{ GDBUS_ASYNC_METHOD("SetDevicePower",
@@ -2570,7 +3015,9 @@ static void technology_put(struct connman_technology *technology)
g_slist_delete_link(technology->driver_list,
technology->driver_list);
}
-
+#ifdef TIZEN_EXT
+ __connman_technology_notify_device_detected(technology, "", false);
+#endif
technology_list = g_slist_remove(technology_list, technology);
technology_dbus_unregister(technology);
@@ -2920,7 +3367,7 @@ int __connman_technology_add_device(struct connman_device *device)
#if defined TIZEN_EXT
bool found = true;
int err = 0;
- if (technology->enabled_devices) {
+ if (technology->enabled_devices && type == CONNMAN_SERVICE_TYPE_WIFI) {
int i = 0;
found = false;
const char *ifname = connman_device_get_string(device, "Interface");
@@ -2957,8 +3404,14 @@ done:
device);
#if defined TIZEN_EXT
+ technology_save_device(device);
+
const char *ifname = connman_device_get_string(device, "Interface");
__connman_technology_notify_device_detected(technology, ifname, true);
+
+ connman_device_set_mac_policy(device, technology->mac_policy);
+ connman_device_set_preassoc_mac_policy(device, technology->preassoc_mac_policy);
+ connman_device_set_random_mac_lifetime(device, technology->random_mac_lifetime);
#endif
return 0;
}
@@ -2983,8 +3436,7 @@ int __connman_technology_remove_device(struct connman_device *device)
device);
#if defined TIZEN_EXT
- const char *ifname = connman_device_get_string(device, "Interface");
- __connman_technology_notify_device_detected(technology, ifname, false);
+ technology_save_device(device);
#endif
if (technology->tethering)
diff --git a/src/tethering.c b/src/tethering.c
index e04756ff..f930a26b 100755
--- a/src/tethering.c
+++ b/src/tethering.c
@@ -386,7 +386,8 @@ static void setup_tun_interface(unsigned int flags, unsigned change,
if ((__connman_inet_modify_address(RTM_NEWADDR,
NLM_F_REPLACE | NLM_F_ACK, pn->index, AF_INET,
- server_ip, peer_ip, prefixlen, NULL)) < 0) {
+ server_ip, peer_ip, prefixlen, NULL, true))
+ < 0) {
DBG("address setting failed");
return;
}
@@ -637,8 +638,8 @@ void __connman_tethering_client_register(const char *addr)
void __connman_tethering_client_unregister(const char *addr)
{
- g_hash_table_remove(clients_table, addr);
client_removed(addr);
+ g_hash_table_remove(clients_table, addr);
}
int __connman_tethering_init(void)
diff --git a/src/timeserver.c b/src/timeserver.c
index ac99f76d..2df609f3 100755
--- a/src/timeserver.c
+++ b/src/timeserver.c
@@ -29,6 +29,7 @@
#include <stdlib.h>
#include <gweb/gresolv.h>
#include <netdb.h>
+#include <sys/time.h>
#include "connman.h"
@@ -40,6 +41,7 @@ static GSList *ts_list = NULL;
static char *ts_current = NULL;
static int ts_recheck_id = 0;
static int ts_backoff_id = 0;
+static bool ts_is_synced = false;
static GResolv *resolv = NULL;
static int resolv_id = 0;
@@ -53,10 +55,26 @@ static void resolv_debug(const char *str, void *data)
static void ntp_callback(bool success, void *user_data)
{
+ dbus_uint64_t timestamp;
+ struct timeval tv;
+
DBG("success %d", success);
- if (!success)
+ __connman_timeserver_set_synced(success);
+ if (!success) {
sync_next();
+ return;
+ }
+
+ if (gettimeofday(&tv, NULL) < 0) {
+ connman_warn("Failed to get current time");
+ }
+
+ timestamp = tv.tv_sec;
+ connman_dbus_property_changed_basic(
+ CONNMAN_MANAGER_PATH,
+ CONNMAN_CLOCK_INTERFACE, "Time",
+ DBUS_TYPE_UINT64, &timestamp);
}
static void save_timeservers(char **servers)
@@ -188,7 +206,12 @@ static void sync_next(void)
return;
}
#if defined TIZEN_EXT
- if (!simplified_log)
+ if (ts_current[0] == '\0') {
+ DBG("current time server is empty. ignore next time server..");
+ return;
+ }
+
+ if (!simplified_log)
#endif
DBG("Resolving timeserver %s", ts_current);
#if defined TIZEN_EXT
@@ -290,6 +313,7 @@ GSList *__connman_timeserver_get_all(struct connman_service *service)
static gboolean ts_recheck(gpointer user_data)
{
+ struct connman_service *service;
GSList *ts;
ts = __connman_timeserver_get_all(connman_service_get_default());
@@ -305,7 +329,8 @@ static gboolean ts_recheck(gpointer user_data)
g_slist_free_full(ts, g_free);
- __connman_timeserver_sync(NULL);
+ service = connman_service_get_default();
+ __connman_timeserver_sync(service);
return FALSE;
}
@@ -345,31 +370,16 @@ static void ts_recheck_enable(void)
NULL);
}
-/*
- * This function must be called everytime the default service changes, the
- * service timeserver(s) or gateway changes or the global timeserver(s) changes.
- */
-int __connman_timeserver_sync(struct connman_service *default_service)
+static void ts_reset(struct connman_service *service)
{
- struct connman_service *service;
char **nameservers;
int i;
- if (default_service)
- service = default_service;
- else
- service = connman_service_get_default();
-
- if (!service)
- return -EINVAL;
+ if (!resolv)
+ return;
-#if !defined TIZEN_EXT
- if (service == ts_service)
- return -EALREADY;
-#endif
+ __connman_timeserver_set_synced(false);
- if (!resolv)
- return 0;
/*
* Before we start creating the new timeserver list we must stop
* any ongoing ntp query and server resolution.
@@ -385,13 +395,12 @@ int __connman_timeserver_sync(struct connman_service *default_service)
g_resolv_flush_nameservers(resolv);
nameservers = connman_service_get_nameservers(service);
- if (!nameservers)
- return -EINVAL;
-
- for (i = 0; nameservers[i]; i++)
- g_resolv_add_nameserver(resolv, nameservers[i], 53, 0);
+ if (nameservers) {
+ for (i = 0; nameservers[i]; i++)
+ g_resolv_add_nameserver(resolv, nameservers[i], 53, 0);
- g_strfreev(nameservers);
+ g_strfreev(nameservers);
+ }
g_slist_free_full(timeservers_list, g_free);
@@ -401,15 +410,49 @@ int __connman_timeserver_sync(struct connman_service *default_service)
if (!timeservers_list) {
DBG("No timeservers set.");
- return 0;
+ return;
}
ts_recheck_enable();
ts_service = service;
timeserver_sync_start();
+}
- return 0;
+void __connman_timeserver_sync(struct connman_service *service)
+{
+ if (!service || ts_service == service)
+ return;
+
+ ts_reset(service);
+}
+
+void __connman_timeserver_conf_update(struct connman_service *service)
+{
+ if (!service || (ts_service && ts_service != service))
+ return;
+
+ ts_reset(service);
+}
+
+
+bool __connman_timeserver_is_synced(void)
+{
+ return ts_is_synced;
+}
+
+void __connman_timeserver_set_synced(bool status)
+{
+ dbus_bool_t is_synced;
+
+ if (ts_is_synced == status)
+ return;
+
+ ts_is_synced = status;
+ is_synced = status;
+ connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
+ CONNMAN_CLOCK_INTERFACE, "TimeserverSynced",
+ DBUS_TYPE_BOOLEAN, &is_synced);
}
static int timeserver_start(struct connman_service *service)
@@ -451,7 +494,9 @@ static int timeserver_start(struct connman_service *service)
g_strfreev(nameservers);
}
- return __connman_timeserver_sync(service);
+ __connman_timeserver_sync(service);
+
+ return 0;
}
static void timeserver_stop(void)
@@ -478,9 +523,13 @@ static void timeserver_stop(void)
int __connman_timeserver_system_set(char **servers)
{
+ struct connman_service *service;
+
save_timeservers(servers);
- __connman_timeserver_sync(NULL);
+ service = connman_service_get_default();
+ if (service)
+ ts_reset(service);
return 0;
}
diff --git a/src/timezone.c b/src/timezone.c
index 8e912670..cc499097 100755
--- a/src/timezone.c
+++ b/src/timezone.c
@@ -187,7 +187,10 @@ static char *find_origin(void *src_map, struct stat *src_st,
subpath, d->d_name);
if (compare_file(src_map, src_st, pathname) == 0) {
- str = g_strdup_printf("%s/%s",
+ if (!subpath)
+ str = g_strdup(d->d_name);
+ else
+ str = g_strdup_printf("%s/%s",
subpath, d->d_name);
closedir(dir);
return str;
diff --git a/src/wispr.c b/src/wispr.c
index 62f6b8db..f4dcb73e 100755
--- a/src/wispr.c
+++ b/src/wispr.c
@@ -30,9 +30,6 @@
#include "connman.h"
-#define STATUS_URL_IPV4 "http://ipv4.connman.net/online/status.html"
-#define STATUS_URL_IPV6 "http://ipv6.connman.net/online/status.html"
-
struct connman_wispr_message {
bool has_error;
const char *current_element;
@@ -96,6 +93,10 @@ static bool wispr_portal_web_result(GWebResult *result, gpointer user_data);
static GHashTable *wispr_portal_list = NULL;
+static char *online_check_ipv4_url = NULL;
+static char *online_check_ipv6_url = NULL;
+static bool enable_online_to_ready_transition = false;
+
static void connman_wispr_message_init(struct connman_wispr_message *msg)
{
DBG("");
@@ -424,7 +425,8 @@ static void wispr_portal_error(struct connman_wispr_portal_context *wp_context)
wp_context->wispr_result = CONNMAN_WISPR_RESULT_FAILED;
#if defined TIZEN_EXT
- connman_service_set_internet_connection(wp_context->service, false);
+ if (TIZEN_INS_ENABLED)
+ connman_service_set_internet_connection(wp_context->service, false);
#endif
}
@@ -454,10 +456,14 @@ static void portal_manage_status(GWebResult *result,
&str))
connman_info("Client-Timezone: %s", str);
- free_connman_wispr_portal_context(wp_context);
+ if (!enable_online_to_ready_transition)
+ free_connman_wispr_portal_context(wp_context);
__connman_service_ipconfig_indicate_state(service,
CONNMAN_SERVICE_STATE_ONLINE, type);
+
+ if (enable_online_to_ready_transition)
+ __connman_service_online_check(service, type, true);
}
static bool wispr_route_request(const char *address, int ai_family,
@@ -559,12 +565,31 @@ static void wispr_portal_browser_reply_cb(struct connman_service *service,
const char *error, void *user_data)
{
struct connman_wispr_portal_context *wp_context = user_data;
+ struct connman_wispr_portal *wispr_portal;
+ int index;
DBG("");
if (!service || !wp_context)
return;
+ /*
+ * No way to cancel this if wp_context has been freed, so we lookup
+ * from the service and check that this is still the right context.
+ */
+ index = __connman_service_get_index(service);
+ if (index < 0)
+ return;
+
+ wispr_portal = g_hash_table_lookup(wispr_portal_list,
+ GINT_TO_POINTER(index));
+ if (!wispr_portal)
+ return;
+
+ if (wp_context != wispr_portal->ipv4_context &&
+ wp_context != wispr_portal->ipv6_context)
+ return;
+
if (!authentication_done) {
wispr_portal_error(wp_context);
free_wispr_routes(wp_context);
@@ -742,7 +767,12 @@ static bool wispr_portal_web_result(GWebResult *result, gpointer user_data)
wp_context->redirect_url, wp_context);
break;
+ case 300:
+ case 301:
case 302:
+ case 303:
+ case 307:
+ case 308:
if (!g_web_supports_tls() ||
!g_web_result_get_header(result, "Location",
&redirect)) {
@@ -764,8 +794,8 @@ static bool wispr_portal_web_result(GWebResult *result, gpointer user_data)
goto done;
case 400:
case 404:
- if (__connman_service_online_check_failed(wp_context->service,
- wp_context->type) == 0) {
+ __connman_service_online_check(wp_context->service,
+ wp_context->type, false);
#if defined TIZEN_MAINTAIN_ONLINE
if (wp_context->type == CONNMAN_IPCONFIG_TYPE_IPV4) {
if (retried == 0) {
@@ -779,11 +809,6 @@ static bool wispr_portal_web_result(GWebResult *result, gpointer user_data)
break;
}
#endif
- wispr_portal_error(wp_context);
- free_connman_wispr_portal_context(wp_context);
- return false;
- }
-
break;
case 505:
__connman_agent_request_browser(wp_context->service,
@@ -912,10 +937,10 @@ static int wispr_portal_detect(struct connman_wispr_portal_context *wp_context)
if (wp_context->type == CONNMAN_IPCONFIG_TYPE_IPV4) {
g_web_set_address_family(wp_context->web, AF_INET);
- wp_context->status_url = STATUS_URL_IPV4;
+ wp_context->status_url = online_check_ipv4_url;
} else {
g_web_set_address_family(wp_context->web, AF_INET6);
- wp_context->status_url = STATUS_URL_IPV6;
+ wp_context->status_url = online_check_ipv6_url;
}
for (i = 0; nameservers[i]; i++)
@@ -1005,6 +1030,7 @@ int __connman_wispr_start(struct connman_service *service,
void __connman_wispr_stop(struct connman_service *service)
{
+ struct connman_wispr_portal *wispr_portal;
int index;
DBG("service %p", service);
@@ -1016,7 +1042,16 @@ void __connman_wispr_stop(struct connman_service *service)
if (index < 0)
return;
- g_hash_table_remove(wispr_portal_list, GINT_TO_POINTER(index));
+ wispr_portal = g_hash_table_lookup(wispr_portal_list,
+ GINT_TO_POINTER(index));
+ if (!wispr_portal)
+ return;
+
+ if ((wispr_portal->ipv4_context &&
+ service == wispr_portal->ipv4_context->service) ||
+ (wispr_portal->ipv6_context &&
+ service == wispr_portal->ipv6_context->service))
+ g_hash_table_remove(wispr_portal_list, GINT_TO_POINTER(index));
}
int __connman_wispr_init(void)
@@ -1027,6 +1062,14 @@ int __connman_wispr_init(void)
g_direct_equal, NULL,
free_connman_wispr_portal);
+ online_check_ipv4_url =
+ connman_setting_get_string("OnlineCheckIPv4URL");
+ online_check_ipv6_url =
+ connman_setting_get_string("OnlineCheckIPv6URL");
+
+ enable_online_to_ready_transition =
+ connman_setting_get_bool("EnableOnlineToReadyTransition");
+
return 0;
}
diff --git a/test/backtrace b/test/backtrace
index c906f369..c6247090 100755
--- a/test/backtrace
+++ b/test/backtrace
@@ -6,7 +6,7 @@ import sys
import subprocess
if (len(sys.argv) < 3):
- print "Usage: %s [binary] [log]" % (sys.argv[0])
+ print("Usage: %s [binary] [log]" % (sys.argv[0]))
sys.exit(1)
binary = sys.argv[1]
@@ -50,8 +50,8 @@ child_stdout.close()
frame_count = len(frames);
count = 0
-print "-------- backtrace --------"
+print("-------- backtrace --------")
while count < frame_count:
- print "[%d]: %s() [%s]" % (count/2, frames[count], frames[count + 1])
+ print("[%d]: %s() [%s]" % (count/2, frames[count], frames[count + 1]))
count = count + 2
-print "---------------------------"
+print("---------------------------")
diff --git a/test/connect-provider b/test/connect-provider
index 15128c85..504bce47 100755
--- a/test/connect-provider
+++ b/test/connect-provider
@@ -4,15 +4,15 @@ import sys
import dbus
if (len(sys.argv) < 4):
- print "Usage: %s <type> ... " % (sys.argv[0])
- print " type: openconnect"
- print " <name> <host> <domain> <cookie> [servercert]"
- print " type: openvpn"
- print " <name> <host> <domain> [<cafile> <certfile> <keyfile>]"
- print " type: pptp"
- print " <name> <host> <domain> <user> <password>"
- print " type: l2tp"
- print " <name> <host> <domain> <user> <password>"
+ print("Usage: %s <type> ... " % (sys.argv[0]))
+ print(" type: openconnect")
+ print(" <name> <host> <domain> <cookie> [servercert]")
+ print(" type: openvpn")
+ print(" <name> <host> <domain> [<cafile> <certfile> <keyfile>]")
+ print(" type: pptp")
+ print(" <name> <host> <domain> <user> <password>")
+ print(" type: l2tp")
+ print(" <name> <host> <domain> <user> <password>")
sys.exit(1)
bus = dbus.SystemBus()
@@ -20,7 +20,7 @@ bus = dbus.SystemBus()
manager = dbus.Interface(bus.get_object("net.connman", "/"),
"net.connman.Manager")
-print "Attempting to connect service %s" % (sys.argv[3])
+print("Attempting to connect service %s" % (sys.argv[3]))
if sys.argv[1] == "openconnect":
if (len(sys.argv) > 6):
@@ -67,7 +67,7 @@ elif sys.argv[1] == "l2tp":
"L2TP.Password": sys.argv[6]}))
else:
- print "Unknown VPN type"
+ print("Unknown VPN type")
sys.exit(1)
-print "VPN service path is %s" %(path)
+print("VPN service path is %s" %(path))
diff --git a/test/disable-tethering b/test/disable-tethering
index a3d5908c..41f3d798 100755
--- a/test/disable-tethering
+++ b/test/disable-tethering
@@ -4,7 +4,7 @@ import sys
import dbus
if (len(sys.argv) != 2):
- print "Usage: %s type" % (sys.argv[0])
+ print("Usage: %s type" % (sys.argv[0]))
sys.exit(1)
bus = dbus.SystemBus()
@@ -18,10 +18,10 @@ def technology_disable_tethering(path, tech_type):
properties = tech.GetProperties()
- for key in properties.keys():
+ for key in list(properties.keys()):
if key in ["Type"]:
if properties[key] == tech_type:
- print "Disabling %s tethering" % tech_type
+ print("Disabling %s tethering" % tech_type)
tech.SetProperty("Tethering", dbus.Boolean(0))
return tech_type
@@ -37,4 +37,4 @@ for path,_ in technologies:
break;
if tech == None:
- print "Failed to disable %s tethering" % (sys.argv[1])
+ print("Failed to disable %s tethering" % (sys.argv[1]))
diff --git a/test/enable-tethering b/test/enable-tethering
index cbcd4e72..13e5a18c 100755
--- a/test/enable-tethering
+++ b/test/enable-tethering
@@ -4,10 +4,10 @@ import sys
import dbus
if (len(sys.argv) >= 3 and len(sys.argv) != 4 and sys.argv[1] == "wifi"):
- print "Usage: %s wifi [SSID] [passphrase]" % (sys.argv[0])
+ print("Usage: %s wifi [SSID] [passphrase]" % (sys.argv[0]))
sys.exit(1)
elif (len(sys.argv) < 2):
- print "Usage: %s type" % (sys.argv[0])
+ print("Usage: %s type" % (sys.argv[0]))
sys.exit(1)
bus = dbus.SystemBus()
@@ -21,7 +21,7 @@ def technology_enable_tethering(path, tech_type, ssid, psk):
properties = tech.GetProperties()
- for key in properties.keys():
+ for key in list(properties.keys()):
if key in ["Type"]:
if properties[key] == tech_type:
if len(ssid) > 0:
@@ -30,7 +30,7 @@ def technology_enable_tethering(path, tech_type, ssid, psk):
if len(psk) > 0:
tech.SetProperty("TetheringPassphrase",
psk)
- print "Enabling %s tethering" % tech_type
+ print("Enabling %s tethering" % tech_type)
tech.SetProperty("Tethering", dbus.Boolean(1))
return tech_type
@@ -51,4 +51,4 @@ for path,_ in technologies:
break;
if tech == None:
- print "Failed to enable %s tethering" % (sys.argv[1])
+ print("Failed to enable %s tethering" % (sys.argv[1]))
diff --git a/test/get-global-timeservers b/test/get-global-timeservers
index adcf175a..2436b363 100755
--- a/test/get-global-timeservers
+++ b/test/get-global-timeservers
@@ -9,4 +9,4 @@ clock = dbus.Interface(bus.get_object('net.connman', '/'),
properties = clock.GetProperties()
-print "Timeserver is %s" % (properties["Timeservers"])
+print("Timeserver is %s" % (properties["Timeservers"]))
diff --git a/test/get-proxy-autoconfig b/test/get-proxy-autoconfig
index 6709a9e8..b96e800e 100755
--- a/test/get-proxy-autoconfig
+++ b/test/get-proxy-autoconfig
@@ -1,12 +1,12 @@
#!/usr/bin/python
import dbus
-import urllib
+import urllib.request, urllib.parse, urllib.error
def get_pac(url):
- conn = urllib.urlopen(url, proxies={})
+ conn = urllib.request.urlopen(url, proxies={})
data = conn.read()
- print data
+ print(data)
conn.close()
bus = dbus.SystemBus()
@@ -23,15 +23,15 @@ for entry in services:
proxy = properties["Proxy"]
if "Method" in proxy:
- print "[ %s ]" % (path)
+ print("[ %s ]" % (path))
method = proxy["Method"]
- print "Method = %s" % (method)
+ print("Method = %s" % (method))
if method in ["auto"]:
url = proxy["URL"]
- print "URL = %s" % (url)
- print
+ print("URL = %s" % (url))
+ print()
get_pac(url)
else:
- print
+ print()
diff --git a/test/get-services b/test/get-services
index 09564804..2fa8b5b7 100755
--- a/test/get-services
+++ b/test/get-services
@@ -4,7 +4,7 @@ import dbus
def extract_values(values):
val = "{"
- for key in values.keys():
+ for key in list(values.keys()):
val += " " + key + "="
if key in ["Servers", "Excludes"]:
val += extract_list(values[key])
@@ -31,9 +31,9 @@ for entry in services:
path = entry[0]
properties = entry[1]
- print "[ %s ]" % (path)
+ print("[ %s ]" % (path))
- for key in properties.keys():
+ for key in list(properties.keys()):
if key in ["IPv4", "IPv4.Configuration",
"IPv6", "IPv6.Configuration",
"Proxy", "Proxy.Configuration",
@@ -53,6 +53,6 @@ for entry in services:
val = int(properties[key])
else:
val = str(properties[key])
- print " %s = %s" % (key, val)
+ print(" %s = %s" % (key, val))
- print
+ print()
diff --git a/test/get-state b/test/get-state
index 75d5a16a..e991f583 100755
--- a/test/get-state
+++ b/test/get-state
@@ -9,4 +9,4 @@ manager = dbus.Interface(bus.get_object('net.connman', "/"),
properties = manager.GetProperties()
-print "System is %s" % (properties["State"])
+print("System is %s" % (properties["State"]))
diff --git a/test/list-services b/test/list-services
index a2610d7e..4accf773 100755
--- a/test/list-services
+++ b/test/list-services
@@ -4,7 +4,7 @@ import dbus
def extract_values(values):
val = "{"
- for key in values.keys():
+ for key in list(values.keys()):
val += " " + key + "="
if key in ["PrefixLength"]:
val += "%s" % (int(values[key]))
@@ -34,9 +34,9 @@ for path, properties in manager.GetServices():
service = dbus.Interface(bus.get_object("net.connman", path),
"net.connman.Service")
identifier = path[path.rfind("/") + 1:]
- print "[ %s ]" % (identifier)
+ print("[ %s ]" % (identifier))
- for key in properties.keys():
+ for key in list(properties.keys()):
if key in ["IPv4", "IPv4.Configuration",
"IPv6", "IPv6.Configuration",
"Proxy", "Proxy.Configuration",
@@ -58,6 +58,6 @@ for path, properties in manager.GetServices():
val = int(properties[key])
else:
val = properties[key]
- print " %s = %s" % (key, val)
+ print(" %s = %s" % (key, val))
- print
+ print()
diff --git a/test/monitor-connman b/test/monitor-connman
index 1b3b84c7..c6edd760 100755
--- a/test/monitor-connman
+++ b/test/monitor-connman
@@ -1,6 +1,6 @@
#!/usr/bin/python
-import gobject
+from gi.repository import GLib
import dbus
import dbus.mainloop.glib
@@ -19,7 +19,7 @@ def extract_list(list):
def extract_values(values):
val = "{"
- for key in values.keys():
+ for key in list(values.keys()):
val += " " + key + "="
if key in ["PrefixLength"]:
val += "%s" % (int(values[key]))
@@ -54,7 +54,7 @@ def property_changed(name, value, path, interface):
iface = interface[interface.rfind(".") + 1:]
val = extract(name, value)
- print "{%s} [%s] %s = %s" % (iface, path, name, val)
+ print("{%s} [%s] %s = %s" % (iface, path, name, val))
def message_filter(connection, message):
if not isinstance(message, MethodCallMessage):
@@ -82,6 +82,6 @@ if __name__ == '__main__':
bus.add_match_string("member=Update,interface=net.connman.Notification")
bus.add_message_filter(message_filter)
- mainloop = gobject.MainLoop()
+ mainloop = GLib.MainLoop()
mainloop.run()
diff --git a/test/monitor-services b/test/monitor-services
index 9476bf8f..c520a8cd 100755
--- a/test/monitor-services
+++ b/test/monitor-services
@@ -1,13 +1,13 @@
#!/usr/bin/python
-import gobject
+from gi.repository import GLib
import dbus
import dbus.mainloop.glib
def extract_values(values):
val = "{"
- for key in values.keys():
+ for key in list(values.keys()):
val += " " + key + "="
if key in ["Servers", "Excludes"]:
val += extract_list(values[key])
@@ -42,27 +42,27 @@ def property_changed(name, value, path):
val = int(value)
else:
val = str(value)
- print "[%s] %s = %s" % (service, name, val)
+ print("[%s] %s = %s" % (service, name, val))
def services_changed(services, removed):
for i in services:
service = i[0][i[0].rfind("/") + 1:]
- print "[%s] changed" % (service)
- for n in i[1].keys():
+ print("[%s] changed" % (service))
+ for n in list(i[1].keys()):
property_changed(n, i[1][n], i[0])
for i in removed:
service = i[i.rfind("/") + 1:]
- print "[%s] removed" % (service)
+ print("[%s] removed" % (service))
def technology_added(path, properties):
technology = path[path.rfind("/") + 1:]
- print "[%s] added" % (technology)
- for n in properties.keys():
+ print("[%s] added" % (technology))
+ for n in list(properties.keys()):
property_changed(n, properties[n], technology)
def technology_removed(path):
technology = path[path.rfind("/") + 1:]
- print "[%s] removed" % (technology)
+ print("[%s] removed" % (technology))
if __name__ == '__main__':
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
@@ -102,5 +102,5 @@ if __name__ == '__main__':
signal_name="PropertyChanged",
path_keyword="path")
- mainloop = gobject.MainLoop()
+ mainloop = GLib.MainLoop()
mainloop.run()
diff --git a/test/monitor-vpn b/test/monitor-vpn
index 2b636871..e019e6ec 100755
--- a/test/monitor-vpn
+++ b/test/monitor-vpn
@@ -21,7 +21,7 @@ def extract_list(list):
def extract_values(values):
val = "{"
- for key in values.keys():
+ for key in list(values.keys()):
val += " " + key + "="
if key in ["ProtocolFamily"]:
val += "%s" % (int(values[key]))
@@ -50,7 +50,7 @@ def property_changed(name, value, path, interface):
iface = interface[interface.rfind(".") + 1:]
val = extract(name, value)
- print "{%s} [%s] %s = %s" % (iface, path, name, val)
+ print("{%s} [%s] %s = %s" % (iface, path, name, val))
def message_filter(connection, message):
if not isinstance(message, MethodCallMessage):
diff --git a/test/p2p-on-supplicant b/test/p2p-on-supplicant
index 8cc76e81..22501fc3 100755
--- a/test/p2p-on-supplicant
+++ b/test/p2p-on-supplicant
@@ -3,10 +3,9 @@
from os import O_NONBLOCK
from sys import stdin, stdout, exit, version_info, argv
from fcntl import fcntl, F_GETFL, F_SETFL
-import glib
+from gi.repository import GLib
import dbus
import dbus.mainloop.glib
-import gobject
import argparse
WPA_NAME='fi.w1.wpa_supplicant1'
@@ -32,17 +31,17 @@ class InputLine:
flags = fcntl(stdin.fileno(), F_GETFL)
flags |= O_NONBLOCK
fcntl(stdin.fileno(), F_SETFL, flags)
- glib.io_add_watch(stdin, glib.IO_IN, self.input_cb)
+ GLib.io_add_watch(stdin, GLib.IO_IN, self.input_cb)
self.prompt()
def prompt(self):
self.line = ''
- print '> ',
+ print('> ', end=' ')
stdout.flush()
def input_cb(self, fd, event):
- if event != glib.IO_IN:
+ if event != GLib.IO_IN:
return
self.line += fd.read();
@@ -58,7 +57,7 @@ class InputLine:
return True
def error_print(ex):
- print 'Command Error: %s' % ex
+ print('Command Error: %s' % ex)
def checkarg(nb_args = 0, min_args = False):
def under(function):
@@ -81,11 +80,11 @@ def print_dict(d):
for k in d:
try:
if type(d[k]) is dbus.Byte:
- print 'Key %s --> 0x%x' % (k, d[k])
+ print('Key %s --> 0x%x' % (k, d[k]))
else:
- print 'Key %s --> %s' % (k, d[k])
+ print('Key %s --> %s' % (k, d[k]))
except:
- print "Error: Key %s content cannot be printed" % k
+ print("Error: Key %s content cannot be printed" % k)
pass
def print_tuple(t):
@@ -93,7 +92,7 @@ def print_tuple(t):
if type(e) is dbus.Dictionary:
print_dict(e)
else:
- print 'Element: %s' % e
+ print('Element: %s' % e)
class Wpa_s:
def __init__(self, bus, iface_name, command):
@@ -116,41 +115,41 @@ class Wpa_s:
try:
self.create_if([iface_name])
except:
- print "Error creating interface: %s" % iface_name
+ print("Error creating interface: %s" % iface_name)
if len(command.strip(' ')):
self.__command(command)
def help(self, args):
- list = self.command_list.keys()
+ list = list(self.command_list.keys())
list.sort()
for key in list:
help = ''
- if (self.command_list[key].has_key(ArgFields.help)):
+ if (ArgFields.help in self.command_list[key]):
help = self.command_list[key][ArgFields.help]
- print "%s\t%s" % (key.rjust(25), help.ljust(50))
+ print("%s\t%s" % (key.rjust(25), help.ljust(50)))
def __command(self, cmd_line):
cmd = cmd_line.split(' ')
try:
func = getattr(self, cmd[0])
- except Exception, e:
- print 'Error: command unknown - %s' % e
+ except Exception as e:
+ print('Error: command unknown - %s' % e)
return
try:
func(cmd[1:])
- except Exception, e:
+ except Exception as e:
error_print(e)
def __wpa_property_changed(*args, **kwargs):
- print 'WPA - Signal: %s' % kwargs.get('signal')
+ print('WPA - Signal: %s' % kwargs.get('signal'))
def __if_property_changed(*args, **kwargs):
signal = kwargs.get('signal')
- print 'IF - Signal: %s' % signal
+ print('IF - Signal: %s' % signal)
if signal == 'BSSAdded':
return
@@ -159,12 +158,12 @@ class Wpa_s:
print_tuple(args[1:])
def __p2p_property_changed(*args, **kwargs):
- print 'IF P2P - Signal: %s' % kwargs.get('signal')
+ print('IF P2P - Signal: %s' % kwargs.get('signal'))
if args[0].debug:
print_tuple(args[1:])
def __peer_if_p2p_property_changed(*args, **kwargs):
- print 'Peer - ',
+ print('Peer - ', end=' ')
args[0].__p2p_property_changed(*args, **kwargs)
def __DeviceFound(self, object_path):
@@ -187,31 +186,31 @@ class Wpa_s:
del self.peers[object_path]
def __PeerJoined(self, object_path):
- print 'Peer %s joined' % object_path
+ print('Peer %s joined' % object_path)
def __PeerDisconnected(self, object_path):
- print 'Peer %s disconnected' % object_path
+ print('Peer %s disconnected' % object_path)
def __group_if_property_changed(*args, **kwargs):
- print 'Group - ',
+ print('Group - ', end=' ')
args[0].__if_property_changed(*args, **kwargs)
def __group_if_p2p_property_changed(*args, **kwargs):
- print 'Group - ',
+ print('Group - ', end=' ')
args[0].__p2p_property_changed(*args, **kwargs)
def __GroupFinished(self, properties):
- print 'Group running on %s is being removed' % ifname
+ print('Group running on %s is being removed' % ifname)
self.group_obj = self.group_if = self.group_iface_path = None
if self.debug:
print_dict(properties)
def __InvitationResult(self, response):
- print 'Invitation result status: %d ' % response['status']
+ print('Invitation result status: %d ' % response['status'])
- if response.has_key('bssid'):
- print 'bssid: %s' % response['bssid']
+ if 'bssid' in response:
+ print('bssid: %s' % response['bssid'])
if self.debug:
print_dict(response)
@@ -257,11 +256,11 @@ class Wpa_s:
def __ServiceDiscoveryResponse(self, response):
peer = response['peer_object']
if peer in self.peers:
- print 'Peer %s has this TLVs:' % (self.peers[peer]['DeviceName'])
- print response['tlvs']
+ print('Peer %s has this TLVs:' % (self.peers[peer]['DeviceName']))
+ print(response['tlvs'])
def __InterfaceAdded(self, path, properties):
- print 'Interface %s Added (%s)' % (properties['Ifname'], path)
+ print('Interface %s Added (%s)' % (properties['Ifname'], path))
if self.debug:
print_dict(properties)
p2p = dbus.Interface(self.bus.get_object(WPA_INTF,
@@ -269,7 +268,7 @@ class Wpa_s:
print_dict(p2p.GetAll(WPA_P2P_INTF))
def __InterfaceRemoved(self, path):
- print 'Interface Removed (%s)' % (path)
+ print('Interface Removed (%s)' % (path))
def __listen_if_signals(self):
self.bus.add_signal_receiver(self.__if_property_changed,
@@ -312,7 +311,7 @@ class Wpa_s:
p2p_if.Set(WPA_P2P_INTF, 'P2PDeviceConfig',
dbus.Dictionary({ 'DeviceName' : 'ConnManP2P' },
signature='sv'))
- print 'Interface %s: %s' % (iface_name, self.iface_path)
+ print('Interface %s: %s' % (iface_name, self.iface_path))
self.iface_name = iface_name
self.__listen_if_signals()
@@ -342,7 +341,7 @@ class Wpa_s:
return
self.wpa.RemoveInterface(self.iface_path)
- print 'Interface %s removed' % self.iface_name
+ print('Interface %s removed' % self.iface_name)
self.__reset()
@checkarg()
@@ -351,7 +350,7 @@ class Wpa_s:
return
self.iface.Scan(({ 'Type': 'passive' }))
- print 'Scan started'
+ print('Scan started')
@checkarg()
def quit(self, args = None):
@@ -382,7 +381,7 @@ class Wpa_s:
return
for p in self.peers:
- print 'Peer Name=%s' % (self.peers[p]['DeviceName'])
+ print('Peer Name=%s' % (self.peers[p]['DeviceName']))
def __find_peer(self, peer_name, ret_object_path = False):
if len(self.peers) == 0:
@@ -395,7 +394,7 @@ class Wpa_s:
break
if not peer:
- print 'No peer found under the name: %s' % peer_name
+ print('No peer found under the name: %s' % peer_name)
p = None
if ret_object_path:
@@ -426,19 +425,19 @@ class Wpa_s:
if (peer['groupcapability'] & P2P_GROUP_CAPAB_GROUP_OWNER ==
P2P_GROUP_CAPAB_GROUP_OWNER):
- print 'Joining an existing P2P group'
+ print('Joining an existing P2P group')
pin = self.p2p.Connect(({ 'peer' : peer_path,
'wps_method' : 'pbc',
'join' : True,
'go_intent' : 0 }))
else:
- print 'Associating with another P2P device'
+ print('Associating with another P2P device')
pin = self.p2p.Connect(({ 'peer' : peer_path,
'wps_method' : 'pbc',
'join' : False,
'go_intent' : 7 }))
if not pin:
- print 'WPS PIN in use: %s' % pin
+ print('WPS PIN in use: %s' % pin)
@checkarg(nb_args = 1)
def p2p_disconnect(self, args):
@@ -450,7 +449,7 @@ class Wpa_s:
return
if not self.group_if:
- print 'Peer %s is not connected' % (peer['DeviceName'])
+ print('Peer %s is not connected' % (peer['DeviceName']))
return
self.group_if.Disconnect()
@@ -496,7 +495,7 @@ class Wpa_s:
sd_req.append(dbus.Byte(a))
ref = self.p2p.ServiceDiscoveryRequest(({ 'tlv' : sd_req }))
- print 'Service discovery reference: %s' % ref
+ print('Service discovery reference: %s' % ref)
@checkarg(nb_args = 1)
def p2p_serv_disc_cancel_req(self, args):
@@ -518,7 +517,7 @@ class Wpa_s:
service['query'] = args[1]
service['response'] = args[2]
else:
- print 'Unknown service: %s' % args[0]
+ print('Unknown service: %s' % args[0])
return
self.p2p.AddService((service))
@@ -535,7 +534,7 @@ class Wpa_s:
elif args[0] == 'bonjour':
service['query'] = args[1]
else:
- print 'Unknown service: %s' % args[0]
+ print('Unknown service: %s' % args[0])
return
self.p2p.DeleteService((service))
@@ -593,16 +592,16 @@ def build_args(parser):
command['p2p_service_flush'] = {}
command['p2p_invite'] = {ArgFields.help:'<p2p device name>'}
- command_list = command.keys()
+ command_list = list(command.keys())
command_list.sort()
subparsers = parser.add_subparsers(help='commands', dest='command')
subparsers.add_parser('')
for key in command_list:
help=None
metavar=None
- if command[key].has_key(ArgFields.help):
+ if ArgFields.help in command[key]:
help = command[key][ArgFields.help]
- if command[key].has_key(ArgFields.metavar):
+ if ArgFields.metavar in command[key]:
metavar = command[key][ArgFields.metavar]
command_parser = subparsers.add_parser(key, help=help)
command_parser.add_argument(key, nargs='*', metavar=metavar, help=help)
@@ -610,10 +609,6 @@ def build_args(parser):
return command
def main():
- if version_info.major != 2:
- print 'You need to run this under Python 2.x'
- exit(1)
-
parser = argparse.ArgumentParser(description='Connman P2P Test')
command_list = build_args(parser)
@@ -634,7 +629,7 @@ def main():
bus = dbus.SystemBus()
- mainloop = gobject.MainLoop()
+ mainloop = GLib.MainLoop()
wpa_s = Wpa_s(bus, args.ifname, args.command + params)
diff --git a/test/remove-provider b/test/remove-provider
index 39f8de77..a2f3e6f4 100755
--- a/test/remove-provider
+++ b/test/remove-provider
@@ -4,7 +4,7 @@ import sys
import dbus
if (len(sys.argv) < 2):
- print "Usage: %s <VPN service path> " % (sys.argv[0])
+ print("Usage: %s <VPN service path> " % (sys.argv[0]))
sys.exit(1)
bus = dbus.SystemBus()
@@ -14,6 +14,6 @@ manager = dbus.Interface(bus.get_object("net.connman", "/"),
path = "" + sys.argv[1]
-print "remove path is %s" %(path)
+print("remove path is %s" %(path))
manager.RemoveProvider(sys.argv[1])
diff --git a/test/service-move-before b/test/service-move-before
index d912c88b..81526377 100755
--- a/test/service-move-before
+++ b/test/service-move-before
@@ -4,7 +4,7 @@ import sys
import dbus
def print_usage():
- print "Usage: %s <service> <target service>" % (sys.argv[0])
+ print("Usage: %s <service> <target service>" % (sys.argv[0]))
if (len(sys.argv) < 2):
@@ -20,8 +20,8 @@ path2 = "/net/connman/service/" + sys.argv[2]
service2 = dbus.Interface(bus.get_object('net.connman', path2),
'net.connman.Service')
-print "Moving %s before %s" % (sys.argv[1], sys.argv[2])
+print("Moving %s before %s" % (sys.argv[1], sys.argv[2]))
service.MoveBefore(service2)
-print
+print()
diff --git a/test/set-clock b/test/set-clock
index a9db3e32..bb443d07 100755
--- a/test/set-clock
+++ b/test/set-clock
@@ -4,7 +4,7 @@ import sys
import dbus
def print_usage():
- print "Usage: %s TimeUpdates|TimezoneUpdates manual|auto" % (sys.argv[0])
+ print("Usage: %s TimeUpdates|TimezoneUpdates manual|auto" % (sys.argv[0]))
sys.exit(1)
@@ -26,7 +26,7 @@ bus = dbus.SystemBus()
clock = dbus.Interface(bus.get_object('net.connman', '/'),
'net.connman.Clock')
-print "Setting %s to %s" % (sys.argv[1], sys.argv[2])
+print("Setting %s to %s" % (sys.argv[1], sys.argv[2]))
clock.SetProperty(sys.argv[1], make_variant(sys.argv[2]),
signature=dbus.Signature('sv'))
diff --git a/test/set-domains b/test/set-domains
index 87e563e0..ec98c5e3 100755
--- a/test/set-domains
+++ b/test/set-domains
@@ -4,7 +4,7 @@ import sys
import dbus
if (len(sys.argv) < 2):
- print "Usage: %s <service> [domain*]" % (sys.argv[0])
+ print("Usage: %s <service> [domain*]" % (sys.argv[0]))
sys.exit(1)
bus = dbus.SystemBus()
@@ -14,7 +14,7 @@ service = dbus.Interface(bus.get_object('net.connman', path),
properties = service.GetProperties()
-print "Setting domains to %s" % (sys.argv[2:])
+print("Setting domains to %s" % (sys.argv[2:]))
service.SetProperty("Domains.Configuration",
dbus.Array(sys.argv[2:], signature=dbus.Signature('s')))
diff --git a/test/set-global-timeservers b/test/set-global-timeservers
index d7551a11..1489ec71 100755
--- a/test/set-global-timeservers
+++ b/test/set-global-timeservers
@@ -4,7 +4,7 @@ import sys
import dbus
if (len(sys.argv) < 1):
- print "Usage: %s [timeserver*]" % (sys.argv[0])
+ print("Usage: %s [timeserver*]" % (sys.argv[0]))
sys.exit(1)
bus = dbus.SystemBus()
@@ -12,7 +12,7 @@ bus = dbus.SystemBus()
clock = dbus.Interface(bus.get_object('net.connman', '/'),
'net.connman.Clock')
-print "Setting timeserver to %s" % (sys.argv[1:])
+print("Setting timeserver to %s" % (sys.argv[1:]))
clock.SetProperty("Timeservers", dbus.Array(sys.argv[1:],
signature=dbus.Signature('s')))
diff --git a/test/set-ipv4-method b/test/set-ipv4-method
index 235113fe..09c194d7 100755
--- a/test/set-ipv4-method
+++ b/test/set-ipv4-method
@@ -7,7 +7,7 @@ def make_variant(string):
return dbus.String(string, variant_level=1)
def print_usage():
- print "Usage: %s <service> [off|dhcp|manual <address> [netmask] [gateway]]" % (sys.argv[0])
+ print("Usage: %s <service> [off|dhcp|manual <address> [netmask] [gateway]]" % (sys.argv[0]))
if (len(sys.argv) < 3):
@@ -21,7 +21,7 @@ service = dbus.Interface(bus.get_object('net.connman', path),
properties = service.GetProperties()
-print "Setting method %s for %s" % (sys.argv[2], sys.argv[1])
+print("Setting method %s for %s" % (sys.argv[2], sys.argv[1]))
ipv4_configuration = { "Method": make_variant(sys.argv[2]) }
if (len(sys.argv) > 3):
@@ -32,6 +32,6 @@ if (len(sys.argv) > 5):
ipv4_configuration["Gateway"] = make_variant(sys.argv[5])
service.SetProperty("IPv4.Configuration", ipv4_configuration)
-print "New IPv4.Configuration: ", ipv4_configuration
+print("New IPv4.Configuration: ", ipv4_configuration)
-print
+print()
diff --git a/test/set-ipv6-method b/test/set-ipv6-method
index eb1f1b5b..5536e6f0 100755
--- a/test/set-ipv6-method
+++ b/test/set-ipv6-method
@@ -10,7 +10,7 @@ def make_byte_variant(string):
return dbus.Byte(int(string), variant_level=1)
def print_usage():
- print "Usage: %s <service> off|manual|auto [<address> [prefixlen] [gateway]] [<privacy>]" % (sys.argv[0])
+ print("Usage: %s <service> off|manual|auto [<address> [prefixlen] [gateway]] [<privacy>]" % (sys.argv[0]))
if (len(sys.argv) < 3):
print_usage()
@@ -23,7 +23,7 @@ service = dbus.Interface(bus.get_object('net.connman', path),
properties = service.GetProperties()
-print "Setting method %s for %s" % (sys.argv[2], sys.argv[1])
+print("Setting method %s for %s" % (sys.argv[2], sys.argv[1]))
ipv6_configuration = { "Method": make_variant(sys.argv[2])}
if sys.argv[2] == "auto":
@@ -38,6 +38,6 @@ else:
ipv6_configuration["Gateway"] = make_variant(sys.argv[5])
service.SetProperty("IPv6.Configuration", ipv6_configuration)
-print "New IPv6.Configuration: ", ipv6_configuration
+print("New IPv6.Configuration: ", ipv6_configuration)
-print
+print()
diff --git a/test/set-nameservers b/test/set-nameservers
index ece69b87..584df7ea 100755
--- a/test/set-nameservers
+++ b/test/set-nameservers
@@ -4,7 +4,7 @@ import sys
import dbus
if (len(sys.argv) < 2):
- print "Usage: %s <service> [nameserver*]" % (sys.argv[0])
+ print("Usage: %s <service> [nameserver*]" % (sys.argv[0]))
sys.exit(1)
bus = dbus.SystemBus()
@@ -14,7 +14,7 @@ service = dbus.Interface(bus.get_object('net.connman', path),
properties = service.GetProperties()
-print "Setting nameserver to %s" % (sys.argv[2:])
+print("Setting nameserver to %s" % (sys.argv[2:]))
service.SetProperty("Nameservers.Configuration",
dbus.Array(sys.argv[2:], signature=dbus.Signature('s')))
diff --git a/test/set-proxy b/test/set-proxy
index b9da7b09..f308d327 100755
--- a/test/set-proxy
+++ b/test/set-proxy
@@ -4,12 +4,12 @@ import sys
import dbus
if (len(sys.argv) < 2):
- print "Usage:"
- print "%s <service> direct" % (sys.argv[0])
- print "%s <service> manual [servers=uri1,uri2,...] [excludes=host1,host2,...]" % (sys.argv[0])
- print "%s <service> auto url=[pac-url]" % (sys.argv[0])
- print "Example: %s service0 manual servers=proxy.example.com:8080" % sys.argv[0]
- print " This would set the proxy uri and the method to manual"
+ print("Usage:")
+ print("%s <service> direct" % (sys.argv[0]))
+ print("%s <service> manual [servers=uri1,uri2,...] [excludes=host1,host2,...]" % (sys.argv[0]))
+ print("%s <service> auto url=[pac-url]" % (sys.argv[0]))
+ print("Example: %s service0 manual servers=proxy.example.com:8080" % sys.argv[0])
+ print(" This would set the proxy uri and the method to manual")
sys.exit(1)
bus = dbus.SystemBus()
@@ -40,5 +40,5 @@ for arg in sys.argv[3:]:
try:
service.SetProperty("Proxy.Configuration", dbus.Dictionary(values, signature='sv'))
-except dbus.exceptions.DBusException, e_msg:
- print e_msg
+except dbus.exceptions.DBusException as e_msg:
+ print(e_msg)
diff --git a/test/set-timeservers b/test/set-timeservers
index 19cc9389..55a1984a 100755
--- a/test/set-timeservers
+++ b/test/set-timeservers
@@ -4,7 +4,7 @@ import sys
import dbus
if (len(sys.argv) < 2):
- print "Usage: %s <service> [timeserver*]" % (sys.argv[0])
+ print("Usage: %s <service> [timeserver*]" % (sys.argv[0]))
sys.exit(1)
bus = dbus.SystemBus()
@@ -14,7 +14,7 @@ service = dbus.Interface(bus.get_object('net.connman', path),
properties = service.GetProperties()
-print "Setting timeserver to %s" % (sys.argv[2:])
+print("Setting timeserver to %s" % (sys.argv[2:]))
service.SetProperty("Timeservers.Configuration",
dbus.Array(sys.argv[2:], signature=dbus.Signature('s')))
diff --git a/test/set-timezone b/test/set-timezone
new file mode 100755
index 00000000..4808bd87
--- /dev/null
+++ b/test/set-timezone
@@ -0,0 +1,21 @@
+#!/usr/bin/python
+
+import sys
+import dbus
+
+if (len(sys.argv) != 2):
+ print("Usage: %s <timezone>" % (sys.argv[0]))
+ sys.exit(1)
+
+bus = dbus.SystemBus()
+
+clock = dbus.Interface(bus.get_object('net.connman', '/'),
+ 'net.connman.Clock')
+
+print("Setting timezone to %s" % (sys.argv[1]))
+
+try:
+ clock.SetProperty("Timezone", dbus.String(sys.argv[1], variant_level=1),
+ signature=dbus.Signature('sv'))
+except dbus.exceptions.DBusException as e_msg:
+ print(e_msg)
diff --git a/test/show-introspection b/test/show-introspection
index 4b6450f0..983b36fe 100755
--- a/test/show-introspection
+++ b/test/show-introspection
@@ -7,7 +7,7 @@ bus = dbus.SystemBus()
object = dbus.Interface(bus.get_object("net.connman", '/'),
"org.freedesktop.DBus.Introspectable")
-print object.Introspect()
+print(object.Introspect())
manager = dbus.Interface(bus.get_object("net.connman", "/"),
"net.connman.Manager")
@@ -18,4 +18,4 @@ for path, properties in technologies:
object = dbus.Interface(bus.get_object("net.connman", path),
"org.freedesktop.DBus.Introspectable")
- print object.Introspect()
+ print(object.Introspect())
diff --git a/test/simple-agent b/test/simple-agent
index 01c82baf..04de3f60 100755
--- a/test/simple-agent
+++ b/test/simple-agent
@@ -1,6 +1,6 @@
#!/usr/bin/python
-import gobject
+from gi.repository import GLib
import dbus
import dbus.service
@@ -32,8 +32,8 @@ class Agent(dbus.service.Object):
response = {}
if not self.identity and not self.passphrase and not self.wpspin:
- print "Service credentials requested, type cancel to cancel"
- args = raw_input('Answer: ')
+ print("Service credentials requested, type cancel to cancel")
+ args = input('Answer: ')
for arg in args.split():
if arg.startswith("cancel"):
@@ -62,9 +62,9 @@ class Agent(dbus.service.Object):
response = {}
if not self.username and not self.password:
- print "User login requested, type cancel to cancel"
- print "or browser to login through the browser by yourself."
- args = raw_input('Answer: ')
+ print("User login requested, type cancel to cancel")
+ print("or browser to login through the browser by yourself.")
+ args = input('Answer: ')
for arg in args.split():
if arg.startswith("cancel") or arg.startswith("browser"):
@@ -87,7 +87,7 @@ class Agent(dbus.service.Object):
response = {}
if not self.name and not self.ssid:
- args = raw_input('Answer ')
+ args = input('Answer ')
for arg in args.split():
if arg.startswith("Name="):
@@ -110,18 +110,18 @@ class Agent(dbus.service.Object):
in_signature='oa{sv}',
out_signature='a{sv}')
def RequestInput(self, path, fields):
- print "RequestInput (%s,%s)" % (path, fields)
+ print("RequestInput (%s,%s)" % (path, fields))
response = {}
- if fields.has_key("Name"):
+ if "Name" in fields:
response.update(self.input_hidden())
- if fields.has_key("Passphrase"):
+ if "Passphrase" in fields:
response.update(self.input_passphrase())
- if fields.has_key("Username"):
+ if "Username" in fields:
response.update(self.input_username())
- if response.has_key("Error"):
+ if "Error" in response:
if response["Error"] == "cancel":
raise Canceled("canceled")
return
@@ -129,7 +129,7 @@ class Agent(dbus.service.Object):
raise LaunchBrowser("launch browser")
return
- print "returning (%s)" % (response)
+ print("returning (%s)" % (response))
return response
@@ -137,12 +137,12 @@ class Agent(dbus.service.Object):
in_signature='os',
out_signature='')
def RequestBrowser(self, path, url):
- print "RequestBrowser (%s,%s)" % (path, url)
+ print("RequestBrowser (%s,%s)" % (path, url))
- print "Please login through the given url in a browser"
- print "Then press enter to accept or some text to cancel"
+ print("Please login through the given url in a browser")
+ print("Then press enter to accept or some text to cancel")
- args = raw_input('> ')
+ args = input('> ')
if len(args) > 0:
raise Canceled("canceled")
@@ -153,8 +153,8 @@ class Agent(dbus.service.Object):
in_signature='os',
out_signature='')
def ReportError(self, path, error):
- print "ReportError %s, %s" % (path, error)
- retry = raw_input("Retry service (yes/no): ")
+ print("ReportError %s, %s" % (path, error))
+ retry = input("Retry service (yes/no): ")
if (retry == "yes"):
class Retry(dbus.DBusException):
_dbus_error_name = "net.connman.Agent.Error.Retry"
@@ -167,7 +167,7 @@ class Agent(dbus.service.Object):
@dbus.service.method("net.connman.Agent",
in_signature='', out_signature='')
def Cancel(self):
- print "Cancel"
+ print("Cancel")
class VpnAgent(dbus.service.Object):
name = None
@@ -185,8 +185,8 @@ class VpnAgent(dbus.service.Object):
response = {}
if not self.cookie:
- print "VPN credentials requested, type cancel to cancel"
- args = raw_input('Answer: ')
+ print("VPN credentials requested, type cancel to cancel")
+ args = input('Answer: ')
for arg in args.split():
if arg.startswith("cancel"):
@@ -204,8 +204,8 @@ class VpnAgent(dbus.service.Object):
response = {}
if not self.username and not self.password:
- print "User login requested, type cancel to cancel"
- args = raw_input('Answer: ')
+ print("User login requested, type cancel to cancel")
+ args = input('Answer: ')
for arg in args.split():
if arg.startswith("cancel"):
@@ -228,21 +228,21 @@ class VpnAgent(dbus.service.Object):
in_signature='oa{sv}',
out_signature='a{sv}')
def RequestInput(self, path, fields):
- print "RequestInput (%s,%s)" % (path, fields)
+ print("RequestInput (%s,%s)" % (path, fields))
response = {}
- if fields.has_key("OpenConnect.Cookie"):
+ if "OpenConnect.Cookie" in fields:
response.update(self.input_cookie())
- if fields.has_key("Username") or fields.has_key("Password"):
+ if "Username" in fields or "Password" in fields:
response.update(self.input_username())
- if response.has_key("Error"):
+ if "Error" in response:
if response["Error"] == "cancel":
raise Canceled("canceled")
return
- print "returning (%s)" % (response)
+ print("returning (%s)" % (response))
return response
@@ -250,8 +250,8 @@ class VpnAgent(dbus.service.Object):
in_signature='os',
out_signature='')
def ReportError(self, path, error):
- print "ReportError %s, %s" % (path, error)
- retry = raw_input("Retry service (yes/no): ")
+ print("ReportError %s, %s" % (path, error))
+ retry = input("Retry service (yes/no): ")
if (retry == "yes"):
class Retry(dbus.DBusException):
_dbus_error_name = "net.connman.vpn.Agent.Error.Retry"
@@ -264,7 +264,7 @@ class VpnAgent(dbus.service.Object):
@dbus.service.method("net.connman.vpn.Agent",
in_signature='', out_signature='')
def Cancel(self):
- print "Cancel"
+ print("Cancel")
def vpnNameOwnerChanged(proxy):
if proxy:
@@ -276,22 +276,22 @@ def vpnNameOwnerChanged(proxy):
'net.connman.vpn.Manager')
vpn_manager.RegisterAgent(path)
except:
- print "vpn agent is not registered"
+ print("vpn agent is not registered")
else:
print("vpnd is disconnected from system bus")
vpn_manager = None
def print_usage():
- print "Usage:"
- print "For hidden service:"
- print "%s Name=<hidden service name> [SSID=<hidden ssid>]" % (sys.argv[0])
- print "For EAP/WPA input:"
- print "%s Identity=<identity> Passphrase=<passphrase> WPS=<wpspin>" % (sys.argv[0])
- print "For WISPr login, L2TP or PPTP input:"
- print "%s Username=<username> Password=<password>" % (sys.argv[0])
- print "For OpenConnect input:"
- print "%s Cookie=<string>" % (sys.argv[0])
- print "Help: %s help" % (sys.argv[0])
+ print("Usage:")
+ print("For hidden service:")
+ print("%s Name=<hidden service name> [SSID=<hidden ssid>]" % (sys.argv[0]))
+ print("For EAP/WPA input:")
+ print("%s Identity=<identity> Passphrase=<passphrase> WPS=<wpspin>" % (sys.argv[0]))
+ print("For WISPr login, L2TP or PPTP input:")
+ print("%s Username=<username> Password=<password>" % (sys.argv[0]))
+ print("For OpenConnect input:")
+ print("%s Cookie=<string>" % (sys.argv[0]))
+ print("Help: %s help" % (sys.argv[0]))
sys.exit(1)
if __name__ == '__main__':
@@ -314,7 +314,7 @@ if __name__ == '__main__':
vpn_object = VpnAgent(bus, vpn_path)
except:
vpn_manager = None
- print "net.connman.vpn is not present"
+ print("net.connman.vpn is not present")
if len(sys.argv) >= 2:
for arg in sys.argv[1:]:
@@ -342,7 +342,7 @@ if __name__ == '__main__':
try:
manager.RegisterAgent(path)
except:
- print "Cannot register connman agent."
+ print("Cannot register connman agent.")
if vpn_manager != None:
try:
@@ -351,7 +351,7 @@ if __name__ == '__main__':
except:
"Cannot register vpn agent"
- mainloop = gobject.MainLoop()
+ mainloop = GLib.MainLoop()
mainloop.run()
#manager.UnregisterAgent(path)
diff --git a/test/test-clock b/test/test-clock
index e9b76fca..c086ffc6 100755
--- a/test/test-clock
+++ b/test/test-clock
@@ -9,11 +9,11 @@ clock = dbus.Interface(bus.get_object("net.connman", "/"),
properties = clock.GetProperties()
-for key in properties.keys():
+for key in list(properties.keys()):
if key in ["Timeservers"]:
list = ""
for val in properties[key]:
list = list + val + " "
- print "%s = [ %s]" % (key, list)
+ print("%s = [ %s]" % (key, list))
else:
- print "%s = %s" % (key, properties[key])
+ print("%s = %s" % (key, properties[key]))
diff --git a/test/test-compat b/test/test-compat
index cd1ca7a7..c9cdbab3 100755
--- a/test/test-compat
+++ b/test/test-compat
@@ -12,4 +12,4 @@ states = [ "unknown", "asleep", "connecting", "connected", "disconnected" ]
state = manager.state()
-print "System is %s" % (states[state])
+print("System is %s" % (states[state]))
diff --git a/test/test-connman b/test/test-connman
index d047c86d..45a18d97 100755
--- a/test/test-connman
+++ b/test/test-connman
@@ -9,19 +9,19 @@ manager = dbus.Interface(bus.get_object("net.connman", "/"),
"net.connman.Manager")
if len(sys.argv) < 2:
- print "Usage: %s <command>" % (sys.argv[0])
- print ""
- print " state"
- print " services"
- print " autoconnect <service> [autoconnect]"
- print " connect <service>"
- print " disconnect <service>"
- print " remove <service>"
- print ""
- print " scan <type>"
- print " enable <type>"
- print " disable <type>"
- print " offlinemode [on|off]"
+ print("Usage: %s <command>" % (sys.argv[0]))
+ print("")
+ print(" state")
+ print(" services")
+ print(" autoconnect <service> [autoconnect]")
+ print(" connect <service>")
+ print(" disconnect <service>")
+ print(" remove <service>")
+ print("")
+ print(" scan <type>")
+ print(" enable <type>")
+ print(" disable <type>")
+ print(" offlinemode [on|off]")
sys.exit(1)
def print_services(services):
@@ -45,25 +45,25 @@ def print_services(services):
else:
favorite = " "
- if "Name" in properties.keys():
+ if "Name" in list(properties.keys()):
name = properties["Name"]
else:
name = "{" + properties["Type"] + "}"
- print "%s%s%s %-26s { %s }" % (favorite, autoconnect, state,
- name, identifier)
+ print("%s%s%s %-26s { %s }" % (favorite, autoconnect, state,
+ name, identifier))
if sys.argv[1] == "state":
properties = manager.GetProperties()
- print "System is %s" % (properties["State"])
+ print("System is %s" % (properties["State"]))
elif sys.argv[1] in ["services", "list", "show"]:
print_services(manager.GetServices())
elif sys.argv[1] in ["autoconnect", "autoconn"]:
if (len(sys.argv) < 3):
- print "Need at least service parameter"
+ print("Need at least service parameter")
sys.exit(1)
path = "/net/connman/service/" + sys.argv[2]
@@ -77,25 +77,25 @@ elif sys.argv[1] in ["autoconnect", "autoconn"]:
service.SetProperty("AutoConnect", autoconnect);
- print "Auto connect %s for %s" % (autoconnect, sys.argv[2])
+ print("Auto connect %s for %s" % (autoconnect, sys.argv[2]))
else:
properties = service.GetProperties()
- if "Name" in properties.keys():
+ if "Name" in list(properties.keys()):
name = properties["Name"]
else:
name = "{" + properties["Type"] + "}"
- if "AutoConnect" in properties.keys():
+ if "AutoConnect" in list(properties.keys()):
autoconnect = properties["AutoConnect"]
else:
autoconnect = dbus.Boolean(0)
- print "Auto connect %s for %s" % (autoconnect, name)
+ print("Auto connect %s for %s" % (autoconnect, name))
elif sys.argv[1] in ["connect", "conn"]:
if (len(sys.argv) < 3):
- print "Need at least service parameter"
+ print("Need at least service parameter")
sys.exit(1)
path = "/net/connman/service/" + sys.argv[2]
@@ -105,12 +105,12 @@ elif sys.argv[1] in ["connect", "conn"]:
try:
service.Connect(timeout=60000)
- except dbus.DBusException, error:
- print "%s: %s" % (error._dbus_error_name, error.message)
+ except dbus.DBusException as error:
+ print("%s: %s" % (error._dbus_error_name, error.message))
elif sys.argv[1] in ["disconnect", "disc"]:
if (len(sys.argv) < 3):
- print "Need at least service parameter"
+ print("Need at least service parameter")
sys.exit(1)
path = "/net/connman/service/" + sys.argv[2]
@@ -120,12 +120,12 @@ elif sys.argv[1] in ["disconnect", "disc"]:
try:
service.Disconnect()
- except dbus.DBusException, error:
- print "%s: %s" % (error._dbus_error_name, error.message)
+ except dbus.DBusException as error:
+ print("%s: %s" % (error._dbus_error_name, error.message))
elif sys.argv[1] in ["remove"]:
if (len(sys.argv) < 3):
- print "Need at least service parameter"
+ print("Need at least service parameter")
sys.exit(1)
path = "/net/connman/service/" + sys.argv[2]
@@ -136,13 +136,13 @@ elif sys.argv[1] in ["remove"]:
properties = service.GetProperties()
if properties["Favorite"] == dbus.Boolean(0):
- print "Only favorite services can be removed"
+ print("Only favorite services can be removed")
sys.exit(1)
try:
service.Remove()
- except dbus.DBusException, error:
- print "%s: %s" % (error._dbus_error_name, error.message)
+ except dbus.DBusException as error:
+ print("%s: %s" % (error._dbus_error_name, error.message))
elif sys.argv[1] == "scan":
if len(sys.argv) == 3:
@@ -151,7 +151,7 @@ elif sys.argv[1] == "scan":
"net.connman.Technology")
technology.Scan()
else:
- print "'%s' takes two arguments" % sys.argv[1]
+ print("'%s' takes two arguments" % sys.argv[1])
elif sys.argv[1] == "enable":
if len(sys.argv) == 3:
@@ -160,7 +160,7 @@ elif sys.argv[1] == "enable":
"net.connman.Technology")
technology.SetProperty("Powered", True)
else:
- print "'%s' takes two arguments" % sys.argv[1]
+ print("'%s' takes two arguments" % sys.argv[1])
elif sys.argv[1] == "disable":
if len(sys.argv) == 3:
@@ -169,7 +169,7 @@ elif sys.argv[1] == "disable":
"net.connman.Technology")
technology.SetProperty("Powered", False)
else:
- print "'%s' takes two arguments" % sys.argv[1]
+ print("'%s' takes two arguments" % sys.argv[1])
elif sys.argv[1] in ["offlinemode", "flightmode"]:
@@ -179,15 +179,15 @@ elif sys.argv[1] in ["offlinemode", "flightmode"]:
elif sys.argv[2] == "off" or sys.argv[2] == "0" or sys.argv[2] == "no":
active = dbus.Boolean(0)
else:
- print "Use either 'on', '1', 'yes', 'off', '0' or 'no'"
+ print("Use either 'on', '1', 'yes', 'off', '0' or 'no'")
exit()
manager.SetProperty("OfflineMode", active)
elif len(sys.argv) == 2:
properties = manager.GetProperties()
- print "Offline mode is %s" % (properties["OfflineMode"])
+ print("Offline mode is %s" % (properties["OfflineMode"]))
else:
- print "'%s' takes max. two arguments" % sys.argv[1]
+ print("'%s' takes max. two arguments" % sys.argv[1])
else:
- print "Unknown command"
+ print("Unknown command")
diff --git a/test/test-counter b/test/test-counter
index ce835802..4c551620 100755
--- a/test/test-counter
+++ b/test/test-counter
@@ -1,7 +1,8 @@
#!/usr/bin/python
+from gi.repository import GLib
+
import sys
-import gobject
import dbus
import dbus.service
@@ -24,7 +25,7 @@ def make_bytes_readable(bytes):
return ''
def print_stats(stats):
- keys = stats.keys()
+ keys = list(stats.keys())
keys.sort()
for key in keys:
@@ -36,7 +37,7 @@ def print_stats(stats):
if hstr:
str = "%s (%s)" % (str, hstr)
- print str
+ print(str)
class Counter(dbus.service.Object):
@dbus.service.method("net.connman.Counter",
@@ -48,13 +49,13 @@ class Counter(dbus.service.Object):
@dbus.service.method("net.connman.Counter",
in_signature='oa{sv}a{sv}', out_signature='')
def Usage(self, path, home, roaming):
- print "%s" % (path)
+ print("%s" % (path))
if len(home) > 0:
- print " Home"
+ print(" Home")
print_stats(home)
if len(roaming) > 0:
- print " Roaming"
+ print(" Roaming")
print_stats(roaming)
if __name__ == '__main__':
@@ -73,7 +74,7 @@ if __name__ == '__main__':
manager.RegisterCounter(path, dbus.UInt32(10), dbus.UInt32(period))
- mainloop = gobject.MainLoop()
+ mainloop = GLib.MainLoop()
mainloop.run()
#manager.UnregisterCounter(path)
diff --git a/test/test-manager b/test/test-manager
index 2b4493c5..2bc53acc 100755
--- a/test/test-manager
+++ b/test/test-manager
@@ -4,7 +4,7 @@ import dbus
def extract_values(values):
val = "{"
- for key in values.keys():
+ for key in list(values.keys()):
val += " " + key + "="
if key in ["PrefixLength"]:
val += "%s" % (int(values[key]))
@@ -30,23 +30,23 @@ manager = dbus.Interface(bus.get_object("net.connman", "/"),
properties = manager.GetProperties()
-for key in properties.keys():
+for key in list(properties.keys()):
if key in ["OfflineMode", "SessionMode"]:
- print "%s" % (key)
+ print("%s" % (key))
if properties[key] == dbus.Boolean(1):
- print " true"
+ print(" true")
else:
- print " false"
+ print(" false")
else:
- print "%s" % (key)
- print " %s" % (properties[key])
+ print("%s" % (key))
+ print(" %s" % (properties[key]))
print ("Services")
services = manager.GetServices()
for (path, properties) in services:
- print " %s" % (path)
- for key in properties.keys():
+ print(" %s" % (path))
+ for key in list(properties.keys()):
if key in ["Available", "Remember", "Default",
"Favorite", "Immutable", "AutoConnect",
"LoginRequired",
@@ -73,14 +73,14 @@ for (path, properties) in services:
else:
val = str(properties[key])
- print " %s = %s" % (key, val)
+ print(" %s = %s" % (key, val))
print ("Technologies")
technologies = manager.GetTechnologies()
for (path, properties) in technologies:
- print " %s" % (path)
- for key in properties.keys():
+ print(" %s" % (path))
+ for key in list(properties.keys()):
if key in ["Connected", "Powered", "Tethering"]:
if properties[key] == dbus.Boolean(1):
@@ -90,4 +90,4 @@ for (path, properties) in technologies:
else:
val = properties[key]
- print " %s = %s" % (key, val)
+ print(" %s = %s" % (key, val))
diff --git a/test/test-new-supplicant b/test/test-new-supplicant
index be230dc4..face1308 100755
--- a/test/test-new-supplicant
+++ b/test/test-new-supplicant
@@ -11,4 +11,4 @@ bus = dbus.SystemBus()
dummy = dbus.Interface(bus.get_object(WPA_NAME, WPA_PATH),
'org.freedesktop.DBus.Introspectable')
-print dummy.Introspect()
+print(dummy.Introspect())
diff --git a/test/test-session b/test/test-session
index 2d82fb65..112074f1 100755
--- a/test/test-session
+++ b/test/test-session
@@ -1,15 +1,13 @@
#!/usr/bin/python
+from gi.repository import GLib
+
import sys
-import gobject
-import string
import dbus
import dbus.service
import dbus.mainloop.glib
-import glib
-
import traceback
def extract_list(list):
@@ -21,7 +19,7 @@ def extract_list(list):
def extract_values(values):
val = "{"
- for key in values.keys():
+ for key in list(values.keys()):
val += " " + key + "="
if key in ["PrefixLength"]:
val += "%s" % (int(values[key]))
@@ -41,26 +39,26 @@ class Notification(dbus.service.Object):
@dbus.service.method("net.connman.Notification",
in_signature='', out_signature='')
def Release(self):
- print "Release %s" % (self._object_path)
+ print("Release %s" % (self._object_path))
session_name = self._object_path.split('/')[-1]
self.app.release(session_name)
@dbus.service.method("net.connman.Notification",
in_signature='a{sv}', out_signature='')
def Update(self, settings):
- print "Update called at %s" % (self._object_path)
+ print("Update called at %s" % (self._object_path))
try:
- for key in settings.keys():
+ for key in list(settings.keys()):
if key in ["IPv4", "IPv6"]:
val = extract_values(settings[key])
elif key in ["AllowedBearers"]:
val = extract_list(settings[key])
else:
val = settings[key]
- print " %s = %s" % (key, val)
+ print(" %s = %s" % (key, val))
except:
- print "Exception:"
+ print("Exception:")
traceback.print_exc()
class SessionApplication(dbus.service.Object):
@@ -80,15 +78,15 @@ class SessionApplication(dbus.service.Object):
def connman_name_owner_changed(self, proxy):
try:
if proxy:
- print "connman appeared on D-Bus ", str(proxy)
+ print("connman appeared on D-Bus ", str(proxy))
bus = dbus.SystemBus()
self.manager = dbus.Interface(bus.get_object("net.connman", "/"),
"net.connman.Manager")
else:
- print "connman disappeared on D-Bus"
+ print("connman disappeared on D-Bus")
self.manager = None
- for s in self.sessions.keys():
+ for s in list(self.sessions.keys()):
self.sessions[s]['notify'].remove_from_connection()
self.sessions[s]['notify'] = None
@@ -127,18 +125,18 @@ class SessionApplication(dbus.service.Object):
return value
def find_session(self, session_name):
- if not session_name in self.sessions.keys():
+ if not session_name in list(self.sessions.keys()):
return None
return self.sessions[session_name]
@dbus.service.method("com.example.TestSession",
in_signature='', out_signature='')
def CreateSession(self, session_name):
- print "Create session"
+ print("Create session")
s = self.find_session(session_name)
if s and s['session'] :
- print "Session %s already created-> drop reqest" % (session_name)
+ print("Session %s already created-> drop request" % (session_name))
return
try:
@@ -149,29 +147,29 @@ class SessionApplication(dbus.service.Object):
s['notify_path'] = self._object_path + "/" + session_name
s['notify'] = Notification(bus, self, s['notify_path'])
s['notify'].add_to_connection(bus, s['notify_path'])
- if not 'settings' in s.keys():
+ if not 'settings' in list(s.keys()):
s['settings'] = {};
s['session_path'] = self.manager.CreateSession(s['settings'], s['notify_path'])
- print "notify path %s" % (s['notify_path'])
- print "session path %s" % (s['session_path'])
+ print("notify path %s" % (s['notify_path']))
+ print("session path %s" % (s['session_path']))
s['session'] = dbus.Interface(bus.get_object("net.connman", s['session_path']),
"net.connman.Session")
self.sessions[session_name] = s
- except dbus.DBusException, e:
+ except dbus.DBusException as e:
if e.get_dbus_name() in ['net.connman.Error.Failed']:
- print e.get_dbus_message()
+ print(e.get_dbus_message())
return
traceback.print_exc()
@dbus.service.method("com.example.TestSession",
in_signature='', out_signature='')
def DestroySession(self, session_name):
- print "Destroy session"
+ print("Destroy session")
s = self.find_session(session_name)
if s == None or s['session'] == None:
- print "The session is not running -> drop request"
+ print("The session is not running -> drop request")
return
try:
@@ -182,92 +180,92 @@ class SessionApplication(dbus.service.Object):
@dbus.service.method("com.example.TestSession",
in_signature='', out_signature='')
def Connect(self, session_name):
- print "Connect session"
+ print("Connect session")
s = self.find_session(session_name)
if s == None or s['session'] == None:
- print "The session is not running -> drop request"
+ print("The session is not running -> drop request")
return
try:
s['session'].Connect()
- except dbus.DBusException, e:
+ except dbus.DBusException as e:
if e.get_dbus_name() in ['net.connman.Error.Failed']:
- print e.get_dbus_message()
+ print(e.get_dbus_message())
return
traceback.print_exc()
@dbus.service.method("com.example.TestSession",
in_signature='', out_signature='')
def Disconnect(self, session_name):
- print "Disconnect session"
+ print("Disconnect session")
s = self.find_session(session_name)
if s == None or s['session'] == None:
- print "The session is not running -> drop request"
+ print("The session is not running -> drop request")
return
try:
s['session'].Disconnect()
- except dbus.DBusException, e:
+ except dbus.DBusException as e:
if e.get_dbus_name() in ['net.connman.Error.Failed']:
- print e.get_dbus_message()
+ print(e.get_dbus_message())
return
traceback.print_exc()
@dbus.service.method("com.example.TestSession",
in_signature='', out_signature='')
def Change(self, session_name, key, value):
- print "Update session settings"
+ print("Update session settings")
s = self.find_session(session_name)
if s == None or s['session'] == None:
- print "The session is not running -> drop request"
+ print("The session is not running -> drop request")
return
try:
val = self.type_convert(key, value)
s['session'].Change(key, val)
- except dbus.DBusException, e:
+ except dbus.DBusException as e:
if e.get_dbus_name() in ['net.connman.Error.Failed']:
- print e.get_dbus_message()
+ print(e.get_dbus_message())
return
traceback.print_exc()
@dbus.service.method("com.example.TestSession",
in_signature='', out_signature='')
def Configure(self, session_name, key, value):
- print "Configure session settings"
+ print("Configure session settings")
s = self.find_session(session_name)
if s == None:
s = {}
s['notify_path'] = None
s['notify'] = None
- if not 'settings' in s.keys():
+ if not 'settings' in list(s.keys()):
s['settings'] = {};
s['session_path'] = None
s['session'] = None
self.sessions[session_name] = s
if s and s['session']:
- print "The session is running, use change -> drop request"
+ print("The session is running, use change -> drop request")
return
val = self.type_convert(key, value)
s['settings'][key] = val
def main():
if len(sys.argv) < 2:
- print "Usage: %s <command>" % (sys.argv[0])
- print ""
- print " enable"
- print " disable"
- print " create <app_path> <session_name>"
- print " destroy <app_path> <session_name>"
- print " connect <app_path> <session_name>"
- print " disconnect <app_path> <session_name>"
- print " change <app_path> <session_name> <key> <value>"
- print " configure <app_path> <session_name> <key> <value>"
- print ""
- print " run <app_path>"
+ print("Usage: %s <command>" % (sys.argv[0]))
+ print("")
+ print(" enable")
+ print(" disable")
+ print(" create <app_path> <session_name>")
+ print(" destroy <app_path> <session_name>")
+ print(" connect <app_path> <session_name>")
+ print(" disconnect <app_path> <session_name>")
+ print(" change <app_path> <session_name> <key> <value>")
+ print(" configure <app_path> <session_name> <key> <value>")
+ print("")
+ print(" run <app_path>")
sys.exit(1)
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
@@ -287,17 +285,17 @@ def main():
return
if (len(sys.argv) < 3):
- print "Need test application path"
+ print("Need test application path")
sys.exit(1)
app_path = sys.argv[2]
bus = dbus.SessionBus()
- app_name = "com.example.SessionApplication.%s" % (string.strip(app_path, "/"))
+ app_name = "com.example.SessionApplication.%s" % (str.strip(app_path, "/"))
if sys.argv[1] == "run":
name = dbus.service.BusName(app_name, bus)
- mainloop = gobject.MainLoop()
+ mainloop = GLib.MainLoop()
app = SessionApplication(bus, app_path, mainloop)
@@ -321,20 +319,20 @@ def main():
elif sys.argv[1] == "change":
if len(sys.argv) < 5:
- print "Arguments missing"
+ print("Arguments missing")
sys.exit(1)
app.Change(sys.argv[3], sys.argv[4], sys.argv[5:])
elif sys.argv[1] == "configure":
if len(sys.argv) < 5:
- print "Arguments missing"
+ print("Arguments missing")
sys.exit(1)
app.Configure(sys.argv[3], sys.argv[4], sys.argv[5:])
else:
- print "Unknown command '%s'" % sys.argv[1]
+ print("Unknown command '%s'" % sys.argv[1])
sys.exit(1)
if __name__ == '__main__':
diff --git a/test/vpn-connect b/test/vpn-connect
index 0f8636da..29753dc8 100755
--- a/test/vpn-connect
+++ b/test/vpn-connect
@@ -4,7 +4,7 @@ import sys
import dbus
if (len(sys.argv) < 2):
- print "Usage: %s <VPN connection id>" % (sys.argv[0])
+ print("Usage: %s <VPN connection id>" % (sys.argv[0]))
sys.exit(1)
bus = dbus.SystemBus()
@@ -16,7 +16,7 @@ connections = manager.GetConnections()
path = "/net/connman/vpn/connection/" + sys.argv[1]
-print "Attempting to connect VPN %s" % (path)
+print("Attempting to connect VPN %s" % (path))
connection = dbus.Interface(bus.get_object("net.connman.vpn", path),
"net.connman.vpn.Connection")
diff --git a/test/vpn-disconnect b/test/vpn-disconnect
index d7a49ba9..dccad2c8 100755
--- a/test/vpn-disconnect
+++ b/test/vpn-disconnect
@@ -4,7 +4,7 @@ import sys
import dbus
if (len(sys.argv) < 1):
- print "Usage: %s <VPN connection id>" % (sys.argv[0])
+ print("Usage: %s <VPN connection id>" % (sys.argv[0]))
sys.exit(1)
bus = dbus.SystemBus()
@@ -16,7 +16,7 @@ connections = manager.GetConnections()
path = "/net/connman/vpn/connection/" + sys.argv[1]
-print "Attempting to disconnect VPN %s" % (path)
+print("Attempting to disconnect VPN %s" % (path))
connection = dbus.Interface(bus.get_object("net.connman.vpn", path),
"net.connman.vpn.Connection")
diff --git a/test/vpn-get b/test/vpn-get
index f1f760cc..c9c5a700 100755
--- a/test/vpn-get
+++ b/test/vpn-get
@@ -4,7 +4,7 @@ import dbus
def extract_values(values):
val = "{"
- for key in values.keys():
+ for key in list(values.keys()):
val += " " + key + "="
if key in ["Servers", "Excludes"]:
val += extract_list(values[key])
@@ -34,15 +34,15 @@ for entry in manager.GetConnections():
path = entry[0]
properties = entry[1]
- print "[ %s ]" % (path)
+ print("[ %s ]" % (path))
- for key in properties.keys():
+ for key in list(properties.keys()):
if key in ["IPv4", "IPv6" ]:
val = extract_values(properties[key])
elif key in ["Nameservers","ServerRoutes","UserRoutes"]:
val = extract_list(properties[key])
else:
val = str(properties[key])
- print " %s = %s" % (key, val)
+ print(" %s = %s" % (key, val))
- print
+ print()
diff --git a/test/vpn-property b/test/vpn-property
index d05f4c7a..feddb5fc 100755
--- a/test/vpn-property
+++ b/test/vpn-property
@@ -8,7 +8,7 @@ def make_variant(string):
def extract_values(values):
val = "{"
- for key in values.keys():
+ for key in list(values.keys()):
val += " " + key + "="
if key in ["Servers", "Excludes"]:
val += extract_list(values[key])
@@ -32,7 +32,7 @@ def extract_list(list):
argc = len(sys.argv)
if (argc < 2):
- print "Usage: %s <VPN connection id> [<property name>] [<property values>]" % (sys.argv[0])
+ print("Usage: %s <VPN connection id> [<property name>] [<property values>]" % (sys.argv[0]))
sys.exit(1)
bus = dbus.SystemBus()
@@ -44,29 +44,29 @@ connections = manager.GetConnections()
path = "/net/connman/vpn/connection/" + sys.argv[1]
-print "Attempting to connect VPN %s" % (path)
+print("Attempting to connect VPN %s" % (path))
connection = dbus.Interface(bus.get_object("net.connman.vpn", path),
"net.connman.vpn.Connection")
if (argc < 3):
properties = connection.GetProperties()
- for key in properties.keys():
+ for key in list(properties.keys()):
if key in ["IPv4", "IPv6" ]:
val = extract_values(properties[key])
elif key in ["Nameservers","ServerRoutes","UserRoutes"]:
val = extract_list(properties[key])
else:
val = str(properties[key])
- print " %s = %s" % (key, val)
+ print(" %s = %s" % (key, val))
elif (argc < 4):
try:
connection.ClearProperty(sys.argv[2])
- except dbus.DBusException, error:
- print "%s: %s" % (error._dbus_error_name, error.message)
+ except dbus.DBusException as error:
+ print("%s: %s" % (error._dbus_error_name, error.message))
else:
try:
connection.SetProperty(sys.argv[2], sys.argv[3])
- except dbus.DBusException, error:
- print "%s: %s" % (error._dbus_error_name, error.message)
+ except dbus.DBusException as error:
+ print("%s: %s" % (error._dbus_error_name, error.message))
diff --git a/tools/ip6tables-test.c b/tools/ip6tables-test.c
index 41e842dd..a52f4af0 100644
--- a/tools/ip6tables-test.c
+++ b/tools/ip6tables-test.c
@@ -45,7 +45,7 @@ int main(int argc, char *argv[])
{
enum iptables_command cmd = IPTABLES_COMMAND_UNKNOWN;
char *table = NULL, *chain = NULL, *rule = NULL, *tmp;
- int err, c, i;
+ int err = -EINVAL, c, i;
opterr = 0;
diff --git a/tools/iptables-test.c b/tools/iptables-test.c
index e9b7cb22..f9d091eb 100755
--- a/tools/iptables-test.c
+++ b/tools/iptables-test.c
@@ -44,7 +44,7 @@ int main(int argc, char *argv[])
{
enum iptables_command cmd = IPTABLES_COMMAND_UNKNOWN;
char *table = NULL, *chain = NULL, *rule = NULL, *tmp;
- int err, c, i;
+ int err = -EINVAL, c, i;
opterr = 0;
diff --git a/tools/netlink-test.c b/tools/netlink-test.c
deleted file mode 100755
index 221e3490..00000000
--- a/tools/netlink-test.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- *
- * Connection Manager
- *
- * Copyright (C) 2013-2014 BMW Car IT GmbH.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <sys/socket.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <linux/genetlink.h>
-#include <linux/netfilter/nfnetlink.h>
-#include <net/if.h>
-
-#include <string.h>
-#include <stdio.h>
-#include <inttypes.h>
-#include <errno.h>
-
-#include <glib.h>
-
-#include "../src/shared/netlink.h"
-
-#define NFGEN_DATA(nlh) ((void *)((char *)(nlh) + \
- NLMSG_ALIGN(sizeof(struct nfgenmsg))))
-#define NLA_DATA(nla) ((void *)((char*)(nla) + NLA_HDRLEN))
-#define NLA_OK(nla,len) ((len) >= (int)sizeof(struct nlattr) && \
- (nla)->nla_len >= sizeof(struct nlattr) && \
- (nla)->nla_len <= (len))
-#define NLA_NEXT(nla,attrlen) ((attrlen) -= NLA_ALIGN((nla)->nla_len), \
- (struct nlattr*)(((char*)(nla)) + \
- NLA_ALIGN((nla)->nla_len)))
-
-static GMainLoop *mainloop;
-
-static void do_debug(const char *str, void *user_data)
-{
- const char *prefix = user_data;
-
- printf("%s%s\n", prefix, str);
-}
-
-static void getlink_callback(unsigned int error, uint16_t type, const void *data,
- uint32_t len, void *user_data)
-{
- const struct ifinfomsg *ifi = data;
- struct rtattr *rta;
- int bytes;
- char ifname[IF_NAMESIZE];
- uint32_t index, flags;
-
- g_assert_cmpuint(error, ==, 0);
-
- bytes = len - NLMSG_ALIGN(sizeof(struct ifinfomsg));
-
- memset(ifname, 0, sizeof(ifname));
-
- index = ifi->ifi_index;
- flags = ifi->ifi_flags;
-
- for (rta = IFLA_RTA(ifi); RTA_OK(rta, bytes);
- rta = RTA_NEXT(rta, bytes)) {
- switch (rta->rta_type) {
- case IFLA_IFNAME:
- if (RTA_PAYLOAD(rta) <= IF_NAMESIZE)
- strcpy(ifname, RTA_DATA(rta));
- break;
- }
- }
-
- printf("index=%d flags=0x%08x name=%s\n", index, flags, ifname);
-
- g_main_loop_quit(mainloop);
-}
-
-static void test_case_1(void)
-{
- struct netlink_info *netlink;
- struct ifinfomsg msg;
-
- netlink = netlink_new(NETLINK_ROUTE);
-
- printf("\n");
- netlink_set_debug(netlink, do_debug, "[NETLINK] ", NULL);
-
- memset(&msg, 0, sizeof(msg));
-
- netlink_send(netlink, RTM_GETLINK, NLM_F_DUMP, &msg, sizeof(msg),
- getlink_callback, NULL, NULL);
-
- mainloop = g_main_loop_new(NULL, FALSE);
- g_main_loop_run(mainloop);
- g_main_loop_unref(mainloop);
-
- netlink_destroy(netlink);
-}
-
-int main(int argc, char *argv[])
-{
- g_test_init(&argc, &argv, NULL);
-
- g_test_add_func("/netlink/Test case 1", test_case_1);
-
- return g_test_run();
-}
diff --git a/tools/stats-tool.c b/tools/stats-tool.c
index 5695048f..105dc497 100755
--- a/tools/stats-tool.c
+++ b/tools/stats-tool.c
@@ -108,12 +108,10 @@ static char *option_last_file_name = NULL;
static bool parse_start_ts(const char *key, const char *value,
gpointer user_data, GError **error)
{
- GTimeVal time_val;
+ struct tm tm;
- if (!g_time_val_from_iso8601(value, &time_val))
- return false;
-
- option_start_ts = time_val.tv_sec;
+ strptime(value, "%FT%TZ", &tm);
+ option_start_ts = mktime(&tm);
return true;
}
diff --git a/unit/test-iptables.c b/unit/test-iptables.c
index cd261d05..f08736ea 100644
--- a/unit/test-iptables.c
+++ b/unit/test-iptables.c
@@ -69,13 +69,13 @@ static void set_test_config(enum configtype type)
#define IP6T_SO_GET_INFO (IP6T_BASE_CTL)
#define IP6T_SO_GET_ENTRIES (IP6T_BASE_CTL + 1)
-int xt_match_parse(int c, char **argv, int invert, unsigned int *flags,
+int static xt_match_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
{
return 0;
}
-int xt_target_parse(int c, char **argv, int invert, unsigned int *flags,
+int static xt_target_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **targetinfo)
{
return 0;
diff --git a/vpn/main.c b/vpn/main.c
index 474c62fb..e4f4a105 100755
--- a/vpn/main.c
+++ b/vpn/main.c
@@ -44,74 +44,10 @@
#define CONFIGMAINFILE CONFIGDIR "/connman-vpn.conf"
-#define DEFAULT_INPUT_REQUEST_TIMEOUT 300 * 1000
-#define DEFAULT_BROWSER_LAUNCH_TIMEOUT 300 * 1000
-
static GMainLoop *main_loop = NULL;
static unsigned int __terminated = 0;
-static struct {
- unsigned int timeout_inputreq;
- unsigned int timeout_browserlaunch;
-} connman_vpn_settings = {
- .timeout_inputreq = DEFAULT_INPUT_REQUEST_TIMEOUT,
- .timeout_browserlaunch = DEFAULT_BROWSER_LAUNCH_TIMEOUT,
-};
-
-static GKeyFile *load_config(const char *file)
-{
- GError *err = NULL;
- GKeyFile *keyfile;
-
- keyfile = g_key_file_new();
-
- g_key_file_set_list_separator(keyfile, ',');
-
- if (!g_key_file_load_from_file(keyfile, file, 0, &err)) {
- if (err->code != G_FILE_ERROR_NOENT) {
- connman_error("Parsing %s failed: %s", file,
- err->message);
- }
-
- g_error_free(err);
- g_key_file_free(keyfile);
- return NULL;
- }
-
- return keyfile;
-}
-
-static void parse_config(GKeyFile *config, const char *file)
-{
- GError *error = NULL;
- int timeout;
-
- if (!config)
- return;
-
- DBG("parsing %s", file);
-
- timeout = g_key_file_get_integer(config, "General",
- "InputRequestTimeout", &error);
- if (!error && timeout >= 0)
- connman_vpn_settings.timeout_inputreq = timeout * 1000;
-
- g_clear_error(&error);
-}
-
-static int config_init(const char *file)
-{
- GKeyFile *config;
-
- config = load_config(file);
- parse_config(config, file);
- if (config)
- g_key_file_free(config);
-
- return 0;
-}
-
static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
gpointer user_data)
{
@@ -193,7 +129,6 @@ static gchar *option_plugin = NULL;
static gchar *option_noplugin = NULL;
static bool option_detach = true;
static bool option_version = false;
-static bool option_routes = false;
static bool parse_debug(const char *key, const char *value,
gpointer user_data, GError **error)
@@ -220,19 +155,17 @@ static GOptionEntry options[] = {
{ "nodaemon", 'n', G_OPTION_FLAG_REVERSE,
G_OPTION_ARG_NONE, &option_detach,
"Don't fork daemon to background" },
- { "routes", 'r', 0, G_OPTION_ARG_NONE, &option_routes,
- "Create/delete VPN routes" },
{ "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
"Show version information and exit" },
{ NULL },
};
+#if defined TIZEN_EXT
bool connman_setting_get_bool(const char *key)
{
return false;
}
-#if defined TIZEN_EXT
unsigned int connman_setting_get_uint(const char *key)
{
return 0;
@@ -242,7 +175,11 @@ int connman_setting_get_int(const char *key)
{
return 0;
}
-#endif
+
+char *connman_setting_get_string(const char *key)
+{
+ return NULL;
+}
char **connman_setting_get_string_list(const char *key)
{
@@ -254,23 +191,19 @@ unsigned int *connman_setting_get_uint_list(const char *key)
return NULL;
}
+unsigned int connman_timeout_browser_launch(void)
+{
+ return 0;
+}
+#endif
+
/*
* This function will be called from generic src/agent.c code so we have
* to use connman_ prefix instead of vpn_ one.
*/
unsigned int connman_timeout_input_request(void)
{
- return connman_vpn_settings.timeout_inputreq;
-}
-
-unsigned int connman_timeout_browser_launch(void)
-{
- return connman_vpn_settings.timeout_browserlaunch;
-}
-
-const char *connman_option_get_string(const char *key)
-{
- return NULL;
+ return __vpn_settings_get_timeout_inputreq();
}
int main(int argc, char *argv[])
@@ -354,13 +287,13 @@ int main(int argc, char *argv[])
__connman_dbus_init(conn);
if (!option_config)
- config_init(CONFIGMAINFILE);
+ __vpn_settings_init(CONFIGMAINFILE);
else
- config_init(option_config);
+ __vpn_settings_init(option_config);
__connman_inotify_init();
__connman_agent_init();
- __vpn_provider_init(option_routes);
+ __vpn_provider_init();
__vpn_manager_init();
__vpn_ipconfig_init();
__vpn_rtnl_init();
@@ -388,6 +321,7 @@ int main(int argc, char *argv[])
__connman_inotify_cleanup();
__connman_dbus_cleanup();
__connman_log_cleanup(false);
+ __vpn_settings_cleanup();
dbus_connection_unref(conn);
diff --git a/vpn/plugins/l2tp.c b/vpn/plugins/l2tp.c
index 5d83eb88..ee40dd72 100755
--- a/vpn/plugins/l2tp.c
+++ b/vpn/plugins/l2tp.c
@@ -4,6 +4,7 @@
*
* Copyright (C) 2010,2013 BMW Car IT GmbH.
* Copyright (C) 2012-2013 Intel Corporation. All rights reserved.
+ * Copyright (C) 2019-2021 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -65,6 +66,7 @@ enum {
OPT_L2G = 2,
OPT_L2 = 3,
OPT_PPPD = 4,
+ OPT_L2LNS = 5,
};
struct {
@@ -83,7 +85,7 @@ struct {
{ "L2TP.DefaultRoute", "defaultroute", OPT_L2, NULL, OPT_STRING },
{ "L2TP.FlowBit", "flow bit", OPT_L2, NULL, OPT_STRING },
{ "L2TP.TunnelRWS", "tunnel rws", OPT_L2, NULL, OPT_STRING },
- { "L2TP.Exclusive", "exclusive", OPT_L2, NULL, OPT_STRING },
+ { "L2TP.Exclusive", "exclusive", OPT_L2LNS, NULL, OPT_STRING },
{ "L2TP.Autodial", "autodial", OPT_L2, "yes", OPT_STRING },
{ "L2TP.Redial", "redial", OPT_L2, "yes", OPT_STRING },
{ "L2TP.RedialTimeout", "redial timeout", OPT_L2, "10", OPT_STRING },
@@ -96,7 +98,7 @@ struct {
{ "L2TP.ForceUserSpace", "force userspace", OPT_L2G, NULL, OPT_STRING },
{ "L2TP.ListenAddr", "listen-addr", OPT_L2G, NULL, OPT_STRING },
{ "L2TP.Rand Source", "rand source", OPT_L2G, NULL, OPT_STRING },
- { "L2TP.IPsecSaref", "ipsec saref", OPT_L2G, NULL, OPT_STRING },
+ { "L2TP.IPsecSaref", "ipsec saref", OPT_L2G, "no", OPT_STRING },
{ "L2TP.Port", "port", OPT_L2G, NULL, OPT_STRING },
{ "PPPD.EchoFailure", "lcp-echo-failure", OPT_PPPD, "0", OPT_STRING },
{ "PPPD.EchoInterval", "lcp-echo-interval", OPT_PPPD, "0", OPT_STRING },
@@ -120,12 +122,40 @@ struct {
static DBusConnection *connection;
struct l2tp_private_data {
+ struct vpn_provider *provider;
struct connman_task *task;
char *if_name;
vpn_provider_connect_cb_t cb;
void *user_data;
};
+static void l2tp_connect_done(struct l2tp_private_data *data, int err)
+{
+ vpn_provider_connect_cb_t cb;
+ void *user_data;
+
+ if (!data || !data->cb)
+ return;
+
+ /* Ensure that callback is called only once */
+ cb = data->cb;
+ user_data = data->user_data;
+ data->cb = NULL;
+ data->user_data = NULL;
+ cb(data->provider, user_data, err);
+}
+
+static void free_private_data(struct l2tp_private_data *data)
+{
+ if (vpn_provider_get_plugin_data(data->provider) == data)
+ vpn_provider_set_plugin_data(data->provider, NULL);
+
+ l2tp_connect_done(data, EIO);
+ vpn_provider_unref(data->provider);
+ g_free(data->if_name);
+ g_free(data);
+}
+
static DBusMessage *l2tp_get_sec(struct connman_task *task,
DBusMessage *msg, void *user_data)
{
@@ -163,6 +193,9 @@ static int l2tp_notify(DBusMessage *msg, struct vpn_provider *provider)
char *addressv4 = NULL, *netmask = NULL, *gateway = NULL;
char *ifname = NULL, *nameservers = NULL;
struct connman_ipaddress *ipaddress = NULL;
+ struct l2tp_private_data *data;
+
+ data = vpn_provider_get_plugin_data(provider);
dbus_message_iter_init(msg, &iter);
@@ -178,13 +211,25 @@ static int l2tp_notify(DBusMessage *msg, struct vpn_provider *provider)
DBG("authentication failure");
vpn_provider_set_string(provider, "L2TP.User", NULL);
- vpn_provider_set_string(provider, "L2TP.Password", NULL);
+ vpn_provider_set_string_hide_value(provider, "L2TP.Password",
+ NULL);
+ l2tp_connect_done(data, EACCES);
return VPN_STATE_AUTH_FAILURE;
}
- if (strcmp(reason, "connect"))
+ if (strcmp(reason, "connect")) {
+ l2tp_connect_done(data, EIO);
+
+ /*
+ * Stop the task to avoid potential looping of this state when
+ * authentication fails.
+ */
+ if (data && data->task)
+ connman_task_stop(data->task);
+
return VPN_STATE_DISCONNECT;
+ }
dbus_message_iter_recurse(&iter, &dict);
@@ -244,6 +289,8 @@ static int l2tp_notify(DBusMessage *msg, struct vpn_provider *provider)
connman_ipaddress_set_ipv4(ipaddress, addressv4, netmask,
gateway);
+ connman_ipaddress_set_p2p(ipaddress, true);
+
vpn_provider_set_ipaddress(provider, ipaddress);
vpn_provider_set_nameservers(provider, nameservers);
@@ -253,6 +300,8 @@ static int l2tp_notify(DBusMessage *msg, struct vpn_provider *provider)
g_free(nameservers);
connman_ipaddress_free(ipaddress);
+ l2tp_connect_done(data, 0);
+
return VPN_STATE_CONNECT;
}
@@ -454,6 +503,9 @@ static int l2tp_write_config(struct vpn_provider *provider,
l2tp_write_option(fd, "[global]", NULL);
l2tp_write_fields(provider, fd, OPT_L2G);
+ l2tp_write_option(fd, "[lns default]", NULL);
+ l2tp_write_fields(provider, fd, OPT_L2LNS);
+
l2tp_write_option(fd, "[lac l2tp]", NULL);
option = vpn_provider_get_string(provider, "Host");
@@ -469,9 +521,10 @@ static int l2tp_write_config(struct vpn_provider *provider,
static void l2tp_died(struct connman_task *task, int exit_code, void *user_data)
{
+ struct l2tp_private_data *data = user_data;
char *conf_file;
- vpn_died(task, exit_code, user_data);
+ vpn_died(task, exit_code, data->provider);
conf_file = g_strdup_printf(VPN_STATEDIR "/connman-xl2tpd.conf");
unlink(conf_file);
@@ -480,6 +533,8 @@ static void l2tp_died(struct connman_task *task, int exit_code, void *user_data)
conf_file = g_strdup_printf(VPN_STATEDIR "/connman-ppp-option.conf");
unlink(conf_file);
g_free(conf_file);
+
+ free_private_data(data);
}
struct request_input_reply {
@@ -491,16 +546,28 @@ struct request_input_reply {
static void request_input_reply(DBusMessage *reply, void *user_data)
{
struct request_input_reply *l2tp_reply = user_data;
+ struct l2tp_private_data *data;
const char *error = NULL;
char *username = NULL, *password = NULL;
char *key;
DBusMessageIter iter, dict;
+ int err;
DBG("provider %p", l2tp_reply->provider);
- if (!reply || dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
- if (reply)
- error = dbus_message_get_error_name(reply);
+ if (!reply)
+ goto done;
+
+ data = l2tp_reply->user_data;
+
+ err = vpn_agent_check_and_process_reply_error(reply,
+ l2tp_reply->provider, data->task, data->cb,
+ data->user_data);
+ if (err) {
+ /* Ensure cb is called only once */
+ data->cb = NULL;
+ data->user_data = NULL;
+ error = dbus_message_get_error_name(reply);
goto done;
}
@@ -593,6 +660,9 @@ static int request_input(struct vpn_provider *provider,
connman_dbus_dict_open(&iter, &dict);
+ if (vpn_provider_get_authentication_errors(provider))
+ vpn_agent_append_auth_failure(&dict, provider, NULL);
+
vpn_agent_append_user_info(&dict, provider, "L2TP.User");
vpn_agent_append_host_and_name(&dict, provider);
@@ -624,16 +694,16 @@ static int request_input(struct vpn_provider *provider,
return -EINPROGRESS;
}
-static int run_connect(struct vpn_provider *provider,
- struct connman_task *task, const char *if_name,
- vpn_provider_connect_cb_t cb, void *user_data,
+static int run_connect(struct l2tp_private_data *data,
const char *username, const char *password)
{
- char *l2tp_name, *pppd_name;
+ struct vpn_provider *provider = data->provider;
+ struct connman_task *task = data->task;
+ char *l2tp_name, *ctrl_name, *pppd_name;
int l2tp_fd, pppd_fd;
int err;
- if (!username || !password) {
+ if (!username || !*username || !password || !*password) {
DBG("Cannot connect username %s password %p",
username, password);
err = -EINVAL;
@@ -652,12 +722,24 @@ static int run_connect(struct vpn_provider *provider,
goto done;
}
- pppd_name = g_strdup_printf(VPN_STATEDIR "/connman-ppp-option.conf");
+ ctrl_name = g_strconcat(VPN_STATEDIR, "/connman-xl2tpd-control", NULL);
+
+ if (mkfifo(ctrl_name, S_IRUSR|S_IWUSR) != 0 && errno != EEXIST) {
+ connman_error("Error creating xl2tp control pipe");
+ g_free(l2tp_name);
+ g_free(ctrl_name);
+ close(l2tp_fd);
+ err = -EIO;
+ goto done;
+ }
+
+ pppd_name = g_strconcat(VPN_STATEDIR, "/connman-ppp-option.conf", NULL);
pppd_fd = open(pppd_name, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
if (pppd_fd < 0) {
connman_error("Error writing pppd config");
g_free(l2tp_name);
+ g_free(ctrl_name);
g_free(pppd_name);
close(l2tp_fd);
err = -EIO;
@@ -669,34 +751,28 @@ static int run_connect(struct vpn_provider *provider,
write_pppd_option(provider, pppd_fd);
connman_task_add_argument(task, "-D", NULL);
+ connman_task_add_argument(task, "-C", ctrl_name);
connman_task_add_argument(task, "-c", l2tp_name);
g_free(l2tp_name);
+ g_free(ctrl_name);
g_free(pppd_name);
close(l2tp_fd);
close(pppd_fd);
- err = connman_task_run(task, l2tp_died, provider,
- NULL, NULL, NULL);
+ err = connman_task_run(task, l2tp_died, data, NULL, NULL, NULL);
if (err < 0) {
connman_error("l2tp failed to start");
err = -EIO;
- goto done;
}
done:
- if (cb)
- cb(provider, user_data, err);
+ if (err)
+ l2tp_connect_done(data, -err);
return err;
}
-static void free_private_data(struct l2tp_private_data *data)
-{
- g_free(data->if_name);
- g_free(data);
-}
-
static void request_input_cb(struct vpn_provider *provider,
const char *username,
const char *password,
@@ -704,7 +780,7 @@ static void request_input_cb(struct vpn_provider *provider,
{
struct l2tp_private_data *data = user_data;
- if (!username || !password)
+ if (!username || !*username || !password || !*password)
DBG("Requesting username %s or password failed, error %s",
username, error);
else if (error)
@@ -714,10 +790,7 @@ static void request_input_cb(struct vpn_provider *provider,
vpn_provider_set_string_hide_value(provider, "L2TP.Password",
password);
- run_connect(provider, data->task, data->if_name, data->cb,
- data->user_data, username, password);
-
- free_private_data(data);
+ run_connect(data, username, password);
}
static int l2tp_connect(struct vpn_provider *provider,
@@ -725,9 +798,21 @@ static int l2tp_connect(struct vpn_provider *provider,
vpn_provider_connect_cb_t cb, const char *dbus_sender,
void *user_data)
{
+ struct l2tp_private_data *data;
const char *username, *password;
int err;
+ data = g_try_new0(struct l2tp_private_data, 1);
+ if (!data)
+ return -ENOMEM;
+
+ data->provider = vpn_provider_ref(provider);
+ data->task = task;
+ data->if_name = g_strdup(if_name);
+ data->cb = cb;
+ data->user_data = user_data;
+ vpn_provider_set_plugin_data(provider, data);
+
if (connman_task_set_notify(task, "getsec",
l2tp_get_sec, provider) != 0) {
err = -ENOMEM;
@@ -739,34 +824,20 @@ static int l2tp_connect(struct vpn_provider *provider,
DBG("user %s password %p", username, password);
- if (!username || !password) {
- struct l2tp_private_data *data;
-
- data = g_try_new0(struct l2tp_private_data, 1);
- if (!data)
- return -ENOMEM;
-
- data->task = task;
- data->if_name = g_strdup(if_name);
- data->cb = cb;
- data->user_data = user_data;
-
+ if (!username || !*username || !password || !*password) {
err = request_input(provider, request_input_cb, dbus_sender,
data);
- if (err != -EINPROGRESS) {
- free_private_data(data);
- goto done;
- }
+ if (err != -EINPROGRESS)
+ goto error;
+
return err;
}
-done:
- return run_connect(provider, task, if_name, cb, user_data,
- username, password);
+ return run_connect(data, username, password);
error:
- if (cb)
- cb(provider, user_data, err);
+ l2tp_connect_done(data, -err);
+ free_private_data(data);
return err;
}
@@ -783,7 +854,12 @@ static int l2tp_error_code(struct vpn_provider *provider, int exit_code)
static void l2tp_disconnect(struct vpn_provider *provider)
{
- vpn_provider_set_string(provider, "L2TP.Password", NULL);
+ if (!provider)
+ return;
+
+ vpn_provider_set_string_hide_value(provider, "L2TP.Password", NULL);
+
+ connman_agent_cancel(provider);
}
static struct vpn_driver vpn_driver = {
diff --git a/vpn/plugins/libwireguard.c b/vpn/plugins/libwireguard.c
new file mode 100644
index 00000000..c1f55a72
--- /dev/null
+++ b/vpn/plugins/libwireguard.c
@@ -0,0 +1,998 @@
+// SPDX-License-Identifier: LGPL-2.1+
+/*
+ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ * Copyright (C) 2008-2012 Pablo Neira Ayuso <pablo@netfilter.org>.
+ */
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <linux/genetlink.h>
+#include <linux/if_link.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#include <libmnl/libmnl.h>
+
+#include "src/shared/mnlg.h"
+#include "wireguard.h"
+
+/* wireguard.h netlink uapi: */
+
+#define WG_GENL_NAME "wireguard"
+#define WG_GENL_VERSION 1
+
+enum wg_cmd {
+ WG_CMD_GET_DEVICE,
+ WG_CMD_SET_DEVICE,
+ __WG_CMD_MAX
+};
+
+enum wgdevice_flag {
+ WGDEVICE_F_REPLACE_PEERS = 1U << 0
+};
+enum wgdevice_attribute {
+ WGDEVICE_A_UNSPEC,
+ WGDEVICE_A_IFINDEX,
+ WGDEVICE_A_IFNAME,
+ WGDEVICE_A_PRIVATE_KEY,
+ WGDEVICE_A_PUBLIC_KEY,
+ WGDEVICE_A_FLAGS,
+ WGDEVICE_A_LISTEN_PORT,
+ WGDEVICE_A_FWMARK,
+ WGDEVICE_A_PEERS,
+ __WGDEVICE_A_LAST
+};
+
+enum wgpeer_flag {
+ WGPEER_F_REMOVE_ME = 1U << 0,
+ WGPEER_F_REPLACE_ALLOWEDIPS = 1U << 1
+};
+enum wgpeer_attribute {
+ WGPEER_A_UNSPEC,
+ WGPEER_A_PUBLIC_KEY,
+ WGPEER_A_PRESHARED_KEY,
+ WGPEER_A_FLAGS,
+ WGPEER_A_ENDPOINT,
+ WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
+ WGPEER_A_LAST_HANDSHAKE_TIME,
+ WGPEER_A_RX_BYTES,
+ WGPEER_A_TX_BYTES,
+ WGPEER_A_ALLOWEDIPS,
+ WGPEER_A_PROTOCOL_VERSION,
+ __WGPEER_A_LAST
+};
+
+enum wgallowedip_attribute {
+ WGALLOWEDIP_A_UNSPEC,
+ WGALLOWEDIP_A_FAMILY,
+ WGALLOWEDIP_A_IPADDR,
+ WGALLOWEDIP_A_CIDR_MASK,
+ __WGALLOWEDIP_A_LAST
+};
+
+/* wireguard-specific parts: */
+
+struct inflatable_buffer {
+ char *buffer;
+ char *next;
+ bool good;
+ size_t len;
+ size_t pos;
+};
+
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+static int add_next_to_inflatable_buffer(struct inflatable_buffer *buffer)
+{
+ size_t len, expand_to;
+ char *new_buffer;
+
+ if (!buffer->good || !buffer->next) {
+ free(buffer->next);
+ buffer->good = false;
+ return 0;
+ }
+
+ len = strlen(buffer->next) + 1;
+
+ if (len == 1) {
+ free(buffer->next);
+ buffer->good = false;
+ return 0;
+ }
+
+ if (buffer->len - buffer->pos <= len) {
+ expand_to = max(buffer->len * 2, buffer->len + len + 1);
+ new_buffer = realloc(buffer->buffer, expand_to);
+ if (!new_buffer) {
+ free(buffer->next);
+ buffer->good = false;
+ return -errno;
+ }
+ memset(&new_buffer[buffer->len], 0, expand_to - buffer->len);
+ buffer->buffer = new_buffer;
+ buffer->len = expand_to;
+ }
+ memcpy(&buffer->buffer[buffer->pos], buffer->next, len);
+ free(buffer->next);
+ buffer->good = false;
+ buffer->pos += len;
+ return 0;
+}
+
+static int parse_linkinfo(const struct nlattr *attr, void *data)
+{
+ struct inflatable_buffer *buffer = data;
+
+ if (mnl_attr_get_type(attr) == IFLA_INFO_KIND && !strcmp(WG_GENL_NAME, mnl_attr_get_str(attr)))
+ buffer->good = true;
+ return MNL_CB_OK;
+}
+
+static int parse_infomsg(const struct nlattr *attr, void *data)
+{
+ struct inflatable_buffer *buffer = data;
+
+ if (mnl_attr_get_type(attr) == IFLA_LINKINFO)
+ return mnl_attr_parse_nested(attr, parse_linkinfo, data);
+ else if (mnl_attr_get_type(attr) == IFLA_IFNAME)
+ buffer->next = strdup(mnl_attr_get_str(attr));
+ return MNL_CB_OK;
+}
+
+static int read_devices_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct inflatable_buffer *buffer = data;
+ int ret;
+
+ buffer->good = false;
+ buffer->next = NULL;
+ ret = mnl_attr_parse(nlh, sizeof(struct ifinfomsg), parse_infomsg, data);
+ if (ret != MNL_CB_OK)
+ return ret;
+ ret = add_next_to_inflatable_buffer(buffer);
+ if (ret < 0)
+ return ret;
+ if (nlh->nlmsg_type != NLMSG_DONE)
+ return MNL_CB_OK + 1;
+ return MNL_CB_OK;
+}
+
+static int fetch_device_names(struct inflatable_buffer *buffer)
+{
+ struct mnl_socket *nl = NULL;
+ char *rtnl_buffer = NULL;
+ size_t message_len;
+ unsigned int portid, seq;
+ ssize_t len;
+ int ret = 0;
+ struct nlmsghdr *nlh;
+ struct ifinfomsg *ifm;
+
+ ret = -ENOMEM;
+ rtnl_buffer = calloc(MNL_SOCKET_BUFFER_SIZE, 1);
+ if (!rtnl_buffer)
+ goto cleanup;
+
+ nl = mnl_socket_open(NETLINK_ROUTE);
+ if (!nl) {
+ ret = -errno;
+ goto cleanup;
+ }
+
+ if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
+ ret = -errno;
+ goto cleanup;
+ }
+
+ seq = time(NULL);
+ portid = mnl_socket_get_portid(nl);
+ nlh = mnl_nlmsg_put_header(rtnl_buffer);
+ nlh->nlmsg_type = RTM_GETLINK;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
+ nlh->nlmsg_seq = seq;
+ ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm));
+ ifm->ifi_family = AF_UNSPEC;
+ message_len = nlh->nlmsg_len;
+
+ if (mnl_socket_sendto(nl, rtnl_buffer, message_len) < 0) {
+ ret = -errno;
+ goto cleanup;
+ }
+
+another:
+ if ((len = mnl_socket_recvfrom(nl, rtnl_buffer, MNL_SOCKET_BUFFER_SIZE)) < 0) {
+ ret = -errno;
+ goto cleanup;
+ }
+ if ((len = mnl_cb_run(rtnl_buffer, len, seq, portid, read_devices_cb, buffer)) < 0) {
+ /* Netlink returns NLM_F_DUMP_INTR if the set of all tunnels changed
+ * during the dump. That's unfortunate, but is pretty common on busy
+ * systems that are adding and removing tunnels all the time. Rather
+ * than retrying, potentially indefinitely, we just work with the
+ * partial results. */
+ if (errno != EINTR) {
+ ret = -errno;
+ goto cleanup;
+ }
+ }
+ if (len == MNL_CB_OK + 1)
+ goto another;
+ ret = 0;
+
+cleanup:
+ free(rtnl_buffer);
+ if (nl)
+ mnl_socket_close(nl);
+ return ret;
+}
+
+static int add_del_iface(const char *ifname, bool add)
+{
+ struct mnl_socket *nl = NULL;
+ char *rtnl_buffer;
+ ssize_t len;
+ int ret;
+ struct nlmsghdr *nlh;
+ struct ifinfomsg *ifm;
+ struct nlattr *nest;
+
+ rtnl_buffer = calloc(MNL_SOCKET_BUFFER_SIZE, 1);
+ if (!rtnl_buffer) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ nl = mnl_socket_open(NETLINK_ROUTE);
+ if (!nl) {
+ ret = -errno;
+ goto cleanup;
+ }
+
+ if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
+ ret = -errno;
+ goto cleanup;
+ }
+
+ nlh = mnl_nlmsg_put_header(rtnl_buffer);
+ nlh->nlmsg_type = add ? RTM_NEWLINK : RTM_DELLINK;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | (add ? NLM_F_CREATE | NLM_F_EXCL : 0);
+ nlh->nlmsg_seq = time(NULL);
+ ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm));
+ ifm->ifi_family = AF_UNSPEC;
+ mnl_attr_put_strz(nlh, IFLA_IFNAME, ifname);
+ nest = mnl_attr_nest_start(nlh, IFLA_LINKINFO);
+ mnl_attr_put_strz(nlh, IFLA_INFO_KIND, WG_GENL_NAME);
+ mnl_attr_nest_end(nlh, nest);
+
+ if (mnl_socket_sendto(nl, rtnl_buffer, nlh->nlmsg_len) < 0) {
+ ret = -errno;
+ goto cleanup;
+ }
+ if ((len = mnl_socket_recvfrom(nl, rtnl_buffer, MNL_SOCKET_BUFFER_SIZE)) < 0) {
+ ret = -errno;
+ goto cleanup;
+ }
+ if (mnl_cb_run(rtnl_buffer, len, nlh->nlmsg_seq, mnl_socket_get_portid(nl), NULL, NULL) < 0) {
+ ret = -errno;
+ goto cleanup;
+ }
+ ret = 0;
+
+cleanup:
+ free(rtnl_buffer);
+ if (nl)
+ mnl_socket_close(nl);
+ return ret;
+}
+
+int wg_set_device(wg_device *dev)
+{
+ int ret = 0;
+ wg_peer *peer = NULL;
+ wg_allowedip *allowedip = NULL;
+ struct nlattr *peers_nest, *peer_nest, *allowedips_nest, *allowedip_nest;
+ struct nlmsghdr *nlh;
+ struct mnlg_socket *nlg;
+
+ nlg = mnlg_socket_open(WG_GENL_NAME, WG_GENL_VERSION);
+ if (!nlg)
+ return -errno;
+
+again:
+ nlh = mnlg_msg_prepare(nlg, WG_CMD_SET_DEVICE, NLM_F_REQUEST | NLM_F_ACK);
+ mnl_attr_put_strz(nlh, WGDEVICE_A_IFNAME, dev->name);
+
+ if (!peer) {
+ uint32_t flags = 0;
+
+ if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY)
+ mnl_attr_put(nlh, WGDEVICE_A_PRIVATE_KEY, sizeof(dev->private_key), dev->private_key);
+ if (dev->flags & WGDEVICE_HAS_LISTEN_PORT)
+ mnl_attr_put_u16(nlh, WGDEVICE_A_LISTEN_PORT, dev->listen_port);
+ if (dev->flags & WGDEVICE_HAS_FWMARK)
+ mnl_attr_put_u32(nlh, WGDEVICE_A_FWMARK, dev->fwmark);
+ if (dev->flags & WGDEVICE_REPLACE_PEERS)
+ flags |= WGDEVICE_F_REPLACE_PEERS;
+ if (flags)
+ mnl_attr_put_u32(nlh, WGDEVICE_A_FLAGS, flags);
+ }
+ if (!dev->first_peer)
+ goto send;
+ peers_nest = peer_nest = allowedips_nest = allowedip_nest = NULL;
+ peers_nest = mnl_attr_nest_start(nlh, WGDEVICE_A_PEERS);
+ for (peer = peer ? peer : dev->first_peer; peer; peer = peer->next_peer) {
+ uint32_t flags = 0;
+
+ peer_nest = mnl_attr_nest_start_check(nlh, MNL_SOCKET_BUFFER_SIZE, 0);
+ if (!peer_nest)
+ goto toobig_peers;
+ if (!mnl_attr_put_check(nlh, MNL_SOCKET_BUFFER_SIZE, WGPEER_A_PUBLIC_KEY, sizeof(peer->public_key), peer->public_key))
+ goto toobig_peers;
+ if (peer->flags & WGPEER_REMOVE_ME)
+ flags |= WGPEER_F_REMOVE_ME;
+ if (!allowedip) {
+ if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS)
+ flags |= WGPEER_F_REPLACE_ALLOWEDIPS;
+ if (peer->flags & WGPEER_HAS_PRESHARED_KEY) {
+ if (!mnl_attr_put_check(nlh, MNL_SOCKET_BUFFER_SIZE, WGPEER_A_PRESHARED_KEY, sizeof(peer->preshared_key), peer->preshared_key))
+ goto toobig_peers;
+ }
+ if (peer->endpoint.addr.sa_family == AF_INET) {
+ if (!mnl_attr_put_check(nlh, MNL_SOCKET_BUFFER_SIZE, WGPEER_A_ENDPOINT, sizeof(peer->endpoint.addr4), &peer->endpoint.addr4))
+ goto toobig_peers;
+ } else if (peer->endpoint.addr.sa_family == AF_INET6) {
+ if (!mnl_attr_put_check(nlh, MNL_SOCKET_BUFFER_SIZE, WGPEER_A_ENDPOINT, sizeof(peer->endpoint.addr6), &peer->endpoint.addr6))
+ goto toobig_peers;
+ }
+ if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL) {
+ if (!mnl_attr_put_u16_check(nlh, MNL_SOCKET_BUFFER_SIZE, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, peer->persistent_keepalive_interval))
+ goto toobig_peers;
+ }
+ }
+ if (flags) {
+ if (!mnl_attr_put_u32_check(nlh, MNL_SOCKET_BUFFER_SIZE, WGPEER_A_FLAGS, flags))
+ goto toobig_peers;
+ }
+ if (peer->first_allowedip) {
+ if (!allowedip)
+ allowedip = peer->first_allowedip;
+ allowedips_nest = mnl_attr_nest_start_check(nlh, MNL_SOCKET_BUFFER_SIZE, WGPEER_A_ALLOWEDIPS);
+ if (!allowedips_nest)
+ goto toobig_allowedips;
+ for (; allowedip; allowedip = allowedip->next_allowedip) {
+ allowedip_nest = mnl_attr_nest_start_check(nlh, MNL_SOCKET_BUFFER_SIZE, 0);
+ if (!allowedip_nest)
+ goto toobig_allowedips;
+ if (!mnl_attr_put_u16_check(nlh, MNL_SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_FAMILY, allowedip->family))
+ goto toobig_allowedips;
+ if (allowedip->family == AF_INET) {
+ if (!mnl_attr_put_check(nlh, MNL_SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_IPADDR, sizeof(allowedip->ip4), &allowedip->ip4))
+ goto toobig_allowedips;
+ } else if (allowedip->family == AF_INET6) {
+ if (!mnl_attr_put_check(nlh, MNL_SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_IPADDR, sizeof(allowedip->ip6), &allowedip->ip6))
+ goto toobig_allowedips;
+ }
+ if (!mnl_attr_put_u8_check(nlh, MNL_SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_CIDR_MASK, allowedip->cidr))
+ goto toobig_allowedips;
+ mnl_attr_nest_end(nlh, allowedip_nest);
+ allowedip_nest = NULL;
+ }
+ mnl_attr_nest_end(nlh, allowedips_nest);
+ allowedips_nest = NULL;
+ }
+
+ mnl_attr_nest_end(nlh, peer_nest);
+ peer_nest = NULL;
+ }
+ mnl_attr_nest_end(nlh, peers_nest);
+ peers_nest = NULL;
+ goto send;
+toobig_allowedips:
+ if (allowedip_nest)
+ mnl_attr_nest_cancel(nlh, allowedip_nest);
+ if (allowedips_nest)
+ mnl_attr_nest_end(nlh, allowedips_nest);
+ mnl_attr_nest_end(nlh, peer_nest);
+ mnl_attr_nest_end(nlh, peers_nest);
+ goto send;
+toobig_peers:
+ if (peer_nest)
+ mnl_attr_nest_cancel(nlh, peer_nest);
+ mnl_attr_nest_end(nlh, peers_nest);
+ goto send;
+send:
+ if (mnlg_socket_send(nlg, nlh) < 0) {
+ ret = -errno;
+ goto out;
+ }
+ errno = 0;
+ if (mnlg_socket_recv_run(nlg, NULL, NULL) < 0) {
+ ret = errno ? -errno : -EINVAL;
+ goto out;
+ }
+ if (peer)
+ goto again;
+
+out:
+ mnlg_socket_close(nlg);
+ errno = -ret;
+ return ret;
+}
+
+static int parse_allowedip(const struct nlattr *attr, void *data)
+{
+ wg_allowedip *allowedip = data;
+
+ switch (mnl_attr_get_type(attr)) {
+ case WGALLOWEDIP_A_UNSPEC:
+ break;
+ case WGALLOWEDIP_A_FAMILY:
+ if (!mnl_attr_validate(attr, MNL_TYPE_U16))
+ allowedip->family = mnl_attr_get_u16(attr);
+ break;
+ case WGALLOWEDIP_A_IPADDR:
+ if (mnl_attr_get_payload_len(attr) == sizeof(allowedip->ip4))
+ memcpy(&allowedip->ip4, mnl_attr_get_payload(attr), sizeof(allowedip->ip4));
+ else if (mnl_attr_get_payload_len(attr) == sizeof(allowedip->ip6))
+ memcpy(&allowedip->ip6, mnl_attr_get_payload(attr), sizeof(allowedip->ip6));
+ break;
+ case WGALLOWEDIP_A_CIDR_MASK:
+ if (!mnl_attr_validate(attr, MNL_TYPE_U8))
+ allowedip->cidr = mnl_attr_get_u8(attr);
+ break;
+ }
+
+ return MNL_CB_OK;
+}
+
+static int parse_allowedips(const struct nlattr *attr, void *data)
+{
+ wg_peer *peer = data;
+ wg_allowedip *new_allowedip = calloc(1, sizeof(wg_allowedip));
+ int ret;
+
+ if (!new_allowedip)
+ return MNL_CB_ERROR;
+ if (!peer->first_allowedip)
+ peer->first_allowedip = peer->last_allowedip = new_allowedip;
+ else {
+ peer->last_allowedip->next_allowedip = new_allowedip;
+ peer->last_allowedip = new_allowedip;
+ }
+ ret = mnl_attr_parse_nested(attr, parse_allowedip, new_allowedip);
+ if (!ret)
+ return ret;
+ if (!((new_allowedip->family == AF_INET && new_allowedip->cidr <= 32) || (new_allowedip->family == AF_INET6 && new_allowedip->cidr <= 128))) {
+ errno = EAFNOSUPPORT;
+ return MNL_CB_ERROR;
+ }
+ return MNL_CB_OK;
+}
+
+bool wg_key_is_zero(const wg_key key)
+{
+ volatile uint8_t acc = 0;
+ unsigned int i;
+
+ for (i = 0; i < sizeof(wg_key); ++i) {
+ acc |= key[i];
+ __asm__ ("" : "=r" (acc) : "0" (acc));
+ }
+ return 1 & ((acc - 1) >> 8);
+}
+
+static int parse_peer(const struct nlattr *attr, void *data)
+{
+ wg_peer *peer = data;
+
+ switch (mnl_attr_get_type(attr)) {
+ case WGPEER_A_UNSPEC:
+ break;
+ case WGPEER_A_PUBLIC_KEY:
+ if (mnl_attr_get_payload_len(attr) == sizeof(peer->public_key)) {
+ memcpy(peer->public_key, mnl_attr_get_payload(attr), sizeof(peer->public_key));
+ peer->flags |= WGPEER_HAS_PUBLIC_KEY;
+ }
+ break;
+ case WGPEER_A_PRESHARED_KEY:
+ if (mnl_attr_get_payload_len(attr) == sizeof(peer->preshared_key)) {
+ memcpy(peer->preshared_key, mnl_attr_get_payload(attr), sizeof(peer->preshared_key));
+ if (!wg_key_is_zero(peer->preshared_key))
+ peer->flags |= WGPEER_HAS_PRESHARED_KEY;
+ }
+ break;
+ case WGPEER_A_ENDPOINT: {
+ struct sockaddr *addr;
+
+ if (mnl_attr_get_payload_len(attr) < sizeof(*addr))
+ break;
+ addr = mnl_attr_get_payload(attr);
+ if (addr->sa_family == AF_INET && mnl_attr_get_payload_len(attr) == sizeof(peer->endpoint.addr4))
+ memcpy(&peer->endpoint.addr4, addr, sizeof(peer->endpoint.addr4));
+ else if (addr->sa_family == AF_INET6 && mnl_attr_get_payload_len(attr) == sizeof(peer->endpoint.addr6))
+ memcpy(&peer->endpoint.addr6, addr, sizeof(peer->endpoint.addr6));
+ break;
+ }
+ case WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL:
+ if (!mnl_attr_validate(attr, MNL_TYPE_U16))
+ peer->persistent_keepalive_interval = mnl_attr_get_u16(attr);
+ break;
+ case WGPEER_A_LAST_HANDSHAKE_TIME:
+ if (mnl_attr_get_payload_len(attr) == sizeof(peer->last_handshake_time))
+ memcpy(&peer->last_handshake_time, mnl_attr_get_payload(attr), sizeof(peer->last_handshake_time));
+ break;
+ case WGPEER_A_RX_BYTES:
+ if (!mnl_attr_validate(attr, MNL_TYPE_U64))
+ peer->rx_bytes = mnl_attr_get_u64(attr);
+ break;
+ case WGPEER_A_TX_BYTES:
+ if (!mnl_attr_validate(attr, MNL_TYPE_U64))
+ peer->tx_bytes = mnl_attr_get_u64(attr);
+ break;
+ case WGPEER_A_ALLOWEDIPS:
+ return mnl_attr_parse_nested(attr, parse_allowedips, peer);
+ }
+
+ return MNL_CB_OK;
+}
+
+static int parse_peers(const struct nlattr *attr, void *data)
+{
+ wg_device *device = data;
+ wg_peer *new_peer = calloc(1, sizeof(wg_peer));
+ int ret;
+
+ if (!new_peer)
+ return MNL_CB_ERROR;
+ if (!device->first_peer)
+ device->first_peer = device->last_peer = new_peer;
+ else {
+ device->last_peer->next_peer = new_peer;
+ device->last_peer = new_peer;
+ }
+ ret = mnl_attr_parse_nested(attr, parse_peer, new_peer);
+ if (!ret)
+ return ret;
+ if (!(new_peer->flags & WGPEER_HAS_PUBLIC_KEY)) {
+ errno = ENXIO;
+ return MNL_CB_ERROR;
+ }
+ return MNL_CB_OK;
+}
+
+static int parse_device(const struct nlattr *attr, void *data)
+{
+ wg_device *device = data;
+
+ switch (mnl_attr_get_type(attr)) {
+ case WGDEVICE_A_UNSPEC:
+ break;
+ case WGDEVICE_A_IFINDEX:
+ if (!mnl_attr_validate(attr, MNL_TYPE_U32))
+ device->ifindex = mnl_attr_get_u32(attr);
+ break;
+ case WGDEVICE_A_IFNAME:
+ if (!mnl_attr_validate(attr, MNL_TYPE_STRING)) {
+ strncpy(device->name, mnl_attr_get_str(attr), sizeof(device->name) - 1);
+ device->name[sizeof(device->name) - 1] = '\0';
+ }
+ break;
+ case WGDEVICE_A_PRIVATE_KEY:
+ if (mnl_attr_get_payload_len(attr) == sizeof(device->private_key)) {
+ memcpy(device->private_key, mnl_attr_get_payload(attr), sizeof(device->private_key));
+ device->flags |= WGDEVICE_HAS_PRIVATE_KEY;
+ }
+ break;
+ case WGDEVICE_A_PUBLIC_KEY:
+ if (mnl_attr_get_payload_len(attr) == sizeof(device->public_key)) {
+ memcpy(device->public_key, mnl_attr_get_payload(attr), sizeof(device->public_key));
+ device->flags |= WGDEVICE_HAS_PUBLIC_KEY;
+ }
+ break;
+ case WGDEVICE_A_LISTEN_PORT:
+ if (!mnl_attr_validate(attr, MNL_TYPE_U16))
+ device->listen_port = mnl_attr_get_u16(attr);
+ break;
+ case WGDEVICE_A_FWMARK:
+ if (!mnl_attr_validate(attr, MNL_TYPE_U32))
+ device->fwmark = mnl_attr_get_u32(attr);
+ break;
+ case WGDEVICE_A_PEERS:
+ return mnl_attr_parse_nested(attr, parse_peers, device);
+ }
+
+ return MNL_CB_OK;
+}
+
+static int read_device_cb(const struct nlmsghdr *nlh, void *data)
+{
+ return mnl_attr_parse(nlh, sizeof(struct genlmsghdr), parse_device, data);
+}
+
+static void coalesce_peers(wg_device *device)
+{
+ wg_peer *old_next_peer, *peer = device->first_peer;
+
+ while (peer && peer->next_peer) {
+ if (memcmp(peer->public_key, peer->next_peer->public_key, sizeof(wg_key))) {
+ peer = peer->next_peer;
+ continue;
+ }
+ if (!peer->first_allowedip) {
+ peer->first_allowedip = peer->next_peer->first_allowedip;
+ peer->last_allowedip = peer->next_peer->last_allowedip;
+ } else {
+ peer->last_allowedip->next_allowedip = peer->next_peer->first_allowedip;
+ peer->last_allowedip = peer->next_peer->last_allowedip;
+ }
+ old_next_peer = peer->next_peer;
+ peer->next_peer = old_next_peer->next_peer;
+ free(old_next_peer);
+ }
+}
+
+int wg_get_device(wg_device **device, const char *device_name)
+{
+ int ret = 0;
+ struct nlmsghdr *nlh;
+ struct mnlg_socket *nlg;
+
+try_again:
+ *device = calloc(1, sizeof(wg_device));
+ if (!*device)
+ return -errno;
+
+ nlg = mnlg_socket_open(WG_GENL_NAME, WG_GENL_VERSION);
+ if (!nlg) {
+ wg_free_device(*device);
+ *device = NULL;
+ return -errno;
+ }
+
+ nlh = mnlg_msg_prepare(nlg, WG_CMD_GET_DEVICE, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
+ mnl_attr_put_strz(nlh, WGDEVICE_A_IFNAME, device_name);
+ if (mnlg_socket_send(nlg, nlh) < 0) {
+ ret = -errno;
+ goto out;
+ }
+ errno = 0;
+ if (mnlg_socket_recv_run(nlg, read_device_cb, *device) < 0) {
+ ret = errno ? -errno : -EINVAL;
+ goto out;
+ }
+ coalesce_peers(*device);
+
+out:
+ if (nlg)
+ mnlg_socket_close(nlg);
+ if (ret) {
+ wg_free_device(*device);
+ if (ret == -EINTR)
+ goto try_again;
+ *device = NULL;
+ }
+ errno = -ret;
+ return ret;
+}
+
+/* first\0second\0third\0forth\0last\0\0 */
+char *wg_list_device_names(void)
+{
+ struct inflatable_buffer buffer = { .len = MNL_SOCKET_BUFFER_SIZE };
+ int ret;
+
+ ret = -ENOMEM;
+ buffer.buffer = calloc(1, buffer.len);
+ if (!buffer.buffer)
+ goto err;
+
+ ret = fetch_device_names(&buffer);
+err:
+ errno = -ret;
+ if (errno) {
+ free(buffer.buffer);
+ return NULL;
+ }
+ return buffer.buffer;
+}
+
+int wg_add_device(const char *device_name)
+{
+ return add_del_iface(device_name, true);
+}
+
+int wg_del_device(const char *device_name)
+{
+ return add_del_iface(device_name, false);
+}
+
+void wg_free_device(wg_device *dev)
+{
+ wg_peer *peer, *np;
+ wg_allowedip *allowedip, *na;
+
+ if (!dev)
+ return;
+ for (peer = dev->first_peer, np = peer ? peer->next_peer : NULL; peer; peer = np, np = peer ? peer->next_peer : NULL) {
+ for (allowedip = peer->first_allowedip, na = allowedip ? allowedip->next_allowedip : NULL; allowedip; allowedip = na, na = allowedip ? allowedip->next_allowedip : NULL)
+ free(allowedip);
+ free(peer);
+ }
+ free(dev);
+}
+
+static void encode_base64(char dest[static 4], const uint8_t src[static 3])
+{
+ const uint8_t input[] = { (src[0] >> 2) & 63, ((src[0] << 4) | (src[1] >> 4)) & 63, ((src[1] << 2) | (src[2] >> 6)) & 63, src[2] & 63 };
+ unsigned int i;
+
+ for (i = 0; i < 4; ++i)
+ dest[i] = input[i] + 'A'
+ + (((25 - input[i]) >> 8) & 6)
+ - (((51 - input[i]) >> 8) & 75)
+ - (((61 - input[i]) >> 8) & 15)
+ + (((62 - input[i]) >> 8) & 3);
+
+}
+
+void wg_key_to_base64(wg_key_b64_string base64, const wg_key key)
+{
+ unsigned int i;
+
+ for (i = 0; i < 32 / 3; ++i)
+ encode_base64(&base64[i * 4], &key[i * 3]);
+ encode_base64(&base64[i * 4], (const uint8_t[]){ key[i * 3 + 0], key[i * 3 + 1], 0 });
+ base64[sizeof(wg_key_b64_string) - 2] = '=';
+ base64[sizeof(wg_key_b64_string) - 1] = '\0';
+}
+
+static int decode_base64(const char src[static 4])
+{
+ int val = 0;
+ unsigned int i;
+
+ for (i = 0; i < 4; ++i)
+ val |= (-1
+ + ((((('A' - 1) - src[i]) & (src[i] - ('Z' + 1))) >> 8) & (src[i] - 64))
+ + ((((('a' - 1) - src[i]) & (src[i] - ('z' + 1))) >> 8) & (src[i] - 70))
+ + ((((('0' - 1) - src[i]) & (src[i] - ('9' + 1))) >> 8) & (src[i] + 5))
+ + ((((('+' - 1) - src[i]) & (src[i] - ('+' + 1))) >> 8) & 63)
+ + ((((('/' - 1) - src[i]) & (src[i] - ('/' + 1))) >> 8) & 64)
+ ) << (18 - 6 * i);
+ return val;
+}
+
+int wg_key_from_base64(wg_key key, const wg_key_b64_string base64)
+{
+ unsigned int i;
+ int val;
+ volatile uint8_t ret = 0;
+
+ if (strlen(base64) != sizeof(wg_key_b64_string) - 1 || base64[sizeof(wg_key_b64_string) - 2] != '=') {
+ errno = EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < 32 / 3; ++i) {
+ val = decode_base64(&base64[i * 4]);
+ ret |= (uint32_t)val >> 31;
+ key[i * 3 + 0] = (val >> 16) & 0xff;
+ key[i * 3 + 1] = (val >> 8) & 0xff;
+ key[i * 3 + 2] = val & 0xff;
+ }
+ val = decode_base64((const char[]){ base64[i * 4 + 0], base64[i * 4 + 1], base64[i * 4 + 2], 'A' });
+ ret |= ((uint32_t)val >> 31) | (val & 0xff);
+ key[i * 3 + 0] = (val >> 16) & 0xff;
+ key[i * 3 + 1] = (val >> 8) & 0xff;
+ errno = EINVAL & ~((ret - 1) >> 8);
+out:
+ return -errno;
+}
+
+typedef int64_t fe[16];
+
+static __attribute__((noinline)) void memzero_explicit(void *s, size_t count)
+{
+ memset(s, 0, count);
+ __asm__ __volatile__("": :"r"(s) :"memory");
+}
+
+static void carry(fe o)
+{
+ int i;
+
+ for (i = 0; i < 16; ++i) {
+ o[(i + 1) % 16] += (i == 15 ? 38 : 1) * (o[i] >> 16);
+ o[i] &= 0xffff;
+ }
+}
+
+static void cswap(fe p, fe q, int b)
+{
+ int i;
+ int64_t t, c = ~(b - 1);
+
+ for (i = 0; i < 16; ++i) {
+ t = c & (p[i] ^ q[i]);
+ p[i] ^= t;
+ q[i] ^= t;
+ }
+
+ memzero_explicit(&t, sizeof(t));
+ memzero_explicit(&c, sizeof(c));
+ memzero_explicit(&b, sizeof(b));
+}
+
+static void pack(uint8_t *o, const fe n)
+{
+ int i, j, b;
+ fe m, t;
+
+ memcpy(t, n, sizeof(t));
+ carry(t);
+ carry(t);
+ carry(t);
+ for (j = 0; j < 2; ++j) {
+ m[0] = t[0] - 0xffed;
+ for (i = 1; i < 15; ++i) {
+ m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1);
+ m[i - 1] &= 0xffff;
+ }
+ m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1);
+ b = (m[15] >> 16) & 1;
+ m[14] &= 0xffff;
+ cswap(t, m, 1 - b);
+ }
+ for (i = 0; i < 16; ++i) {
+ o[2 * i] = t[i] & 0xff;
+ o[2 * i + 1] = t[i] >> 8;
+ }
+
+ memzero_explicit(m, sizeof(m));
+ memzero_explicit(t, sizeof(t));
+ memzero_explicit(&b, sizeof(b));
+}
+
+static void add(fe o, const fe a, const fe b)
+{
+ int i;
+
+ for (i = 0; i < 16; ++i)
+ o[i] = a[i] + b[i];
+}
+
+static void subtract(fe o, const fe a, const fe b)
+{
+ int i;
+
+ for (i = 0; i < 16; ++i)
+ o[i] = a[i] - b[i];
+}
+
+static void multmod(fe o, const fe a, const fe b)
+{
+ int i, j;
+ int64_t t[31] = { 0 };
+
+ for (i = 0; i < 16; ++i) {
+ for (j = 0; j < 16; ++j)
+ t[i + j] += a[i] * b[j];
+ }
+ for (i = 0; i < 15; ++i)
+ t[i] += 38 * t[i + 16];
+ memcpy(o, t, sizeof(fe));
+ carry(o);
+ carry(o);
+
+ memzero_explicit(t, sizeof(t));
+}
+
+static void invert(fe o, const fe i)
+{
+ fe c;
+ int a;
+
+ memcpy(c, i, sizeof(c));
+ for (a = 253; a >= 0; --a) {
+ multmod(c, c, c);
+ if (a != 2 && a != 4)
+ multmod(c, c, i);
+ }
+ memcpy(o, c, sizeof(fe));
+
+ memzero_explicit(c, sizeof(c));
+}
+
+static void clamp_key(uint8_t *z)
+{
+ z[31] = (z[31] & 127) | 64;
+ z[0] &= 248;
+}
+
+void wg_generate_public_key(wg_key public_key, const wg_key private_key)
+{
+ int i, r;
+ uint8_t z[32];
+ fe a = { 1 }, b = { 9 }, c = { 0 }, d = { 1 }, e, f;
+
+ memcpy(z, private_key, sizeof(z));
+ clamp_key(z);
+
+ for (i = 254; i >= 0; --i) {
+ r = (z[i >> 3] >> (i & 7)) & 1;
+ cswap(a, b, r);
+ cswap(c, d, r);
+ add(e, a, c);
+ subtract(a, a, c);
+ add(c, b, d);
+ subtract(b, b, d);
+ multmod(d, e, e);
+ multmod(f, a, a);
+ multmod(a, c, a);
+ multmod(c, b, e);
+ add(e, a, c);
+ subtract(a, a, c);
+ multmod(b, a, a);
+ subtract(c, d, f);
+ multmod(a, c, (const fe){ 0xdb41, 1 });
+ add(a, a, d);
+ multmod(c, c, a);
+ multmod(a, d, f);
+ multmod(d, b, (const fe){ 9 });
+ multmod(b, e, e);
+ cswap(a, b, r);
+ cswap(c, d, r);
+ }
+ invert(c, c);
+ multmod(a, a, c);
+ pack(public_key, a);
+
+ memzero_explicit(&r, sizeof(r));
+ memzero_explicit(z, sizeof(z));
+ memzero_explicit(a, sizeof(a));
+ memzero_explicit(b, sizeof(b));
+ memzero_explicit(c, sizeof(c));
+ memzero_explicit(d, sizeof(d));
+ memzero_explicit(e, sizeof(e));
+ memzero_explicit(f, sizeof(f));
+}
+
+void wg_generate_private_key(wg_key private_key)
+{
+ wg_generate_preshared_key(private_key);
+ clamp_key(private_key);
+}
+
+void wg_generate_preshared_key(wg_key preshared_key)
+{
+ ssize_t ret;
+ size_t i;
+ int fd;
+#if defined(__OpenBSD__) || (defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12) || (defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)))
+ if (!getentropy(preshared_key, sizeof(wg_key)))
+ return;
+#endif
+#if defined(__NR_getrandom) && defined(__linux__)
+ if (syscall(__NR_getrandom, preshared_key, sizeof(wg_key), 0) == sizeof(wg_key))
+ return;
+#endif
+ fd = open("/dev/urandom", O_RDONLY);
+ assert(fd >= 0);
+ for (i = 0; i < sizeof(wg_key); i += ret) {
+ ret = read(fd, preshared_key + i, sizeof(wg_key) - i);
+ assert(ret > 0);
+ }
+ close(fd);
+}
diff --git a/vpn/plugins/openconnect.c b/vpn/plugins/openconnect.c
index 8e74479f..fb63a1a3 100755
--- a/vpn/plugins/openconnect.c
+++ b/vpn/plugins/openconnect.c
@@ -3,6 +3,7 @@
* ConnMan VPN daemon
*
* Copyright (C) 2007-2013 Intel Corporation. All rights reserved.
+ * Copyright (C) 2019 Jolla Ltd. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -41,31 +42,168 @@
#include <connman/setting.h>
#include <connman/vpn-dbus.h>
+#include <openconnect.h>
+
#include "../vpn-provider.h"
#include "../vpn-agent.h"
#include "vpn.h"
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+#define OC_MAX_READBUF_LEN 128
+
+enum opt_type {
+ OPT_STRING = 0,
+ OPT_BOOL = 1,
+};
struct {
- const char *cm_opt;
- const char *oc_opt;
- char has_value;
+ const char *cm_opt;
+ const char *oc_opt;
+ bool has_value;
+ bool enabled; // Use as task parameter
+ enum opt_type type;
} oc_options[] = {
- { "OpenConnect.NoCertCheck", "--no-cert-check", 0 },
+ { "OpenConnect.AllowSelfSignedCert", NULL, 1, 0, OPT_BOOL},
+ { "OpenConnect.AuthType", NULL, 1, 0, OPT_STRING},
+ { "OpenConnect.CACert", "--cafile", 1, 1, OPT_STRING},
+ { "OpenConnect.ClientCert", NULL, 1, 0, OPT_STRING},
+ { "OpenConnect.DisableIPv6", "--disable-ipv6", 1, 1, OPT_BOOL},
+ { "OpenConnect.PKCSClientCert", NULL, 1, 0, OPT_STRING},
+ { "OpenConnect.Protocol", "--protocol", 1, 1, OPT_STRING},
+ /* --no-cert-check is disabled in openconnect 8.02 */
+ { "OpenConnect.NoCertCheck", "--no-cert-check", 0, 0, OPT_BOOL},
+ { "OpenConnect.NoHTTPKeepalive", "--no-http-keepalive", 1, 1, OPT_BOOL},
+ { "OpenConnect.NoDTLS", "--no-dtls", 1, 1, OPT_BOOL},
+ { "OpenConnect.ServerCert", "--servercert", 1, 1, OPT_STRING},
+ { "OpenConnect.Usergroup", "--usergroup", 1, 1, OPT_STRING},
+ { "OpenConnect.UserPrivateKey", NULL, 1, 0, OPT_STRING},
+ { "VPN.MTU", "--base-mtu", 1, 1, OPT_STRING},
};
+enum oc_connect_type {
+ OC_CONNECT_COOKIE = 0,
+ OC_CONNECT_COOKIE_WITH_USERPASS,
+ OC_CONNECT_USERPASS,
+ OC_CONNECT_PUBLICKEY,
+ OC_CONNECT_PKCS,
+};
+
+static const char *connect_types[] = {"cookie", "cookie_with_userpass",
+ "userpass", "publickey", "pkcs", NULL};
+
struct oc_private_data {
struct vpn_provider *provider;
struct connman_task *task;
char *if_name;
+ char *dbus_sender;
vpn_provider_connect_cb_t cb;
void *user_data;
+
+ GThread *cookie_thread;
+ struct openconnect_info *vpninfo;
+ int fd_cmd;
+ int err;
+
+ int fd_in;
+ int err_ch_id;
+ GIOChannel *err_ch;
+ enum oc_connect_type connect_type;
+ bool tried_passphrase;
+ bool group_set;
};
+typedef void (*request_input_reply_cb_t) (DBusMessage *reply,
+ void *user_data);
+
+static int run_connect(struct oc_private_data *data, const char *cookie);
+static int request_input_credentials_full(
+ struct oc_private_data *data,
+ request_input_reply_cb_t cb,
+ void *user_data);
+
+static bool is_valid_protocol(const char* protocol)
+{
+ int num_protocols;
+ int i;
+ struct oc_vpn_proto *protos;
+
+ if (!protocol || !*protocol)
+ return false;
+
+ num_protocols = openconnect_get_supported_protocols(&protos);
+
+ for (i = 0; i < num_protocols; i++)
+ if (!strcmp(protos[i].name, protocol))
+ break;
+
+ openconnect_free_supported_protocols(protos);
+
+ return i < num_protocols;
+}
+
+static void oc_connect_done(struct oc_private_data *data, int err)
+{
+ connman_info("data %p err %d/%s", data, err, strerror(err));
+
+ if (data && data->cb) {
+ vpn_provider_connect_cb_t cb = data->cb;
+ void *user_data = data->user_data;
+
+ /* Make sure we don't invoke this callback twice */
+ data->cb = NULL;
+ data->user_data = NULL;
+ cb(data->provider, user_data, err);
+ }
+}
+
+static void close_io_channel(struct oc_private_data *data, GIOChannel *channel)
+{
+ int id = 0;
+
+ connman_info("data %p channel %p", data, channel);
+
+ if (!data || !channel)
+ return;
+
+ if (data->err_ch == channel) {
+ id = data->err_ch_id;
+ data->err_ch = NULL;
+ data->err_ch_id = 0;
+ } else {
+ return;
+ }
+
+ if (id)
+ g_source_remove(id);
+
+ g_io_channel_shutdown(channel, FALSE, NULL);
+ g_io_channel_unref(channel);
+}
+
static void free_private_data(struct oc_private_data *data)
{
+ connman_info("data %p", data);
+
+ if (!data || !data->provider)
+ return;
+
+ connman_info("provider %p", data->provider);
+
+ if (data->vpninfo)
+ openconnect_vpninfo_free(data->vpninfo);
+
+ if (vpn_provider_get_plugin_data(data->provider) == data)
+ vpn_provider_set_plugin_data(data->provider, NULL);
+
+ vpn_provider_unref(data->provider);
+
+ if (data->fd_in > 0)
+ close(data->fd_in);
+ data->fd_in = -1;
+ close_io_channel(data, data->err_ch);
+
+ g_free(data->dbus_sender);
g_free(data->if_name);
g_free(data);
}
@@ -73,17 +211,51 @@ static void free_private_data(struct oc_private_data *data)
static int task_append_config_data(struct vpn_provider *provider,
struct connman_task *task)
{
- const char *option;
+ const char *option = NULL;
int i;
for (i = 0; i < (int)ARRAY_SIZE(oc_options); i++) {
- if (!oc_options[i].oc_opt)
+ if (!oc_options[i].oc_opt || !oc_options[i].enabled)
continue;
- option = vpn_provider_get_string(provider,
- oc_options[i].cm_opt);
- if (!option)
- continue;
+ if (oc_options[i].has_value) {
+ option = vpn_provider_get_string(provider,
+ oc_options[i].cm_opt);
+ if (!option)
+ continue;
+
+ /* Add boolean type values only if set as true. */
+ if (oc_options[i].type == OPT_BOOL) {
+ if (!vpn_provider_get_boolean(provider,
+ oc_options[i].cm_opt,
+ false))
+ continue;
+
+ /* No option is set for boolean type values. */
+ option = NULL;
+ }
+
+ /* Skip protocol if it is invalid. */
+ if (!g_strcmp0(oc_options[i].cm_opt,
+ "OpenConnect.Protocol")) {
+ if (!is_valid_protocol(option))
+ continue;
+ }
+ }
+
+ /*
+ * Add server certificate fingerprint only when self signed
+ * certificates are explicitly allowed. Using --servercert as
+ * parameter will accept any server with matching fingerprint,
+ * which would disregard the setting of AllowSelfSignedCert.
+ */
+ if (!g_strcmp0(oc_options[i].cm_opt,
+ "OpenConnect.ServerCert")) {
+ if (!vpn_provider_get_boolean(provider,
+ "OpenConnect.AllowSelfSignedCert",
+ false))
+ continue;
+ }
if (connman_task_add_argument(task,
oc_options[i].oc_opt,
@@ -103,6 +275,11 @@ static int oc_notify(DBusMessage *msg, struct vpn_provider *provider)
char *netmask = NULL, *gateway = NULL;
unsigned char prefix_len = 0;
struct connman_ipaddress *ipaddress;
+ struct oc_private_data *data;
+
+ connman_info("provider %p", provider);
+
+ data = vpn_provider_get_plugin_data(provider);
dbus_message_iter_init(msg, &iter);
@@ -111,6 +288,7 @@ static int oc_notify(DBusMessage *msg, struct vpn_provider *provider)
if (!provider) {
connman_error("No provider found");
+ oc_connect_done(data, ENOENT);
return VPN_STATE_FAILURE;
}
@@ -204,6 +382,8 @@ static int oc_notify(DBusMessage *msg, struct vpn_provider *provider)
else
connman_ipaddress_set_ipv6(ipaddress, addressv6,
prefix_len, gateway);
+
+ connman_ipaddress_set_p2p(ipaddress, true);
vpn_provider_set_ipaddress(provider, ipaddress);
vpn_provider_set_domain(provider, domain);
@@ -214,112 +394,883 @@ static int oc_notify(DBusMessage *msg, struct vpn_provider *provider)
g_free(domain);
connman_ipaddress_free(ipaddress);
+ oc_connect_done(data, 0);
return VPN_STATE_CONNECT;
}
-static int run_connect(struct vpn_provider *provider,
- struct connman_task *task, const char *if_name,
- vpn_provider_connect_cb_t cb, void *user_data)
+static ssize_t full_write(int fd, const char *buf, size_t len)
{
- const char *vpnhost, *vpncookie, *servercert, *mtu;
- int fd, err = 0, len;
+ ssize_t byte_write;
+
+ while (len) {
+ byte_write = write(fd, buf, len);
+ if (byte_write < 0) {
+ connman_error("failed to write config to openconnect: "
+ " %s\n", strerror(errno));
+ return byte_write;
+ }
+ len -= byte_write;
+ buf += byte_write;
+ }
- vpnhost = vpn_provider_get_string(provider, "OpenConnect.VPNHost");
- if (!vpnhost)
- vpnhost = vpn_provider_get_string(provider, "Host");
- vpncookie = vpn_provider_get_string(provider, "OpenConnect.Cookie");
- servercert = vpn_provider_get_string(provider,
- "OpenConnect.ServerCert");
+ return len;
+}
- if (!vpncookie || !servercert) {
- err = -EINVAL;
- goto done;
+static ssize_t write_data(int fd, const char *data)
+{
+ gchar *buf;
+ ssize_t len;
+
+ if (!data || !*data)
+ return -1;
+
+ buf = g_strdup_printf("%s\n", data);
+
+ len = full_write(fd, buf, strlen(buf));
+
+ g_free(buf);
+
+ return len;
+}
+
+static void oc_died(struct connman_task *task, int exit_code, void *user_data)
+{
+ struct oc_private_data *data = user_data;
+
+ connman_info("task %p data %p exit_code %d user_data %p", task, data,
+ exit_code, user_data);
+
+ if (!data)
+ return;
+
+ if (data->provider) {
+ connman_agent_cancel(data->provider);
+
+ if (task)
+ vpn_died(task, exit_code, data->provider);
}
- task_append_config_data(provider, task);
+ free_private_data(data);
+}
+
+static bool strv_contains_prefix(const char *strv[], const char *str)
+{
+ int i;
+
+ if (!strv || !str || !*str)
+ return false;
+
+ for (i = 0; strv[i]; i++) {
+ if (g_str_has_prefix(str, strv[i]))
+ return true;
+ }
+
+ return false;
+}
+
+static void clear_provider_credentials(struct vpn_provider *provider,
+ bool clear_pkcs_pass)
+{
+ const char *keys[] = { "OpenConnect.PKCSPassword",
+ "OpenConnect.Username",
+ "OpenConnect.Password",
+ "OpenConnect.SecondPassword",
+ "OpenConnect.Cookie",
+ NULL
+ };
+ size_t i;
+
+ connman_info("provider %p", provider);
+
+ for (i = !clear_pkcs_pass; keys[i]; i++) {
+ if (!vpn_provider_get_string_immutable(provider, keys[i]))
+ vpn_provider_set_string_hide_value(provider, keys[i],
+ "-");
+ }
+}
+
+static void __attribute__ ((format(printf, 3, 4))) oc_progress(void *user_data,
+ int level, const char *fmt, ...)
+{
+ va_list ap;
+ char *msg;
+
+ va_start(ap, fmt);
+ msg = g_strdup_vprintf(fmt, ap);
+
+ connman_debug("%s", msg);
+ g_free(msg);
+
+ va_end(ap);
+}
+
+/*
+ * There is no enum / defines for these in openconnect.h, but these values
+ * are based on the comment for openconnect_validate_peer_cert_vfn.
+ */
+enum oc_cert_status {
+ OC_CERT_ACCEPT = 0,
+ OC_CERT_REJECT = 1
+};
+
+struct validate_cert_data {
+ GMutex mutex;
+ GCond cond;
+ const char *reason;
+ struct oc_private_data *data;
+ bool processed;
+ enum oc_cert_status status;
+};
+
+static gboolean validate_cert(void *user_data)
+{
+ struct validate_cert_data *cert_data = user_data;
+ struct oc_private_data *data;
+ const char *server_cert;
+ bool allow_self_signed;
+
+ DBG("");
+
+ g_mutex_lock(&cert_data->mutex);
+
+ data = cert_data->data;
+ server_cert = vpn_provider_get_string(data->provider,
+ "OpenConnect.ServerCert");
+ allow_self_signed = vpn_provider_get_boolean(data->provider,
+ "OpenConnect.AllowSelfSignedCert",
+ false);
+
+ if (!allow_self_signed) {
+ cert_data->status = OC_CERT_REJECT;
+ } else if (server_cert) {
+ /*
+ * Check peer cert hash may return negative values on errors,
+ * but anything non-zero is acceptable.
+ */
+ cert_data->status = openconnect_check_peer_cert_hash(
+ data->vpninfo,
+ server_cert);
+ } else {
+ /*
+ * We could verify this from the agent at this point, and
+ * release the thread upon reply.
+ */
+ DBG("Server cert hash: %s",
+ openconnect_get_peer_cert_hash(data->vpninfo));
+ vpn_provider_set_string(data->provider,
+ "OpenConnect.ServerCert",
+ openconnect_get_peer_cert_hash(data->vpninfo));
+ cert_data->status = OC_CERT_ACCEPT;
+ }
+
+ cert_data->processed = true;
+ g_cond_signal(&cert_data->cond);
+ g_mutex_unlock(&cert_data->mutex);
+
+ return G_SOURCE_REMOVE;
+}
+
+static int oc_validate_peer_cert(void *user_data, const char *reason)
+{
+ struct validate_cert_data data = { .reason = reason,
+ .data = user_data,
+ .processed = false };
+
+ g_cond_init(&data.cond);
+ g_mutex_init(&data.mutex);
+
+ g_mutex_lock(&data.mutex);
+
+ g_idle_add(validate_cert, &data);
+
+ while (!data.processed)
+ g_cond_wait(&data.cond, &data.mutex);
+
+ g_mutex_unlock(&data.mutex);
+
+ g_mutex_clear(&data.mutex);
+ g_cond_clear(&data.cond);
+
+ return data.status;
+}
+
+struct process_form_data {
+ GMutex mutex;
+ GCond cond;
+ struct oc_auth_form *form;
+ struct oc_private_data *data;
+ bool processed;
+ int status;
+};
+
+static void request_input_pkcs_reply(DBusMessage *reply, void *user_data)
+{
+ struct process_form_data *form_data = user_data;
+ struct oc_private_data *data = form_data->data;
+ struct oc_form_opt *opt;
+ const char *key;
+ const char *password = NULL;
+ DBusMessageIter iter, dict;
+
+ connman_info("provider %p", data->provider);
- connman_task_add_argument(task, "--servercert", servercert);
+ if (!reply) {
+ data->err = ENOENT;
+ goto err;
+ }
- mtu = vpn_provider_get_string(provider, "VPN.MTU");
+ if ((data->err = vpn_agent_check_and_process_reply_error(reply,
+ data->provider,
+ data->task,
+ data->cb,
+ data->user_data))) {
+ data->cb = NULL;
+ data->user_data = NULL;
+ goto err;
+ }
+
+ if (!vpn_agent_check_reply_has_dict(reply)) {
+ data->err = ENOENT;
+ goto err;
+ }
- if (mtu)
- connman_task_add_argument(task, "--mtu", (char *)mtu);
+ dbus_message_iter_init(reply, &iter);
+ dbus_message_iter_recurse(&iter, &dict);
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+ break;
+
+ dbus_message_iter_get_basic(&entry, &key);
+
+ if (g_str_equal(key, "OpenConnect.PKCSPassword")) {
+ dbus_message_iter_next(&entry);
+ if (dbus_message_iter_get_arg_type(&entry)
+ != DBUS_TYPE_VARIANT)
+ break;
+ dbus_message_iter_recurse(&entry, &value);
+ if (dbus_message_iter_get_arg_type(&value)
+ != DBUS_TYPE_STRING)
+ break;
+ dbus_message_iter_get_basic(&value, &password);
+ vpn_provider_set_string_hide_value(data->provider, key,
+ password);
+ }
+
+ dbus_message_iter_next(&dict);
+ }
+
+ if (!password)
+ goto err;
+
+ for (opt = form_data->form->opts; opt; opt = opt->next) {
+ if (opt->flags & OC_FORM_OPT_IGNORE)
+ continue;
+
+ if (opt->type == OC_FORM_OPT_PASSWORD &&
+ g_str_has_prefix(opt->name,
+ "openconnect_pkcs")) {
+ opt->_value = strdup(password);
+ form_data->status = OC_FORM_RESULT_OK;
+ data->tried_passphrase = true;
+ break;
+ }
+ }
+
+ goto out;
+
+err:
+ form_data->status = OC_FORM_RESULT_ERR;
+
+out:
+ form_data->processed = true;
+ g_cond_signal(&form_data->cond);
+ g_mutex_unlock(&form_data->mutex);
+}
+
+static gboolean io_channel_err_cb(GIOChannel *source, GIOCondition condition,
+ gpointer user_data)
+{
+ struct oc_private_data *data;
+ const char *auth_failures[] = {
+ /* Cookie not valid */
+ "Got inappropriate HTTP CONNECT response: "
+ "HTTP/1.1 401 Unauthorized",
+ /* Invalid cookie */
+ "VPN service unavailable",
+ NULL
+ };
+ const char *conn_failures[] = {
+ "Failed to connect to",
+ "Failed to open HTTPS connection to",
+ NULL
+ };
+ const char *server_key_hash = " --servercert ";
+ char *str;
+ int err = 0;
+
+ data = user_data;
+
+ if (!data)
+ return G_SOURCE_REMOVE;
+
+ if (source && data->err_ch != source)
+ return G_SOURCE_REMOVE;
+
+ if ((condition & G_IO_IN)) {
+ gsize len;
+
+ if (g_io_channel_read_line(source, &str, &len, NULL,
+ NULL) != G_IO_STATUS_NORMAL)
+ err = EIO;
+ else
+ g_strchomp(str);
+
+ connman_info("openconnect: %s", str);
+
+ if (err || !str || !*str) {
+ connman_info("error reading from openconnect");
+ } else if (g_str_has_prefix(str, server_key_hash)) {
+ const char *fingerprint;
+ int position;
+ bool allow_self_signed;
+
+ allow_self_signed = vpn_provider_get_boolean(
+ data->provider,
+ "OpenConnect.AllowSelfSignedCert",
+ false);
+
+ if (allow_self_signed) {
+ position = strlen(server_key_hash) + 1;
+ fingerprint = g_strstrip(str + position);
+
+ connman_info("Set server key hash: \"%s\"",
+ fingerprint);
+
+ vpn_provider_set_string(data->provider,
+ "OpenConnect.ServerCert",
+ str + strlen(server_key_hash));
+ } else {
+ connman_warn("Self signed certificate is not "
+ "allowed");
+ err = ECONNREFUSED;
+ }
+ } else if (strv_contains_prefix(auth_failures, str)) {
+ connman_warn("authentication failed: %s", str);
+ err = EACCES;
+ } else if (strv_contains_prefix(conn_failures, str)) {
+ connman_warn("connection failed: %s", str);
+ err = ECONNREFUSED;
+ }
+
+ g_free(str);
+ } else if (condition & (G_IO_ERR | G_IO_HUP)) {
+ connman_info("Err channel termination");
+ close_io_channel(data, source);
+ return G_SOURCE_REMOVE;
+ }
+
+ if (err) {
+ switch (err) {
+ case EACCES:
+ clear_provider_credentials(data->provider, true);
+ break;
+ case ECONNREFUSED:
+ /*
+ * This will trigger VPN_PROVIDER_ERROR_CONNECT_FAILED
+ * in vpn-provider.c:connect_cb().
+ */
+ default:
+ break;
+ }
+
+ oc_connect_done(data, err);
+ }
+
+ return G_SOURCE_CONTINUE;
+}
+
+static gboolean process_auth_form(void *user_data)
+{
+ struct process_form_data *form_data = user_data;
+ struct oc_private_data *data = form_data->data;
+ struct oc_form_opt_select *authgroup_opt;
+ struct oc_form_opt *opt;
+ const char *password;
+ const char *group;
+ int i;
+
+ g_mutex_lock(&form_data->mutex);
+
+ DBG("");
+
+ /*
+ * Special handling for "GROUP:" field, if present.
+ * Different group selections can make other fields disappear/appear
+ */
+ if (form_data->form->authgroup_opt) {
+ group = vpn_provider_get_string(data->provider, "OpenConnect.Group");
+ authgroup_opt = form_data->form->authgroup_opt;
+
+ if (group && !data->group_set) {
+ for (i = 0; i < authgroup_opt->nr_choices; i++) {
+ struct oc_choice *choice = authgroup_opt->choices[i];
+
+ if (!strcmp(group, choice->label)) {
+ DBG("Switching to auth group: %s", group);
+ openconnect_set_option_value(&authgroup_opt->form,
+ choice->name);
+ data->group_set = true;
+ form_data->status = OC_FORM_RESULT_NEWGROUP;
+ goto out;
+ }
+ }
+
+ connman_warn("Group choice %s not present", group);
+ data->err = -EACCES;
+ clear_provider_credentials(data->provider, true);
+ form_data->status = OC_FORM_RESULT_ERR;
+ goto out;
+ }
+ }
+
+ switch (data->connect_type) {
+ case OC_CONNECT_USERPASS:
+ case OC_CONNECT_COOKIE_WITH_USERPASS:
+ break;
+
+ case OC_CONNECT_PKCS:
+ password = vpn_provider_get_string(data->provider,
+ "OpenConnect.PKCSPassword");
+
+ for (opt = form_data->form->opts; opt; opt = opt->next) {
+ if (opt->flags & OC_FORM_OPT_IGNORE)
+ continue;
+
+ if (opt->type == OC_FORM_OPT_PASSWORD &&
+ g_str_has_prefix(opt->name,
+ "openconnect_pkcs"))
+ break;
+ }
+
+ if (opt) {
+ if (password && g_strcmp0(password, "-")) {
+ opt->_value = strdup(password);
+ data->tried_passphrase = true;
+ form_data->status = OC_FORM_RESULT_OK;
+ goto out;
+ } else {
+ if (data->tried_passphrase) {
+ vpn_provider_add_error(data->provider,
+ VPN_PROVIDER_ERROR_AUTH_FAILED);
+ clear_provider_credentials(
+ data->provider,
+ true);
+ }
+ request_input_credentials_full(data,
+ request_input_pkcs_reply,
+ form_data);
+ return G_SOURCE_REMOVE;
+ }
+ }
+
+ /* fall-through */
+
+ /*
+ * In case of public key, reaching here means that the
+ * passphrase previously provided was incorrect.
+ */
+ case OC_CONNECT_PUBLICKEY:
+ data->err = -EACCES;
+ clear_provider_credentials(data->provider, true);
+
+ /* fall-through */
+ default:
+ form_data->status = OC_FORM_RESULT_ERR;
+ goto out;
+ }
+
+ /*
+ * Form values are released with free(), so always use strdup()
+ * instead of g_strdup()
+ */
+ for (opt = form_data->form->opts; opt; opt = opt->next) {
+ if (opt->flags & OC_FORM_OPT_IGNORE)
+ continue;
+
+ if (opt->type == OC_FORM_OPT_TEXT &&
+ g_str_has_prefix(opt->name, "user")) {
+ const char *user = vpn_provider_get_string(
+ data->provider,
+ "OpenConnect.Username");
+ if (user)
+ opt->_value = strdup(user);
+ } else if (opt->type == OC_FORM_OPT_PASSWORD &&
+ g_str_has_prefix(opt->name, "password")) {
+
+ const char *pass = vpn_provider_get_string(
+ data->provider,
+ "OpenConnect.Password");
+ if (pass)
+ opt->_value = strdup(pass);
+ } else if (opt->type == OC_FORM_OPT_PASSWORD &&
+ g_str_has_prefix(opt->name, "secondary_password")) {
+ const char *pass = vpn_provider_get_string(
+ data->provider,
+ "OpenConnect.SecondPassword");
+ if (pass)
+ opt->_value = strdup(pass);
+ }
+ }
+
+ form_data->status = OC_FORM_RESULT_OK;
+
+out:
+ form_data->processed = true;
+ g_cond_signal(&form_data->cond);
+ g_mutex_unlock(&form_data->mutex);
+
+ return G_SOURCE_REMOVE;
+}
+
+static int oc_process_auth_form(void *user_data, struct oc_auth_form *form)
+{
+ struct process_form_data data = { .form = form,
+ .data = user_data,
+ .processed = false };
+
+ DBG("");
+
+ g_cond_init(&data.cond);
+ g_mutex_init(&data.mutex);
+
+ g_mutex_lock(&data.mutex);
+ g_idle_add(process_auth_form, &data);
+
+ while (!data.processed)
+ g_cond_wait(&data.cond, &data.mutex);
+
+ g_mutex_unlock(&data.mutex);
+
+ g_mutex_clear(&data.mutex);
+ g_cond_clear(&data.cond);
+
+ return data.status;
+}
+
+static gboolean authenticated(void *user_data)
+{
+ struct oc_private_data *data = user_data;
+ int rv = GPOINTER_TO_INT(g_thread_join(data->cookie_thread));
+
+ DBG("");
+
+ data->cookie_thread = NULL;
+
+ if (rv == 0)
+ rv = run_connect(data, openconnect_get_cookie(data->vpninfo));
+ else if (rv < 0)
+ clear_provider_credentials(data->provider, true);
+
+ openconnect_vpninfo_free(data->vpninfo);
+ data->vpninfo = NULL;
+
+ if (rv != -EINPROGRESS) {
+ oc_connect_done(data, data->err ? data->err : rv);
+ free_private_data(data);
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static void *obtain_cookie_thread(void *user_data)
+{
+ struct oc_private_data *data = user_data;
+ int ret;
+
+ DBG("%p", data->vpninfo);
+
+ ret = openconnect_obtain_cookie(data->vpninfo);
+
+ g_idle_add(authenticated, data);
+
+ return GINT_TO_POINTER(ret);
+}
+
+static int authenticate(struct oc_private_data *data)
+{
+ const char *cert = NULL;
+ const char *key = NULL;
+ const char *urlpath;
+ const char *vpnhost;
+
+ DBG("");
+
+ switch (data->connect_type) {
+ case OC_CONNECT_PKCS:
+ cert = vpn_provider_get_string(data->provider,
+ "OpenConnect.PKCSClientCert");
+ break;
+ case OC_CONNECT_PUBLICKEY:
+ cert = vpn_provider_get_string(data->provider,
+ "OpenConnect.ClientCert");
+ key = vpn_provider_get_string(data->provider,
+ "OpenConnect.UserPrivateKey");
+ break;
+
+ case OC_CONNECT_USERPASS:
+ case OC_CONNECT_COOKIE_WITH_USERPASS:
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ openconnect_init_ssl();
+ data->vpninfo = openconnect_vpninfo_new("ConnMan VPN Agent",
+ oc_validate_peer_cert,
+ NULL,
+ oc_process_auth_form,
+ oc_progress,
+ data);
+
+ /* Replicating how openconnect's --usergroup argument works */
+ urlpath = vpn_provider_get_string(data->provider,
+ "OpenConnect.Usergroup");
+ if (urlpath)
+ openconnect_set_urlpath(data->vpninfo, urlpath);
+
+ if (vpn_provider_get_boolean(data->provider,
+ "OpenConnect.DisableIPv6", false))
+ openconnect_disable_ipv6(data->vpninfo);
+
+ vpnhost = vpn_provider_get_string(data->provider,
+ "OpenConnect.VPNHost");
+ if (!vpnhost || !*vpnhost)
+ vpnhost = vpn_provider_get_string(data->provider, "Host");
+
+ openconnect_set_hostname(data->vpninfo, vpnhost);
+
+ if (cert)
+ openconnect_set_client_cert(data->vpninfo, cert, key);
+
+ data->fd_cmd = openconnect_setup_cmd_pipe(data->vpninfo);
+
+ /*
+ * openconnect_obtain_cookie blocks, so run it in background thread
+ * instead
+ */
+ data->cookie_thread = g_thread_try_new("obtain_cookie",
+ obtain_cookie_thread,
+ data, NULL);
+
+ if (!data->cookie_thread)
+ return -EIO;
+
+ return -EINPROGRESS;
+}
+
+static int run_connect(struct oc_private_data *data, const char *cookie)
+{
+ struct vpn_provider *provider;
+ struct connman_task *task;
+ const char *vpnhost;
+ int fd_err;
+ int err = 0;
+ bool allow_self_signed;
+ const char *server_cert;
+
+ if (!data || !cookie)
+ return -EINVAL;
+
+ provider = data->provider;
+ task = data->task;
+
+ server_cert = vpn_provider_get_string(provider,
+ "OpenConnect.ServerCert");
+ allow_self_signed = vpn_provider_get_boolean(provider,
+ "OpenConnect.AllowSelfSignedCert",
+ false);
+
+ DBG("provider %p task %p", provider, task);
- connman_task_add_argument(task, "--syslog", NULL);
connman_task_add_argument(task, "--cookie-on-stdin", NULL);
- connman_task_add_argument(task, "--script",
- SCRIPTDIR "/openconnect-script");
+ vpnhost = vpn_provider_get_string(provider, "OpenConnect.VPNHost");
+ if (!vpnhost || !*vpnhost)
+ vpnhost = vpn_provider_get_string(provider, "Host");
+
+ task_append_config_data(provider, task);
+
+ connman_task_add_argument(task, "--script", SCRIPTDIR "/vpn-script");
- connman_task_add_argument(task, "--interface", if_name);
+ connman_task_add_argument(task, "--interface", data->if_name);
connman_task_add_argument(task, (char *)vpnhost, NULL);
- err = connman_task_run(task, vpn_died, provider,
- &fd, NULL, NULL);
+ err = connman_task_run(task, oc_died, data, &data->fd_in,
+ NULL, &fd_err);
if (err < 0) {
- connman_error("openconnect failed to start");
err = -EIO;
goto done;
}
- len = strlen(vpncookie);
- if (write(fd, vpncookie, len) != (ssize_t)len ||
- write(fd, "\n", 1) != 1) {
- connman_error("openconnect failed to take cookie on stdin");
+ if (write_data(data->fd_in, cookie) != 0) {
+ connman_error("openconnect failed to take cookie on "
+ "stdin");
err = -EIO;
+ }
+
+ if (!server_cert || !allow_self_signed) {
+ if (write_data(data->fd_in,
+ (allow_self_signed ? "yes" : "no"))) {
+ connman_error("openconnect failed to take certificate "
+ "acknowledgement on stdin");
+ err = -EIO;
+ }
+ }
+
+ if (err) {
+ if (fd_err >= 0)
+ close(fd_err);
+
goto done;
}
+ err = -EINPROGRESS;
+
+ data->err_ch = g_io_channel_unix_new(fd_err);
+
+ /* Use ASCII encoding only */
+ if (g_io_channel_set_encoding(data->err_ch, NULL, NULL) !=
+ G_IO_STATUS_NORMAL) {
+ close_io_channel(data, data->err_ch);
+ err = -EIO;
+ } else {
+ data->err_ch_id = g_io_add_watch(data->err_ch,
+ G_IO_IN | G_IO_ERR | G_IO_HUP,
+ (GIOFunc)io_channel_err_cb, data);
+ }
+
done:
- if (cb)
- cb(provider, user_data, err);
+ clear_provider_credentials(data->provider, err != -EINPROGRESS);
return err;
}
-static void request_input_append_informational(DBusMessageIter *iter,
- void *user_data)
+static void request_input_append(DBusMessageIter *iter,
+ const char *str_type, const char *str, void *user_data)
{
- const char *str;
+ const char *string;
- str = "string";
- connman_dbus_dict_append_basic(iter, "Type", DBUS_TYPE_STRING, &str);
+ connman_dbus_dict_append_basic(iter, "Type",
+ DBUS_TYPE_STRING, &str_type);
+ connman_dbus_dict_append_basic(iter, "Requirement",
+ DBUS_TYPE_STRING, &str);
- str = "informational";
- connman_dbus_dict_append_basic(iter, "Requirement", DBUS_TYPE_STRING,
- &str);
+ if (!user_data)
+ return;
- str = user_data;
- connman_dbus_dict_append_basic(iter, "Value", DBUS_TYPE_STRING, &str);
+ string = user_data;
+ connman_dbus_dict_append_basic(iter, "Value", DBUS_TYPE_STRING,
+ &string);
+}
+
+static void request_input_append_informational(DBusMessageIter *iter,
+ void *user_data)
+{
+ request_input_append(iter, "string", "informational", user_data);
}
static void request_input_append_mandatory(DBusMessageIter *iter,
void *user_data)
{
- char *str = "string";
+ request_input_append(iter, "string", "mandatory", user_data);
+}
- connman_dbus_dict_append_basic(iter, "Type",
- DBUS_TYPE_STRING, &str);
- str = "mandatory";
- connman_dbus_dict_append_basic(iter, "Requirement",
- DBUS_TYPE_STRING, &str);
+static void request_input_append_optional(DBusMessageIter *iter,
+ void *user_data)
+{
+ request_input_append(iter, "string", "optional", user_data);
}
-static void request_input_cookie_reply(DBusMessage *reply, void *user_data)
+static void request_input_append_password(DBusMessageIter *iter,
+ void *user_data)
+{
+ request_input_append(iter, "password", "mandatory", user_data);
+}
+
+static void request_input_append_to_dict(struct vpn_provider *provider,
+ DBusMessageIter *dict,
+ connman_dbus_append_cb_t function_cb, const char *key)
+{
+ const char *str;
+ bool immutable = false;
+
+ if (!provider || !dict || !function_cb || !key)
+ return;
+
+ str = vpn_provider_get_string(provider, key);
+ /* Ignore empty informational content */
+ if (!str && function_cb == request_input_append_informational)
+ return;
+
+ /* If value is "-", it is cleared by VPN agent */
+ if (!g_strcmp0(str, "-"))
+ str = NULL;
+
+ if (str)
+ immutable = vpn_provider_get_string_immutable(provider, key);
+
+ if (immutable) {
+ /* Hide immutable password types */
+ if (function_cb == request_input_append_password)
+ str = "********";
+
+ /* Send immutable as informational */
+ function_cb = request_input_append_informational;
+ }
+
+ connman_dbus_dict_append_dict(dict, key, function_cb,
+ str ? (void *)str : NULL);
+}
+
+static void request_input_credentials_reply(DBusMessage *reply, void *user_data)
{
struct oc_private_data *data = user_data;
- char *cookie = NULL, *servercert = NULL, *vpnhost = NULL;
- char *key;
+ const char *cookie = NULL;
+ const char *servercert = NULL;
+ const char *vpnhost = NULL;
+ const char *username = NULL;
+ const char *password = NULL;
+ const char *second_password = NULL;
+ const char *pkcspassword = NULL;
+ const char *key;
DBusMessageIter iter, dict;
+ int err;
- DBG("provider %p", data->provider);
+ connman_info("provider %p", data->provider);
- if (!reply || dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
+ if (!reply) {
+ err = ENOENT;
goto err;
+ }
+
+ err = vpn_agent_check_and_process_reply_error(reply, data->provider,
+ data->task, data->cb, data->user_data);
+ if (err) {
+ /* Ensure cb is called only once */
+ data->cb = NULL;
+ data->user_data = NULL;
+ goto out;
+ }
- if (!vpn_agent_check_reply_has_dict(reply))
+ if (!vpn_agent_check_reply_has_dict(reply)) {
+ err = ENOENT;
goto err;
+ }
dbus_message_iter_init(reply, &iter);
dbus_message_iter_recurse(&iter, &dict);
@@ -344,7 +1295,6 @@ static void request_input_cookie_reply(DBusMessage *reply, void *user_data)
dbus_message_iter_get_basic(&value, &cookie);
vpn_provider_set_string_hide_value(data->provider,
key, cookie);
-
} else if (g_str_equal(key, "OpenConnect.ServerCert")) {
dbus_message_iter_next(&entry);
if (dbus_message_iter_get_arg_type(&entry)
@@ -369,43 +1319,129 @@ static void request_input_cookie_reply(DBusMessage *reply, void *user_data)
break;
dbus_message_iter_get_basic(&value, &vpnhost);
vpn_provider_set_string(data->provider, key, vpnhost);
+ } else if (g_str_equal(key, "Username")) {
+ dbus_message_iter_next(&entry);
+ if (dbus_message_iter_get_arg_type(&entry)
+ != DBUS_TYPE_VARIANT)
+ break;
+ dbus_message_iter_recurse(&entry, &value);
+ if (dbus_message_iter_get_arg_type(&value)
+ != DBUS_TYPE_STRING)
+ break;
+ dbus_message_iter_get_basic(&value, &username);
+ vpn_provider_set_string_hide_value(data->provider,
+ "OpenConnect.Username", username);
+ } else if (g_str_equal(key, "Password")) {
+ dbus_message_iter_next(&entry);
+ if (dbus_message_iter_get_arg_type(&entry)
+ != DBUS_TYPE_VARIANT)
+ break;
+ dbus_message_iter_recurse(&entry, &value);
+ if (dbus_message_iter_get_arg_type(&value)
+ != DBUS_TYPE_STRING)
+ break;
+ dbus_message_iter_get_basic(&value, &password);
+ vpn_provider_set_string_hide_value(data->provider,
+ "OpenConnect.Password", password);
+ } else if (g_str_equal(key, "OpenConnect.SecondPassword")) {
+ dbus_message_iter_next(&entry);
+ if (dbus_message_iter_get_arg_type(&entry)
+ != DBUS_TYPE_VARIANT)
+ break;
+ dbus_message_iter_recurse(&entry, &value);
+ if (dbus_message_iter_get_arg_type(&value)
+ != DBUS_TYPE_STRING)
+ break;
+ dbus_message_iter_get_basic(&value, &second_password);
+ vpn_provider_set_string_hide_value(data->provider,
+ "OpenConnect.SecondPassword",
+ second_password);
+ } else if (g_str_equal(key, "OpenConnect.PKCSPassword")) {
+ dbus_message_iter_next(&entry);
+ if (dbus_message_iter_get_arg_type(&entry)
+ != DBUS_TYPE_VARIANT)
+ break;
+ dbus_message_iter_recurse(&entry, &value);
+ if (dbus_message_iter_get_arg_type(&value)
+ != DBUS_TYPE_STRING)
+ break;
+ dbus_message_iter_get_basic(&value, &pkcspassword);
+ vpn_provider_set_string_hide_value(data->provider, key,
+ pkcspassword);
}
dbus_message_iter_next(&dict);
}
- if (!cookie || !servercert || !vpnhost)
- goto err;
+ switch (data->connect_type) {
+ case OC_CONNECT_COOKIE:
+ if (!cookie) {
+ err = EACCES;
+ goto err;
+ }
- run_connect(data->provider, data->task, data->if_name, data->cb,
- data->user_data);
+ break;
+ case OC_CONNECT_USERPASS:
+ /* fall through */
+ case OC_CONNECT_COOKIE_WITH_USERPASS:
+ if (!username || !password) {
+ err = EACCES;
+ goto err;
+ }
- free_private_data(data);
+ break;
+ case OC_CONNECT_PUBLICKEY:
+ break; // This should not be reached.
+ case OC_CONNECT_PKCS:
+ if (!pkcspassword) {
+ err = EACCES;
+ goto err;
+ }
+
+ break;
+ }
+
+ if (cookie)
+ err = run_connect(data, cookie);
+ else
+ err = authenticate(data);
+
+ if (err != -EINPROGRESS)
+ goto err;
return;
err:
- vpn_provider_indicate_error(data->provider,
- VPN_PROVIDER_ERROR_AUTH_FAILED);
+ oc_connect_done(data, err);
+out:
free_private_data(data);
}
-static int request_cookie_input(struct vpn_provider *provider,
- struct oc_private_data *data,
- const char *dbus_sender)
+static int request_input_credentials_full(
+ struct oc_private_data *data,
+ request_input_reply_cb_t cb,
+ void *user_data)
{
DBusMessage *message;
- const char *path, *agent_sender, *agent_path;
+ const char *path;
+ const char *agent_sender;
+ const char *agent_path;
+ const char *username;
DBusMessageIter iter;
DBusMessageIter dict;
- const char *str;
int err;
void *agent;
+ bool use_second_password = false;
+
+ if (!data || !cb)
+ return -ESRCH;
- agent = connman_agent_get_info(dbus_sender, &agent_sender,
- &agent_path);
- if (!provider || !agent || !agent_path)
+ connman_info("provider %p", data->provider);
+
+ agent = connman_agent_get_info(data->dbus_sender,
+ &agent_sender, &agent_path);
+ if (!data->provider || !agent || !agent_path)
return -ESRCH;
message = dbus_message_new_method_call(agent_sender, agent_path,
@@ -416,120 +1452,290 @@ static int request_cookie_input(struct vpn_provider *provider,
dbus_message_iter_init_append(message, &iter);
- path = vpn_provider_get_path(provider);
- dbus_message_iter_append_basic(&iter,
- DBUS_TYPE_OBJECT_PATH, &path);
+ path = vpn_provider_get_path(data->provider);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
connman_dbus_dict_open(&iter, &dict);
- str = vpn_provider_get_string(provider, "OpenConnect.CACert");
- if (str)
- connman_dbus_dict_append_dict(&dict, "OpenConnect.CACert",
+ request_input_append_to_dict(data->provider, &dict,
request_input_append_informational,
- (void *)str);
-
- str = vpn_provider_get_string(provider, "OpenConnect.ClientCert");
- if (str)
- connman_dbus_dict_append_dict(&dict, "OpenConnect.ClientCert",
+ "OpenConnect.CACert");
+
+ /*
+ * For backwards compatibility add OpenConnect.ServerCert and
+ * OpenConnect.VPNHost as mandatory only in the default authentication
+ * mode. Otherwise. add the fields as informational. These should be
+ * set in provider settings and not to be queried with every connection
+ * attempt.
+ */
+ request_input_append_to_dict(data->provider, &dict,
+ data->connect_type == OC_CONNECT_COOKIE ?
+ request_input_append_optional :
request_input_append_informational,
- (void *)str);
+ "OpenConnect.ServerCert");
- connman_dbus_dict_append_dict(&dict, "OpenConnect.ServerCert",
- request_input_append_mandatory, NULL);
-
- connman_dbus_dict_append_dict(&dict, "OpenConnect.VPNHost",
- request_input_append_mandatory, NULL);
-
- connman_dbus_dict_append_dict(&dict, "OpenConnect.Cookie",
- request_input_append_mandatory, NULL);
+ request_input_append_to_dict(data->provider, &dict,
+ data->connect_type == OC_CONNECT_COOKIE ?
+ request_input_append_optional :
+ request_input_append_informational,
+ "OpenConnect.VPNHost");
+
+ if (vpn_provider_get_authentication_errors(data->provider))
+ vpn_agent_append_auth_failure(&dict, data->provider, NULL);
+
+ switch (data->connect_type) {
+ case OC_CONNECT_COOKIE:
+ request_input_append_to_dict(data->provider, &dict,
+ request_input_append_mandatory,
+ "OpenConnect.Cookie");
+ break;
+ /*
+ * The authentication is done with username and password to get the
+ * cookie for connection.
+ */
+ case OC_CONNECT_COOKIE_WITH_USERPASS:
+ /* fallthrough */
+ case OC_CONNECT_USERPASS:
+ username = vpn_provider_get_string(data->provider,
+ "OpenConnect.Username");
+ vpn_agent_append_user_info(&dict, data->provider, username);
+
+ use_second_password = vpn_provider_get_boolean(data->provider,
+ "OpenConnect.UseSecondPassword",
+ false);
+
+ if (use_second_password)
+ request_input_append_to_dict(data->provider, &dict,
+ request_input_append_password,
+ "OpenConnect.SecondPassword");
+
+ break;
+ case OC_CONNECT_PUBLICKEY:
+ return -EINVAL;
+ case OC_CONNECT_PKCS:
+ request_input_append_to_dict(data->provider, &dict,
+ request_input_append_informational,
+ "OpenConnect.PKCSClientCert");
+
+ /* Do not allow to store or retrieve the encrypted PKCS pass */
+ vpn_agent_append_allow_credential_storage(&dict, false);
+ vpn_agent_append_allow_credential_retrieval(&dict, false);
+
+ /*
+ * Indicate to keep credentials, the PKCS password should not
+ * affect the credential storing.
+ */
+ vpn_agent_append_keep_credentials(&dict, true);
+
+ request_input_append_to_dict(data->provider, &dict,
+ request_input_append_password,
+ "OpenConnect.PKCSPassword");
+ break;
+ }
- vpn_agent_append_host_and_name(&dict, provider);
+ vpn_agent_append_host_and_name(&dict, data->provider);
connman_dbus_dict_close(&iter, &dict);
- err = connman_agent_queue_message(provider, message,
- connman_timeout_input_request(),
- request_input_cookie_reply, data, agent);
+ err = connman_agent_queue_message(data->provider, message,
+ connman_timeout_input_request(), cb, user_data, agent);
- if (err < 0 && err != -EBUSY) {
- DBG("error %d sending agent request", err);
- dbus_message_unref(message);
+ dbus_message_unref(message);
+ if (err < 0 && err != -EBUSY) {
+ connman_error("cannot send agent request, error: %d", err);
return err;
}
- dbus_message_unref(message);
-
return -EINPROGRESS;
}
+static int request_input_credentials(struct oc_private_data *data,
+ request_input_reply_cb_t cb)
+{
+ return request_input_credentials_full(data, cb, data);
+}
+
+static enum oc_connect_type get_authentication_type(
+ struct vpn_provider *provider)
+{
+ const char *auth;
+ enum oc_connect_type type;
+
+ auth = vpn_provider_get_string(provider, "OpenConnect.AuthType");
+ if (!auth)
+ goto out;
+
+ for (type = 0; connect_types[type]; type++) {
+ if (!g_strcmp0(auth, connect_types[type])) {
+ connman_info("auth type %d/%s", type,
+ connect_types[type]);
+ return type;
+ }
+ }
+
+out:
+ /* Default to cookie */
+ return OC_CONNECT_COOKIE;
+}
+
static int oc_connect(struct vpn_provider *provider,
struct connman_task *task, const char *if_name,
vpn_provider_connect_cb_t cb,
const char *dbus_sender, void *user_data)
{
- const char *vpnhost, *vpncookie, *servercert;
+ struct oc_private_data *data;
+ const char *vpncookie = NULL;
+ const char *certificate;
+ const char *username;
+ const char *password;
+ const char *second_password = NULL;
+ const char *private_key;
int err;
+ bool use_second_password = false;
- vpnhost = vpn_provider_get_string(provider, "Host");
- if (!vpnhost) {
- connman_error("Host not set; cannot enable VPN");
- return -EINVAL;
- }
+ connman_info("provider %p task %p", provider, task);
+
+ data = g_try_new0(struct oc_private_data, 1);
+ if (!data)
+ return -ENOMEM;
- vpncookie = vpn_provider_get_string(provider, "OpenConnect.Cookie");
- servercert = vpn_provider_get_string(provider,
- "OpenConnect.ServerCert");
- if (!vpncookie || !servercert) {
- struct oc_private_data *data;
+ vpn_provider_set_plugin_data(provider, data);
+ data->provider = vpn_provider_ref(provider);
+ data->task = task;
+ data->if_name = g_strdup(if_name);
+ data->dbus_sender = g_strdup(dbus_sender);
+ data->cb = cb;
+ data->user_data = user_data;
+ data->connect_type = get_authentication_type(provider);
+
+ switch (data->connect_type) {
+ case OC_CONNECT_COOKIE:
+ vpncookie = vpn_provider_get_string(provider,
+ "OpenConnect.Cookie");
+ if (!vpncookie || !g_strcmp0(vpncookie, "-"))
+ goto request_input;
+
+ break;
+ case OC_CONNECT_USERPASS:
+ username = vpn_provider_get_string(provider,
+ "OpenConnect.Username");
+ password = vpn_provider_get_string(provider,
+ "OpenConnect.Password");
+
+ use_second_password = vpn_provider_get_boolean(provider,
+ "OpenConnect.UseSecondPassword",
+ false);
+
+ if (use_second_password)
+ second_password = vpn_provider_get_string(provider,
+ "OpenConnect.SecondPassword");
+
+ if (!username || !password || !g_strcmp0(username, "-") ||
+ !g_strcmp0(password, "-") ||
+ (use_second_password && !second_password))
+ goto request_input;
+
+ break;
+ case OC_CONNECT_COOKIE_WITH_USERPASS:
+ vpncookie = vpn_provider_get_string(provider,
+ "OpenConnect.Cookie");
+ /* Username and password must be set if cookie is missing */
+ if (!vpncookie) {
+ username = vpn_provider_get_string(provider,
+ "OpenConnect.Username");
+ password = vpn_provider_get_string(provider,
+ "OpenConnect.Password");
+
+ if (!username || !password ||
+ !g_strcmp0(username, "-") ||
+ !g_strcmp0(password, "-"))
+ goto request_input;
+ } else if (!g_strcmp0(vpncookie, "-")) {
+ goto request_input;
+ }
- data = g_try_new0(struct oc_private_data, 1);
- if (!data)
- return -ENOMEM;
+ break;
+ case OC_CONNECT_PUBLICKEY:
+ certificate = vpn_provider_get_string(provider,
+ "OpenConnect.ClientCert");
+ private_key = vpn_provider_get_string(provider,
+ "OpenConnect.UserPrivateKey");
- data->provider = provider;
- data->task = task;
- data->if_name = g_strdup(if_name);
- data->cb = cb;
- data->user_data = user_data;
+ if (!certificate || !private_key) {
+ connman_warn("missing certificate and/or private key");
+ oc_connect_done(data, EACCES);
+ free_private_data(data);
+ return -EACCES;
+ }
- err = request_cookie_input(provider, data, dbus_sender);
- if (err != -EINPROGRESS) {
- vpn_provider_indicate_error(data->provider,
- VPN_PROVIDER_ERROR_LOGIN_FAILED);
+ break;
+ case OC_CONNECT_PKCS:
+ certificate = vpn_provider_get_string(provider,
+ "OpenConnect.PKCSClientCert");
+ if (!certificate) {
+ connman_warn("missing PKCS certificate");
+ oc_connect_done(data, EACCES);
free_private_data(data);
+ return -EACCES;
}
- return err;
+
+ break;
+ }
+
+ if (vpncookie && g_strcmp0(vpncookie, "-"))
+ return run_connect(data, vpncookie);
+ return authenticate(data);
+
+request_input:
+ err = request_input_credentials(data, request_input_credentials_reply);
+ if (err != -EINPROGRESS) {
+ oc_connect_done(data, err);
+ vpn_provider_indicate_error(data->provider,
+ VPN_PROVIDER_ERROR_LOGIN_FAILED);
+ free_private_data(data);
+ }
+
+ return err;
+}
+
+static void oc_disconnect(struct vpn_provider *provider)
+{
+ struct oc_private_data *data;
+
+ connman_info("provider %p", provider);
+
+ if (!provider)
+ return;
+
+ /*
+ * OpenConnect may be disconnect by timeout in connmand before running
+ * the openconnect process. In such case it is important to cancel the
+ * agent request to avoid having multiple ones visible.
+ */
+ connman_agent_cancel(provider);
+
+ data = vpn_provider_get_plugin_data(provider);
+
+ if (!data)
+ return;
+
+ if (data->cookie_thread) {
+ char cmd = OC_CMD_CANCEL;
+ int w = write(data->fd_cmd, &cmd, 1);
+ if (w != 1)
+ DBG("Write failed, might be leaking a thread");
}
- return run_connect(provider, task, if_name, cb, user_data);
}
static int oc_save(struct vpn_provider *provider, GKeyFile *keyfile)
{
- const char *setting, *option;
+ const char *save_group;
+ const char *option;
int i;
- setting = vpn_provider_get_string(provider,
- "OpenConnect.ServerCert");
- if (setting)
- g_key_file_set_string(keyfile,
- vpn_provider_get_save_group(provider),
- "OpenConnect.ServerCert", setting);
-
- setting = vpn_provider_get_string(provider,
- "OpenConnect.CACert");
- if (setting)
- g_key_file_set_string(keyfile,
- vpn_provider_get_save_group(provider),
- "OpenConnect.CACert", setting);
-
- setting = vpn_provider_get_string(provider,
- "VPN.MTU");
- if (setting)
- g_key_file_set_string(keyfile,
- vpn_provider_get_save_group(provider),
- "VPN.MTU", setting);
+ save_group = vpn_provider_get_save_group(provider);
for (i = 0; i < (int)ARRAY_SIZE(oc_options); i++) {
if (strncmp(oc_options[i].cm_opt, "OpenConnect.", 12) == 0) {
@@ -538,8 +1744,7 @@ static int oc_save(struct vpn_provider *provider, GKeyFile *keyfile)
if (!option)
continue;
- g_key_file_set_string(keyfile,
- vpn_provider_get_save_group(provider),
+ g_key_file_set_string(keyfile, save_group,
oc_options[i].cm_opt, option);
}
}
@@ -549,20 +1754,30 @@ static int oc_save(struct vpn_provider *provider, GKeyFile *keyfile)
static int oc_error_code(struct vpn_provider *provider, int exit_code)
{
+ connman_info("%d", exit_code);
+
+ /* OpenConnect process return values are ambiguous in definition
+ * https://github.com/openconnect/openconnect/blob/master/main.c#L1693
+ * and it is safer not to rely on them. Login error cannot be
+ * differentiated from connection errors, e.g., when self signed
+ * certificate is rejected by user setting.
+ */
switch (exit_code) {
- case 1:
case 2:
- vpn_provider_set_string_hide_value(provider,
- "OpenConnect.Cookie", NULL);
+ /* Cookie has failed */
+ clear_provider_credentials(provider, false);
return VPN_PROVIDER_ERROR_LOGIN_FAILED;
+ case 1:
+ /* fall through */
default:
return VPN_PROVIDER_ERROR_UNKNOWN;
}
}
static int oc_route_env_parse(struct vpn_provider *provider, const char *key,
- int *family, unsigned long *idx, enum vpn_provider_route_type *type)
+ int *family, unsigned long *idx,
+ enum vpn_provider_route_type *type)
{
char *end;
const char *start;
@@ -593,6 +1808,7 @@ static int oc_route_env_parse(struct vpn_provider *provider, const char *key,
static struct vpn_driver vpn_driver = {
.notify = oc_notify,
.connect = oc_connect,
+ .disconnect = oc_disconnect,
.error_code = oc_error_code,
.save = oc_save,
.route_env_parse = oc_route_env_parse,
diff --git a/vpn/plugins/openvpn.c b/vpn/plugins/openvpn.c
index 6b090e45..5ab5c5c4 100755
--- a/vpn/plugins/openvpn.c
+++ b/vpn/plugins/openvpn.c
@@ -3,6 +3,7 @@
* ConnMan VPN daemon
*
* Copyright (C) 2010-2014 BMW Car IT GmbH.
+ * Copyright (C) 2016-2019 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -30,6 +31,9 @@
#include <stdio.h>
#include <net/if.h>
#include <linux/if_tun.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <glib.h>
@@ -39,8 +43,12 @@
#include <connman/task.h>
#include <connman/dbus.h>
#include <connman/ipconfig.h>
+#include <connman/agent.h>
+#include <connman/setting.h>
+#include <connman/vpn-dbus.h>
#include "../vpn-provider.h"
+#include "../vpn-agent.h"
#include "vpn.h"
@@ -48,34 +56,94 @@
static DBusConnection *connection;
+enum opt_type {
+ OPT_NONE = 0,
+ OPT_STRING = 1,
+ OPT_BOOL = 2,
+};
+
struct {
- const char *cm_opt;
- const char *ov_opt;
- char has_value;
+ const char *cm_opt;
+ const char *ov_opt;
+ const char *ov_opt_to_null;
+ enum opt_type opt_type;
} ov_options[] = {
- { "Host", "--remote", 1 },
- { "OpenVPN.CACert", "--ca", 1 },
- { "OpenVPN.Cert", "--cert", 1 },
- { "OpenVPN.Key", "--key", 1 },
- { "OpenVPN.MTU", "--mtu", 1 },
- { "OpenVPN.NSCertType", "--ns-cert-type", 1 },
- { "OpenVPN.Proto", "--proto", 1 },
- { "OpenVPN.Port", "--port", 1 },
- { "OpenVPN.AuthUserPass", "--auth-user-pass", 1 },
- { "OpenVPN.AskPass", "--askpass", 1 },
- { "OpenVPN.AuthNoCache", "--auth-nocache", 0 },
- { "OpenVPN.TLSRemote", "--tls-remote", 1 },
- { "OpenVPN.TLSAuth", NULL, 1 },
- { "OpenVPN.TLSAuthDir", NULL, 1 },
- { "OpenVPN.Cipher", "--cipher", 1 },
- { "OpenVPN.Auth", "--auth", 1 },
- { "OpenVPN.CompLZO", "--comp-lzo", 0 },
- { "OpenVPN.RemoteCertTls", "--remote-cert-tls", 1 },
- { "OpenVPN.ConfigFile", "--config", 1 },
- { "OpenVPN.DeviceType", NULL, 1 },
- { "OpenVPN.Verb", "--verb", 1 },
+ { "Host", "--remote", NULL, OPT_STRING},
+ { "OpenVPN.CACert", "--ca", NULL, OPT_STRING},
+ { "OpenVPN.Cert", "--cert", NULL, OPT_STRING},
+ { "OpenVPN.Key", "--key", NULL, OPT_STRING},
+ { "OpenVPN.MTU", "--tun-mtu", NULL, OPT_STRING},
+ { "OpenVPN.NSCertType", "--ns-cert-type", NULL, OPT_STRING},
+ { "OpenVPN.Proto", "--proto", NULL, OPT_STRING},
+ { "OpenVPN.Port", "--port", NULL, OPT_STRING},
+ /*
+ * If the AuthUserPass option is "-", provide the input via management
+ * interface. To facilitate this set the option as NULL.
+ */
+ { "OpenVPN.AuthUserPass", "--auth-user-pass", "-", OPT_STRING},
+ { "OpenVPN.AskPass", "--askpass", NULL, OPT_STRING},
+ { "OpenVPN.AuthNoCache", "--auth-nocache", NULL, OPT_BOOL},
+ { "OpenVPN.TLSRemote", "--tls-remote", NULL, OPT_STRING},
+ { "OpenVPN.TLSAuth", NULL, NULL, OPT_NONE},
+ { "OpenVPN.TLSCipher", "--tls-cipher", NULL, OPT_STRING},
+ { "OpenVPN.TLSAuthDir", NULL, NULL, OPT_NONE},
+ { "OpenVPN.Cipher", "--cipher", NULL, OPT_STRING},
+ { "OpenVPN.Auth", "--auth", NULL, OPT_STRING},
+ /* Is set to adaptive by default if value is omitted */
+ { "OpenVPN.CompLZO", "--comp-lzo", NULL, OPT_STRING},
+ { "OpenVPN.RemoteCertTls", "--remote-cert-tls", NULL, OPT_STRING},
+ { "OpenVPN.ConfigFile", "--config", NULL, OPT_STRING},
+ { "OpenVPN.DeviceType", NULL, NULL, OPT_NONE},
+ { "OpenVPN.Verb", "--verb", NULL, OPT_STRING},
+ { "OpenVPN.Ping", "--ping", NULL, OPT_STRING},
+ { "OpenVPN.PingExit", "--ping-exit", NULL, OPT_STRING},
+ { "OpenVPN.RemapUsr1", "--remap-usr1", NULL, OPT_STRING},
};
+struct ov_private_data {
+ struct vpn_provider *provider;
+ struct connman_task *task;
+ char *dbus_sender;
+ char *if_name;
+ vpn_provider_connect_cb_t cb;
+ void *user_data;
+ char *mgmt_path;
+ guint mgmt_timer_id;
+ guint mgmt_event_id;
+ GIOChannel *mgmt_channel;
+ int connect_attempts;
+ int failed_attempts_privatekey;
+};
+
+static void ov_connect_done(struct ov_private_data *data, int err)
+{
+ if (data && data->cb) {
+ vpn_provider_connect_cb_t cb = data->cb;
+ void *user_data = data->user_data;
+
+ /* Make sure we don't invoke this callback twice */
+ data->cb = NULL;
+ data->user_data = NULL;
+ cb(data->provider, user_data, err);
+ }
+
+ if (!err)
+ data->failed_attempts_privatekey = 0;
+}
+
+static void free_private_data(struct ov_private_data *data)
+{
+ if (vpn_provider_get_plugin_data(data->provider) == data)
+ vpn_provider_set_plugin_data(data->provider, NULL);
+
+ ov_connect_done(data, EIO);
+ vpn_provider_unref(data->provider);
+ g_free(data->dbus_sender);
+ g_free(data->if_name);
+ g_free(data->mgmt_path);
+ g_free(data);
+}
+
struct nameserver_entry {
int id;
char *nameserver;
@@ -98,8 +166,15 @@ static struct nameserver_entry *ov_append_dns_entries(const char *key,
options[2]) {
entry = g_try_new(struct nameserver_entry, 1);
+#if defined TIZEN_EXT
+ if (!entry) {
+ g_strfreev(options);
+ return NULL;
+ }
+#else
if (!entry)
return NULL;
+#endif
entry->nameserver = g_strdup(options[2]);
entry->id = atoi(key + 15); /* foreign_option_XXX */
@@ -162,6 +237,7 @@ static int ov_notify(DBusMessage *msg, struct vpn_provider *provider)
char *address = NULL, *gateway = NULL, *peer = NULL, *netmask = NULL;
struct connman_ipaddress *ipaddress;
GSList *nameserver_list = NULL;
+ struct ov_private_data *data = vpn_provider_get_plugin_data(provider);
dbus_message_iter_init(msg, &iter);
@@ -173,8 +249,12 @@ static int ov_notify(DBusMessage *msg, struct vpn_provider *provider)
return VPN_STATE_FAILURE;
}
- if (strcmp(reason, "up"))
+ DBG("%p %s", vpn_provider_get_name(provider), reason);
+
+ if (strcmp(reason, "up")) {
+ ov_connect_done(data, EIO);
return VPN_STATE_DISCONNECT;
+ }
dbus_message_iter_recurse(&iter, &dict);
@@ -231,6 +311,7 @@ static int ov_notify(DBusMessage *msg, struct vpn_provider *provider)
connman_ipaddress_set_ipv4(ipaddress, address, netmask, gateway);
connman_ipaddress_set_peer(ipaddress, peer);
+ connman_ipaddress_set_p2p(ipaddress, true);
vpn_provider_set_ipaddress(provider, ipaddress);
if (nameserver_list) {
@@ -266,6 +347,7 @@ static int ov_notify(DBusMessage *msg, struct vpn_provider *provider)
g_free(netmask);
connman_ipaddress_free(ipaddress);
+ ov_connect_done(data, 0);
return VPN_STATE_CONNECT;
}
@@ -292,85 +374,106 @@ static int ov_save(struct vpn_provider *provider, GKeyFile *keyfile)
static int task_append_config_data(struct vpn_provider *provider,
struct connman_task *task)
{
- const char *option;
int i;
for (i = 0; i < (int)ARRAY_SIZE(ov_options); i++) {
- if (!ov_options[i].ov_opt)
- continue;
+ const char *ov_opt = ov_options[i].ov_opt;
+ const char *cm_opt = ov_options[i].cm_opt;
+ const char *option = NULL;
+ const char *opt_to_null;
- option = vpn_provider_get_string(provider,
- ov_options[i].cm_opt);
- if (!option)
+ switch (ov_options[i].opt_type) {
+ case OPT_NONE:
continue;
- if (connman_task_add_argument(task,
- ov_options[i].ov_opt,
- ov_options[i].has_value ? option : NULL) < 0) {
- return -EIO;
+ case OPT_STRING:
+ if (!ov_opt)
+ continue;
+
+ option = vpn_provider_get_string(provider, cm_opt);
+ /*
+ * A string option may be used alone without a value
+ * in which case the default value is used by OpenVPN.
+ */
+ if (!option && !vpn_provider_setting_key_exists(
+ provider, ov_opt))
+ continue;
+
+ opt_to_null = ov_options[i].ov_opt_to_null;
+ if (opt_to_null && !g_strcmp0(option, opt_to_null))
+ option = NULL;
+
+ break;
+
+ case OPT_BOOL:
+ if (!ov_opt)
+ continue;
+
+ /* Ignore the boolean toggle if option is disabled. */
+ if (!vpn_provider_get_boolean(provider, cm_opt, false))
+ continue;
+
+ break;
}
+
+ if (connman_task_add_argument(task, ov_opt, option))
+ return -EIO;
+
}
return 0;
}
-static gboolean can_read_data(GIOChannel *chan,
- GIOCondition cond, gpointer data)
+static void close_management_interface(struct ov_private_data *data)
{
- void (*cbf)(const char *format, ...) = data;
- gchar *str;
- gsize size;
+ if (data->mgmt_path) {
+ if (unlink(data->mgmt_path) && errno != ENOENT)
+ connman_warn("Unable to unlink management socket %s: "
+ "%d", data->mgmt_path, errno);
- if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
- return FALSE;
+ g_free(data->mgmt_path);
+ data->mgmt_path = NULL;
+ }
- g_io_channel_read_line(chan, &str, &size, NULL, NULL);
- cbf(str);
- g_free(str);
+ if (data->mgmt_timer_id != 0) {
+ g_source_remove(data->mgmt_timer_id);
+ data->mgmt_timer_id = 0;
+ }
- return TRUE;
+ if (data->mgmt_event_id) {
+ g_source_remove(data->mgmt_event_id);
+ data->mgmt_event_id = 0;
+ }
+
+ if (data->mgmt_channel) {
+ g_io_channel_shutdown(data->mgmt_channel, FALSE, NULL);
+ g_io_channel_unref(data->mgmt_channel);
+ data->mgmt_channel = NULL;
+ }
}
-static int setup_log_read(int stdout_fd, int stderr_fd)
+static void ov_died(struct connman_task *task, int exit_code, void *user_data)
{
- GIOChannel *chan;
- int watch;
+ struct ov_private_data *data = user_data;
- chan = g_io_channel_unix_new(stdout_fd);
- g_io_channel_set_close_on_unref(chan, TRUE);
- watch = g_io_add_watch(chan, G_IO_IN | G_IO_NVAL | G_IO_ERR | G_IO_HUP,
- can_read_data, connman_debug);
- g_io_channel_unref(chan);
+ /* Cancel any pending agent requests */
+ connman_agent_cancel(data->provider);
- if (watch == 0)
- return -EIO;
+ close_management_interface(data);
- chan = g_io_channel_unix_new(stderr_fd);
- g_io_channel_set_close_on_unref(chan, TRUE);
- watch = g_io_add_watch(chan, G_IO_IN | G_IO_NVAL | G_IO_ERR | G_IO_HUP,
- can_read_data, connman_error);
- g_io_channel_unref(chan);
+ vpn_died(task, exit_code, data->provider);
- return watch == 0? -EIO : 0;
+ free_private_data(data);
}
-static int ov_connect(struct vpn_provider *provider,
- struct connman_task *task, const char *if_name,
- vpn_provider_connect_cb_t cb, const char *dbus_sender,
- void *user_data)
+static int run_connect(struct ov_private_data *data,
+ vpn_provider_connect_cb_t cb, void *user_data)
{
+ struct vpn_provider *provider = data->provider;
+ struct connman_task *task = data->task;
const char *option;
- int stdout_fd, stderr_fd;
int err = 0;
- option = vpn_provider_get_string(provider, "Host");
- if (!option) {
- connman_error("Host not set; cannot enable VPN");
- return -EINVAL;
- }
-
- task_append_config_data(provider, task);
-
option = vpn_provider_get_string(provider, "OpenVPN.ConfigFile");
if (!option) {
/*
@@ -390,6 +493,17 @@ static int ov_connect(struct vpn_provider *provider,
connman_task_add_argument(task, "--client", NULL);
}
+ if (data->mgmt_path) {
+ connman_task_add_argument(task, "--management", NULL);
+ connman_task_add_argument(task, data->mgmt_path, NULL);
+ connman_task_add_argument(task, "unix", NULL);
+ connman_task_add_argument(task, "--management-query-passwords",
+ NULL);
+ connman_task_add_argument(task, "--auth-retry", "interact");
+ }
+
+ connman_task_add_argument(task, "--syslog", NULL);
+
connman_task_add_argument(task, "--script-security", "2");
connman_task_add_argument(task, "--up",
@@ -408,7 +522,7 @@ static int ov_connect(struct vpn_provider *provider,
connman_task_add_argument(task, "CONNMAN_PATH",
connman_task_get_path(task));
- connman_task_add_argument(task, "--dev", if_name);
+ connman_task_add_argument(task, "--dev", data->if_name);
option = vpn_provider_get_string(provider, "OpenVPN.DeviceType");
if (option) {
connman_task_add_argument(task, "--dev-type", option);
@@ -427,29 +541,660 @@ static int ov_connect(struct vpn_provider *provider,
#endif
/*
- * Disable client restarts because we can't handle this at the
- * moment. The problem is that when OpenVPN decides to switch
+ * Disable client restarts with TCP because we can't handle this at
+ * the moment. The problem is that when OpenVPN decides to switch
* from CONNECTED state to RECONNECTING and then to RESOLVE,
* it is not possible to do a DNS lookup. The DNS server is
- * not accessable through the tunnel anymore and so we end up
+ * not accessible through the tunnel anymore and so we end up
* trying to resolve the OpenVPN servers address.
- */
- connman_task_add_argument(task, "--ping-restart", "0");
+ *
+ * Disable connetion retrying when OpenVPN is connected over TCP.
+ * With TCP OpenVPN attempts to handle reconnection silently without
+ * reporting the error back when establishing a connection or
+ * reconnecting as succesful one. The latter causes trouble if the
+ * retries are not limited to 1 (no retry) as the interface is up and
+ * connman regards it as the default route and network ceases to work,
+ * including DNS.
+ */
+ option = vpn_provider_get_string(provider, "OpenVPN.Proto");
+ if (option && g_str_has_prefix(option, "tcp")) {
+ option = vpn_provider_get_string(provider, "OpenVPN.PingExit");
+ if (!option)
+ connman_task_add_argument(task, "--ping-restart", "0");
+
+ connman_task_add_argument(task, "--connect-retry-max", "1");
+ /* Apply defaults for --ping and --ping-exit only with UDP protocol. */
+ } else {
+ /* Apply default of 10 second interval for ping if omitted. */
+ option = vpn_provider_get_string(provider, "OpenVPN.Ping");
+ if (!option)
+ connman_task_add_argument(task, "--ping", "10");
+
+ /* Apply default of 60 seconds for ping exit if omitted. */
+ option = vpn_provider_get_string(provider, "OpenVPN.PingExit");
+ if (!option)
+ connman_task_add_argument(task, "--ping-exit", "60");
+ }
- err = connman_task_run(task, vpn_died, provider,
- NULL, &stdout_fd, &stderr_fd);
+ err = connman_task_run(task, ov_died, data, NULL, NULL, NULL);
if (err < 0) {
+ data->cb = NULL;
+ data->user_data = NULL;
connman_error("openvpn failed to start");
- err = -EIO;
- goto done;
+ return -EIO;
+ } else {
+ /* This lets the caller know that the actual result of
+ * the operation will be reported to the callback */
+ return -EINPROGRESS;
+ }
+}
+
+static void ov_quote_credential(GString *line, const char *cred)
+{
+ if (!line)
+ return;
+
+ g_string_append_c(line, '"');
+
+ while (*cred != '\0') {
+
+ switch (*cred) {
+ case ' ':
+ case '"':
+ case '\\':
+ g_string_append_c(line, '\\');
+ break;
+ default:
+ break;
+ }
+
+ g_string_append_c(line, *cred++);
+ }
+
+ g_string_append_c(line, '"');
+}
+
+static void ov_return_credentials(struct ov_private_data *data,
+ const char *username, const char *password)
+{
+ GString *reply_string;
+ gchar *reply;
+ gsize len;
+
+ reply_string = g_string_new(NULL);
+
+ g_string_append(reply_string, "username \"Auth\" ");
+ ov_quote_credential(reply_string, username);
+ g_string_append_c(reply_string, '\n');
+
+ g_string_append(reply_string, "password \"Auth\" ");
+ ov_quote_credential(reply_string, password);
+ g_string_append_c(reply_string, '\n');
+
+ len = reply_string->len;
+ reply = g_string_free(reply_string, FALSE);
+
+ g_io_channel_write_chars(data->mgmt_channel, reply, len, NULL, NULL);
+ g_io_channel_flush(data->mgmt_channel, NULL);
+
+ memset(reply, 0, len);
+ g_free(reply);
+}
+
+static void ov_return_private_key_password(struct ov_private_data *data,
+ const char *privatekeypass)
+{
+ GString *reply_string;
+ gchar *reply;
+ gsize len;
+
+ reply_string = g_string_new(NULL);
+
+ g_string_append(reply_string, "password \"Private Key\" ");
+ ov_quote_credential(reply_string, privatekeypass);
+ g_string_append_c(reply_string, '\n');
+
+ len = reply_string->len;
+ reply = g_string_free(reply_string, FALSE);
+
+ g_io_channel_write_chars(data->mgmt_channel, reply, len, NULL, NULL);
+ g_io_channel_flush(data->mgmt_channel, NULL);
+
+ memset(reply, 0, len);
+ g_free(reply);
+}
+
+static void request_input_append_informational(DBusMessageIter *iter,
+ void *user_data)
+{
+ char *str = "string";
+
+ connman_dbus_dict_append_basic(iter, "Type",
+ DBUS_TYPE_STRING, &str);
+ str = "informational";
+ connman_dbus_dict_append_basic(iter, "Requirement",
+ DBUS_TYPE_STRING, &str);
+}
+
+static void request_input_append_mandatory(DBusMessageIter *iter,
+ void *user_data)
+{
+ char *str = "string";
+
+ connman_dbus_dict_append_basic(iter, "Type",
+ DBUS_TYPE_STRING, &str);
+ str = "mandatory";
+ connman_dbus_dict_append_basic(iter, "Requirement",
+ DBUS_TYPE_STRING, &str);
+}
+
+static void request_input_append_password(DBusMessageIter *iter,
+ void *user_data)
+{
+ char *str = "password";
+
+ connman_dbus_dict_append_basic(iter, "Type",
+ DBUS_TYPE_STRING, &str);
+ str = "mandatory";
+ connman_dbus_dict_append_basic(iter, "Requirement",
+ DBUS_TYPE_STRING, &str);
+}
+
+static void request_input_credentials_reply(DBusMessage *reply,
+ void *user_data)
+{
+ struct ov_private_data *data = user_data;
+ char *username = NULL;
+ char *password = NULL;
+ char *key;
+ DBusMessageIter iter, dict;
+ DBusError error;
+ int err = 0;
+
+ connman_info("provider %p", data->provider);
+
+ /*
+ * When connmand calls disconnect because of connection timeout no
+ * reply is received.
+ */
+ if (!reply) {
+ err = ENOENT;
+ goto err;
+ }
+
+ dbus_error_init(&error);
+
+ err = vpn_agent_check_and_process_reply_error(reply, data->provider,
+ data->task, data->cb, data->user_data);
+ if (err) {
+ /* Ensure cb is called only once */
+ data->cb = NULL;
+ data->user_data = NULL;
+ return;
+ }
+
+ if (!vpn_agent_check_reply_has_dict(reply)) {
+ err = ENOENT;
+ goto err;
+ }
+
+ dbus_message_iter_init(reply, &iter);
+ dbus_message_iter_recurse(&iter, &dict);
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+ break;
+
+ dbus_message_iter_get_basic(&entry, &key);
+
+ if (g_str_equal(key, "OpenVPN.Password")) {
+ dbus_message_iter_next(&entry);
+ if (dbus_message_iter_get_arg_type(&entry)
+ != DBUS_TYPE_VARIANT)
+ break;
+ dbus_message_iter_recurse(&entry, &value);
+ if (dbus_message_iter_get_arg_type(&value)
+ != DBUS_TYPE_STRING)
+ break;
+ dbus_message_iter_get_basic(&value, &password);
+ vpn_provider_set_string_hide_value(data->provider,
+ key, password);
+
+ } else if (g_str_equal(key, "OpenVPN.Username")) {
+ dbus_message_iter_next(&entry);
+ if (dbus_message_iter_get_arg_type(&entry)
+ != DBUS_TYPE_VARIANT)
+ break;
+ dbus_message_iter_recurse(&entry, &value);
+ if (dbus_message_iter_get_arg_type(&value)
+ != DBUS_TYPE_STRING)
+ break;
+ dbus_message_iter_get_basic(&value, &username);
+ vpn_provider_set_string_hide_value(data->provider,
+ key, username);
+ }
+
+ dbus_message_iter_next(&dict);
+ }
+
+ if (!password || !username) {
+ vpn_provider_indicate_error(data->provider,
+ VPN_PROVIDER_ERROR_AUTH_FAILED);
+ err = EACCES;
+ goto err;
}
- err = setup_log_read(stdout_fd, stderr_fd);
-done:
- if (cb)
- cb(provider, user_data, err);
+ ov_return_credentials(data, username, password);
+
+ return;
+
+err:
+ ov_connect_done(data, err);
+}
+
+static int request_credentials_input(struct ov_private_data *data)
+{
+ DBusMessage *message;
+ const char *path, *agent_sender, *agent_path;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ int err;
+ void *agent;
+
+ agent = connman_agent_get_info(data->dbus_sender, &agent_sender,
+ &agent_path);
+ if (!agent || !agent_path)
+ return -ESRCH;
+
+ message = dbus_message_new_method_call(agent_sender, agent_path,
+ VPN_AGENT_INTERFACE,
+ "RequestInput");
+ if (!message)
+ return -ENOMEM;
+
+ dbus_message_iter_init_append(message, &iter);
+
+ path = vpn_provider_get_path(data->provider);
+ dbus_message_iter_append_basic(&iter,
+ DBUS_TYPE_OBJECT_PATH, &path);
+
+ connman_dbus_dict_open(&iter, &dict);
+
+ if (vpn_provider_get_authentication_errors(data->provider))
+ vpn_agent_append_auth_failure(&dict, data->provider, NULL);
+
+ /* Request temporary properties to pass on to openvpn */
+ connman_dbus_dict_append_dict(&dict, "OpenVPN.Username",
+ request_input_append_mandatory, NULL);
+
+ connman_dbus_dict_append_dict(&dict, "OpenVPN.Password",
+ request_input_append_password, NULL);
+
+ vpn_agent_append_host_and_name(&dict, data->provider);
+
+ connman_dbus_dict_close(&iter, &dict);
+
+ err = connman_agent_queue_message(data->provider, message,
+ connman_timeout_input_request(),
+ request_input_credentials_reply, data, agent);
+
+ if (err < 0 && err != -EBUSY) {
+ connman_error("error %d sending agent request", err);
+ dbus_message_unref(message);
+
+ return err;
+ }
+
+ dbus_message_unref(message);
+
+ return -EINPROGRESS;
+}
+
+static void request_input_private_key_reply(DBusMessage *reply,
+ void *user_data)
+{
+ struct ov_private_data *data = user_data;
+ const char *privatekeypass = NULL;
+ const char *key;
+ DBusMessageIter iter, dict;
+ DBusError error;
+ int err = 0;
+
+ connman_info("provider %p", data->provider);
+
+ /*
+ * When connmand calls disconnect because of connection timeout no
+ * reply is received.
+ */
+ if (!reply) {
+ err = ENOENT;
+ goto err;
+ }
+
+ dbus_error_init(&error);
+
+ err = vpn_agent_check_and_process_reply_error(reply, data->provider,
+ data->task, data->cb, data->user_data);
+ if (err) {
+ /* Ensure cb is called only once */
+ data->cb = NULL;
+ data->user_data = NULL;
+ return;
+ }
+
+ if (!vpn_agent_check_reply_has_dict(reply)) {
+ err = ENOENT;
+ goto err;
+ }
+
+ dbus_message_iter_init(reply, &iter);
+ dbus_message_iter_recurse(&iter, &dict);
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+ break;
+
+ dbus_message_iter_get_basic(&entry, &key);
+
+ if (g_str_equal(key, "OpenVPN.PrivateKeyPassword")) {
+ dbus_message_iter_next(&entry);
+ if (dbus_message_iter_get_arg_type(&entry)
+ != DBUS_TYPE_VARIANT)
+ break;
+ dbus_message_iter_recurse(&entry, &value);
+ if (dbus_message_iter_get_arg_type(&value)
+ != DBUS_TYPE_STRING)
+ break;
+ dbus_message_iter_get_basic(&value, &privatekeypass);
+ vpn_provider_set_string_hide_value(data->provider,
+ key, privatekeypass);
+
+ }
+
+ dbus_message_iter_next(&dict);
+ }
+
+ if (!privatekeypass) {
+ vpn_provider_indicate_error(data->provider,
+ VPN_PROVIDER_ERROR_AUTH_FAILED);
+
+ err = EACCES;
+ goto err;
+ }
+
+ ov_return_private_key_password(data, privatekeypass);
+
+ return;
+
+err:
+ ov_connect_done(data, err);
+}
+
+static int request_private_key_input(struct ov_private_data *data)
+{
+ DBusMessage *message;
+ const char *path, *agent_sender, *agent_path;
+ const char *privatekeypass;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ int err;
+ void *agent;
+
+ /*
+ * First check if this is the second attempt to get the key within
+ * this connection. In such case there has been invalid Private Key
+ * Password and it must be reset, and queried from user.
+ */
+ if (data->failed_attempts_privatekey) {
+ vpn_provider_set_string_hide_value(data->provider,
+ "OpenVPN.PrivateKeyPassword", NULL);
+ } else {
+ /* If the encrypted Private key password is kept in memory and
+ * use it first. If authentication fails this is cleared,
+ * likewise it is when connman-vpnd is restarted.
+ */
+ privatekeypass = vpn_provider_get_string(data->provider,
+ "OpenVPN.PrivateKeyPassword");
+ if (privatekeypass) {
+ ov_return_private_key_password(data, privatekeypass);
+ goto out;
+ }
+ }
+
+ agent = connman_agent_get_info(data->dbus_sender, &agent_sender,
+ &agent_path);
+ if (!agent || !agent_path)
+ return -ESRCH;
+
+ message = dbus_message_new_method_call(agent_sender, agent_path,
+ VPN_AGENT_INTERFACE,
+ "RequestInput");
+ if (!message)
+ return -ENOMEM;
+
+ dbus_message_iter_init_append(message, &iter);
+
+ path = vpn_provider_get_path(data->provider);
+ dbus_message_iter_append_basic(&iter,
+ DBUS_TYPE_OBJECT_PATH, &path);
+
+ connman_dbus_dict_open(&iter, &dict);
+
+ connman_dbus_dict_append_dict(&dict, "OpenVPN.PrivateKeyPassword",
+ request_input_append_password, NULL);
+
+ vpn_agent_append_host_and_name(&dict, data->provider);
+
+ /* Do not allow to store or retrieve the encrypted Private Key pass */
+ vpn_agent_append_allow_credential_storage(&dict, false);
+ vpn_agent_append_allow_credential_retrieval(&dict, false);
+
+ /*
+ * Indicate to keep credentials, the enc Private Key password should
+ * not affect the credential storing.
+ */
+ vpn_agent_append_keep_credentials(&dict, true);
+
+ connman_dbus_dict_append_dict(&dict, "Enter Private Key password",
+ request_input_append_informational, NULL);
+
+ connman_dbus_dict_close(&iter, &dict);
+
+ err = connman_agent_queue_message(data->provider, message,
+ connman_timeout_input_request(),
+ request_input_private_key_reply, data, agent);
+
+ if (err < 0 && err != -EBUSY) {
+ connman_error("error %d sending agent request", err);
+ dbus_message_unref(message);
+
+ return err;
+ }
+
+ dbus_message_unref(message);
+
+out:
+ return -EINPROGRESS;
+}
+
+static gboolean ov_management_handle_input(GIOChannel *source,
+ GIOCondition condition, gpointer user_data)
+{
+ struct ov_private_data *data = user_data;
+ char *str = NULL;
+ int err = 0;
+ bool close = false;
+
+ if (condition & G_IO_IN) {
+ /*
+ * Just return if line is not read and str is not allocated.
+ * Condition check handles closing of the channel later.
+ */
+ if (g_io_channel_read_line(source, &str, NULL, NULL, NULL) !=
+ G_IO_STATUS_NORMAL)
+ return true;
+
+ str[strlen(str) - 1] = '\0';
+ connman_warn("openvpn request %s", str);
+
+ if (g_str_has_prefix(str, ">PASSWORD:Need 'Auth'")) {
+ /*
+ * Request credentials from the user
+ */
+ err = request_credentials_input(data);
+ if (err != -EINPROGRESS)
+ close = true;
+ } else if (g_str_has_prefix(str,
+ ">PASSWORD:Need 'Private Key'")) {
+ err = request_private_key_input(data);
+ if (err != -EINPROGRESS)
+ close = true;
+ } else if (g_str_has_prefix(str,
+ ">PASSWORD:Verification Failed: 'Auth'")) {
+ /*
+ * Add error only, state change indication causes
+ * signal to be sent, which is not desired when
+ * OpenVPN is in interactive mode.
+ */
+ vpn_provider_add_error(data->provider,
+ VPN_PROVIDER_ERROR_AUTH_FAILED);
+ /*
+ * According to the OpenVPN manual about management interface
+ * https://openvpn.net/community-resources/management-interface/
+ * this should be received but it does not seem to be reported
+ * when decrypting private key fails. This requires following
+ * patch for OpenVPN (at least <= 2.4.5) in order to work:
+ * https://git.sailfishos.org/mer-core/openvpn/blob/
+ * 4f4b4af116292a207416c8a990392e35a6fc41af/rpm/privatekey-
+ * passphrase-handling.diff
+ */
+ } else if (g_str_has_prefix(str, ">PASSWORD:Verification "
+ "Failed: 'Private Key'")) {
+ data->failed_attempts_privatekey++;
+ }
+
+ g_free(str);
+ } else if (condition & (G_IO_ERR | G_IO_HUP)) {
+ connman_warn("Management channel termination");
+ close = true;
+ }
+
+ if (close)
+ close_management_interface(data);
+
+ return true;
+}
+
+static int ov_management_connect_timer_cb(gpointer user_data)
+{
+ struct ov_private_data *data = user_data;
+
+ if (!data->mgmt_channel) {
+ int fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd >= 0) {
+ struct sockaddr_un remote;
+ int err;
+
+ memset(&remote, 0, sizeof(remote));
+ remote.sun_family = AF_UNIX;
+ g_strlcpy(remote.sun_path, data->mgmt_path,
+ sizeof(remote.sun_path));
+
+ err = connect(fd, (struct sockaddr *)&remote,
+ sizeof(remote));
+ if (err == 0) {
+ data->mgmt_channel = g_io_channel_unix_new(fd);
+ data->mgmt_event_id =
+ g_io_add_watch(data->mgmt_channel,
+ G_IO_IN | G_IO_ERR | G_IO_HUP,
+ ov_management_handle_input,
+ data);
+
+ connman_warn("Connected management socket");
+ data->mgmt_timer_id = 0;
+ return G_SOURCE_REMOVE;
+ }
+ close(fd);
+ }
+ }
+
+ data->connect_attempts++;
+ if (data->connect_attempts > 30) {
+ connman_warn("Unable to connect management socket");
+ data->mgmt_timer_id = 0;
+ return G_SOURCE_REMOVE;
+ }
+
+ return G_SOURCE_CONTINUE;
+}
+
+static int ov_connect(struct vpn_provider *provider,
+ struct connman_task *task, const char *if_name,
+ vpn_provider_connect_cb_t cb, const char *dbus_sender,
+ void *user_data)
+{
+ const char *tmpdir;
+ struct ov_private_data *data;
+
+ /*
+ * Explicitly set limit of 10 for authentication errors. This defines
+ * the authentication error message limit from the server before VPN
+ * agent is instructed to clear the credentials. This is effective only
+ * after a successful connection has been made within CONNECT_OK_DIFF
+ * time. User defined value for "AuthErrorLimit" overrides this.
+ */
+ vpn_provider_set_auth_error_limit(provider, 10);
+
+ data = g_try_new0(struct ov_private_data, 1);
+ if (!data)
+ return -ENOMEM;
+
+ vpn_provider_set_plugin_data(provider, data);
+ data->provider = vpn_provider_ref(provider);
+ data->task = task;
+ data->dbus_sender = g_strdup(dbus_sender);
+ data->if_name = g_strdup(if_name);
+ data->cb = cb;
+ data->user_data = user_data;
+
+ /*
+ * We need to use the management interface to provide
+ * the user credentials and password for decrypting private key.
+ */
+
+ /* Use env TMPDIR for creating management socket, fall back to /tmp */
+ tmpdir = getenv("TMPDIR");
+ if (!tmpdir || !*tmpdir)
+ tmpdir = "/tmp";
+
+ /* Set up the path for the management interface */
+ data->mgmt_path = g_strconcat(tmpdir, "/connman-vpn-management-",
+ vpn_provider_get_ident(provider), NULL);
+ if (unlink(data->mgmt_path) != 0 && errno != ENOENT) {
+ connman_warn("Unable to unlink management socket %s: %d",
+ data->mgmt_path, errno);
+ }
+
+ data->mgmt_timer_id = g_timeout_add(200,
+ ov_management_connect_timer_cb, data);
+
+ task_append_config_data(provider, task);
+
+ return run_connect(data, cb, user_data);
+}
+
+static void ov_disconnect(struct vpn_provider *provider)
+{
+ if (!provider)
+ return;
+
+ connman_agent_cancel(provider);
- return err;
+ vpn_provider_set_state(provider, VPN_PROVIDER_STATE_DISCONNECT);
}
static int ov_device_flags(struct vpn_provider *provider)
@@ -466,14 +1211,16 @@ static int ov_device_flags(struct vpn_provider *provider)
}
if (!g_str_equal(option, "tun")) {
- connman_warn("bad OpenVPN.DeviceType value, falling back to tun");
+ connman_warn("bad OpenVPN.DeviceType value "
+ "falling back to tun");
}
return IFF_TUN;
}
static int ov_route_env_parse(struct vpn_provider *provider, const char *key,
- int *family, unsigned long *idx, enum vpn_provider_route_type *type)
+ int *family, unsigned long *idx,
+ enum vpn_provider_route_type *type)
{
char *end;
const char *start;
@@ -499,6 +1246,7 @@ static int ov_route_env_parse(struct vpn_provider *provider, const char *key,
static struct vpn_driver vpn_driver = {
.notify = ov_notify,
.connect = ov_connect,
+ .disconnect = ov_disconnect,
.save = ov_save,
.device_flags = ov_device_flags,
.route_env_parse = ov_route_env_parse,
diff --git a/vpn/plugins/pptp.c b/vpn/plugins/pptp.c
index 3dc93b03..7274376f 100755
--- a/vpn/plugins/pptp.c
+++ b/vpn/plugins/pptp.c
@@ -4,6 +4,7 @@
*
* Copyright (C) 2010,2013-2014 BMW Car IT GmbH.
* Copyright (C) 2012-2013 Intel Corporation. All rights reserved.
+ * Copyright (C) 2019-2021 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -54,15 +55,18 @@
enum {
OPT_STRING = 1,
OPT_BOOL = 2,
+ OPT_PPTP_ONLY = 3,
};
struct {
const char *cm_opt;
const char *pptp_opt;
- const char *vpnc_default;
+ const char *pptp_default;
int type;
} pptp_options[] = {
{ "PPTP.User", "user", NULL, OPT_STRING },
+ { "PPTP.IdleWait", "--idle-wait", NULL, OPT_PPTP_ONLY},
+ { "PPTP.MaxEchoWait", "--max-echo-wait", NULL, OPT_PPTP_ONLY},
{ "PPPD.EchoFailure", "lcp-echo-failure", "0", OPT_STRING },
{ "PPPD.EchoInterval", "lcp-echo-interval", "0", OPT_STRING },
{ "PPPD.Debug", "debug", NULL, OPT_STRING },
@@ -83,12 +87,40 @@ struct {
static DBusConnection *connection;
struct pptp_private_data {
+ struct vpn_provider *provider;
struct connman_task *task;
char *if_name;
vpn_provider_connect_cb_t cb;
void *user_data;
};
+static void pptp_connect_done(struct pptp_private_data *data, int err)
+{
+ vpn_provider_connect_cb_t cb;
+ void *user_data;
+
+ if (!data || !data->cb)
+ return;
+
+ /* Ensure that callback is called only once */
+ cb = data->cb;
+ user_data = data->user_data;
+ data->cb = NULL;
+ data->user_data = NULL;
+ cb(data->provider, user_data, err);
+}
+
+static void free_private_data(struct pptp_private_data *data)
+{
+ if (vpn_provider_get_plugin_data(data->provider) == data)
+ vpn_provider_set_plugin_data(data->provider, NULL);
+
+ pptp_connect_done(data, EIO);
+ vpn_provider_unref(data->provider);
+ g_free(data->if_name);
+ g_free(data);
+}
+
static DBusMessage *pptp_get_sec(struct connman_task *task,
DBusMessage *msg, void *user_data)
{
@@ -122,6 +154,9 @@ static int pptp_notify(DBusMessage *msg, struct vpn_provider *provider)
char *addressv4 = NULL, *netmask = NULL, *gateway = NULL;
char *ifname = NULL, *nameservers = NULL;
struct connman_ipaddress *ipaddress = NULL;
+ struct pptp_private_data *data;
+
+ data = vpn_provider_get_plugin_data(provider);
dbus_message_iter_init(msg, &iter);
@@ -137,13 +172,25 @@ static int pptp_notify(DBusMessage *msg, struct vpn_provider *provider)
DBG("authentication failure");
vpn_provider_set_string(provider, "PPTP.User", NULL);
- vpn_provider_set_string(provider, "PPTP.Password", NULL);
+ vpn_provider_set_string_hide_value(provider, "PPTP.Password",
+ NULL);
+ pptp_connect_done(data, EACCES);
return VPN_STATE_AUTH_FAILURE;
}
- if (strcmp(reason, "connect"))
+ if (strcmp(reason, "connect")) {
+ pptp_connect_done(data, EIO);
+
+ /*
+ * Stop the task to avoid potential looping of this state when
+ * authentication fails.
+ */
+ if (data && data->task)
+ connman_task_stop(data->task);
+
return VPN_STATE_DISCONNECT;
+ }
dbus_message_iter_recurse(&iter, &dict);
@@ -203,6 +250,7 @@ static int pptp_notify(DBusMessage *msg, struct vpn_provider *provider)
connman_ipaddress_set_ipv4(ipaddress, addressv4, netmask,
gateway);
+ connman_ipaddress_set_p2p(ipaddress, true);
vpn_provider_set_ipaddress(provider, ipaddress);
vpn_provider_set_nameservers(provider, nameservers);
@@ -212,6 +260,7 @@ static int pptp_notify(DBusMessage *msg, struct vpn_provider *provider)
g_free(nameservers);
connman_ipaddress_free(ipaddress);
+ pptp_connect_done(data, 0);
return VPN_STATE_CONNECT;
}
@@ -273,6 +322,16 @@ static void pptp_write_bool_option(struct connman_task *task,
}
}
+static void pptp_died(struct connman_task *task, int exit_code,
+ void *user_data)
+{
+ struct pptp_private_data *data = user_data;
+
+ vpn_died(task, exit_code, data->provider);
+
+ free_private_data(data);
+}
+
struct request_input_reply {
struct vpn_provider *provider;
vpn_provider_password_cb_t callback;
@@ -282,16 +341,28 @@ struct request_input_reply {
static void request_input_reply(DBusMessage *reply, void *user_data)
{
struct request_input_reply *pptp_reply = user_data;
+ struct pptp_private_data *data;
const char *error = NULL;
char *username = NULL, *password = NULL;
char *key;
DBusMessageIter iter, dict;
+ int err;
DBG("provider %p", pptp_reply->provider);
- if (!reply || dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
- if (reply)
- error = dbus_message_get_error_name(reply);
+ if (!reply)
+ goto done;
+
+ data = pptp_reply->user_data;
+
+ err = vpn_agent_check_and_process_reply_error(reply,
+ pptp_reply->provider, data->task, data->cb,
+ data->user_data);
+ if (err) {
+ /* Ensure cb is called only once */
+ data->cb = NULL;
+ data->user_data = NULL;
+ error = dbus_message_get_error_name(reply);
goto done;
}
@@ -384,6 +455,9 @@ static int request_input(struct vpn_provider *provider,
connman_dbus_dict_open(&iter, &dict);
+ if (vpn_provider_get_authentication_errors(provider))
+ vpn_agent_append_auth_failure(&dict, provider, NULL);
+
vpn_agent_append_user_info(&dict, provider, "PPTP.User");
vpn_agent_append_host_and_name(&dict, provider);
@@ -415,23 +489,18 @@ static int request_input(struct vpn_provider *provider,
return -EINPROGRESS;
}
-static int run_connect(struct vpn_provider *provider,
- struct connman_task *task, const char *if_name,
- vpn_provider_connect_cb_t cb, void *user_data,
- const char *username, const char *password)
+static int run_connect(struct pptp_private_data *data, const char *username,
+ const char *password)
{
- const char *opt_s, *host;
+ struct vpn_provider *provider = data->provider;
+ struct connman_task *task = data->task;
+ GString *pptp_opt_s;
+ const char *opt_s;
+ const char *host;
char *str;
int err, i;
- host = vpn_provider_get_string(provider, "Host");
- if (!host) {
- connman_error("Host not set; cannot enable VPN");
- err = -EINVAL;
- goto done;
- }
-
- if (!username || !password) {
+ if (!username || !*username || !password || !*password) {
DBG("Cannot connect username %s password %p",
username, password);
err = -EINVAL;
@@ -440,16 +509,12 @@ static int run_connect(struct vpn_provider *provider,
DBG("username %s password %p", username, password);
- str = g_strdup_printf("%s %s --nolaunchpppd --loglevel 2",
- PPTP, host);
- if (!str) {
- connman_error("can not allocate memory");
- err = -ENOMEM;
- goto done;
- }
+ host = vpn_provider_get_string(provider, "Host");
- connman_task_add_argument(task, "pty", str);
- g_free(str);
+ /* Create PPTP options for pppd "pty" */
+ pptp_opt_s = g_string_new(NULL);
+ g_string_append_printf(pptp_opt_s, "%s %s --nolaunchpppd --loglevel 2",
+ PPTP, host);
connman_task_add_argument(task, "nodetach", NULL);
connman_task_add_argument(task, "lock", NULL);
@@ -464,7 +529,7 @@ static int run_connect(struct vpn_provider *provider,
opt_s = vpn_provider_get_string(provider,
pptp_options[i].cm_opt);
if (!opt_s)
- opt_s = pptp_options[i].vpnc_default;
+ opt_s = pptp_options[i].pptp_default;
if (!opt_s)
continue;
@@ -475,32 +540,31 @@ static int run_connect(struct vpn_provider *provider,
else if (pptp_options[i].type == OPT_BOOL)
pptp_write_bool_option(task,
pptp_options[i].pptp_opt, opt_s);
+ else if (pptp_options[i].type == OPT_PPTP_ONLY)
+ g_string_append_printf(pptp_opt_s, " %s %s",
+ pptp_options[i].pptp_opt, opt_s);
}
+ str = g_string_free(pptp_opt_s, FALSE);
+ connman_task_add_argument(task, "pty", str);
+ g_free(str);
+
connman_task_add_argument(task, "plugin",
SCRIPTDIR "/libppp-plugin.so");
- err = connman_task_run(task, vpn_died, provider,
- NULL, NULL, NULL);
+ err = connman_task_run(task, pptp_died, data, NULL, NULL, NULL);
if (err < 0) {
connman_error("pptp failed to start");
err = -EIO;
- goto done;
}
done:
- if (cb)
- cb(provider, user_data, err);
+ if (err)
+ pptp_connect_done(data, -err);
return err;
}
-static void free_private_data(struct pptp_private_data *data)
-{
- g_free(data->if_name);
- g_free(data);
-}
-
static void request_input_cb(struct vpn_provider *provider,
const char *username,
const char *password,
@@ -508,7 +572,7 @@ static void request_input_cb(struct vpn_provider *provider,
{
struct pptp_private_data *data = user_data;
- if (!username || !password)
+ if (!username || !*username || !password || !*password)
DBG("Requesting username %s or password failed, error %s",
username, error);
else if (error)
@@ -518,10 +582,7 @@ static void request_input_cb(struct vpn_provider *provider,
vpn_provider_set_string_hide_value(provider, "PPTP.Password",
password);
- run_connect(provider, data->task, data->if_name, data->cb,
- data->user_data, username, password);
-
- free_private_data(data);
+ run_connect(data, username, password);
}
static int pptp_connect(struct vpn_provider *provider,
@@ -529,9 +590,21 @@ static int pptp_connect(struct vpn_provider *provider,
vpn_provider_connect_cb_t cb, const char *dbus_sender,
void *user_data)
{
+ struct pptp_private_data *data;
const char *username, *password;
int err;
+ data = g_try_new0(struct pptp_private_data, 1);
+ if (!data)
+ return -ENOMEM;
+
+ data->provider = vpn_provider_ref(provider);
+ data->task = task;
+ data->if_name = g_strdup(if_name);
+ data->cb = cb;
+ data->user_data = user_data;
+ vpn_provider_set_plugin_data(provider, data);
+
DBG("iface %s provider %p user %p", if_name, provider, user_data);
if (connman_task_set_notify(task, "getsec",
@@ -545,34 +618,20 @@ static int pptp_connect(struct vpn_provider *provider,
DBG("user %s password %p", username, password);
- if (!username || !password) {
- struct pptp_private_data *data;
-
- data = g_try_new0(struct pptp_private_data, 1);
- if (!data)
- return -ENOMEM;
-
- data->task = task;
- data->if_name = g_strdup(if_name);
- data->cb = cb;
- data->user_data = user_data;
-
+ if (!username || !*username || !password || !*password) {
err = request_input(provider, request_input_cb, dbus_sender,
data);
- if (err != -EINPROGRESS) {
- free_private_data(data);
- goto done;
- }
+ if (err != -EINPROGRESS)
+ goto error;
+
return err;
}
-done:
- return run_connect(provider, task, if_name, cb, user_data,
- username, password);
+ return run_connect(data, username, password);
error:
- if (cb)
- cb(provider, user_data, err);
+ pptp_connect_done(data, -err);
+ free_private_data(data);
return err;
}
@@ -594,7 +653,12 @@ static int pptp_error_code(struct vpn_provider *provider, int exit_code)
static void pptp_disconnect(struct vpn_provider *provider)
{
- vpn_provider_set_string(provider, "PPTP.Password", NULL);
+ if (!provider)
+ return;
+
+ vpn_provider_set_string_hide_value(provider, "PPTP.Password", NULL);
+
+ connman_agent_cancel(provider);
}
static struct vpn_driver vpn_driver = {
diff --git a/vpn/plugins/vpn.c b/vpn/plugins/vpn.c
index d9c6dbbb..b89c2223 100755
--- a/vpn/plugins/vpn.c
+++ b/vpn/plugins/vpn.c
@@ -33,6 +33,9 @@
#include <sys/types.h>
#include <linux/if_tun.h>
#include <net/if.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
#include <dbus/dbus.h>
@@ -47,6 +50,7 @@
#include "../vpn-provider.h"
#include "vpn.h"
+#include "../vpn.h"
struct vpn_data {
struct vpn_provider *provider;
@@ -61,7 +65,7 @@ struct vpn_data {
struct vpn_driver_data {
const char *name;
const char *program;
- struct vpn_driver *vpn_driver;
+ const struct vpn_driver *vpn_driver;
struct vpn_provider_driver provider_driver;
};
@@ -85,8 +89,10 @@ static int stop_vpn(struct vpn_provider *provider)
vpn_driver_data = g_hash_table_lookup(driver_hash, name);
if (vpn_driver_data && vpn_driver_data->vpn_driver &&
- vpn_driver_data->vpn_driver->flags == VPN_FLAG_NO_TUN)
+ vpn_driver_data->vpn_driver->flags & VPN_FLAG_NO_TUN) {
+ vpn_driver_data->vpn_driver->disconnect(data->provider);
return 0;
+ }
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = data->tun_flags | IFF_NO_PI;
@@ -284,7 +290,7 @@ static DBusMessage *vpn_notify(struct connman_task *task,
* We need to remove first the old address, just
* replacing the old address will not work as expected
* because the old address will linger in the interface
- * and not disapper so the clearing is needed here.
+ * and not disappear so the clearing is needed here.
*
* Also the state must change, otherwise the routes
* will not be set properly.
@@ -465,12 +471,120 @@ exist_err:
return ret;
}
+static gid_t get_gid(const char *group_name)
+{
+ struct group *grp;
+
+ grp = vpn_util_get_group(group_name);
+ if (grp)
+ return grp->gr_gid;
+
+ return -1;
+}
+
+static uid_t get_uid(const char *user_name)
+{
+ struct passwd *pw;
+
+ pw = vpn_util_get_passwd(user_name);
+ if (pw)
+ return pw->pw_uid;
+
+ return -1;
+}
+
+static gint get_supplementary_gids(gchar **groups, gid_t **gid_list)
+{
+ gint group_count = 0;
+ gid_t *list = NULL;
+ int i;
+
+ if (groups) {
+ for(i = 0; groups[i]; i++) {
+ group_count++;
+
+ list = (gid_t*)g_try_realloc(list,
+ sizeof(gid_t) * group_count);
+
+ if (!list) {
+ DBG("cannot allocate supplementary group list");
+ break;
+ }
+
+ list[i] = get_gid(groups[i]);
+ }
+ }
+
+ *gid_list = list;
+
+ return group_count;
+}
+
+static void vpn_task_setup(gpointer user_data)
+{
+ struct vpn_plugin_data *data;
+ uid_t uid;
+ gid_t gid;
+ gid_t *gid_list = NULL;
+ size_t gid_list_size;
+ const gchar *user;
+ const gchar *group;
+ gchar **suppl_groups;
+
+ data = user_data;
+ user = vpn_settings_get_binary_user(data);
+ group = vpn_settings_get_binary_group(data);
+ suppl_groups = vpn_settings_get_binary_supplementary_groups(data);
+
+ uid = get_uid(user);
+ gid = get_gid(group);
+ gid_list_size = get_supplementary_gids(suppl_groups, &gid_list);
+
+ DBG("vpn_task_setup uid:%d gid:%d supplementary group list size:%zu",
+ uid, gid, gid_list_size);
+
+
+ /* Change group if proper group name was set, requires CAP_SETGID.*/
+ if (gid > 0 && setgid(gid))
+ connman_error("error setting gid %d %s", gid, strerror(errno));
+
+ /* Set the supplementary groups if list exists, requires CAP_SETGID. */
+ if (gid_list_size && gid_list && setgroups(gid_list_size, gid_list))
+ connman_error("error setting gid list %s", strerror(errno));
+
+ /* Change user for the task if set, requires CAP_SETUID */
+ if (uid > 0 && setuid(uid))
+ connman_error("error setting uid %d %s", uid, strerror(errno));
+}
+
+
+static gboolean update_provider_state(gpointer data)
+{
+ struct vpn_provider *provider = data;
+ struct vpn_data *vpn_data;
+ int index;
+
+ DBG("");
+
+ vpn_data = vpn_provider_get_data(provider);
+
+ index = vpn_provider_get_index(provider);
+ DBG("index to watch %d", index);
+ vpn_provider_ref(provider);
+ vpn_data->watch = vpn_rtnl_add_newlink_watch(index,
+ vpn_newlink, provider);
+ connman_inet_ifup(index);
+
+ return FALSE;
+}
+
static int vpn_connect(struct vpn_provider *provider,
vpn_provider_connect_cb_t cb,
const char *dbus_sender, void *user_data)
{
struct vpn_data *data = vpn_provider_get_data(provider);
struct vpn_driver_data *vpn_driver_data;
+ struct vpn_plugin_data *vpn_plugin_data;
const char *name;
int ret = 0, tun_flags = IFF_TUN;
enum vpn_state state = VPN_STATE_UNKNOWN;
@@ -519,7 +633,7 @@ static int vpn_connect(struct vpn_provider *provider,
goto exist_err;
}
- if (vpn_driver_data->vpn_driver->flags != VPN_FLAG_NO_TUN) {
+ if (!(vpn_driver_data->vpn_driver->flags & VPN_FLAG_NO_TUN)) {
if (vpn_driver_data->vpn_driver->device_flags) {
tun_flags = vpn_driver_data->vpn_driver->device_flags(provider);
}
@@ -528,7 +642,30 @@ static int vpn_connect(struct vpn_provider *provider,
goto exist_err;
}
- data->task = connman_task_create(vpn_driver_data->program);
+
+ if (vpn_driver_data && vpn_driver_data->vpn_driver &&
+ vpn_driver_data->vpn_driver->flags & VPN_FLAG_NO_DAEMON) {
+
+ ret = vpn_driver_data->vpn_driver->connect(provider,
+ NULL, NULL, cb, dbus_sender, user_data);
+ if (ret) {
+ stop_vpn(provider);
+ goto exist_err;
+ }
+
+ DBG("%s started with dev %s",
+ vpn_driver_data->provider_driver.name, data->if_name);
+
+ data->state = VPN_STATE_CONNECT;
+
+ g_timeout_add(1, update_provider_state, provider);
+ return -EINPROGRESS;
+ }
+
+ vpn_plugin_data =
+ vpn_settings_get_vpn_plugin_config(vpn_driver_data->name);
+ data->task = connman_task_create(vpn_driver_data->program,
+ vpn_task_setup, vpn_plugin_data);
if (!data->task) {
ret = -ENOMEM;
@@ -545,7 +682,6 @@ static int vpn_connect(struct vpn_provider *provider,
goto exist_err;
}
-
#if defined TIZEN_EXT
if(vpn_driver_data->vpn_driver->set_event_cb)
vpn_driver_data->vpn_driver->set_event_cb(vpn_event, provider);
@@ -609,7 +745,15 @@ static int vpn_disconnect(struct vpn_provider *provider)
}
data->state = VPN_STATE_DISCONNECT;
- connman_task_stop(data->task);
+
+ if (!vpn_driver_data->vpn_driver->disconnect) {
+ DBG("Driver has no disconnect() implementation, set provider "
+ "state to disconnect.");
+ vpn_provider_set_state(provider, VPN_PROVIDER_STATE_DISCONNECT);
+ }
+
+ if (data->task)
+ connman_task_stop(data->task);
return 0;
}
@@ -633,7 +777,8 @@ static int vpn_remove(struct vpn_provider *provider)
data->watch = 0;
}
- connman_task_stop(data->task);
+ if (data->task)
+ connman_task_stop(data->task);
g_usleep(G_USEC_PER_SEC);
stop_vpn(provider);
@@ -687,7 +832,7 @@ static int vpn_route_env_parse(struct vpn_provider *provider, const char *key,
return 0;
}
-int vpn_register(const char *name, struct vpn_driver *vpn_driver,
+int vpn_register(const char *name, const struct vpn_driver *vpn_driver,
const char *program)
{
struct vpn_driver_data *data;
@@ -699,6 +844,9 @@ int vpn_register(const char *name, struct vpn_driver *vpn_driver,
data->name = name;
data->program = program;
+ if (vpn_settings_parse_vpn_plugin_config(data->name) != 0)
+ DBG("No configuration provided for VPN plugin %s", data->name);
+
data->vpn_driver = vpn_driver;
data->provider_driver.name = name;
@@ -737,6 +885,7 @@ void vpn_unregister(const char *name)
return;
vpn_provider_driver_unregister(&data->provider_driver);
+ vpn_settings_delete_vpn_plugin_config(name);
g_hash_table_remove(driver_hash, name);
diff --git a/vpn/plugins/vpn.h b/vpn/plugins/vpn.h
index 318a10c5..7956ffaf 100755
--- a/vpn/plugins/vpn.h
+++ b/vpn/plugins/vpn.h
@@ -28,7 +28,8 @@
extern "C" {
#endif
-#define VPN_FLAG_NO_TUN 1
+#define VPN_FLAG_NO_TUN 1
+#define VPN_FLAG_NO_DAEMON 2
enum vpn_state {
VPN_STATE_UNKNOWN = 0,
@@ -64,7 +65,7 @@ struct vpn_driver {
enum vpn_provider_route_type *type);
};
-int vpn_register(const char *name, struct vpn_driver *driver,
+int vpn_register(const char *name, const struct vpn_driver *driver,
const char *program);
void vpn_unregister(const char *provider_name);
void vpn_died(struct connman_task *task, int exit_code, void *user_data);
diff --git a/vpn/plugins/vpnc.c b/vpn/plugins/vpnc.c
index af9dbe76..d11b9111 100755
--- a/vpn/plugins/vpnc.c
+++ b/vpn/plugins/vpnc.c
@@ -30,6 +30,10 @@
#include <stdio.h>
#include <net/if.h>
#include <linux/if_tun.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include <fcntl.h>
#include <glib.h>
@@ -39,14 +43,18 @@
#include <connman/task.h>
#include <connman/ipconfig.h>
#include <connman/dbus.h>
+#include <connman/agent.h>
+#include <connman/setting.h>
+#include <connman/vpn-dbus.h>
#include "../vpn-provider.h"
+#include "../vpn-agent.h"
#include "vpn.h"
+#include "../vpn.h"
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
-
-static DBusConnection *connection;
+#define PID_PATH_ROOT "/var/run/user"
enum {
OPT_STRING = 1,
@@ -83,25 +91,104 @@ struct {
true },
};
+struct vc_private_data {
+ struct vpn_provider *provider;
+ struct connman_task *task;
+ char *if_name;
+ vpn_provider_connect_cb_t cb;
+ void *user_data;
+ int err_ch_id;
+ GIOChannel *err_ch;
+};
+
+static void vc_connect_done(struct vc_private_data *data, int err)
+{
+ DBG("data %p err %d", data, err);
+
+ if (data && data->cb) {
+ vpn_provider_connect_cb_t cb = data->cb;
+ void *user_data = data->user_data;
+
+ /* Make sure we don't invoke this callback twice */
+ data->cb = NULL;
+ data->user_data = NULL;
+ cb(data->provider, user_data, err);
+ }
+}
+
+static void close_io_channel(struct vc_private_data *data, GIOChannel *channel)
+{
+ if (!data || !channel)
+ return;
+
+ if (data->err_ch == channel) {
+ DBG("closing stderr");
+
+ if (data->err_ch_id) {
+ g_source_remove(data->err_ch_id);
+ data->err_ch_id = 0;
+ }
+
+ if (!data->err_ch)
+ return;
+
+ g_io_channel_shutdown(data->err_ch, FALSE, NULL);
+ g_io_channel_unref(data->err_ch);
+
+ data->err_ch = NULL;
+ }
+}
+
+static void free_private_data(struct vc_private_data *data)
+{
+ DBG("data %p", data);
+
+ if (!data || !data->provider)
+ return;
+
+ DBG("provider %p", data->provider);
+
+ if (vpn_provider_get_plugin_data(data->provider) == data)
+ vpn_provider_set_plugin_data(data->provider, NULL);
+
+ vpn_provider_unref(data->provider);
+
+ g_free(data->if_name);
+ g_free(data);
+}
+
static int vc_notify(DBusMessage *msg, struct vpn_provider *provider)
{
DBusMessageIter iter, dict;
char *address = NULL, *netmask = NULL, *gateway = NULL;
struct connman_ipaddress *ipaddress;
const char *reason, *key, *value;
+ struct vc_private_data *data;
+ int type;
+
+ data = vpn_provider_get_plugin_data(provider);
dbus_message_iter_init(msg, &iter);
+ type = dbus_message_iter_get_arg_type(&iter);
+ if (type != DBUS_TYPE_STRING) {
+ DBG("invalid D-Bus arg type %d", type);
+ return VPN_STATE_FAILURE;
+ }
+
dbus_message_iter_get_basic(&iter, &reason);
dbus_message_iter_next(&iter);
if (!provider) {
connman_error("No provider found");
+ vc_connect_done(data, ENOENT);
return VPN_STATE_FAILURE;
}
- if (strcmp(reason, "connect"))
+ if (g_strcmp0(reason, "connect")) {
+ vc_connect_done(data, EIO);
return VPN_STATE_DISCONNECT;
+ }
dbus_message_iter_recurse(&iter, &dict);
@@ -109,8 +196,18 @@ static int vc_notify(DBusMessage *msg, struct vpn_provider *provider)
DBusMessageIter entry;
dbus_message_iter_recurse(&dict, &entry);
+
+ type = dbus_message_iter_get_arg_type(&entry);
+ if (type != DBUS_TYPE_STRING)
+ continue;
+
dbus_message_iter_get_basic(&entry, &key);
dbus_message_iter_next(&entry);
+
+ type = dbus_message_iter_get_arg_type(&entry);
+ if (type != DBUS_TYPE_STRING)
+ continue;
+
dbus_message_iter_get_basic(&entry, &value);
DBG("%s = %s", key, value);
@@ -143,11 +240,12 @@ static int vc_notify(DBusMessage *msg, struct vpn_provider *provider)
g_free(address);
g_free(netmask);
g_free(gateway);
-
+ vc_connect_done(data, EIO);
return VPN_STATE_FAILURE;
}
connman_ipaddress_set_ipv4(ipaddress, address, netmask, gateway);
+ connman_ipaddress_set_p2p(ipaddress, true);
vpn_provider_set_ipaddress(provider, ipaddress);
g_free(address);
@@ -155,6 +253,7 @@ static int vc_notify(DBusMessage *msg, struct vpn_provider *provider)
g_free(gateway);
connman_ipaddress_free(ipaddress);
+ vc_connect_done(data, 0);
return VPN_STATE_CONNECT;
}
@@ -263,27 +362,144 @@ static int vc_save(struct vpn_provider *provider, GKeyFile *keyfile)
return 0;
}
-static int vc_connect(struct vpn_provider *provider,
- struct connman_task *task, const char *if_name,
- vpn_provider_connect_cb_t cb, const char *dbus_sender,
- void *user_data)
+static void vc_died(struct connman_task *task, int exit_code, void *user_data)
{
- const char *option;
- int err = 0, fd;
+ struct vc_private_data *data = user_data;
- option = vpn_provider_get_string(provider, "Host");
- if (!option) {
- connman_error("Host not set; cannot enable VPN");
- err = -EINVAL;
- goto done;
+ DBG("task %p data %p exit_code %d user_data %p", task, data, exit_code,
+ user_data);
+
+ if (!data)
+ return;
+
+ if (data->provider) {
+ connman_agent_cancel(data->provider);
+
+ if (task)
+ vpn_died(task, exit_code, data->provider);
}
- option = vpn_provider_get_string(provider, "VPNC.IPSec.ID");
- if (!option) {
- connman_error("Group not set; cannot enable VPN");
- err = -EINVAL;
- goto done;
+
+ free_private_data(data);
+}
+
+static gboolean io_channel_cb(GIOChannel *source, GIOCondition condition,
+ gpointer user_data)
+{
+ struct vc_private_data *data;
+ const char *auth_failures[] = {
+ VPNC ": hash comparison failed",
+ VPNC ": authentication unsuccessful",
+ VPNC ": expected xauth packet; rejected",
+ NULL
+ };
+ const char *conn_failures[] = {
+ VPNC ": unknown host",
+ VPNC ": no response from target",
+ VPNC ": receiving packet: No route to host",
+ NULL
+ };
+ char *str;
+ int i;
+
+ data = user_data;
+
+ if ((condition & G_IO_IN) &&
+ g_io_channel_read_line(source, &str, NULL, NULL, NULL) ==
+ G_IO_STATUS_NORMAL) {
+ str[strlen(str) - 1] = '\0';
+
+ for (i = 0; auth_failures[i]; i++) {
+ if (g_str_has_prefix(str, auth_failures[i])) {
+ DBG("authentication failed: %s", str);
+
+ vpn_provider_indicate_error(data->provider,
+ VPN_PROVIDER_ERROR_AUTH_FAILED);
+ }
+ }
+
+ for (i = 0; conn_failures[i]; i++) {
+ if (g_str_has_prefix(str, conn_failures[i])) {
+ DBG("connection failed: %s", str);
+
+ vpn_provider_indicate_error(data->provider,
+ VPN_PROVIDER_ERROR_CONNECT_FAILED);
+ }
+ }
+
+ g_free(str);
+ } else if (condition & (G_IO_ERR | G_IO_HUP)) {
+ DBG("Channel termination");
+ close_io_channel(data, source);
+ return G_SOURCE_REMOVE;
+ }
+
+ return G_SOURCE_CONTINUE;
+}
+
+static char *create_pid_path(const char *user, const char *group)
+{
+ struct passwd *pwd;
+ struct group *grp;
+ char *uid_str;
+ char *pid_path = NULL;
+ int mode = S_IRWXU|S_IRWXG;
+ gid_t gid;
+
+ if (!user || !*user)
+ return NULL;
+
+ if (vpn_settings_is_system_user(user))
+ return NULL;
+
+ pwd = vpn_util_get_passwd(user);
+ uid_str = g_strdup_printf("%d", pwd->pw_uid);
+
+ grp = vpn_util_get_group(group);
+ gid = grp ? grp->gr_gid : pwd->pw_gid;
+
+ pid_path = g_build_filename(PID_PATH_ROOT, uid_str, "vpnc", "pid",
+ NULL);
+ if (vpn_util_create_path(pid_path, pwd->pw_uid, gid, mode)) {
+ g_free(pid_path);
+ pid_path = NULL;
}
+ g_free(uid_str);
+
+ return pid_path;
+}
+
+static int run_connect(struct vc_private_data *data)
+{
+ struct vpn_provider *provider;
+ struct connman_task *task;
+ struct vpn_plugin_data *plugin_data;
+ const char *credentials[] = {"VPNC.IPSec.Secret", "VPNC.Xauth.Username",
+ "VPNC.Xauth.Password", NULL};
+ const char *if_name;
+ const char *option;
+ char *pid_path;
+ int err;
+ int fd_in;
+ int fd_err;
+ int i;
+
+ provider = data->provider;
+ task = data->task;
+ if_name = data->if_name;
+
+ DBG("provider %p task %p interface %s user_data %p", provider, task,
+ if_name, data->user_data);
+
+ /*
+ * Change to use C locale, options should be in ASCII according to
+ * documentation. To be on the safe side, set both LANG and LC_ALL.
+ * This is required especially when the VPNC processe is ran using an
+ * user other than root.
+ */
+ connman_task_add_variable(task,"LANG", "C");
+ connman_task_add_variable(task,"LC_ALL", "C");
+
connman_task_add_argument(task, "--non-inter", NULL);
connman_task_add_argument(task, "--no-detach", NULL);
@@ -298,8 +514,21 @@ static int vc_connect(struct vpn_provider *provider,
connman_task_add_argument(task, "--ifmode", "tun");
}
- connman_task_add_argument(task, "--script",
- SCRIPTDIR "/openconnect-script");
+ plugin_data = vpn_settings_get_vpn_plugin_config("vpnc");
+
+ option = vpn_settings_get_binary_user(plugin_data);
+ if (option) {
+ pid_path = create_pid_path(option,
+ vpn_settings_get_binary_group(
+ plugin_data));
+ if (pid_path)
+ connman_task_add_argument(task, "--pid-file",
+ pid_path);
+
+ g_free(pid_path);
+ }
+
+ connman_task_add_argument(task, "--script", SCRIPTDIR "/vpn-script");
option = vpn_provider_get_string(provider, "VPNC.Debug");
if (option)
@@ -307,25 +536,363 @@ static int vc_connect(struct vpn_provider *provider,
connman_task_add_argument(task, "-", NULL);
- err = connman_task_run(task, vpn_died, provider,
- &fd, NULL, NULL);
+ err = connman_task_run(data->task, vc_died, data, &fd_in, NULL,
+ &fd_err);
if (err < 0) {
connman_error("vpnc failed to start");
err = -EIO;
goto done;
}
- err = vc_write_config_data(provider, fd);
+ err = vc_write_config_data(provider, fd_in);
+
+ if (err) {
+ DBG("config write error %s", strerror(err));
+ goto done;
+ }
+
+ err = -EINPROGRESS;
- close(fd);
+ data->err_ch = g_io_channel_unix_new(fd_err);
+ data->err_ch_id = g_io_add_watch(data->err_ch,
+ G_IO_IN | G_IO_ERR | G_IO_HUP,
+ (GIOFunc)io_channel_cb, data);
done:
- if (cb)
- cb(provider, user_data, err);
+ close(fd_in);
+
+ /*
+ * Clear out credentials if they are non-immutable. If this is called
+ * directly from vc_connect() all credentials are read from config and
+ * are set as immutable, so no change is done. In case a VPN agent is
+ * used these values should be reset to "-" in order to retrieve them
+ * from VPN agent next time VPN connection is established. This supports
+ * then partially defined credentials in .config and some can be
+ * retrieved using an agent.
+ */
+ for (i = 0; credentials[i]; i++) {
+ const char *key = credentials[i];
+ if (!vpn_provider_get_string_immutable(provider, key))
+ vpn_provider_set_string(provider, key, "-");
+ }
return err;
}
+static void request_input_append_mandatory(DBusMessageIter *iter,
+ void *user_data)
+{
+ char *str = "string";
+
+ connman_dbus_dict_append_basic(iter, "Type",
+ DBUS_TYPE_STRING, &str);
+ str = "mandatory";
+ connman_dbus_dict_append_basic(iter, "Requirement",
+ DBUS_TYPE_STRING, &str);
+
+ if (!user_data)
+ return;
+
+ str = user_data;
+ connman_dbus_dict_append_basic(iter, "Value", DBUS_TYPE_STRING, &str);
+}
+
+static void request_input_append_password(DBusMessageIter *iter,
+ void *user_data)
+{
+ char *str = "password";
+
+ connman_dbus_dict_append_basic(iter, "Type",
+ DBUS_TYPE_STRING, &str);
+ str = "mandatory";
+ connman_dbus_dict_append_basic(iter, "Requirement",
+ DBUS_TYPE_STRING, &str);
+
+ if (!user_data)
+ return;
+
+ str = user_data;
+ connman_dbus_dict_append_basic(iter, "Value", DBUS_TYPE_STRING, &str);
+}
+
+static void request_input_append_informational(DBusMessageIter *iter,
+ void *user_data)
+{
+ char *str = "password";
+
+ connman_dbus_dict_append_basic(iter, "Type",
+ DBUS_TYPE_STRING, &str);
+ str = "informational";
+ connman_dbus_dict_append_basic(iter, "Requirement",
+ DBUS_TYPE_STRING, &str);
+
+ if (!user_data)
+ return;
+
+ str = user_data;
+ connman_dbus_dict_append_basic(iter, "Value", DBUS_TYPE_STRING, &str);
+}
+
+static void request_input_append_to_dict(struct vpn_provider *provider,
+ DBusMessageIter *dict,
+ connman_dbus_append_cb_t function_cb, const char *key)
+{
+ const char *str;
+ bool immutable = false;
+
+ if (!provider || !dict || !function_cb || !key)
+ return;
+
+ str = vpn_provider_get_string(provider, key);
+
+ /* If value is "-", it is cleared by VPN agent */
+ if (!g_strcmp0(str, "-"))
+ str = NULL;
+
+ if (str)
+ immutable = vpn_provider_get_string_immutable(provider, key);
+
+ if (immutable) {
+ /* Hide immutable password types */
+ if (function_cb == request_input_append_password)
+ str = "********";
+
+ /* Send immutable as informational */
+ function_cb = request_input_append_informational;
+ }
+
+ connman_dbus_dict_append_dict(dict, key, function_cb, (void *)str);
+}
+
+static void request_input_credentials_reply(DBusMessage *reply, void *user_data)
+{
+ struct vc_private_data *data = user_data;
+ char *secret = NULL, *username = NULL, *password = NULL;
+ const char *key;
+ DBusMessageIter iter, dict;
+ int err;
+
+ DBG("provider %p", data->provider);
+
+ if (!reply) {
+ err = ENOENT;
+ goto err;
+ }
+
+ err = vpn_agent_check_and_process_reply_error(reply, data->provider,
+ data->task, data->cb, data->user_data);
+ if (err) {
+ /* Ensure cb is called only once */
+ data->cb = NULL;
+ data->user_data = NULL;
+ return;
+ }
+
+ if (!vpn_agent_check_reply_has_dict(reply)) {
+ err = ENOENT;
+ goto err;
+ }
+
+ dbus_message_iter_init(reply, &iter);
+ dbus_message_iter_recurse(&iter, &dict);
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+ break;
+
+ dbus_message_iter_get_basic(&entry, &key);
+
+ if (g_str_equal(key, "VPNC.IPSec.Secret")) {
+ dbus_message_iter_next(&entry);
+ if (dbus_message_iter_get_arg_type(&entry)
+ != DBUS_TYPE_VARIANT)
+ break;
+ dbus_message_iter_recurse(&entry, &value);
+ if (dbus_message_iter_get_arg_type(&value)
+ != DBUS_TYPE_STRING)
+ break;
+ dbus_message_iter_get_basic(&value, &secret);
+ vpn_provider_set_string_hide_value(data->provider,
+ key, secret);
+
+ } else if (g_str_equal(key, "VPNC.Xauth.Username")) {
+ dbus_message_iter_next(&entry);
+ if (dbus_message_iter_get_arg_type(&entry)
+ != DBUS_TYPE_VARIANT)
+ break;
+ dbus_message_iter_recurse(&entry, &value);
+ if (dbus_message_iter_get_arg_type(&value)
+ != DBUS_TYPE_STRING)
+ break;
+ dbus_message_iter_get_basic(&value, &username);
+ vpn_provider_set_string(data->provider, key, username);
+
+ } else if (g_str_equal(key, "VPNC.Xauth.Password")) {
+ dbus_message_iter_next(&entry);
+ if (dbus_message_iter_get_arg_type(&entry)
+ != DBUS_TYPE_VARIANT)
+ break;
+ dbus_message_iter_recurse(&entry, &value);
+ if (dbus_message_iter_get_arg_type(&value)
+ != DBUS_TYPE_STRING)
+ break;
+ dbus_message_iter_get_basic(&value, &password);
+ vpn_provider_set_string_hide_value(data->provider, key,
+ password);
+ }
+
+ dbus_message_iter_next(&dict);
+ }
+
+ if (!secret || !username || !password) {
+ vpn_provider_indicate_error(data->provider,
+ VPN_PROVIDER_ERROR_AUTH_FAILED);
+ err = EACCES;
+ goto err;
+ }
+
+ /* vpn_provider.c:connect_cb() expects positive errors */
+ err = -run_connect(data);
+ if (err != EINPROGRESS)
+ goto err;
+
+ return;
+
+err:
+ vc_connect_done(data, err);
+}
+
+static int request_input_credentials(struct vc_private_data *data,
+ const char* dbus_sender)
+{
+ DBusMessage *message;
+ const char *path, *agent_sender, *agent_path;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ int err;
+ void *agent;
+
+ if (!data || !data->provider)
+ return -ENOENT;
+
+ DBG("data %p provider %p sender %s", data, data->provider, dbus_sender);
+
+ agent = connman_agent_get_info(dbus_sender, &agent_sender, &agent_path);
+ if (!agent || !agent_path)
+ return -ESRCH;
+
+ message = dbus_message_new_method_call(agent_sender, agent_path,
+ VPN_AGENT_INTERFACE,
+ "RequestInput");
+ if (!message)
+ return -ENOMEM;
+
+ dbus_message_iter_init_append(message, &iter);
+
+ path = vpn_provider_get_path(data->provider);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
+
+ connman_dbus_dict_open(&iter, &dict);
+
+ if (vpn_provider_get_authentication_errors(data->provider))
+ vpn_agent_append_auth_failure(&dict, data->provider, NULL);
+
+ request_input_append_to_dict(data->provider, &dict,
+ request_input_append_password,
+ "VPNC.IPSec.Secret");
+ request_input_append_to_dict(data->provider, &dict,
+ request_input_append_mandatory,
+ "VPNC.Xauth.Username");
+ request_input_append_to_dict(data->provider, &dict,
+ request_input_append_password,
+ "VPNC.Xauth.Password");
+
+ vpn_agent_append_host_and_name(&dict, data->provider);
+
+ connman_dbus_dict_close(&iter, &dict);
+
+ err = connman_agent_queue_message(data->provider, message,
+ connman_timeout_input_request(),
+ request_input_credentials_reply, data, agent);
+
+ dbus_message_unref(message);
+
+ if (err < 0 && err != -EBUSY) {
+ DBG("error %d sending agent request", err);
+ return err;
+ }
+
+ return -EINPROGRESS;
+}
+
+static int vc_connect(struct vpn_provider *provider,
+ struct connman_task *task, const char *if_name,
+ vpn_provider_connect_cb_t cb, const char *dbus_sender,
+ void *user_data)
+{
+ struct vc_private_data *data;
+ const char *option;
+ bool username_set = false;
+ bool password_set = false;
+ bool ipsec_secret_set = false;
+ int err;
+
+ DBG("provider %p if_name %s user_data %p", provider, if_name, user_data);
+
+ option = vpn_provider_get_string(provider, "VPNC.IPSec.ID");
+ if (!option) {
+ connman_error("Group not set; cannot enable VPN");
+ return -EINVAL;
+ }
+
+ option = vpn_provider_get_string(provider, "VPNC.IPSec.Secret");
+ if (option && *option && g_strcmp0(option, "-"))
+ ipsec_secret_set = true;
+
+ option = vpn_provider_get_string(provider, "VPNC.Xauth.Username");
+ if (option && *option && g_strcmp0(option, "-"))
+ username_set = true;
+
+ option = vpn_provider_get_string(provider, "VPNC.Xauth.Password");
+ if (option && *option && g_strcmp0(option, "-"))
+ password_set = true;
+
+ data = g_try_new0(struct vc_private_data, 1);
+ if (!data)
+ return -ENOMEM;
+
+ vpn_provider_set_plugin_data(provider, data);
+ data->provider = vpn_provider_ref(provider);
+ data->task = task;
+ data->if_name = g_strdup(if_name);
+ data->cb = cb;
+ data->user_data = user_data;
+
+ if (!ipsec_secret_set || !username_set || !password_set) {
+ err = request_input_credentials(data, dbus_sender);
+ if (err != -EINPROGRESS) {
+ vc_connect_done(data, ECONNABORTED);
+ vpn_provider_indicate_error(data->provider,
+ VPN_PROVIDER_ERROR_LOGIN_FAILED);
+ free_private_data(data);
+ }
+
+ return err;
+ }
+
+ return run_connect(data);
+}
+
+static void vc_disconnect(struct vpn_provider *provider)
+{
+ if (!provider)
+ return;
+
+ connman_agent_cancel(provider);
+}
+
static int vc_error_code(struct vpn_provider *provider, int exit_code)
{
switch (exit_code) {
@@ -361,6 +928,7 @@ static int vc_device_flags(struct vpn_provider *provider)
static struct vpn_driver vpn_driver = {
.notify = vc_notify,
.connect = vc_connect,
+ .disconnect = vc_disconnect,
.error_code = vc_error_code,
.save = vc_save,
.device_flags = vc_device_flags,
@@ -368,16 +936,12 @@ static struct vpn_driver vpn_driver = {
static int vpnc_init(void)
{
- connection = connman_dbus_get_connection();
-
return vpn_register("vpnc", &vpn_driver, VPNC);
}
static void vpnc_exit(void)
{
vpn_unregister("vpnc");
-
- dbus_connection_unref(connection);
}
CONNMAN_PLUGIN_DEFINE(vpnc, "vpnc plugin", VERSION,
diff --git a/vpn/plugins/wireguard.c b/vpn/plugins/wireguard.c
new file mode 100644
index 00000000..6ec18eb4
--- /dev/null
+++ b/vpn/plugins/wireguard.c
@@ -0,0 +1,794 @@
+/*
+ * ConnMan VPN daemon
+ *
+ * Copyright (C) 2019 Daniel Wagner. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include <glib.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/log.h>
+#include <connman/task.h>
+#include <connman/ipconfig.h>
+#include <connman/inet.h>
+#include <connman/dbus.h>
+#include <connman/setting.h>
+#include <connman/vpn-dbus.h>
+
+#include "../vpn-provider.h"
+#include "../vpn.h"
+
+#include "vpn.h"
+#include "wireguard.h"
+
+#define DNS_RERESOLVE_TIMEOUT 20
+#if defined TIZEN_EXT
+#define ADD_ALLOWED_IP_ROUTE_TIMEOUT 2
+#endif /* TIZEN_EXT */
+
+struct wireguard_info {
+ struct wg_device device;
+ struct wg_peer peer;
+ char *endpoint_fqdn;
+ char *port;
+ int reresolve_id;
+#if defined TIZEN_EXT
+ int allowed_ip_route_id;
+#endif /* TIZEN_EXT */
+};
+
+struct sockaddr_u {
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ };
+};
+
+static int parse_key(const char *str, wg_key key)
+{
+ unsigned char *buf;
+ size_t len;
+
+ buf = g_base64_decode(str, &len);
+
+ if (len != 32) {
+ g_free(buf);
+ return -EINVAL;
+ }
+
+ memcpy(key, buf, 32);
+
+ g_free(buf);
+ return 0;
+}
+
+static int parse_allowed_ips(const char *allowed_ips, wg_peer *peer)
+{
+ struct wg_allowedip *curaip, *allowedip;
+ char buf[INET6_ADDRSTRLEN];
+ char **tokens, **toks;
+ char *send;
+ int i;
+
+ curaip = NULL;
+#if defined TIZEN_EXT
+ /**
+ * Note: At API level we donot check Wireguard specific configurations,
+ * User can provide any space separated string for IP.
+ * Ideally it should be using "10.0.0.2/32, 10.0.0.3/32"
+ * However there can be cases like "10.0.0.2/32,10.0.0.3/32"
+ *
+ * So we need to parse the allowed_ips configuration properly.
+ */
+ tokens = g_strsplit(allowed_ips, ",", -1);
+#else
+ tokens = g_strsplit(allowed_ips, ", ", -1);
+#endif
+ for (i = 0; tokens[i]; i++) {
+#if defined TIZEN_EXT
+ int len = strlen(tokens[i]);
+ char *ptr = tokens[i];
+ int j = -1;
+
+ //skip forward spaces
+ while (++j < len && ptr[j] == ' ')
+ ;// Do Nothing
+
+ if (!ptr[j])
+ continue;
+
+ toks = g_strsplit(ptr + j, "/", -1);
+ if (g_strv_length(toks) != 2) {
+ DBG("Ignore AllowedIPs value [%s]", ptr + j);
+ g_strfreev(toks);
+ continue;
+ }
+
+ DBG("Parsed AllowedIPs [%s]", ptr + j);
+#else
+
+ toks = g_strsplit(tokens[i], "/", -1);
+ if (g_strv_length(toks) != 2) {
+ DBG("Ignore AllowedIPs value %s", tokens[i]);
+ g_strfreev(toks);
+ continue;
+ }
+#endif
+
+ allowedip = g_malloc0(sizeof(*allowedip));
+
+ if (inet_pton(AF_INET, toks[0], buf) == 1) {
+ allowedip->family = AF_INET;
+ memcpy(&allowedip->ip4, buf, sizeof(allowedip->ip4));
+ } else if (inet_pton(AF_INET6, toks[0], buf) == 1) {
+ allowedip->family = AF_INET6;
+ memcpy(&allowedip->ip6, buf, sizeof(allowedip->ip6));
+ } else {
+#if defined TIZEN_EXT
+ DBG("Ignore AllowedIPs value [%s]", ptr + j);
+#else
+ DBG("Ignore AllowedIPs value %s", tokens[i]);
+#endif
+ g_free(allowedip);
+ g_strfreev(toks);
+ continue;
+ }
+
+ allowedip->cidr = g_ascii_strtoull(toks[1], &send, 10);
+
+ if (!curaip)
+ peer->first_allowedip = allowedip;
+ else
+ curaip->next_allowedip = allowedip;
+
+ curaip = allowedip;
+#if defined TIZEN_EXT
+ g_strfreev(toks);
+#endif
+ }
+
+ peer->last_allowedip = curaip;
+ g_strfreev(tokens);
+
+ return 0;
+}
+
+static int parse_endpoint(const char *host, const char *port, struct sockaddr_u *addr)
+{
+ struct addrinfo hints;
+ struct addrinfo *result, *rp;
+ int sk;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = 0;
+ hints.ai_protocol = 0;
+
+ if (getaddrinfo(host, port, &hints, &result) < 0) {
+ DBG("Failed to resolve host address");
+ return -EINVAL;
+ }
+
+ for (rp = result; rp; rp = rp->ai_next) {
+ sk = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+ if (sk < 0)
+ continue;
+ if (connect(sk, rp->ai_addr, rp->ai_addrlen) != -1) {
+ /* success */
+ close(sk);
+ break;
+ }
+
+ close(sk);
+ }
+
+ if (!rp) {
+ freeaddrinfo(result);
+ return -EINVAL;
+ }
+
+ memcpy(addr, rp->ai_addr, rp->ai_addrlen);
+ freeaddrinfo(result);
+
+ return 0;
+}
+
+static int parse_address(const char *address, const char *gateway,
+ struct connman_ipaddress **ipaddress)
+{
+ char buf[INET6_ADDRSTRLEN];
+ unsigned char prefixlen;
+ char **tokens;
+ char *end, *netmask;
+ int err;
+
+ tokens = g_strsplit(address, "/", -1);
+ if (g_strv_length(tokens) != 2) {
+ g_strfreev(tokens);
+ return -EINVAL;
+ }
+
+ prefixlen = g_ascii_strtoull(tokens[1], &end, 10);
+
+ if (inet_pton(AF_INET, tokens[0], buf) == 1) {
+ netmask = g_strdup_printf("%d.%d.%d.%d",
+ ((0xffffffff << (32 - prefixlen)) >> 24) & 0xff,
+ ((0xffffffff << (32 - prefixlen)) >> 16) & 0xff,
+ ((0xffffffff << (32 - prefixlen)) >> 8) & 0xff,
+ ((0xffffffff << (32 - prefixlen)) >> 0) & 0xff);
+
+ *ipaddress = connman_ipaddress_alloc(AF_INET);
+ err = connman_ipaddress_set_ipv4(*ipaddress, tokens[0],
+ netmask, gateway);
+ g_free(netmask);
+ } else if (inet_pton(AF_INET6, tokens[0], buf) == 1) {
+ *ipaddress = connman_ipaddress_alloc(AF_INET6);
+ err = connman_ipaddress_set_ipv6(*ipaddress, tokens[0],
+ prefixlen, gateway);
+ } else {
+ DBG("Invalid Wireguard.Address value");
+ err = -EINVAL;
+ }
+
+ connman_ipaddress_set_p2p(*ipaddress, true);
+
+ g_strfreev(tokens);
+ if (err)
+ connman_ipaddress_free(*ipaddress);
+
+ return err;
+}
+
+struct ifname_data {
+ char *ifname;
+ bool found;
+};
+
+static void ifname_check_cb(int index, void *user_data)
+{
+ struct ifname_data *data = (struct ifname_data *)user_data;
+ char *ifname;
+
+ ifname = connman_inet_ifname(index);
+
+ if (!g_strcmp0(ifname, data->ifname))
+ data->found = true;
+}
+
+static char *get_ifname(void)
+{
+ struct ifname_data data;
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ data.ifname = g_strdup_printf("wg%d", i);
+ data.found = false;
+ vpn_ipconfig_foreach(ifname_check_cb, &data);
+
+ if (!data.found)
+ return data.ifname;
+
+ g_free(data.ifname);
+ }
+
+ return NULL;
+}
+
+static bool sockaddr_cmp_addr(struct sockaddr_u *a, struct sockaddr_u *b)
+{
+ if (a->sa.sa_family != b->sa.sa_family)
+ return false;
+
+ if (a->sa.sa_family == AF_INET)
+ return !memcmp(&a->sin, &b->sin, sizeof(struct sockaddr_in));
+ else if (a->sa.sa_family == AF_INET6)
+ return !memcmp(a->sin6.sin6_addr.s6_addr,
+ b->sin6.sin6_addr.s6_addr,
+ sizeof(a->sin6.sin6_addr.s6_addr));
+
+ return false;
+}
+
+#if defined TIZEN_EXT
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdio.h>
+
+#define MAX_SIZE_ERROR_BUFFER 256
+#define MAX_CMD_SIZE 80
+
+typedef struct {
+ struct vpn_provider *provider;
+ struct wireguard_info *info;
+} wg_allowed_ip_route_cb_data_s;
+
+static int wg_execute_cmd(const char *format, ...)
+{
+ int status = 0;
+ int rv = 0;
+ char cmd[MAX_CMD_SIZE] = { 0, };
+ char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, };
+ pid_t pid = 0;
+ va_list va_ptr;
+ gchar **args = NULL;
+
+ va_start(va_ptr, format);
+ vsnprintf(cmd, (unsigned int) MAX_CMD_SIZE, format, va_ptr);
+ va_end(va_ptr);
+
+ if (strlen(cmd) == 0)
+ return -EIO;
+
+ DBG("command: %s", cmd);
+
+ args = g_strsplit_set(cmd, " ", -1);
+
+ errno = 0;
+ if (!(pid = fork())) {
+ DBG("pid(%d), ppid (%d)", getpid(), getppid());
+
+ errno = 0;
+ if (execv(args[0], args) == -1) {
+ DBG("Fail to execute command (%s)",
+ strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER));
+ g_strfreev(args);
+ exit(1);
+ }
+ } else if (pid > 0) {
+ if (waitpid(pid, &status, 0) == -1)
+ DBG("wait pid (%u) status (%d)", pid, status);
+
+ if (WIFEXITED(status)) {
+ rv = WEXITSTATUS(status);
+ DBG("exited, status=%d", rv);
+
+ } else if (WIFSIGNALED(status)) {
+ DBG("killed by signal %d", WTERMSIG(status));
+
+ } else if (WIFSTOPPED(status)) {
+ DBG("stopped by signal %d", WSTOPSIG(status));
+
+ } else if (WIFCONTINUED(status)) {
+ DBG("continued");
+ }
+
+ g_strfreev(args);
+ return rv;
+ }
+
+ DBG("failed to fork(%s)", strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER));
+ g_strfreev(args);
+
+ return -EIO;
+}
+
+static gboolean wg_add_allowed_ip_route_cb(gpointer user_data)
+{
+ wg_allowed_ip_route_cb_data_s *cb_data = user_data;
+ const char *allowed_ips;
+ char **tokens = NULL;
+ char **toks = NULL;
+ int i;
+
+ DBG("");
+
+ allowed_ips = vpn_provider_get_string(cb_data->provider, "WireGuard.AllowedIPs");
+ if (!allowed_ips) {
+ DBG("WireGuard.AllowedIPs is missing");
+ goto done;
+ }
+
+ tokens = g_strsplit(allowed_ips, ",", -1);
+ if (g_strv_length(tokens) == 0)
+ goto done;
+
+ for (i = 0; tokens[i]; i++) {
+ int len = strlen(tokens[i]);
+ char *ptr = tokens[i];
+ int j = -1;
+
+ //skip forward spaces
+ while (++j < len && ptr[j] == ' ')
+ ;// Do Nothing
+
+ if (!ptr[j])
+ continue;
+
+ toks = g_strsplit(ptr + j, "/", -1);
+ if (g_strv_length(toks) != 2) {
+ DBG("Ignore AllowedIPs value [%s]", ptr + j);
+ g_strfreev(toks);
+ continue;
+ }
+ g_strfreev(toks);
+
+ DBG("Allowed IP: [%s], Device Name: [%s]", ptr + j, cb_data->info->device.name);
+
+ // TODO: Remove system call to add route entry present in wg_execute_cmd()
+ if (!g_strcmp0("0.0.0.0/0", ptr + j)) {
+ // TODO: Update default route because user wants all data to be routed from wg0,
+ // when 0.0.0.0/0 is passed in allowed ips list.
+ // Should we replace the default route?
+ // If yes, then how to recover default route when wg0 tunnel is removed.
+ } else {
+ wg_execute_cmd("/usr/sbin/ip route add %s dev %s", ptr + j, cb_data->info->device.name);
+ }
+ }
+
+done:
+ if (tokens)
+ g_strfreev(tokens);
+
+ free(cb_data);
+
+ return FALSE;
+}
+#endif /* TIZEN_EXT */
+
+static gboolean wg_dns_reresolve_cb(gpointer user_data)
+{
+ struct wireguard_info *info = user_data;
+ struct sockaddr_u addr;
+ int err;
+
+ DBG("");
+
+ err = parse_endpoint(info->endpoint_fqdn,
+ info->port, &addr);
+ if (err)
+ return TRUE;
+
+ if (sockaddr_cmp_addr(&addr,
+ (struct sockaddr_u *)&info->peer.endpoint.addr))
+ return TRUE;
+
+ if (addr.sa.sa_family == AF_INET)
+ memcpy(&info->peer.endpoint.addr, &addr.sin,
+ sizeof(info->peer.endpoint.addr4));
+ else
+ memcpy(&info->peer.endpoint.addr, &addr.sin6,
+ sizeof(info->peer.endpoint.addr6));
+
+ DBG("Endpoint address has changed, udpate WireGuard device");
+ err = wg_set_device(&info->device);
+ if (err)
+ DBG("Failed to update Endpoint address for WireGuard device %s",
+ info->device.name);
+
+ return TRUE;
+}
+
+static int wg_connect(struct vpn_provider *provider,
+ struct connman_task *task, const char *if_name,
+ vpn_provider_connect_cb_t cb,
+ const char *dbus_sender, void *user_data)
+{
+ struct connman_ipaddress *ipaddress = NULL;
+ struct wireguard_info *info;
+ const char *option, *gateway;
+ char *ifname;
+ int err = -EINVAL;
+
+ info = g_malloc0(sizeof(struct wireguard_info));
+ info->peer.flags = WGPEER_HAS_PUBLIC_KEY | WGPEER_REPLACE_ALLOWEDIPS;
+ info->device.flags = WGDEVICE_HAS_PRIVATE_KEY;
+ info->device.first_peer = &info->peer;
+ info->device.last_peer = &info->peer;
+
+ vpn_provider_set_plugin_data(provider, info);
+
+ option = vpn_provider_get_string(provider, "WireGuard.ListenPort");
+ if (option) {
+ char *end;
+ info->device.listen_port = g_ascii_strtoull(option, &end, 10);
+ info->device.flags |= WGDEVICE_HAS_LISTEN_PORT;
+ }
+
+ option = vpn_provider_get_string(provider, "WireGuard.DNS");
+ if (option) {
+ err = vpn_provider_set_nameservers(provider, option);
+ if (err)
+ goto done;
+ }
+
+ option = vpn_provider_get_string(provider, "WireGuard.PrivateKey");
+ if (!option) {
+ DBG("WireGuard.PrivateKey is missing");
+ goto done;
+ }
+ err = parse_key(option, info->device.private_key);
+ if (err)
+ goto done;
+
+ option = vpn_provider_get_string(provider, "WireGuard.PublicKey");
+ if (!option) {
+ DBG("WireGuard.PublicKey is missing");
+ goto done;
+ }
+ err = parse_key(option, info->peer.public_key);
+ if (err)
+ goto done;
+
+ option = vpn_provider_get_string(provider, "WireGuard.PresharedKey");
+ if (option) {
+ info->peer.flags |= WGPEER_HAS_PRESHARED_KEY;
+ err = parse_key(option, info->peer.preshared_key);
+ if (err)
+ goto done;
+ }
+
+ option = vpn_provider_get_string(provider, "WireGuard.AllowedIPs");
+ if (!option) {
+ DBG("WireGuard.AllowedIPs is missing");
+ goto done;
+ }
+ err = parse_allowed_ips(option, &info->peer);
+ if (err)
+ goto done;
+
+ option = vpn_provider_get_string(provider,
+ "WireGuard.PersistentKeepalive");
+ if (option) {
+ char *end;
+ info->peer.persistent_keepalive_interval =
+ g_ascii_strtoull(option, &end, 10);
+ info->peer.flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL;
+ }
+
+ option = vpn_provider_get_string(provider, "WireGuard.EndpointPort");
+ if (!option)
+ option = "51820";
+
+ gateway = vpn_provider_get_string(provider, "Host");
+ err = parse_endpoint(gateway, option,
+ (struct sockaddr_u *)&info->peer.endpoint.addr);
+ if (err)
+ goto done;
+
+ info->endpoint_fqdn = g_strdup(gateway);
+ info->port = g_strdup(option);
+
+ option = vpn_provider_get_string(provider, "WireGuard.Address");
+ if (!option) {
+ DBG("Missing WireGuard.Address configuration");
+ goto done;
+ }
+ err = parse_address(option, gateway, &ipaddress);
+ if (err)
+ goto done;
+
+ ifname = get_ifname();
+ if (!ifname) {
+ DBG("Failed to find an usable device name");
+ err = -ENOENT;
+ goto done;
+ }
+ stpncpy(info->device.name, ifname, sizeof(info->device.name) - 1);
+ g_free(ifname);
+
+ err = wg_add_device(info->device.name);
+ if (err) {
+ DBG("Failed to creating WireGuard device %s", info->device.name);
+ goto done;
+ }
+
+ err = wg_set_device(&info->device);
+ if (err) {
+ DBG("Failed to configure WireGuard device %s", info->device.name);
+ wg_del_device(info->device.name);
+ }
+
+ vpn_set_ifname(provider, info->device.name);
+ if (ipaddress)
+ vpn_provider_set_ipaddress(provider, ipaddress);
+
+done:
+ if (cb)
+ cb(provider, user_data, err);
+
+ connman_ipaddress_free(ipaddress);
+
+#if defined TIZEN_EXT
+ if (!err) {
+ const char *allowed_ips = vpn_provider_get_string(provider, "WireGuard.AllowedIPs");
+ if (allowed_ips) {
+ wg_allowed_ip_route_cb_data_s *cb_data =
+ (wg_allowed_ip_route_cb_data_s *) calloc(1, sizeof(wg_allowed_ip_route_cb_data_s));
+ if (cb_data) {
+ cb_data->provider = provider;
+ cb_data->info = info;
+
+ info->allowed_ip_route_id =
+ g_timeout_add_seconds(ADD_ALLOWED_IP_ROUTE_TIMEOUT,
+ wg_add_allowed_ip_route_cb, cb_data);
+ }
+ }
+ }
+#endif /* TIZEN_EXT */
+
+ if (!err)
+ info->reresolve_id =
+ g_timeout_add_seconds(DNS_RERESOLVE_TIMEOUT,
+ wg_dns_reresolve_cb, info);
+
+ return err;
+}
+
+static void wg_disconnect(struct vpn_provider *provider)
+{
+ struct wireguard_info *info;
+
+ info = vpn_provider_get_plugin_data(provider);
+ if (!info)
+ return;
+
+#if defined TIZEN_EXT
+ if (info->allowed_ip_route_id > 0)
+ g_source_remove(info->allowed_ip_route_id);
+#endif /* TIZEN_EXT */
+
+ if (info->reresolve_id > 0)
+ g_source_remove(info->reresolve_id);
+
+ vpn_provider_set_plugin_data(provider, NULL);
+
+ wg_del_device(info->device.name);
+
+ g_free(info->endpoint_fqdn);
+ g_free(info->port);
+ g_free(info);
+}
+
+#if defined TIZEN_EXT
+static int wg_save(struct vpn_provider *provider, GKeyFile *keyfile)
+{
+ const char *option;
+
+ DBG("");
+
+ /*
+ * The client/own device listen port.
+ */
+ option = vpn_provider_get_string(provider, "WireGuard.ListenPort");
+ if (option)
+ g_key_file_set_string(keyfile,
+ vpn_provider_get_save_group(provider),
+ "WireGuard.ListenPort",
+ option);
+
+ /*
+ * comma separated DNS.
+ */
+ option = vpn_provider_get_string(provider, "WireGuard.DNS");
+ if (option)
+ g_key_file_set_string(keyfile,
+ vpn_provider_get_save_group(provider),
+ "WireGuard.DNS",
+ option);
+
+ /*
+ * The client private key.
+ */
+ option = vpn_provider_get_string(provider, "WireGuard.PrivateKey");
+ if (option)
+ g_key_file_set_string(keyfile,
+ vpn_provider_get_save_group(provider),
+ "WireGuard.PrivateKey",
+ option);
+
+ /*
+ * The server public key.
+ */
+ option = vpn_provider_get_string(provider, "WireGuard.PublicKey");
+ if (option)
+ g_key_file_set_string(keyfile,
+ vpn_provider_get_save_group(provider),
+ "WireGuard.PublicKey",
+ option);
+
+ /*
+ * The preshared key.
+ */
+ option = vpn_provider_get_string(provider, "WireGuard.PresharedKey");
+ if (option)
+ g_key_file_set_string(keyfile,
+ vpn_provider_get_save_group(provider),
+ "WireGuard.PresharedKey",
+ option);
+
+ /*
+ * Subnets accessed via VPN tunnel, 0.0.0.0/0 routes all traffic.
+ */
+ option = vpn_provider_get_string(provider, "WireGuard.AllowedIPs");
+ if (option)
+ g_key_file_set_string(keyfile,
+ vpn_provider_get_save_group(provider),
+ "WireGuard.AllowedIPs",
+ option);
+
+ /*
+ * The time in seconds to emit periodic keep alive message.
+ */
+ option = vpn_provider_get_string(provider, "WireGuard.PersistentKeepalive");
+ if (option)
+ g_key_file_set_string(keyfile,
+ vpn_provider_get_save_group(provider),
+ "WireGuard.PersistentKeepalive",
+ option);
+
+ /*
+ * The server listen port, default: 51820
+ */
+ option = vpn_provider_get_string(provider, "WireGuard.EndpointPort");
+ if (option)
+ g_key_file_set_string(keyfile,
+ vpn_provider_get_save_group(provider),
+ "WireGuard.EndpointPort",
+ option);
+
+ /*
+ * Save Address: The internal IP of the client node
+ */
+ option = vpn_provider_get_string(provider, "WireGuard.Address");
+ if (option)
+ g_key_file_set_string(keyfile,
+ vpn_provider_get_save_group(provider),
+ "WireGuard.Address",
+ option);
+
+ return 0;
+}
+#endif
+
+static struct vpn_driver vpn_driver = {
+ .flags = VPN_FLAG_NO_TUN | VPN_FLAG_NO_DAEMON,
+ .connect = wg_connect,
+ .disconnect = wg_disconnect,
+#if defined TIZEN_EXT
+ .save = wg_save,
+#endif
+};
+
+static int wg_init(void)
+{
+ return vpn_register("wireguard", &vpn_driver, NULL);
+}
+
+static void wg_exit(void)
+{
+ vpn_unregister("wireguard");
+}
+
+CONNMAN_PLUGIN_DEFINE(wireguard, "WireGuard VPN plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, wg_init, wg_exit)
diff --git a/vpn/plugins/wireguard.h b/vpn/plugins/wireguard.h
new file mode 100644
index 00000000..e7a1bbf0
--- /dev/null
+++ b/vpn/plugins/wireguard.h
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+/*
+ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ */
+
+#ifndef WIREGUARD_H
+#define WIREGUARD_H
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef uint8_t wg_key[32];
+typedef char wg_key_b64_string[((sizeof(wg_key) + 2) / 3) * 4 + 1];
+
+/* Cross platform __kernel_timespec */
+struct timespec64 {
+ int64_t tv_sec;
+ int64_t tv_nsec;
+};
+
+typedef struct wg_allowedip {
+ uint16_t family;
+ union {
+ struct in_addr ip4;
+ struct in6_addr ip6;
+ };
+ uint8_t cidr;
+ struct wg_allowedip *next_allowedip;
+} wg_allowedip;
+
+enum wg_peer_flags {
+ WGPEER_REMOVE_ME = 1U << 0,
+ WGPEER_REPLACE_ALLOWEDIPS = 1U << 1,
+ WGPEER_HAS_PUBLIC_KEY = 1U << 2,
+ WGPEER_HAS_PRESHARED_KEY = 1U << 3,
+ WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL = 1U << 4
+};
+
+typedef struct wg_peer {
+ enum wg_peer_flags flags;
+
+ wg_key public_key;
+ wg_key preshared_key;
+
+ union {
+ struct sockaddr addr;
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+ } endpoint;
+
+ struct timespec64 last_handshake_time;
+ uint64_t rx_bytes, tx_bytes;
+ uint16_t persistent_keepalive_interval;
+
+ struct wg_allowedip *first_allowedip, *last_allowedip;
+ struct wg_peer *next_peer;
+} wg_peer;
+
+enum wg_device_flags {
+ WGDEVICE_REPLACE_PEERS = 1U << 0,
+ WGDEVICE_HAS_PRIVATE_KEY = 1U << 1,
+ WGDEVICE_HAS_PUBLIC_KEY = 1U << 2,
+ WGDEVICE_HAS_LISTEN_PORT = 1U << 3,
+ WGDEVICE_HAS_FWMARK = 1U << 4
+};
+
+typedef struct wg_device {
+ char name[IFNAMSIZ];
+ uint32_t ifindex;
+
+ enum wg_device_flags flags;
+
+ wg_key public_key;
+ wg_key private_key;
+
+ uint32_t fwmark;
+ uint16_t listen_port;
+
+ struct wg_peer *first_peer, *last_peer;
+} wg_device;
+
+#define wg_for_each_device_name(__names, __name, __len) for ((__name) = (__names), (__len) = 0; ((__len) = strlen(__name)); (__name) += (__len) + 1)
+#define wg_for_each_peer(__dev, __peer) for ((__peer) = (__dev)->first_peer; (__peer); (__peer) = (__peer)->next_peer)
+#define wg_for_each_allowedip(__peer, __allowedip) for ((__allowedip) = (__peer)->first_allowedip; (__allowedip); (__allowedip) = (__allowedip)->next_allowedip)
+
+int wg_set_device(wg_device *dev);
+int wg_get_device(wg_device **dev, const char *device_name);
+int wg_add_device(const char *device_name);
+int wg_del_device(const char *device_name);
+void wg_free_device(wg_device *dev);
+char *wg_list_device_names(void); /* first\0second\0third\0forth\0last\0\0 */
+void wg_key_to_base64(wg_key_b64_string base64, const wg_key key);
+int wg_key_from_base64(wg_key key, const wg_key_b64_string base64);
+bool wg_key_is_zero(const wg_key key);
+void wg_generate_public_key(wg_key public_key, const wg_key private_key);
+void wg_generate_private_key(wg_key private_key);
+void wg_generate_preshared_key(wg_key preshared_key);
+
+#endif
diff --git a/vpn/vpn-agent.c b/vpn/vpn-agent.c
index b0b582b7..ab6fea55 100755
--- a/vpn/vpn-agent.c
+++ b/vpn/vpn-agent.c
@@ -3,6 +3,7 @@
* Connection Manager
*
* Copyright (C) 2012 Intel Corporation. All rights reserved.
+ * Copyright (C) 2019 Jolla Ltd. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -30,6 +31,8 @@
#include <gdbus.h>
#include <connman/log.h>
#include <connman/agent.h>
+#include <connman/vpn-dbus.h>
+#include <connman/task.h>
#include <vpn/vpn-provider.h>
#include "vpn-agent.h"
@@ -102,6 +105,7 @@ void vpn_agent_append_host_and_name(DBusMessageIter *iter,
struct user_info_data {
struct vpn_provider *provider;
const char *username_str;
+ const char *type_str;
};
static void request_input_append_user_info(DBusMessageIter *iter,
@@ -109,10 +113,10 @@ static void request_input_append_user_info(DBusMessageIter *iter,
{
struct user_info_data *data = user_data;
struct vpn_provider *provider = data->provider;
- const char *str = "string";
+ const char *str = NULL;
connman_dbus_dict_append_basic(iter, "Type",
- DBUS_TYPE_STRING, &str);
+ DBUS_TYPE_STRING, &data->type_str);
str = "mandatory";
connman_dbus_dict_append_basic(iter, "Requirement",
DBUS_TYPE_STRING, &str);
@@ -134,12 +138,150 @@ void vpn_agent_append_user_info(DBusMessageIter *iter,
.username_str = username_str
};
+ data.type_str = "string";
connman_dbus_dict_append_dict(iter, "Username",
request_input_append_user_info,
&data);
data.username_str = NULL;
+ data.type_str = "password";
connman_dbus_dict_append_dict(iter, "Password",
request_input_append_user_info,
&data);
}
+
+static void request_input_append_flag(DBusMessageIter *iter,
+ void *user_data)
+{
+ dbus_bool_t data = (dbus_bool_t)GPOINTER_TO_INT(user_data);
+ const char *str = NULL;
+
+ str = "boolean";
+ connman_dbus_dict_append_basic(iter, "Type",
+ DBUS_TYPE_STRING, &str);
+
+ str = "control";
+ connman_dbus_dict_append_basic(iter, "Requirement",
+ DBUS_TYPE_STRING, &str);
+
+ connman_dbus_dict_append_basic(iter, "Value",
+ DBUS_TYPE_BOOLEAN, &data);
+}
+
+void vpn_agent_append_allow_credential_storage(DBusMessageIter *iter,
+ bool allow)
+{
+ connman_dbus_dict_append_dict(iter, "AllowStoreCredentials",
+ request_input_append_flag,
+ GINT_TO_POINTER(allow));
+}
+
+void vpn_agent_append_allow_credential_retrieval(DBusMessageIter *iter,
+ bool allow)
+{
+ connman_dbus_dict_append_dict(iter, "AllowRetrieveCredentials",
+ request_input_append_flag,
+ GINT_TO_POINTER(allow));
+}
+
+void vpn_agent_append_keep_credentials(DBusMessageIter *iter, bool allow)
+{
+ connman_dbus_dict_append_dict(iter, "KeepCredentials",
+ request_input_append_flag,
+ GINT_TO_POINTER(allow));
+}
+
+struct failure_data {
+ struct vpn_provider *provider;
+ const char* type_str;
+ const char *key;
+ const char* str;
+};
+
+static void request_input_append_failure(DBusMessageIter *iter,
+ void *user_data)
+{
+ struct failure_data *data;
+ const char *str;
+
+ data = user_data;
+
+ connman_dbus_dict_append_basic(iter, "Type",
+ DBUS_TYPE_STRING, &data->type_str);
+ str = "informational";
+ connman_dbus_dict_append_basic(iter, "Requirement",
+ DBUS_TYPE_STRING, &str);
+
+ str = data->str;
+
+ /* Try to get information from provider about error */
+ if (!str)
+ str = vpn_provider_get_string(data->provider, data->key);
+
+ if (str)
+ connman_dbus_dict_append_basic(iter, "Value",
+ DBUS_TYPE_STRING, &str);
+}
+
+void vpn_agent_append_auth_failure(DBusMessageIter *iter,
+ struct vpn_provider *provider,
+ const char* information)
+{
+ struct failure_data data;
+ unsigned int value;
+
+ /* Skip if there are no auth errors */
+ value = vpn_provider_get_authentication_errors(provider);
+ if (!value)
+ return;
+
+ data.provider = provider;
+ data.type_str = "string";
+ data.key = "VpnAgent.AuthFailure";
+ data.str = information;
+
+ connman_dbus_dict_append_dict(iter, data.key,
+ request_input_append_failure, &data);
+}
+
+int vpn_agent_check_and_process_reply_error(DBusMessage *reply,
+ struct vpn_provider *provider,
+ struct connman_task *task,
+ vpn_provider_connect_cb_t cb, void *user_data)
+{
+ DBusError error;
+ int err;
+
+ if (!reply || !provider)
+ return EINVAL;
+
+ dbus_error_init(&error);
+
+ if (!dbus_set_error_from_message(&error, reply))
+ return 0;
+
+ if (!g_strcmp0(error.name, VPN_AGENT_INTERFACE ".Error.Canceled"))
+ err = ECANCELED;
+ else if (!g_strcmp0(error.name, "org.freedesktop.DBus.Error.Timeout"))
+ err = ETIMEDOUT;
+ else if (!g_strcmp0(error.name, "org.freedesktop.DBus.Error.NoReply"))
+ err = ENOMSG;
+ else
+ err = EACCES;
+
+ dbus_error_free(&error);
+
+ if (cb)
+ cb(provider, user_data, err);
+
+ if (task)
+ connman_task_stop(task);
+
+ /*
+ * VPN agent dialog cancel, timeout, broken connection should set the
+ * VPN back to idle state
+ */
+ vpn_provider_set_state(provider, VPN_PROVIDER_STATE_IDLE);
+
+ return err;
+}
diff --git a/vpn/vpn-agent.h b/vpn/vpn-agent.h
index c7328d7f..dc797665 100755
--- a/vpn/vpn-agent.h
+++ b/vpn/vpn-agent.h
@@ -38,6 +38,18 @@ bool vpn_agent_check_reply_has_dict(DBusMessage *reply);
void vpn_agent_append_user_info(DBusMessageIter *iter,
struct vpn_provider *provider,
const char *username_str);
+void vpn_agent_append_allow_credential_storage(DBusMessageIter *iter,
+ bool allow);
+void vpn_agent_append_allow_credential_retrieval(DBusMessageIter *iter,
+ bool allow);
+void vpn_agent_append_keep_credentials(DBusMessageIter *iter, bool allow);
+void vpn_agent_append_auth_failure(DBusMessageIter *iter,
+ struct vpn_provider *provider,
+ const char *information);
+int vpn_agent_check_and_process_reply_error(DBusMessage *reply,
+ struct vpn_provider *provider,
+ struct connman_task *task,
+ vpn_provider_connect_cb_t cb, void *user_data);
#ifdef __cplusplus
}
diff --git a/vpn/vpn-config.c b/vpn/vpn-config.c
index 5f0e749a..e412b89c 100755
--- a/vpn/vpn-config.c
+++ b/vpn/vpn-config.c
@@ -234,11 +234,11 @@ static int load_provider(GKeyFile *keyfile, const char *group,
host = get_string(config_provider, "Host");
domain = get_string(config_provider, "Domain");
#if !defined TIZEN_EXT
- if (host && domain) {
+ if (host) {
char *id = __vpn_provider_create_identifier(host, domain);
#else
name = get_string(config_provider, "Name");
- if (host && domain && name) {
+ if (host && name) {
char *id = __vpn_provider_create_identifier(host, domain, name);
#endif
@@ -265,7 +265,7 @@ static int load_provider(GKeyFile *keyfile, const char *group,
#if !defined TIZEN_EXT
DBG("invalid values host %s domain %s", host, domain);
#else
- DBG("invalid values host %s domain %s name %s", host, domain, name);
+ DBG("invalid configuration: no host specified");
#endif
err = -EINVAL;
goto err;
@@ -275,9 +275,6 @@ static int load_provider(GKeyFile *keyfile, const char *group,
config_provider->config_entry = g_strdup_printf("provider_%s",
config_provider->ident);
- g_hash_table_insert(config->provider_table,
- config_provider->ident, config_provider);
-
err = __vpn_provider_create_from_config(
config_provider->setting_strings,
config_provider->config_ident,
@@ -288,6 +285,10 @@ static int load_provider(GKeyFile *keyfile, const char *group,
goto err;
}
+ g_hash_table_insert(config->provider_table, config_provider->ident,
+ config_provider);
+
+
connman_info("Added provider configuration %s",
config_provider->ident);
return 0;
@@ -593,3 +594,18 @@ char **__vpn_config_get_string_list(GKeyFile *key_file,
return strlist;
}
+
+bool __vpn_config_get_boolean(GKeyFile *key_file, const char *group_name,
+ const char *key, bool default_value)
+{
+ GError *error = NULL;
+ bool val;
+
+ val = g_key_file_get_boolean(key_file, group_name, key, &error);
+ if (error) {
+ g_error_free(error);
+ return default_value;
+ }
+
+ return val;
+}
diff --git a/vpn/vpn-ipconfig.c b/vpn/vpn-ipconfig.c
index c096fa37..825b43c4 100755
--- a/vpn/vpn-ipconfig.c
+++ b/vpn/vpn-ipconfig.c
@@ -108,7 +108,7 @@ unsigned int __vpn_ipconfig_get_flags_from_index(int index)
return ipdevice->flags;
}
-void __vpn_ipconfig_foreach(void (*function) (int index,
+void vpn_ipconfig_foreach(void (*function) (int index,
void *user_data), void *user_data)
{
GList *list, *keys;
@@ -211,7 +211,7 @@ int __vpn_ipconfig_address_add(struct vpn_ipconfig *ipconfig, int family)
if (family == AF_INET)
return connman_inet_set_address(ipconfig->index,
- ipconfig->address);
+ ipconfig->address);
else if (family == AF_INET6)
return connman_inet_set_ipv6_address(ipconfig->index,
ipconfig->address);
@@ -282,7 +282,10 @@ static struct vpn_ipconfig *create_ipv6config(int index)
return NULL;
}
+ connman_ipaddress_set_p2p(ipv6config->address, true);
+
ipv6config->system = connman_ipaddress_alloc(AF_INET6);
+ connman_ipaddress_set_p2p(ipv6config->system, true);
DBG("ipconfig %p", ipv6config);
@@ -314,7 +317,10 @@ struct vpn_ipconfig *__vpn_ipconfig_create(int index, int family)
return NULL;
}
+ connman_ipaddress_set_p2p(ipconfig->address, true);
+
ipconfig->system = connman_ipaddress_alloc(AF_INET);
+ connman_ipaddress_set_p2p(ipconfig->system, true);
DBG("ipconfig %p", ipconfig);
diff --git a/vpn/vpn-provider.c b/vpn/vpn-provider.c
index bb1a103a..6defbf27 100755
--- a/vpn/vpn-provider.c
+++ b/vpn/vpn-provider.c
@@ -3,6 +3,7 @@
* ConnMan VPN daemon
*
* Copyright (C) 2012-2013 Intel Corporation. All rights reserved.
+ * Copyright (C) 2019-2021 Jolla Ltd. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -23,6 +24,21 @@
#include <config.h>
#endif
+/*
+ * One hour difference in seconds between connections for checking whether to
+ * treat the authentication error as a real error or as a result of rapid
+ * transport change.
+ */
+#define CONNECT_OK_DIFF ((time_t)60*60)
+#define AUTH_ERROR_LIMIT_DEFAULT 1
+
+#define STATE_INTERVAL_DEFAULT 0
+
+#define CONNMAN_STATE_ONLINE "online"
+#define CONNMAN_STATE_OFFLINE "offline"
+#define CONNMAN_STATE_READY "ready"
+#define CONNMAN_STATE_IDLE "idle"
+
#include <errno.h>
#include <stdio.h>
#include <string.h>
@@ -31,6 +47,7 @@
#include <connman/log.h>
#include <gweb/gresolv.h>
#include <netdb.h>
+#include <time.h>
#include "../src/connman.h"
#include "connman/agent.h"
@@ -43,7 +60,6 @@ static DBusConnection *connection;
static GHashTable *provider_hash;
static GSList *driver_list;
static int configuration_count;
-static bool handle_routes;
struct vpn_route {
int family;
@@ -70,6 +86,7 @@ struct vpn_provider {
char *host;
char *domain;
int family;
+ bool do_split_routing;
GHashTable *routes;
struct vpn_provider_driver *driver;
void *driver_data;
@@ -87,10 +104,57 @@ struct vpn_provider {
bool immutable;
struct connman_ipaddress *prev_ipv4_addr;
struct connman_ipaddress *prev_ipv6_addr;
+ void *plugin_data;
+ unsigned int do_connect_timeout;
+ unsigned int auth_error_counter;
+ unsigned int conn_error_counter;
+ unsigned int signal_watch;
+ unsigned int auth_error_limit;
+ time_t previous_connect_time;
};
+struct vpn_provider_connect_data {
+ DBusConnection *conn;
+ DBusMessage *msg;
+ struct vpn_provider *provider;
+};
+
+static unsigned int get_connman_state_timeout;
+
+static guint connman_signal_watch;
+static guint connman_service_watch;
+
+static bool connman_online;
+static bool state_query_completed;
+
static void append_properties(DBusMessageIter *iter,
struct vpn_provider *provider);
+static int vpn_provider_save(struct vpn_provider *provider);
+
+static void get_connman_state(void);
+
+static void set_state(const char *new_state)
+{
+ if (!new_state || !*new_state)
+ return;
+
+ DBG("old state %s new state %s",
+ connman_online ?
+ CONNMAN_STATE_ONLINE "/" CONNMAN_STATE_READY :
+ CONNMAN_STATE_OFFLINE "/" CONNMAN_STATE_IDLE,
+ new_state);
+
+ /* States "online" and "ready" mean connman is online */
+ if (!g_ascii_strcasecmp(new_state, CONNMAN_STATE_ONLINE) ||
+ !g_ascii_strcasecmp(new_state, CONNMAN_STATE_READY))
+ connman_online = true;
+ /* Everything else means connman is offline */
+ else
+ connman_online = false;
+
+ DBG("set state %s connman_online=%s ", new_state,
+ connman_online ? "true" : "false");
+}
static void free_route(gpointer data)
{
@@ -190,6 +254,39 @@ static int provider_routes_changed(struct vpn_provider *provider)
return 0;
}
+/*
+ * Sort vpn_route struct based on (similarly to the route key in hash table):
+ * 1) IP protocol number
+ * 2) Network addresses
+ * 3) Netmask addresses
+ * 4) Gateway addresses
+ */
+static gint compare_route(gconstpointer a, gconstpointer b)
+{
+ const struct vpn_route *route_a = a;
+ const struct vpn_route *route_b = b;
+ int difference;
+
+ /* If IP families differ, prefer IPv6 over IPv4 */
+ if (route_a->family != route_b->family) {
+ if (route_a->family < route_b->family)
+ return -1;
+
+ if (route_a->family > route_b->family)
+ return 1;
+ }
+
+ /* If networks differ, return */
+ if ((difference = g_strcmp0(route_a->network, route_b->network)))
+ return difference;
+
+ /* If netmasks differ, return. */
+ if ((difference = g_strcmp0(route_a->netmask, route_b->netmask)))
+ return difference;
+
+ return g_strcmp0(route_a->gateway, route_b->gateway);
+}
+
static GSList *read_route_dict(GSList *routes, DBusMessageIter *dicts)
{
DBusMessageIter dict, value, entry;
@@ -258,9 +355,11 @@ static GSList *read_route_dict(GSList *routes, DBusMessageIter *dicts)
} else {
switch (family) {
case '4':
+ case 4:
family = AF_INET;
break;
case '6':
+ case 6:
family = AF_INET6;
break;
default:
@@ -274,7 +373,7 @@ static GSList *read_route_dict(GSList *routes, DBusMessageIter *dicts)
route->netmask = g_strdup(netmask);
route->gateway = g_strdup(gateway);
- routes = g_slist_prepend(routes, route);
+ routes = g_slist_insert_sorted(routes, route, compare_route);
return routes;
}
@@ -326,22 +425,8 @@ static void set_user_networks(struct vpn_provider *provider, GSList *networks)
static void del_routes(struct vpn_provider *provider)
{
GHashTableIter hash;
- gpointer value, key;
g_hash_table_iter_init(&hash, provider->user_routes);
- while (handle_routes && g_hash_table_iter_next(&hash,
- &key, &value)) {
- struct vpn_route *route = value;
- if (route->family == AF_INET6) {
- unsigned char prefixlen = atoi(route->netmask);
- connman_inet_del_ipv6_network_route(provider->index,
- route->network,
- prefixlen);
- } else
- connman_inet_del_host_route(provider->index,
- route->network);
- }
-
g_hash_table_remove_all(provider->user_routes);
g_slist_free_full(provider->user_networks, free_route);
provider->user_networks = NULL;
@@ -364,6 +449,16 @@ static void send_value(const char *path, const char *key, const char *value)
&str);
}
+static void send_value_boolean(const char *path, const char *key,
+ dbus_bool_t value)
+{
+ connman_dbus_property_changed_basic(path,
+ VPN_CONNECTION_INTERFACE,
+ key,
+ DBUS_TYPE_BOOLEAN,
+ &value);
+}
+
static gboolean provider_send_changed(gpointer data)
{
struct vpn_provider *provider = data;
@@ -404,6 +499,206 @@ static DBusMessage *get_properties(DBusConnection *conn,
return reply;
}
+/* True when lists are equal, false otherwise */
+static bool compare_network_lists(GSList *a, GSList *b)
+{
+ struct vpn_route *route_a, *route_b;
+ GSList *iter_a, *iter_b;
+
+ if (!a && !b)
+ return true;
+
+ /*
+ * If either of lists is NULL or the lists are of different size, the
+ * lists are not equal.
+ */
+ if ((!a || !b) || (g_slist_length(a) != g_slist_length(b)))
+ return false;
+
+ /* Routes are in sorted list so items can be compared in order. */
+ for (iter_a = a, iter_b = b; iter_a && iter_b;
+ iter_a = iter_a->next, iter_b = iter_b->next) {
+
+ route_a = iter_a->data;
+ route_b = iter_b->data;
+
+ if (compare_route(route_a, route_b))
+ return false;
+ }
+
+ return true;
+}
+
+static const char *bool2str(bool value)
+{
+ return value ? "true" : "false";
+}
+
+static int set_provider_property(struct vpn_provider *provider,
+ const char *name, DBusMessageIter *value, int type)
+{
+ int err = 0;
+
+ DBG("provider %p", provider);
+
+ if (!provider || !name || !value)
+ return -EINVAL;
+
+ if (g_str_equal(name, "UserRoutes")) {
+ GSList *networks;
+
+ if (type != DBUS_TYPE_ARRAY)
+ return -EINVAL;
+
+ networks = get_user_networks(value);
+
+ if (compare_network_lists(provider->user_networks, networks)) {
+ g_slist_free_full(networks, free_route);
+ return -EALREADY;
+ }
+
+ del_routes(provider);
+ provider->user_networks = networks;
+ set_user_networks(provider, provider->user_networks);
+ send_routes(provider, provider->user_routes, "UserRoutes");
+ } else if (g_str_equal(name, "SplitRouting")) {
+ dbus_bool_t split_routing;
+
+ if (type != DBUS_TYPE_BOOLEAN)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(value, &split_routing);
+
+ DBG("property %s value %s ", name, bool2str(split_routing));
+ vpn_provider_set_boolean(provider, name, split_routing, false);
+ } else {
+ const char *str;
+
+ if (type != DBUS_TYPE_STRING)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(value, &str);
+
+ DBG("property %s value %s", name, str);
+
+ /* Empty string clears the value, similar to ClearProperty. */
+ err = vpn_provider_set_string(provider, name,
+ *str ? str : NULL);
+ }
+
+ return err;
+}
+
+static GString *append_to_gstring(GString *str, const char *value)
+{
+ if (!str)
+ return g_string_new(value);
+
+ g_string_append_printf(str, ",%s", value);
+
+ return str;
+}
+
+static DBusMessage *set_properties(DBusMessageIter *iter, DBusMessage *msg,
+ void *data)
+{
+ struct vpn_provider *provider = data;
+ DBusMessageIter dict;
+ const char *key;
+ bool change = false;
+ GString *invalid = NULL;
+ GString *denied = NULL;
+ int type;
+ int err;
+
+ for (dbus_message_iter_recurse(iter, &dict);
+ dbus_message_iter_get_arg_type(&dict) ==
+ DBUS_TYPE_DICT_ENTRY;
+ dbus_message_iter_next(&dict)) {
+ DBusMessageIter entry, value;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ /*
+ * Ignore invalid types in order to process all values in the
+ * dict. If there is an invalid type in between the dict there
+ * may already be changes on some values and breaking out here
+ * would have the provider in an inconsistent state, leaving
+ * the rest, potentially correct property values untouched.
+ */
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+ continue;
+
+ dbus_message_iter_get_basic(&entry, &key);
+
+ DBG("key %s", key);
+
+ dbus_message_iter_next(&entry);
+ /* Ignore and report back all non variant types. */
+ if (dbus_message_iter_get_arg_type(&entry)
+ != DBUS_TYPE_VARIANT) {
+ invalid = append_to_gstring(invalid, key);
+ continue;
+ }
+
+ dbus_message_iter_recurse(&entry, &value);
+
+ type = dbus_message_iter_get_arg_type(&value);
+ switch (type) {
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_ARRAY:
+ case DBUS_TYPE_BOOLEAN:
+ break;
+ default:
+ /* Ignore and report back all invalid property types */
+ invalid = append_to_gstring(invalid, key);
+ continue;
+ }
+
+ err = set_provider_property(provider, key, &value, type);
+ switch (err) {
+ case 0:
+ change = true;
+ break;
+ case -EINVAL:
+ invalid = append_to_gstring(invalid, key);
+ break;
+ case -EPERM:
+ denied = append_to_gstring(denied, key);
+ break;
+ }
+ }
+
+ if (change)
+ vpn_provider_save(provider);
+
+ if (invalid || denied) {
+ DBusMessage *error;
+ char *invalid_str = g_string_free(invalid, FALSE);
+ char *denied_str = g_string_free(denied, FALSE);
+
+ /*
+ * If there are both invalid and denied properties report
+ * back invalid arguments. Add also the failed properties to
+ * the error message.
+ */
+ error = g_dbus_create_error(msg, (invalid ?
+ CONNMAN_ERROR_INTERFACE ".InvalidProperty" :
+ CONNMAN_ERROR_INTERFACE ".PermissionDenied"),
+ "%s %s%s%s", (invalid ? "Invalid properties" :
+ "Permission denied"),
+ (invalid ? invalid_str : ""),
+ (invalid && denied ? "," : ""),
+ (denied ? denied_str : ""));
+
+ g_free(invalid_str);
+ g_free(denied_str);
+
+ return error;
+ }
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
void *data)
{
@@ -411,6 +706,7 @@ static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
DBusMessageIter iter, value;
const char *name;
int type;
+ int err;
DBG("conn %p", conn);
@@ -432,28 +728,20 @@ static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
dbus_message_iter_recurse(&iter, &value);
type = dbus_message_iter_get_arg_type(&value);
+ if (type == DBUS_TYPE_ARRAY && g_str_equal(name, "Properties"))
+ return set_properties(&value, msg, data);
- if (g_str_equal(name, "UserRoutes")) {
- GSList *networks;
-
- if (type != DBUS_TYPE_ARRAY)
- return __connman_error_invalid_arguments(msg);
-
- networks = get_user_networks(&value);
- if (networks) {
- del_routes(provider);
- provider->user_networks = networks;
- set_user_networks(provider, provider->user_networks);
-
- if (!handle_routes)
- send_routes(provider, provider->user_routes,
- "UserRoutes");
- }
- } else {
- const char *str;
-
- dbus_message_iter_get_basic(&value, &str);
- vpn_provider_set_string(provider, name, str);
+ err = set_provider_property(provider, name, &value, type);
+ switch (err) {
+ case 0:
+ vpn_provider_save(provider);
+ break;
+ case -EALREADY:
+ break;
+ case -EINVAL:
+ return __connman_error_invalid_property(msg);
+ default:
+ return __connman_error_failed(msg, -err);
}
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
@@ -464,6 +752,8 @@ static DBusMessage *clear_property(DBusConnection *conn, DBusMessage *msg,
{
struct vpn_provider *provider = data;
const char *name;
+ bool change = false;
+ int err;
DBG("conn %p", conn);
@@ -474,19 +764,95 @@ static DBusMessage *clear_property(DBusConnection *conn, DBusMessage *msg,
DBUS_TYPE_INVALID);
if (g_str_equal(name, "UserRoutes")) {
+ /*
+ * If either user_routes or user_networks has any entries
+ * there is a change that is to be written to settings file.
+ */
+ if (g_hash_table_size(provider->user_routes) ||
+ provider->user_networks)
+ change = true;
+
del_routes(provider);
- if (!handle_routes)
- send_routes(provider, provider->user_routes, name);
+ send_routes(provider, provider->user_routes, name);
} else if (vpn_provider_get_string(provider, name)) {
- vpn_provider_set_string(provider, name, NULL);
+ err = vpn_provider_set_string(provider, name, NULL);
+ switch (err) {
+ case 0:
+ change = true;
+ /* fall through */
+ case -EALREADY:
+ break;
+ case -EINVAL:
+ return __connman_error_invalid_property(msg);
+ default:
+ return __connman_error_failed(msg, -err);
+ }
} else {
return __connman_error_invalid_property(msg);
}
+ if (change)
+ vpn_provider_save(provider);
+
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
+static gboolean do_connect_timeout_function(gpointer data)
+{
+ struct vpn_provider_connect_data *cdata = data;
+ struct vpn_provider *provider = cdata->provider;
+ int err;
+
+ DBG("");
+
+ /* Keep in main loop if connman is not online. */
+ if (!connman_online)
+ return G_SOURCE_CONTINUE;
+
+ provider->do_connect_timeout = 0;
+ err = __vpn_provider_connect(provider, cdata->msg);
+
+ if (err < 0 && err != -EINPROGRESS) {
+ g_dbus_send_message(cdata->conn,
+ __connman_error_failed(cdata->msg, -err));
+ cdata->msg = NULL;
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static void do_connect_timeout_free(gpointer data)
+{
+ struct vpn_provider_connect_data *cdata = data;
+
+ if (cdata->msg)
+ g_dbus_send_message(cdata->conn,
+ __connman_error_operation_aborted(cdata->msg));
+
+ dbus_connection_unref(cdata->conn);
+ g_free(data);
+}
+
+static void do_connect_later(struct vpn_provider *provider,
+ DBusConnection *conn, DBusMessage *msg)
+{
+ struct vpn_provider_connect_data *cdata =
+ g_new0(struct vpn_provider_connect_data, 1);
+
+ cdata->conn = dbus_connection_ref(conn);
+ cdata->msg = dbus_message_ref(msg);
+ cdata->provider = provider;
+
+ if (provider->do_connect_timeout)
+ g_source_remove(provider->do_connect_timeout);
+
+ provider->do_connect_timeout =
+ g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, 1,
+ do_connect_timeout_function, cdata,
+ do_connect_timeout_free);
+}
+
static DBusMessage *do_connect(DBusConnection *conn, DBusMessage *msg,
void *data)
{
@@ -495,8 +861,27 @@ static DBusMessage *do_connect(DBusConnection *conn, DBusMessage *msg,
DBG("conn %p provider %p", conn, provider);
+ if (!connman_online) {
+ if (state_query_completed) {
+ DBG("%s not started - ConnMan not online/ready",
+ provider->identifier);
+ return __connman_error_failed(msg, ENOLINK);
+ }
+
+ DBG("%s start delayed - ConnMan state not queried",
+ provider->identifier);
+ do_connect_later(provider, conn, msg);
+ return NULL;
+ }
+
+ /* Cancel delayed connection if connmand is online. */
+ if (provider->do_connect_timeout) {
+ g_source_remove(provider->do_connect_timeout);
+ provider->do_connect_timeout = 0;
+ }
+
err = __vpn_provider_connect(provider, msg);
- if (err < 0)
+ if (err < 0 && err != -EINPROGRESS)
return __connman_error_failed(msg, -err);
return NULL;
@@ -601,6 +986,8 @@ static void provider_resolv_host_addr(struct vpn_provider *provider)
void __vpn_provider_append_properties(struct vpn_provider *provider,
DBusMessageIter *iter)
{
+ dbus_bool_t split_routing;
+
if (provider->host)
connman_dbus_dict_append_basic(iter, "Host",
DBUS_TYPE_STRING, &provider->host);
@@ -612,6 +999,10 @@ void __vpn_provider_append_properties(struct vpn_provider *provider,
if (provider->type)
connman_dbus_dict_append_basic(iter, "Type", DBUS_TYPE_STRING,
&provider->type);
+
+ split_routing = provider->do_split_routing;
+ connman_dbus_dict_append_basic(iter, "SplitRouting", DBUS_TYPE_BOOLEAN,
+ &split_routing);
}
int __vpn_provider_append_user_route(struct vpn_provider *provider,
@@ -744,7 +1135,7 @@ static GSList *get_routes(gchar **networks)
static int provider_load_from_keyfile(struct vpn_provider *provider,
GKeyFile *keyfile)
{
- gsize idx = 0;
+ gsize idx;
gchar **settings;
gchar *key, *value;
gsize length, num_user_networks;
@@ -757,28 +1148,26 @@ static int provider_load_from_keyfile(struct vpn_provider *provider,
return -ENOENT;
}
- while (idx < length) {
+ for (idx = 0; idx < length; idx++) {
key = settings[idx];
- if (key) {
- if (g_str_equal(key, "Networks")) {
- networks = __vpn_config_get_string_list(keyfile,
- provider->identifier,
- key,
- &num_user_networks,
+ if (!key)
+ continue;
+
+ if (g_str_equal(key, "Networks")) {
+ networks = __vpn_config_get_string_list(keyfile,
+ provider->identifier,key,
+ &num_user_networks, NULL);
+ provider->user_networks = get_routes(networks);
+ } else {
+ value = __vpn_config_get_string(keyfile,
+ provider->identifier, key,
NULL);
- provider->user_networks = get_routes(networks);
-
- } else {
- value = __vpn_config_get_string(keyfile,
- provider->identifier,
- key, NULL);
- vpn_provider_set_string(provider, key,
- value);
- g_free(value);
- }
+
+ vpn_provider_set_string(provider, key, value);
+ g_free(value);
}
- idx += 1;
}
+
g_strfreev(settings);
g_strfreev(networks);
@@ -855,13 +1244,29 @@ static gchar **create_network_list(GSList *networks, gsize *count)
return result;
}
+static void reset_error_counters(struct vpn_provider *provider)
+{
+ if (!provider)
+ return;
+
+ DBG("provider %p", provider);
+
+ provider->auth_error_counter = provider->conn_error_counter = 0;
+}
+
static int vpn_provider_save(struct vpn_provider *provider)
{
GKeyFile *keyfile;
+ const char *value;
DBG("provider %p immutable %s", provider,
provider->immutable ? "yes" : "no");
+ reset_error_counters(provider);
+
+ if (provider->state == VPN_PROVIDER_STATE_FAILURE)
+ vpn_provider_set_state(provider, VPN_PROVIDER_STATE_IDLE);
+
if (provider->immutable) {
/*
* Do not save providers that are provisioned via .config
@@ -882,6 +1287,12 @@ static int vpn_provider_save(struct vpn_provider *provider)
"Host", provider->host);
g_key_file_set_string(keyfile, provider->identifier,
"VPN.Domain", provider->domain);
+
+ value = vpn_provider_get_string(provider, "AuthErrorLimit");
+ if (value)
+ g_key_file_set_string(keyfile, provider->identifier,
+ "AuthErrorLimit", value);
+
if (provider->user_networks) {
gchar **networks;
gsize network_count;
@@ -998,6 +1409,9 @@ static void provider_destruct(struct vpn_provider *provider)
{
DBG("provider %p", provider);
+ if (provider->do_connect_timeout)
+ g_source_remove(provider->do_connect_timeout);
+
if (provider->notify_id != 0)
g_source_remove(provider->notify_id);
@@ -1085,20 +1499,111 @@ static void connect_cb(struct vpn_provider *provider, void *user_data,
if (reply)
g_dbus_send_message(connection, reply);
- vpn_provider_indicate_error(provider,
+ switch (error) {
+ case EACCES:
+ vpn_provider_indicate_error(provider,
+ VPN_PROVIDER_ERROR_AUTH_FAILED);
+ break;
+ case ENOENT:
+ /*
+ * No reply, disconnect called by connmand because of
+ * connection timeout.
+ */
+ break;
+ case ENOMSG:
+ /* fall through */
+ case ETIMEDOUT:
+ /* No reply or timed out -> cancel the agent request */
+ connman_agent_cancel(provider);
+ vpn_provider_indicate_error(provider,
+ VPN_PROVIDER_ERROR_UNKNOWN);
+ break;
+ case ECANCELED:
+ /* fall through */
+ case ECONNABORTED:
+ /*
+ * This can be called in other situations than when
+ * VPN agent error checker is called. In such case
+ * react to both ECONNABORTED and ECANCELED as if the
+ * connection was called to terminate and do full
+ * disconnect -> idle cycle when being connected or
+ * ready. Setting the state also using the driver
+ * callback (vpn_set_state()) ensures that the driver is
+ * being disconnected as well and eventually the vpn
+ * process gets killed and vpn_died() is called to make
+ * the provider back to idle state.
+ */
+ if (provider->state == VPN_PROVIDER_STATE_CONNECT ||
+ provider->state ==
+ VPN_PROVIDER_STATE_READY) {
+ if (provider->driver->set_state)
+ provider->driver->set_state(provider,
+ VPN_PROVIDER_STATE_DISCONNECT);
+
+ vpn_provider_set_state(provider,
+ VPN_PROVIDER_STATE_DISCONNECT);
+ }
+ break;
+ default:
+ vpn_provider_indicate_error(provider,
VPN_PROVIDER_ERROR_CONNECT_FAILED);
- vpn_provider_set_state(provider, VPN_PROVIDER_STATE_FAILURE);
- } else
+ vpn_provider_set_state(provider,
+ VPN_PROVIDER_STATE_FAILURE);
+ }
+ } else {
+ reset_error_counters(provider);
g_dbus_send_reply(connection, pending, DBUS_TYPE_INVALID);
+ }
dbus_message_unref(pending);
}
int __vpn_provider_connect(struct vpn_provider *provider, DBusMessage *msg)
{
+ DBusMessage *reply;
int err;
- DBG("provider %p", provider);
+ DBG("provider %p state %d", provider, provider->state);
+
+ switch (provider->state) {
+ /*
+ * When previous connection has failed change state to idle and let
+ * the connmand to process this information as well. Return -EINPROGRESS
+ * to indicate that transition is in progress and next connection
+ * attempt will continue as normal.
+ */
+ case VPN_PROVIDER_STATE_FAILURE:
+ if (provider->driver && provider->driver->set_state)
+ provider->driver->set_state(provider,
+ VPN_PROVIDER_STATE_IDLE);
+
+ vpn_provider_set_state(provider, VPN_PROVIDER_STATE_IDLE);
+ /* fall through */
+ /*
+ * If re-using a provider and it is being disconnected let it finish
+ * the disconnect process in order to let vpn.c:vpn_died() to get
+ * processed and everything cleaned up. Otherwise the reference
+ * counters are not decreased properly causing the previous interface
+ * being left up and its routes will remain in routing table. Return
+ * -EINPROGRESS to indicate that transition is in progress.
+ */
+ case VPN_PROVIDER_STATE_DISCONNECT:
+ /*
+ * Failure transition or disconnecting does not yield a
+ * message to be sent. Send in progress message to avoid
+ * D-Bus LimitsExceeded error message.
+ */
+ reply = __connman_error_in_progress(msg);
+ if (reply)
+ g_dbus_send_message(connection, reply);
+
+ return -EINPROGRESS;
+ case VPN_PROVIDER_STATE_UNKNOWN:
+ case VPN_PROVIDER_STATE_IDLE:
+ case VPN_PROVIDER_STATE_CONNECT:
+ case VPN_PROVIDER_STATE_READY:
+ break;
+ }
if (provider->driver && provider->driver->connect) {
const char *dbus_sender = dbus_message_get_sender(msg);
@@ -1296,6 +1801,18 @@ static void append_dns(DBusMessageIter *iter, void *user_data)
append_nameservers(iter, provider->nameservers);
}
+static time_t get_uptime(void)
+{
+ struct timespec t = { 0 };
+
+ if (clock_gettime(CLOCK_BOOTTIME, &t) == -1) {
+ connman_warn("clock_gettime() error %d, uptime failed", errno);
+ return 0;
+ }
+
+ return t.tv_sec;
+}
+
static int provider_indicate_state(struct vpn_provider *provider,
enum vpn_provider_state state)
{
@@ -1311,6 +1828,8 @@ static int provider_indicate_state(struct vpn_provider *provider,
provider->state = state;
if (state == VPN_PROVIDER_STATE_READY) {
+ provider->previous_connect_time = get_uptime();
+
connman_dbus_property_changed_basic(provider->path,
VPN_CONNECTION_INTERFACE, "Index",
DBUS_TYPE_INT32, &provider->index);
@@ -1381,6 +1900,7 @@ static void append_properties(DBusMessageIter *iter,
GHashTableIter hash;
gpointer value, key;
dbus_bool_t immutable;
+ dbus_bool_t split_routing;
connman_dbus_dict_open(iter, &dict);
@@ -1408,6 +1928,10 @@ static void append_properties(DBusMessageIter *iter,
connman_dbus_dict_append_basic(&dict, "Immutable", DBUS_TYPE_BOOLEAN,
&immutable);
+ split_routing = provider->do_split_routing;
+ connman_dbus_dict_append_basic(&dict, "SplitRouting",
+ DBUS_TYPE_BOOLEAN, &split_routing);
+
if (provider->family == AF_INET)
connman_dbus_dict_append_dict(&dict, "IPv4", append_ipv4,
provider);
@@ -1432,8 +1956,7 @@ static void append_properties(DBusMessageIter *iter,
while (g_hash_table_iter_next(&hash, &key, &value)) {
struct vpn_setting *setting = value;
- if (!setting->hide_value &&
- setting->value)
+ if (!setting->hide_value && setting->value)
connman_dbus_dict_append_basic(&dict, key,
DBUS_TYPE_STRING,
&setting->value);
@@ -1462,55 +1985,6 @@ static void connection_added_signal(struct vpn_provider *provider)
dbus_message_unref(signal);
}
-static bool check_host(char **hosts, char *host)
-{
- int i;
-
- if (!hosts)
- return false;
-
- for (i = 0; hosts[i]; i++) {
- if (g_strcmp0(hosts[i], host) == 0)
- return true;
- }
-
- return false;
-}
-
-static void provider_append_routes(gpointer key, gpointer value,
- gpointer user_data)
-{
- struct vpn_route *route = value;
- struct vpn_provider *provider = user_data;
- int index = provider->index;
-
- if (!handle_routes)
- return;
-
- /*
- * If the VPN administrator/user has given a route to
- * VPN server, then we must discard that because the
- * server cannot be contacted via VPN tunnel.
- */
- if (check_host(provider->host_ip, route->network)) {
- DBG("Discarding VPN route to %s via %s at index %d",
- route->network, route->gateway, index);
- return;
- }
-
- if (route->family == AF_INET6) {
- unsigned char prefix_len = atoi(route->netmask);
-
- connman_inet_add_ipv6_network_route(index, route->network,
- route->gateway,
- prefix_len);
- } else {
- connman_inet_add_network_route(index, route->network,
- route->gateway,
- route->netmask);
- }
-}
-
static int set_connected(struct vpn_provider *provider,
bool connected)
{
@@ -1527,18 +2001,8 @@ static int set_connected(struct vpn_provider *provider,
__vpn_ipconfig_address_add(ipconfig, provider->family);
- if (handle_routes)
- __vpn_ipconfig_gateway_add(ipconfig, provider->family);
-
provider_indicate_state(provider,
VPN_PROVIDER_STATE_READY);
-
- g_hash_table_foreach(provider->routes, provider_append_routes,
- provider);
-
- g_hash_table_foreach(provider->user_routes,
- provider_append_routes, provider);
-
} else {
provider_indicate_state(provider,
VPN_PROVIDER_STATE_DISCONNECT);
@@ -1573,24 +2037,52 @@ int vpn_provider_set_state(struct vpn_provider *provider,
return -EINVAL;
}
+void vpn_provider_add_error(struct vpn_provider *provider,
+ enum vpn_provider_error error)
+{
+ switch (error) {
+ case VPN_PROVIDER_ERROR_UNKNOWN:
+ provider->previous_connect_time = 0;
+ break;
+ case VPN_PROVIDER_ERROR_CONNECT_FAILED:
+ provider->previous_connect_time = 0;
+ ++provider->conn_error_counter;
+ break;
+ case VPN_PROVIDER_ERROR_LOGIN_FAILED:
+ case VPN_PROVIDER_ERROR_AUTH_FAILED:
+ ++provider->auth_error_counter;
+ break;
+ }
+
+ DBG("%p connect errors %d auth errors %d", provider,
+ provider->conn_error_counter,
+ provider->auth_error_counter);
+}
+
int vpn_provider_indicate_error(struct vpn_provider *provider,
enum vpn_provider_error error)
{
DBG("provider %p id %s error %d", provider, provider->identifier,
error);
- vpn_provider_set_state(provider, VPN_PROVIDER_STATE_FAILURE);
+ /*
+ * Ignore adding of errors when the VPN is idle or not set. Calls may
+ * happen in a case when networks are rapidly changed and the call to
+ * vpn_died() is done before executing the connect_cb() from the
+ * plugin. Then vpn.c:vpn_died() executes the plugin specific died()
+ * function which may free the plugin private data, containing also
+ * the callback which hasn't yet been called. As a result the provider
+ * might already been reset to idle state when the callback is executed
+ * resulting in unnecessary reset of the previous successful connect
+ * timer and adding of an error for already disconnected VPN.
+ */
+ if (provider->state == VPN_PROVIDER_STATE_IDLE ||
+ provider->state == VPN_PROVIDER_STATE_UNKNOWN)
+ return 0;
- switch (error) {
- case VPN_PROVIDER_ERROR_UNKNOWN:
- case VPN_PROVIDER_ERROR_CONNECT_FAILED:
- break;
+ vpn_provider_set_state(provider, VPN_PROVIDER_STATE_FAILURE);
- case VPN_PROVIDER_ERROR_LOGIN_FAILED:
- case VPN_PROVIDER_ERROR_AUTH_FAILED:
- vpn_provider_set_state(provider, VPN_PROVIDER_STATE_IDLE);
- break;
- }
+ vpn_provider_add_error(provider, error);
if (provider->driver && provider->driver->set_state)
provider->driver->set_state(provider, provider->state);
@@ -1598,10 +2090,61 @@ int vpn_provider_indicate_error(struct vpn_provider *provider,
return 0;
}
+static gboolean provider_property_changed(DBusConnection *conn,
+ DBusMessage *message, void *user_data)
+{
+ DBusMessageIter iter;
+ DBusMessageIter value;
+ struct vpn_provider *provider = user_data;
+ const char *key;
+
+ if (!dbus_message_iter_init(message, &iter))
+ return TRUE;
+
+ dbus_message_iter_get_basic(&iter, &key);
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &value);
+
+ DBG("provider %p key %s", provider, key);
+
+ if (g_str_equal(key, "SplitRouting")) {
+ dbus_bool_t split_routing;
+
+ if (dbus_message_iter_get_arg_type(&value) !=
+ DBUS_TYPE_BOOLEAN)
+ goto out;
+
+ dbus_message_iter_get_basic(&value, &split_routing);
+
+ DBG("property %s value %s", key, bool2str(split_routing));
+
+ /*
+ * Even though this is coming from connmand, signal the value
+ * for other components listening to the changes via VPN API
+ * only. provider.c will skip setting the same value in order
+ * to avoid signaling loop. This is needed for ensuring that
+ * all components using VPN API will be informed about the
+ * correct status of SplitRouting. Especially when loading the
+ * services after a crash, for instance.
+ */
+ vpn_provider_set_boolean(provider, "SplitRouting",
+ split_routing, true);
+ }
+
+out:
+ return TRUE;
+}
+
static int connection_unregister(struct vpn_provider *provider)
{
DBG("provider %p path %s", provider, provider->path);
+ if (provider->signal_watch) {
+ g_dbus_remove_watch(connection, provider->signal_watch);
+ provider->signal_watch = 0;
+ }
+
if (!provider->path)
return -EALREADY;
@@ -1616,6 +2159,8 @@ static int connection_unregister(struct vpn_provider *provider)
static int connection_register(struct vpn_provider *provider)
{
+ char *connmand_vpn_path;
+
DBG("provider %p path %s", provider, provider->path);
if (provider->path)
@@ -1629,6 +2174,18 @@ static int connection_register(struct vpn_provider *provider)
connection_methods, connection_signals,
NULL, provider, NULL);
+ connmand_vpn_path = g_strdup_printf("%s/service/vpn_%s", CONNMAN_PATH,
+ provider->identifier);
+
+ provider->signal_watch = g_dbus_add_signal_watch(connection,
+ CONNMAN_SERVICE, connmand_vpn_path,
+ CONNMAN_SERVICE_INTERFACE,
+ PROPERTY_CHANGED,
+ provider_property_changed,
+ provider, NULL);
+
+ g_free(connmand_vpn_path);
+
return 0;
}
@@ -1666,6 +2223,7 @@ static void provider_initialize(struct vpn_provider *provider)
provider->domain = NULL;
provider->identifier = NULL;
provider->immutable = false;
+ provider->do_split_routing = false;
provider->user_networks = NULL;
provider->routes = g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, free_route);
@@ -1673,6 +2231,7 @@ static void provider_initialize(struct vpn_provider *provider)
g_free, free_route);
provider->setting_strings = g_hash_table_new_full(g_str_hash,
g_str_equal, g_free, free_setting);
+ provider->auth_error_limit = AUTH_ERROR_LIMIT_DEFAULT;
}
static struct vpn_provider *vpn_provider_new(void)
@@ -1714,6 +2273,13 @@ static struct vpn_provider *vpn_provider_get(const char *identifier)
return provider;
}
+static void vpn_provider_put(const char *identifier)
+{
+ configuration_count_del();
+
+ g_hash_table_remove(provider_hash, identifier);
+}
+
static void provider_dbus_ident(char *ident)
{
int i, len = strlen(ident);
@@ -1754,9 +2320,12 @@ static struct vpn_provider *provider_create_from_keyfile(GKeyFile *keyfile,
return NULL;
}
- if (provider_register(provider) == 0)
+ if (!provider_register(provider)) {
connection_register(provider);
+ connection_added_signal(provider);
+ }
}
+
return provider;
}
@@ -1809,9 +2378,10 @@ char *__vpn_provider_create_identifier(const char *host, const char *domain)
{
char *ident;
- ident = g_strdup_printf("%s_%s", host, domain);
- if (!ident)
- return NULL;
+ if (domain)
+ ident = g_strdup_printf("%s_%s", host, domain);
+ else
+ ident = g_strdup_printf("%s", host);
provider_dbus_ident(ident);
@@ -1822,7 +2392,10 @@ char *__vpn_provider_create_identifier(const char *host, const char *domain, con
{
char *ident;
- ident = g_strdup_printf("%s_%s_%s", host, domain, name);
+ if (domain)
+ ident = g_strdup_printf("%s_%s_%s", host, domain, name);
+ else
+ ident = g_strdup_printf("%s_%s", host, name);
if (!ident)
return NULL;
@@ -1841,6 +2414,7 @@ int __vpn_provider_create(DBusMessage *msg)
GSList *networks = NULL;
char *ident;
int err;
+ dbus_bool_t split_routing = false;
dbus_message_iter_init(msg, &iter);
dbus_message_iter_recurse(&iter, &array);
@@ -1867,6 +2441,11 @@ int __vpn_provider_create(DBusMessage *msg)
g_str_equal(key, "Domain"))
dbus_message_iter_get_basic(&value, &domain);
break;
+ case DBUS_TYPE_BOOLEAN:
+ if (g_str_equal(key, "SplitRouting"))
+ dbus_message_iter_get_basic(&value,
+ &split_routing);
+ break;
case DBUS_TYPE_ARRAY:
if (g_str_equal(key, "UserRoutes"))
networks = get_user_networks(&value);
@@ -1876,7 +2455,7 @@ int __vpn_provider_create(DBusMessage *msg)
dbus_message_iter_next(&array);
}
- if (!host || !domain)
+ if (!host)
return -EINVAL;
DBG("Type %s name %s networks %p", type, name, networks);
@@ -1904,6 +2483,7 @@ int __vpn_provider_create(DBusMessage *msg)
provider->domain = g_strdup(domain);
provider->name = g_strdup(name);
provider->type = g_strdup(type);
+ provider->do_split_routing = split_routing;
if (provider_register(provider) == 0)
vpn_provider_load(provider);
@@ -2065,7 +2645,7 @@ int __vpn_provider_create_from_config(GHashTable *settings,
networks_str = get_string(settings, "Networks");
networks = parse_user_networks(networks_str);
- if (!host || !domain) {
+ if (!host) {
err = -EINVAL;
goto fail;
}
@@ -2101,8 +2681,6 @@ int __vpn_provider_create_from_config(GHashTable *settings,
provider->config_file = g_strdup(config_ident);
provider->config_entry = g_strdup(config_entry);
- provider_register(provider);
-
provider_resolv_host_addr(provider);
}
@@ -2137,6 +2715,7 @@ int __vpn_provider_create_from_config(GHashTable *settings,
return 0;
fail:
+ vpn_provider_put(ident);
g_free(ident);
g_slist_free_full(networks, free_route);
@@ -2154,7 +2733,11 @@ static void append_connection_structs(DBusMessageIter *iter, void *user_data)
while (g_hash_table_iter_next(&hash, &key, &value)) {
struct vpn_provider *provider = value;
+#if defined TIZEN_EXT
+ DBG("provider %p", provider);
+#else
DBG("path %s", provider->path);
+#endif
if (!provider->identifier)
continue;
@@ -2184,7 +2767,7 @@ DBusMessage *__vpn_provider_get_connections(DBusMessage *msg)
return reply;
}
-const char *__vpn_provider_get_ident(struct vpn_provider *provider)
+const char *vpn_provider_get_ident(struct vpn_provider *provider)
{
if (!provider)
return NULL;
@@ -2201,35 +2784,58 @@ static int set_string(struct vpn_provider *provider,
hide_value ? "<not printed>" : value);
if (g_str_equal(key, "Type")) {
+ if (!g_strcmp0(provider->type, value))
+ return -EALREADY;
+
g_free(provider->type);
provider->type = g_ascii_strdown(value, -1);
send_value(provider->path, "Type", provider->type);
} else if (g_str_equal(key, "Name")) {
+ if (!g_strcmp0(provider->name, value))
+ return -EALREADY;
+
g_free(provider->name);
provider->name = g_strdup(value);
send_value(provider->path, "Name", provider->name);
} else if (g_str_equal(key, "Host")) {
+ if (!g_strcmp0(provider->host, value))
+ return -EALREADY;
+
g_free(provider->host);
provider->host = g_strdup(value);
send_value(provider->path, "Host", provider->host);
} else if (g_str_equal(key, "VPN.Domain") ||
g_str_equal(key, "Domain")) {
+ if (!g_strcmp0(provider->domain, value))
+ return -EALREADY;
+
g_free(provider->domain);
provider->domain = g_strdup(value);
send_value(provider->path, "Domain", provider->domain);
+ } else if (g_str_equal(key, "SplitRouting")) {
+ connman_warn("VPN SplitRouting value attempted to set as "
+ "string, is boolean");
+ return -EINVAL;
} else {
struct vpn_setting *setting;
+ bool replace = true;
setting = g_hash_table_lookup(provider->setting_strings, key);
- if (setting && !immutable &&
- setting->immutable) {
- DBG("Trying to set immutable variable %s", key);
- return -EPERM;
- }
+ if (setting) {
+ if (!immutable && setting->immutable) {
+ DBG("Trying to set immutable variable %s", key);
+ return -EPERM;
+ } else if (!g_strcmp0(setting->value, value)) {
+ return -EALREADY;
+ }
- setting = g_try_new0(struct vpn_setting, 1);
- if (!setting)
- return -ENOMEM;
+ g_free(setting->value);
+ replace = false;
+ } else {
+ setting = g_try_new0(struct vpn_setting, 1);
+ if (!setting)
+ return -ENOMEM;
+ }
setting->value = g_strdup(value);
setting->hide_value = hide_value;
@@ -2240,8 +2846,9 @@ static int set_string(struct vpn_provider *provider,
if (!hide_value)
send_value(provider->path, key, setting->value);
- g_hash_table_replace(provider->setting_strings,
- g_strdup(key), setting);
+ if (replace)
+ g_hash_table_replace(provider->setting_strings,
+ g_strdup(key), setting);
}
return 0;
@@ -2295,6 +2902,86 @@ const char *vpn_provider_get_string(struct vpn_provider *provider,
return setting->value;
}
+int vpn_provider_set_boolean(struct vpn_provider *provider, const char *key,
+ bool value, bool force_change)
+{
+ DBG("provider %p key %s", provider, key);
+
+ if (g_str_equal(key, "SplitRouting")) {
+ if (provider->do_split_routing == value && !force_change)
+ return -EALREADY;
+
+ DBG("SplitRouting set to %s", bool2str(value));
+
+ provider->do_split_routing = value;
+ send_value_boolean(provider->path, key,
+ provider->do_split_routing);
+ }
+
+ return 0;
+}
+
+bool vpn_provider_get_boolean(struct vpn_provider *provider, const char *key,
+ bool default_value)
+{
+ struct vpn_setting *setting;
+
+ connman_info("provider %p key %s", provider, key);
+
+ setting = g_hash_table_lookup(provider->setting_strings, key);
+ if (!setting || !setting->value)
+ return default_value;
+
+ if (!g_strcmp0(setting->value, "true"))
+ return true;
+
+ if (!g_strcmp0(setting->value, "false"))
+ return false;
+
+ return default_value;
+}
+
+bool vpn_provider_get_string_immutable(struct vpn_provider *provider,
+ const char *key)
+{
+ struct vpn_setting *setting;
+
+ /* These values can be changed if the provider is not immutable */
+ if (g_str_equal(key, "Type")) {
+ return provider->immutable;
+ } else if (g_str_equal(key, "Name")) {
+ return provider->immutable;
+ } else if (g_str_equal(key, "Host")) {
+ return provider->immutable;
+ } else if (g_str_equal(key, "HostIP")) {
+ return provider->immutable;
+ } else if (g_str_equal(key, "VPN.Domain") ||
+ g_str_equal(key, "Domain")) {
+ return provider->immutable;
+ }
+
+ setting = g_hash_table_lookup(provider->setting_strings, key);
+ if (!setting)
+ return true; /* Not found, regard as immutable - no changes */
+
+ return setting->immutable;
+}
+
+bool vpn_provider_setting_key_exists(struct vpn_provider *provider,
+ const char *key)
+{
+ return g_hash_table_contains(provider->setting_strings, key);
+}
+
+void vpn_provider_set_auth_error_limit(struct vpn_provider *provider,
+ unsigned int limit)
+{
+ if (!provider)
+ return;
+
+ provider->auth_error_limit = limit;
+}
+
bool __vpn_provider_check_routes(struct vpn_provider *provider)
{
if (!provider)
@@ -2321,6 +3008,20 @@ void vpn_provider_set_data(struct vpn_provider *provider, void *data)
provider->driver_data = data;
}
+void *vpn_provider_get_plugin_data(struct vpn_provider *provider)
+{
+#if defined TIZEN_EXT
+ if (!provider)
+ return NULL;
+#endif
+ return provider->plugin_data;
+}
+
+void vpn_provider_set_plugin_data(struct vpn_provider *provider, void *data)
+{
+ provider->plugin_data = data;
+}
+
void vpn_provider_set_index(struct vpn_provider *provider, int index)
{
DBG("index %d provider %p", index, provider);
@@ -2329,7 +3030,7 @@ void vpn_provider_set_index(struct vpn_provider *provider, int index)
provider->ipconfig_ipv4 = __vpn_ipconfig_create(index,
AF_INET);
if (!provider->ipconfig_ipv4) {
- DBG("Couldnt create ipconfig for IPv4");
+ DBG("Couldn't create ipconfig for IPv4");
goto done;
}
}
@@ -2340,7 +3041,7 @@ void vpn_provider_set_index(struct vpn_provider *provider, int index)
provider->ipconfig_ipv6 = __vpn_ipconfig_create(index,
AF_INET6);
if (!provider->ipconfig_ipv6) {
- DBG("Couldnt create ipconfig for IPv6");
+ DBG("Couldn't create ipconfig for IPv6");
goto done;
}
}
@@ -2442,7 +3143,7 @@ int vpn_provider_set_nameservers(struct vpn_provider *provider,
if (!nameservers)
return 0;
- provider->nameservers = g_strsplit(nameservers, " ", 0);
+ provider->nameservers = g_strsplit_set(nameservers, ", ", 0);
return 0;
}
@@ -2507,11 +3208,8 @@ int vpn_provider_append_route(struct vpn_provider *provider,
break;
}
- if (!handle_routes) {
- if (route->netmask && route->gateway &&
- route->network)
- provider_schedule_changed(provider);
- }
+ if (route->netmask && route->gateway && route->network)
+ provider_schedule_changed(provider);
return 0;
}
@@ -2568,9 +3266,14 @@ void vpn_provider_driver_unregister(struct vpn_provider_driver *driver)
struct vpn_provider *provider = value;
if (provider && provider->driver &&
- provider->driver->type == driver->type &&
g_strcmp0(provider->driver->name,
driver->name) == 0) {
+ /*
+ * Cancel VPN agent request to avoid segfault at
+ * shutdown as the callback, if set can point to a
+ * function in the plugin that is to be removed.
+ */
+ connman_agent_cancel(provider);
provider->driver = NULL;
}
}
@@ -2591,6 +3294,79 @@ const char *vpn_provider_get_path(struct vpn_provider *provider)
return provider->path;
}
+/*
+ * This crude heuristic is meant to mitigate an issue with certain VPN
+ * providers that allow only one authentication per account at a time. These
+ * providers require the VPN client shuts down cleanly by sending an exit
+ * notification. In many cases this is not possible as the transport may
+ * already be gone and there is no route to the VPN server. In such case server
+ * may return authentication error to indicate that an other client is active
+ * and reserves the slot.
+ *
+ * By allowing the VPN client to try again with the following conditons the
+ * unnecessary credential resets done by VPN agent can be avoided. VPN client
+ * is allowed to retry if 1) there was a successful connection to the server
+ * within the specified CONNECT_OK_DIFF time and 2) the provider specific
+ * limit for auth errors is not reached the unnecessary credential resets in
+ * this case are avoided.
+ *
+ * This feature is controlled by the provider specific value for
+ * "AuthErrorLimit". Setting the value to 0 feature is disabled. User defined
+ * value is preferred if set, otherwise plugin default set with
+ * vpn_provider_set_auth_error_limit() is used, which defaults to
+ * AUTH_ERROR_LIMIT_DEFAULT.
+ */
+static bool ignore_authentication_errors(struct vpn_provider *provider)
+{
+ const char *val;
+ unsigned int limit;
+ time_t uptime;
+ time_t diff;
+
+ val = vpn_provider_get_string(provider, "AuthErrorLimit");
+ if (val)
+ limit = g_ascii_strtoull(val, NULL, 10);
+ else
+ limit = provider->auth_error_limit;
+
+ if (!limit || !provider->previous_connect_time) {
+ DBG("%p errors %u %s", provider, provider->auth_error_counter,
+ !limit ?
+ "disabled by 0 limit" :
+ "no previous ok conn");
+ return false;
+ }
+
+ uptime = get_uptime();
+ diff = uptime - provider->previous_connect_time;
+
+ DBG("%p errors %u limit %u uptime %jd time diff %jd", provider,
+ provider->auth_error_counter, limit,
+ (intmax_t)uptime, (intmax_t)diff);
+
+ if (diff <= CONNECT_OK_DIFF && provider->auth_error_counter <= limit) {
+ DBG("ignore auth errors");
+ return true;
+ }
+
+ return false;
+}
+
+unsigned int vpn_provider_get_authentication_errors(
+ struct vpn_provider *provider)
+{
+ if (ignore_authentication_errors(provider))
+ return 0;
+
+ return provider->auth_error_counter;
+}
+
+unsigned int vpn_provider_get_connection_errors(
+ struct vpn_provider *provider)
+{
+ return provider->conn_error_counter;
+}
+
void vpn_provider_change_address(struct vpn_provider *provider)
{
switch (provider->family) {
@@ -2637,7 +3413,7 @@ void vpn_provider_clear_address(struct vpn_provider *provider, int family)
DBG("ipv6 %s/%d", address, len);
connman_inet_clear_ipv6_address(provider->index,
- address, len);
+ provider->prev_ipv6_addr);
connman_ipaddress_free(provider->prev_ipv6_addr);
provider->prev_ipv6_addr = NULL;
@@ -2727,13 +3503,220 @@ static void remove_unprovisioned_providers(void)
g_strfreev(providers);
}
-int __vpn_provider_init(bool do_routes)
+static gboolean connman_property_changed(DBusConnection *conn,
+ DBusMessage *message,
+ void *user_data)
{
- int err;
+ DBusMessageIter iter, value;
+ const char *key;
+ const char *signature = DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING;
+
+ if (!dbus_message_has_signature(message, signature)) {
+ connman_error("vpn connman property signature \"%s\" "
+ "does not match expected \"%s\"",
+ dbus_message_get_signature(message),
+ signature);
+ return TRUE;
+ }
+
+ if (!dbus_message_iter_init(message, &iter))
+ return TRUE;
+
+ dbus_message_iter_get_basic(&iter, &key);
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &value);
+
+ DBG("key %s", key);
+
+ if (g_str_equal(key, "State")) {
+ const char *str;
+
+ if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_STRING)
+ return TRUE;
+
+ dbus_message_iter_get_basic(&value, &str);
+ set_state(str);
+ }
+
+ return TRUE;
+}
+
+static void get_connman_state_reply(DBusPendingCall *call, void *user_data)
+{
+ DBusMessage *reply = NULL;
+ DBusError error;
+ DBusMessageIter iter, array, dict, value;
+
+ const char *signature = DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
+
+ const char *key;
+ const char *str;
DBG("");
- handle_routes = do_routes;
+ if (!dbus_pending_call_get_completed(call))
+ goto done;
+
+ reply = dbus_pending_call_steal_reply(call);
+
+ dbus_error_init(&error);
+
+ if (dbus_set_error_from_message(&error, reply)) {
+ connman_error("%s", error.message);
+
+ /*
+ * In case of timeout re-add the state function to main
+ * event loop.
+ */
+ if (g_ascii_strcasecmp(error.name, DBUS_ERROR_TIMEOUT) == 0) {
+ DBG("D-Bus timeout, re-add get_connman_state()");
+ get_connman_state();
+ } else {
+ dbus_error_free(&error);
+ goto done;
+ }
+ }
+
+ if (!dbus_message_has_signature(reply, signature)) {
+ connman_error("vpnd signature \"%s\" does not match "
+ "expected \"%s\"",
+ dbus_message_get_signature(reply),
+ signature);
+
+ goto done;
+ }
+
+ if (!dbus_message_iter_init(reply, &array))
+ goto done;
+
+ dbus_message_iter_recurse(&array, &dict);
+
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ dbus_message_iter_recurse(&dict, &iter);
+
+ dbus_message_iter_get_basic(&iter, &key);
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &value);
+
+ if (g_ascii_strcasecmp(key, "State") == 0 &&
+ dbus_message_iter_get_arg_type(&value) ==
+ DBUS_TYPE_STRING) {
+ dbus_message_iter_get_basic(&value, &str);
+
+ DBG("Got initial state %s", str);
+
+ set_state(str);
+
+ /* No need to process further */
+ break;
+ }
+
+ dbus_message_iter_next(&dict);
+ }
+
+ state_query_completed = true;
+
+done:
+ if (reply)
+ dbus_message_unref(reply);
+
+ if (call)
+ dbus_pending_call_unref(call);
+}
+
+static gboolean run_get_connman_state(gpointer user_data)
+{
+ const char *path = "/";
+ const char *method = "GetProperties";
+ gboolean rval = FALSE;
+
+ DBusMessage *msg = NULL;
+ DBusPendingCall *call = NULL;
+
+ DBG("");
+
+ msg = dbus_message_new_method_call(CONNMAN_SERVICE, path,
+ CONNMAN_MANAGER_INTERFACE, method);
+ if (!msg)
+ goto out;
+
+ rval = g_dbus_send_message_with_reply(connection, msg, &call, -1);
+ if (!rval) {
+ connman_error("Cannot call %s on %s", method,
+ CONNMAN_MANAGER_INTERFACE);
+ goto out;
+ }
+
+ if (!call) {
+ connman_error("set pending call failed");
+ rval = FALSE;
+ goto out;
+ }
+
+ if (!dbus_pending_call_set_notify(call, get_connman_state_reply,
+ NULL, NULL)) {
+ connman_error("set notify to pending call failed");
+
+ if (call)
+ dbus_pending_call_unref(call);
+
+ rval = FALSE;
+ }
+
+out:
+ if (msg)
+ dbus_message_unref(msg);
+
+ /* In case sending was success, unset timeout function id */
+ if (rval) {
+ DBG("unsetting get_connman_state_timeout id");
+ get_connman_state_timeout = 0;
+ }
+
+ /* Return FALSE in case of success to remove from main event loop */
+ return !rval;
+}
+
+static void get_connman_state(void)
+{
+ if (get_connman_state_timeout)
+ return;
+
+ get_connman_state_timeout = g_timeout_add(STATE_INTERVAL_DEFAULT,
+ run_get_connman_state, NULL);
+}
+
+static void connman_service_watch_connected(DBusConnection *conn,
+ void *user_data)
+{
+ DBG("");
+
+ get_connman_state();
+}
+
+static void connman_service_watch_disconnected(DBusConnection *conn,
+ void *user_data)
+{
+ DBG("");
+
+ set_state(CONNMAN_STATE_IDLE);
+
+ /* Set state query variable to initial state */
+ state_query_completed = false;
+}
+
+int __vpn_provider_init(void)
+{
+ int err;
+
+ DBG("");
err = connman_agent_driver_register(&agent_driver);
if (err < 0) {
@@ -2748,6 +3731,20 @@ int __vpn_provider_init(bool do_routes)
provider_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, unregister_provider);
+
+ connman_service_watch = g_dbus_add_service_watch(connection,
+ CONNMAN_SERVICE,
+ connman_service_watch_connected,
+ connman_service_watch_disconnected,
+ NULL, NULL);
+
+ connman_signal_watch = g_dbus_add_signal_watch(connection,
+ CONNMAN_SERVICE, NULL,
+ CONNMAN_MANAGER_INTERFACE,
+ PROPERTY_CHANGED,
+ connman_property_changed,
+ NULL, NULL);
+
return 0;
}
@@ -2762,5 +3759,13 @@ void __vpn_provider_cleanup(void)
g_hash_table_destroy(provider_hash);
provider_hash = NULL;
+ if (get_connman_state_timeout) {
+ if (!g_source_remove(get_connman_state_timeout))
+ connman_error("connman state timeout not removed");
+ }
+
+ g_dbus_remove_watch(connection, connman_service_watch);
+ g_dbus_remove_watch(connection, connman_signal_watch);
+
dbus_connection_unref(connection);
}
diff --git a/vpn/vpn-provider.h b/vpn/vpn-provider.h
index 96452c11..5d1455da 100755
--- a/vpn/vpn-provider.h
+++ b/vpn/vpn-provider.h
@@ -3,6 +3,7 @@
* ConnMan VPN daemon
*
* Copyright (C) 2007-2013 Intel Corporation. All rights reserved.
+ * Copyright (C) 2019 Jolla Ltd. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -36,11 +37,6 @@ extern "C" {
* @short_description: Functions for handling providers
*/
-enum vpn_provider_type {
- VPN_PROVIDER_TYPE_UNKNOWN = 0,
- VPN_PROVIDER_TYPE_VPN = 1,
-};
-
enum vpn_provider_state {
VPN_PROVIDER_STATE_UNKNOWN = 0,
VPN_PROVIDER_STATE_IDLE = 1,
@@ -85,10 +81,23 @@ int vpn_provider_set_string_hide_value(struct vpn_provider *provider,
const char *key, const char *value);
const char *vpn_provider_get_string(struct vpn_provider *provider,
const char *key);
+bool vpn_provider_get_string_immutable(struct vpn_provider *provider,
+ const char *key);
+int vpn_provider_set_boolean(struct vpn_provider *provider, const char *key,
+ bool value,
+ bool force_change);
+bool vpn_provider_get_boolean(struct vpn_provider *provider, const char *key,
+ bool default_value);
+bool vpn_provider_setting_key_exists(struct vpn_provider *provider,
+ const char *key);
+void vpn_provider_set_auth_error_limit(struct vpn_provider *provider,
+ unsigned int limit);
int vpn_provider_set_state(struct vpn_provider *provider,
enum vpn_provider_state state);
+void vpn_provider_add_error(struct vpn_provider *provider,
+ enum vpn_provider_error error);
int vpn_provider_indicate_error(struct vpn_provider *provider,
enum vpn_provider_error error);
@@ -97,6 +106,8 @@ int vpn_provider_get_index(struct vpn_provider *provider);
void vpn_provider_set_data(struct vpn_provider *provider, void *data);
void *vpn_provider_get_data(struct vpn_provider *provider);
+void vpn_provider_set_plugin_data(struct vpn_provider *provider, void *data);
+void *vpn_provider_get_plugin_data(struct vpn_provider *provider);
int vpn_provider_set_ipaddress(struct vpn_provider *provider,
struct connman_ipaddress *ipaddress);
int vpn_provider_set_pac(struct vpn_provider *provider,
@@ -114,6 +125,13 @@ const char *vpn_provider_get_save_group(struct vpn_provider *provider);
const char *vpn_provider_get_name(struct vpn_provider *provider);
const char *vpn_provider_get_host(struct vpn_provider *provider);
const char *vpn_provider_get_path(struct vpn_provider *provider);
+const char *vpn_provider_get_ident(struct vpn_provider *provider);
+
+unsigned int vpn_provider_get_authentication_errors(
+ struct vpn_provider *provider);
+unsigned int vpn_provider_get_connection_errors(
+ struct vpn_provider *provider);
+
void vpn_provider_change_address(struct vpn_provider *provider);
void vpn_provider_clear_address(struct vpn_provider *provider, int family);
@@ -131,7 +149,6 @@ typedef void (* vpn_provider_password_cb_t) (struct vpn_provider *provider,
struct vpn_provider_driver {
const char *name;
- enum vpn_provider_type type;
int (*probe) (struct vpn_provider *provider);
int (*remove) (struct vpn_provider *provider);
int (*connect) (struct vpn_provider *provider,
diff --git a/vpn/vpn-rtnl.c b/vpn/vpn-rtnl.c
index 6ddfd832..5a02d779 100755
--- a/vpn/vpn-rtnl.c
+++ b/vpn/vpn-rtnl.c
@@ -184,7 +184,7 @@ int vpn_rtnl_register(struct vpn_rtnl *rtnl)
rtnl_list = g_slist_insert_sorted(rtnl_list, rtnl,
compare_priority);
- __vpn_ipconfig_foreach(trigger_rtnl, rtnl);
+ vpn_ipconfig_foreach(trigger_rtnl, rtnl);
return 0;
}
@@ -797,75 +797,71 @@ static const char *type2string(uint16_t type)
static GIOChannel *channel = NULL;
-struct rtnl_request {
- struct nlmsghdr hdr;
- struct rtgenmsg msg;
-};
-#define RTNL_REQUEST_SIZE (sizeof(struct nlmsghdr) + sizeof(struct rtgenmsg))
+#define RTNL_REQUEST_SIZE (NLMSG_HDRLEN + NLMSG_ALIGN(sizeof(struct rtgenmsg)))
static GSList *request_list = NULL;
static guint32 request_seq = 0;
-static struct rtnl_request *find_request(guint32 seq)
+static struct nlmsghdr *find_request(guint32 seq)
{
GSList *list;
for (list = request_list; list; list = list->next) {
- struct rtnl_request *req = list->data;
+ struct nlmsghdr *hdr = list->data;
- if (req->hdr.nlmsg_seq == seq)
- return req;
+ if (hdr->nlmsg_seq == seq)
+ return hdr;
}
return NULL;
}
-static int send_request(struct rtnl_request *req)
+static int send_request(struct nlmsghdr *hdr)
{
struct sockaddr_nl addr;
int sk;
debug("%s len %d type %d flags 0x%04x seq %d",
- type2string(req->hdr.nlmsg_type),
- req->hdr.nlmsg_len, req->hdr.nlmsg_type,
- req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
+ type2string(hdr->nlmsg_type),
+ hdr->nlmsg_len, hdr->nlmsg_type,
+ hdr->nlmsg_flags, hdr->nlmsg_seq);
sk = g_io_channel_unix_get_fd(channel);
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
- return sendto(sk, req, req->hdr.nlmsg_len, 0,
+ return sendto(sk, hdr, hdr->nlmsg_len, 0,
(struct sockaddr *) &addr, sizeof(addr));
}
-static int queue_request(struct rtnl_request *req)
+static int queue_request(struct nlmsghdr *hdr)
{
- request_list = g_slist_append(request_list, req);
+ request_list = g_slist_append(request_list, hdr);
if (g_slist_length(request_list) > 1)
return 0;
- return send_request(req);
+ return send_request(hdr);
}
static int process_response(guint32 seq)
{
- struct rtnl_request *req;
+ struct nlmsghdr *hdr;
debug("seq %d", seq);
- req = find_request(seq);
- if (req) {
- request_list = g_slist_remove(request_list, req);
- g_free(req);
+ hdr = find_request(seq);
+ if (hdr) {
+ request_list = g_slist_remove(request_list, hdr);
+ g_free(hdr);
}
- req = g_slist_nth_data(request_list, 0);
- if (!req)
+ hdr = g_slist_nth_data(request_list, 0);
+ if (!hdr)
return 0;
- return send_request(req);
+ return send_request(hdr);
}
static void rtnl_message(void *buf, size_t len)
@@ -960,62 +956,65 @@ static gboolean netlink_event(GIOChannel *chan, GIOCondition cond, gpointer data
static int send_getlink(void)
{
- struct rtnl_request *req;
+ struct nlmsghdr *hdr;
+ struct rtgenmsg *msg;
debug("");
- req = g_try_malloc0(RTNL_REQUEST_SIZE);
- if (!req)
- return -ENOMEM;
+ hdr = g_malloc0(RTNL_REQUEST_SIZE);
+
+ hdr->nlmsg_len = RTNL_REQUEST_SIZE;
+ hdr->nlmsg_type = RTM_GETLINK;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ hdr->nlmsg_pid = 0;
+ hdr->nlmsg_seq = request_seq++;
- req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
- req->hdr.nlmsg_type = RTM_GETLINK;
- req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
- req->hdr.nlmsg_pid = 0;
- req->hdr.nlmsg_seq = request_seq++;
- req->msg.rtgen_family = AF_INET;
+ msg = (struct rtgenmsg *) NLMSG_DATA(hdr);
+ msg->rtgen_family = AF_INET;
- return queue_request(req);
+ return queue_request(hdr);
}
static int send_getaddr(void)
{
- struct rtnl_request *req;
+ struct nlmsghdr *hdr;
+ struct rtgenmsg *msg;
debug("");
- req = g_try_malloc0(RTNL_REQUEST_SIZE);
- if (!req)
- return -ENOMEM;
+ hdr = g_malloc0(RTNL_REQUEST_SIZE);
- req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
- req->hdr.nlmsg_type = RTM_GETADDR;
- req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
- req->hdr.nlmsg_pid = 0;
- req->hdr.nlmsg_seq = request_seq++;
- req->msg.rtgen_family = AF_INET;
+ hdr->nlmsg_len = RTNL_REQUEST_SIZE;
+ hdr->nlmsg_type = RTM_GETADDR;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ hdr->nlmsg_pid = 0;
+ hdr->nlmsg_seq = request_seq++;
- return queue_request(req);
+ msg = (struct rtgenmsg *) NLMSG_DATA(hdr);
+ msg->rtgen_family = AF_INET;
+
+ return queue_request(hdr);
}
static int send_getroute(void)
{
- struct rtnl_request *req;
+ struct nlmsghdr *hdr;
+ struct rtgenmsg *msg;
debug("");
- req = g_try_malloc0(RTNL_REQUEST_SIZE);
- if (!req)
- return -ENOMEM;
+ hdr = g_malloc0(RTNL_REQUEST_SIZE);
+
+ hdr->nlmsg_len = RTNL_REQUEST_SIZE;
+ hdr->nlmsg_type = RTM_GETROUTE;
+ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ hdr->nlmsg_pid = 0;
+ hdr->nlmsg_seq = request_seq++;
- req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
- req->hdr.nlmsg_type = RTM_GETROUTE;
- req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
- req->hdr.nlmsg_pid = 0;
- req->hdr.nlmsg_seq = request_seq++;
- req->msg.rtgen_family = AF_INET;
+ msg = (struct rtgenmsg *) NLMSG_DATA(hdr);
+ msg->rtgen_family = AF_INET;
- return queue_request(req);
+ return queue_request(hdr);
}
static gboolean update_timeout_cb(gpointer user_data)
@@ -1158,14 +1157,14 @@ void __vpn_rtnl_cleanup(void)
update_list = NULL;
for (list = request_list; list; list = list->next) {
- struct rtnl_request *req = list->data;
+ struct nlmsghdr *hdr = list->data;
debug("%s len %d type %d flags 0x%04x seq %d",
- type2string(req->hdr.nlmsg_type),
- req->hdr.nlmsg_len, req->hdr.nlmsg_type,
- req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
+ type2string(hdr->nlmsg_type),
+ hdr->nlmsg_len, hdr->nlmsg_type,
+ hdr->nlmsg_flags, hdr->nlmsg_seq);
- g_free(req);
+ g_free(hdr);
list->data = NULL;
}
diff --git a/vpn/vpn-settings.c b/vpn/vpn-settings.c
new file mode 100644
index 00000000..e78e5019
--- /dev/null
+++ b/vpn/vpn-settings.c
@@ -0,0 +1,314 @@
+/*
+ * ConnMan VPN daemon settings
+ *
+ * Copyright (C) 2012-2013 Intel Corporation. All rights reserved.
+ * Copyright (C) 2018-2020 Jolla Ltd. All rights reserved.
+ * Contact: jussi.laakkonen@jolla.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <connman/log.h>
+
+#include "vpn.h"
+
+#define DEFAULT_INPUT_REQUEST_TIMEOUT 300 * 1000
+#define PLUGIN_CONFIGDIR CONFIGDIR "/vpn-plugin"
+#define VPN_GROUP "DACPrivileges"
+
+static struct {
+ unsigned int timeout_inputreq;
+ char *binary_user;
+ char *binary_group;
+ char **binary_supplementary_groups;
+ char **system_binary_users;
+} connman_vpn_settings = {
+ .timeout_inputreq = DEFAULT_INPUT_REQUEST_TIMEOUT,
+ .binary_user = NULL,
+ .binary_group = NULL,
+ .binary_supplementary_groups = NULL,
+ .system_binary_users = NULL,
+};
+
+struct vpn_plugin_data {
+ char *binary_user;
+ char *binary_group;
+ char **binary_supplementary_groups;
+};
+
+GHashTable *plugin_hash = NULL;
+
+bool vpn_settings_is_system_user(const char *user)
+{
+ struct passwd *pwd;
+ struct passwd *system_pwd;
+ int i;
+
+ /*
+ * The username is not set = override should not be used. This is the
+ * case after the override is reset.
+ */
+ if (!user)
+ return true;
+
+ DBG("check user \"%s\"", user);
+
+ /*
+ * Ignore errors if no entry was found. Treat as system user to
+ * prevent using an invalid override.
+ */
+ pwd = vpn_util_get_passwd(user);
+ if (!pwd)
+ return true;
+
+ if (!connman_vpn_settings.system_binary_users) {
+ DBG("no binary users set");
+
+ /*
+ * Check if the user is root, or the uid equals to process
+ * effective uid.
+ */
+ return !pwd->pw_uid || pwd->pw_uid == geteuid();
+ }
+
+ /* Root set as user or the effective user id */
+ if (!pwd->pw_uid || pwd->pw_uid == geteuid())
+ return true;
+
+ for (i = 0; connman_vpn_settings.system_binary_users[i]; i++) {
+ const char *system_user =
+ connman_vpn_settings.system_binary_users[i];
+
+ system_pwd = vpn_util_get_passwd(system_user);
+ if (!system_pwd)
+ continue;
+
+ if (pwd->pw_uid == system_pwd->pw_uid)
+ return true;
+ }
+
+ return false;
+}
+
+const char *vpn_settings_get_binary_user(struct vpn_plugin_data *data)
+{
+ if (data && data->binary_user)
+ return data->binary_user;
+
+ return connman_vpn_settings.binary_user;
+}
+
+const char *vpn_settings_get_binary_group(struct vpn_plugin_data *data)
+{
+ if (data && data->binary_group)
+ return data->binary_group;
+
+ return connman_vpn_settings.binary_group;
+}
+
+char **vpn_settings_get_binary_supplementary_groups(struct vpn_plugin_data *data)
+{
+ if (data && data->binary_supplementary_groups)
+ return data->binary_supplementary_groups;
+
+ return connman_vpn_settings.binary_supplementary_groups;
+}
+
+unsigned int __vpn_settings_get_timeout_inputreq()
+{
+ return connman_vpn_settings.timeout_inputreq;
+}
+
+static char *get_string(GKeyFile *config, const char *group, const char *key)
+{
+ char *str = g_key_file_get_string(config, group, key, NULL);
+ return str ? g_strstrip(str) : NULL;
+}
+
+static char **get_string_list(GKeyFile *config, const char *group,
+ const char *key)
+{
+ gsize len = 0;
+ char **str = g_key_file_get_string_list(config, group, key, &len, NULL);
+
+ if (str) {
+ guint i = 0;
+
+ for (i = 0; i < len ; i++) {
+ str[i] = g_strstrip(str[i]);
+ }
+ }
+
+ return str;
+}
+
+static void parse_config(GKeyFile *config, const char *file)
+{
+ const char *group = "General";
+ GError *error = NULL;
+ int timeout;
+
+ if (!config)
+ return;
+
+ DBG("parsing %s", file);
+
+ timeout = g_key_file_get_integer(config, group,
+ "InputRequestTimeout", &error);
+ if (!error && timeout >= 0)
+ connman_vpn_settings.timeout_inputreq = timeout * 1000;
+
+ g_clear_error(&error);
+
+ connman_vpn_settings.binary_user = get_string(config, VPN_GROUP,
+ "User");
+ connman_vpn_settings.binary_group = get_string(config, VPN_GROUP,
+ "Group");
+ connman_vpn_settings.binary_supplementary_groups = get_string_list(
+ config, VPN_GROUP,
+ "SupplementaryGroups");
+ connman_vpn_settings.system_binary_users = get_string_list(
+ config, VPN_GROUP,
+ "SystemBinaryUsers");
+}
+
+struct vpn_plugin_data *vpn_settings_get_vpn_plugin_config(const char *name)
+{
+ struct vpn_plugin_data *data = NULL;
+
+ if (plugin_hash)
+ data = g_hash_table_lookup(plugin_hash, name);
+
+ return data;
+}
+
+static void vpn_plugin_data_free(gpointer data)
+{
+ struct vpn_plugin_data *plugin_data = (struct vpn_plugin_data*)data;
+
+ g_free(plugin_data->binary_user);
+ g_free(plugin_data->binary_group);
+ g_strfreev(plugin_data->binary_supplementary_groups);
+
+ g_free(data);
+}
+
+int vpn_settings_parse_vpn_plugin_config(const char *name)
+{
+ struct vpn_plugin_data *data;
+ gchar *file;
+ gchar *ext = ".conf";
+ GKeyFile *config;
+ gint err = 0;
+
+ if (!name || !*name)
+ return -EINVAL;
+
+ if (vpn_settings_get_vpn_plugin_config(name))
+ return -EALREADY;
+
+ file = g_strconcat(PLUGIN_CONFIGDIR, "/", name, ext, NULL);
+
+ config = __vpn_settings_load_config(file);
+
+ if (!config) {
+ err = -ENOENT;
+ DBG("Cannot load config %s for %s", file, name);
+ goto out;
+ }
+
+ data = g_try_new0(struct vpn_plugin_data, 1);
+
+ data->binary_user = get_string(config, VPN_GROUP, "User");
+ data->binary_group = get_string(config, VPN_GROUP, "Group");
+ data->binary_supplementary_groups = get_string_list(config, VPN_GROUP,
+ "SupplementaryGroups");
+
+ DBG("Loaded settings for %s: %s - %s",
+ name, data->binary_user, data->binary_group);
+
+ if (!plugin_hash)
+ plugin_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, vpn_plugin_data_free);
+
+ g_hash_table_replace(plugin_hash, g_strdup(name), data);
+
+ g_key_file_unref(config);
+
+out:
+ g_free(file);
+ return err;
+}
+
+void vpn_settings_delete_vpn_plugin_config(const char *name)
+{
+ if (plugin_hash && name)
+ g_hash_table_remove(plugin_hash, name);
+}
+
+GKeyFile *__vpn_settings_load_config(const char *file)
+{
+ GError *err = NULL;
+ GKeyFile *keyfile;
+
+ keyfile = g_key_file_new();
+
+ g_key_file_set_list_separator(keyfile, ',');
+
+ if (!g_key_file_load_from_file(keyfile, file, 0, &err)) {
+ if (err->code != G_FILE_ERROR_NOENT) {
+ connman_error("Parsing %s failed: %s", file,
+ err->message);
+ }
+
+ g_error_free(err);
+ g_key_file_unref(keyfile);
+ return NULL;
+ }
+
+ return keyfile;
+}
+
+int __vpn_settings_init(const char *file)
+{
+ GKeyFile *config;
+
+ config = __vpn_settings_load_config(file);
+ parse_config(config, file);
+ if (config)
+ g_key_file_unref(config);
+
+ return 0;
+}
+
+void __vpn_settings_cleanup()
+{
+ g_free(connman_vpn_settings.binary_user);
+ g_free(connman_vpn_settings.binary_group);
+ g_strfreev(connman_vpn_settings.binary_supplementary_groups);
+ g_strfreev(connman_vpn_settings.system_binary_users);
+
+ if (plugin_hash) {
+ g_hash_table_destroy(plugin_hash);
+ plugin_hash = NULL;
+ }
+}
diff --git a/vpn/vpn-util.c b/vpn/vpn-util.c
new file mode 100644
index 00000000..9ef14d38
--- /dev/null
+++ b/vpn/vpn-util.c
@@ -0,0 +1,224 @@
+/*
+ * ConnMan VPN daemon utils
+ *
+ * Copyright (C) 2020 Jolla Ltd. All rights reserved.
+ * Copyright (C) 2020 Open Mobile Platform LLC.
+ * Contact: jussi.laakkonen@jolla.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <glib/gstdio.h>
+
+#include <connman/log.h>
+
+#include "vpn.h"
+
+static bool is_string_digits(const char *str)
+{
+ int i;
+
+ if (!str || !*str)
+ return false;
+
+ for (i = 0; str[i]; i++) {
+ if (!g_ascii_isdigit(str[i]))
+ return false;
+ }
+
+ return true;
+}
+
+static uid_t get_str_id(const char *username)
+{
+ if (!username || !*username)
+ return 0;
+
+ return (uid_t)g_ascii_strtoull(username, NULL, 10);
+}
+
+struct passwd *vpn_util_get_passwd(const char *username)
+{
+ struct passwd *pwd;
+ uid_t uid;
+
+ if (!username || !*username)
+ return NULL;
+
+ if (is_string_digits(username)) {
+ uid = get_str_id(username);
+ pwd = getpwuid(uid);
+ } else {
+ pwd = getpwnam(username);
+ }
+
+ return pwd;
+}
+
+struct group *vpn_util_get_group(const char *groupname)
+{
+ struct group *grp;
+ gid_t gid;
+
+ if (!groupname || !*groupname)
+ return NULL;
+
+ if (is_string_digits(groupname)) {
+ gid = get_str_id(groupname);
+ grp = getgrgid(gid);
+ } else {
+ grp = getgrnam(groupname);
+ }
+
+ return grp;
+}
+
+/*
+ * These prefixes are used for checking if the requested path for
+ * vpn_util_create_path() is acceptable. Allow only prefixes meant for run-time
+ * or temporary use to limit the access to any system resources.
+ *
+ * VPN core and plugins would need to create only temporary dirs for the
+ * run-time use. The requested dirs can be created for a specific user when
+ * running a VPN plugin as a different user and thus, user specific run dir is
+ * allowed and limitation to access any other system dir is restricted.
+ */
+static const char *allowed_prefixes[] = { "/var/run/connman-vpn/",
+ "/var/run/user/", "/tmp/", NULL };
+
+static int is_path_allowed(const char *path)
+{
+ int err = -EPERM;
+ int i;
+
+ if (!path || !*path || !g_path_is_absolute(path))
+ return -EINVAL;
+
+ if (g_strrstr(path, "..") || g_strrstr(path, "./"))
+ return -EPERM;
+
+ for (i = 0; allowed_prefixes[i]; i++) {
+ if (g_str_has_prefix(path, allowed_prefixes[i])) {
+ const char *suffix = path +
+ strlen(allowed_prefixes[i]);
+
+ /*
+ * Don't allow plain prefixes, an additional dir must
+ * be included after the prexix in the requested path.
+ */
+ if (suffix && *suffix != G_DIR_SEPARATOR &&
+ g_strrstr(suffix,
+ G_DIR_SEPARATOR_S)) {
+ DBG("allowed %s, has suffix %s", path, suffix);
+ err = 0;
+ }
+
+ break;
+ }
+ }
+
+ return err;
+}
+
+int vpn_util_create_path(const char *path, uid_t uid, gid_t grp, int mode)
+{
+ mode_t old_umask;
+ char *dir_p;
+ int err;
+
+ err = is_path_allowed(path);
+ if (err)
+ return err;
+
+ dir_p = g_path_get_dirname(path);
+ if (!dir_p)
+ return -ENOMEM;
+
+ err = g_unlink(dir_p);
+ if (err)
+ err = -errno;
+
+ switch (err) {
+ case 0:
+ /* Removed */
+ case -ENOENT:
+ /* Did not exist */
+ break;
+ case -EACCES:
+ /*
+ * Cannot get write access to the containing directory, check
+ * if the path exists.
+ */
+ if (!g_file_test(dir_p, G_FILE_TEST_EXISTS))
+ goto out;
+
+ /* If the dir does not exist new one cannot be created */
+ if (!g_file_test(dir_p, G_FILE_TEST_IS_DIR))
+ goto out;
+
+ /* Do a chmod as the dir exists */
+ /* fallthrough */
+ case -EISDIR:
+ /* Exists as dir, just chmod and change owner */
+ err = g_chmod(dir_p, mode);
+ if (err) {
+ connman_warn("chmod %s failed, err %d", dir_p, err);
+ err = -errno;
+ }
+
+ goto chown;
+ default:
+ /* Any other error that is not handled here */
+ connman_warn("remove %s failed, err %d", dir_p, err);
+ goto out;
+ }
+
+ /* Set dir creation mask to correspond to the mode */
+ old_umask = umask(~mode & 0777);
+
+ DBG("mkdir %s", dir_p);
+ err = g_mkdir_with_parents(dir_p, mode);
+
+ umask(old_umask);
+
+ if (err) {
+ connman_warn("mkdir %s failed, err %d", dir_p, err);
+ err = -errno;
+ goto out;
+ }
+
+chown:
+ if (uid && grp) {
+ err = chown(dir_p, uid, grp);
+ if (err) {
+ err = -errno;
+ connman_warn("chown %s failed for %d/%d, err %d",
+ dir_p, uid, grp, err);
+ }
+ }
+
+out:
+ g_free(dir_p);
+
+ return err;
+}
+
diff --git a/vpn/vpn.h b/vpn/vpn.h
index 26b13d70..94cee255 100755
--- a/vpn/vpn.h
+++ b/vpn/vpn.h
@@ -35,7 +35,7 @@ struct vpn_ipconfig;
struct connman_ipaddress *__vpn_ipconfig_get_address(struct vpn_ipconfig *ipconfig);
unsigned short __vpn_ipconfig_get_type_from_index(int index);
unsigned int __vpn_ipconfig_get_flags_from_index(int index);
-void __vpn_ipconfig_foreach(void (*function) (int index,
+void vpn_ipconfig_foreach(void (*function) (int index,
void *user_data), void *user_data);
void __vpn_ipconfig_set_local(struct vpn_ipconfig *ipconfig,
const char *address);
@@ -88,7 +88,6 @@ int __vpn_provider_create_from_config(GHashTable *settings,
int __vpn_provider_set_string_immutable(struct vpn_provider *provider,
const char *key, const char *value);
DBusMessage *__vpn_provider_get_connections(DBusMessage *msg);
-const char * __vpn_provider_get_ident(struct vpn_provider *provider);
struct vpn_provider *__vpn_provider_lookup(const char *identifier);
int __vpn_provider_indicate_state(struct vpn_provider *provider,
enum vpn_provider_state state);
@@ -100,7 +99,7 @@ int __vpn_provider_disconnect(struct vpn_provider *provider);
int __vpn_provider_remove(const char *path);
int __vpn_provider_delete(struct vpn_provider *provider);
void __vpn_provider_cleanup(void);
-int __vpn_provider_init(bool handle_routes);
+int __vpn_provider_init();
#include "vpn-rtnl.h"
@@ -115,7 +114,30 @@ int __vpn_rtnl_send(const void *buf, size_t len);
int __vpn_config_init(void);
void __vpn_config_cleanup(void);
-char *__vpn_config_get_string(GKeyFile *key_file,
- const char *group_name, const char *key, GError **error);
-char **__vpn_config_get_string_list(GKeyFile *key_file,
- const char *group_name, const char *key, gsize *length, GError **error);
+char *__vpn_config_get_string(GKeyFile *key_file, const char *group_name,
+ const char *key, GError **error);
+char **__vpn_config_get_string_list(GKeyFile *key_file, const char *group_name,
+ const char *key, gsize *length, GError **error);
+bool __vpn_config_get_boolean(GKeyFile *key_file, const char *group_name,
+ const char *key, bool default_value);
+
+int __vpn_settings_init(const char *file);
+void __vpn_settings_cleanup(void);
+GKeyFile *__vpn_settings_load_config(const char *file);
+unsigned int __vpn_settings_get_timeout_inputreq(void);
+
+struct vpn_plugin_data;
+
+int vpn_settings_parse_vpn_plugin_config(const char* plugin_name);
+void vpn_settings_delete_vpn_plugin_config(const char *name);
+struct vpn_plugin_data* vpn_settings_get_vpn_plugin_config(const char *name);
+
+const char * vpn_settings_get_binary_user(struct vpn_plugin_data *data);
+const char * vpn_settings_get_binary_group(struct vpn_plugin_data *data);
+char ** vpn_settings_get_binary_supplementary_groups(
+ struct vpn_plugin_data *data);
+bool vpn_settings_is_system_user(const char *user);
+
+struct passwd *vpn_util_get_passwd(const char *username);
+struct group *vpn_util_get_group(const char *groupname);
+int vpn_util_create_path(const char *path, uid_t uid, gid_t grp, int mode);