For nest-cam v350 release

Bug: 259322762
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9b4b30d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,73 @@
+*.o
+*.a
+*.lo
+*.la
+.deps
+.libs
+.dirstamp
+Makefile
+Makefile.in
+aclocal.m4
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+depcomp
+compile
+install-sh
+libtool
+ltmain.sh
+missing
+stamp-h1
+autom4te.cache
+
+connman.pc
+include/connman
+include/version.h
+src/builtin.h
+src/connmand
+src/connman.conf
+src/connman.service
+src/*-connman.rules
+plugins/connman.policy
+scripts/connman
+scripts/openconnect-script
+scripts/openvpn-script
+client/connmanctl
+tools/wispr
+tools/dhcp-test
+tools/dhcp-server-test
+tools/addr-test
+tools/tap-test
+tools/web-test
+tools/wpad-test
+tools/resolv-test
+tools/polkit-test
+tools/iptables-test
+tools/supplicant-test
+tools/dbus-test
+tools/stats-tool
+tools/stats-ringbuffer-dump
+tools/private-network-test
+unit/test-session
+unit/test-ippool
+unit/test-nat
+
+doc/*.bak
+doc/*.stamp
+doc/connman.*
+!doc/connman.8
+!doc/connman.conf.5
+doc/connman-*.txt
+doc/*.sgml
+doc/version.xml
+doc/xml
+doc/html
+
+vpn/builtin.h
+vpn/connman-vpnd
+vpn/connman-vpn.service
+vpn/net.connman.vpn.service
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000..93fae59
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,4 @@
+Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>	<luiz.dentz-von@nokia.com>
+Leena Gunda <leena.gunda@wipro.com>			<leena.gunda@wipro.com>
+Flávio Ceolin <flavio.ceolin@profusion.mobi>		<flavio.ceolin@profusion.mobi>
+Daniel Wagner <daniel.wagner@bmw-carit.de>		<daniel.wagner@bmw-carit.de>
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..7035be6
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,53 @@
+Marcel Holtmann <marcel@holtmann.org>
+Inaky Perez-Gonzalez <inaky@linux.intel.com>
+Samuel Ortiz <sameo@linux.intel.com>
+Joshua Lock <josh@linux.intel.com>
+Richard Purdie <rpurdie@linux.intel.com>
+Gustavo Sverzut Barbieri <barbieri@profusion.mobi>
+Martin Xu <martin.xu@intel.com>
+Sam Leffler <sleffler@google.com>
+Daniel Wagner <daniel.wagner@bmw-carit.de>
+Forest Bond <forest@alittletooquiet.net>
+Kalle Valo <kalle.valo@canonical.com>
+Fabien Marotte <fabienx.marotte@linux.intel.com>
+Pekka Pessi <pekka.pessi@nokia.com>
+Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
+Cristiano Fernandes <cristiano.fernandes@hp.com>
+Joey Lee <jlee@novell.com>
+Leena Gunda <leena.gunda@wipro.com>
+Patrik Flykt <patrik.flykt@linux.intel.com>
+David Woodhouse <dwmw2@infradead.org>
+Gustavo Padovan <gustavo@padovan.org>
+Julien Massot <jmassot@aldebaran-robotics.com>
+Jukka Rissanen <jukka.rissanen@linux.intel.com>
+Grant Erickson <marathon96@gmail.com>
+Guillaume Lucas <guillaumex.lucas@intel.com>
+Henri Bragge <henri.bragge@ixonos.com>
+Alok Barsode <alok.barsode@intel.com>
+Sébastien Bianti <sebastien.bianti@linux.intel.com>
+Yu A Wang <yu.a.wang@intel.com>
+Thierry Boureille <thierry.boureille@gmail.com>
+Paolo Pellegrino <paolo.pellegrino@zirak.it>
+Bertrand Aygon <bertrand.aygon@intel.com>
+Jeff Zheng <jeff.zheng@intel.com>
+Philippe Nunes <philippe.nunes@linux.intel.com>
+Danny Jeongseok Seo <s.seo@samsung.com>
+Flávio Ceolin <flavio.ceolin@profusion.mobi>
+Arjan van de Ven <arjan@linux.intel.com>
+Daniel Mack <zonque@gmail.com>
+Guillaume Zajac <guillaume.zajac@linux.intel.com>
+Manfred Kober <manfred.kober@gmx.de>
+Mario Domenech Goulart <mario.goulart@gmail.com>
+Otavio Salvador <otavio@ossystems.com.br>
+Tim Sander <tim01@iss.tu-darmstadt.de>
+Adrien Bustany <adrien.bustany@nokia.com>
+Henrique Dante de Almeida <hdante@profusion.mobi>
+Lucas De Marchi <lucas.demarchi@profusion.mobi>
+Elena Tebesoi <elena.tebesoi@gmail.com>
+Mikel Astiz <mikel.astiz@bmw-carit.de>
+Paulo Pizarro <paulo.pizarro@gmail.com>
+Ross Burton <ross.burton@intel.com>
+Tudor Marcu <tudor.a.marcu@intel.com>
+Ceara Chewning <ceara.k.chewning@intel.com>
+Johannes Berg <johannes.berg@intel.com>
+Justin Maggard <jmaggard10@gmail.com>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..6d45519
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       51 Franklin St, 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.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, 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 or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+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 give any other recipients of the Program a copy of this License
+along with the Program.
+
+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 Program or any portion
+of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+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 Program, 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 Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) 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; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, 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 executable.  However, as a
+special exception, the source code 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.
+
+If distribution of executable or 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 counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program 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.
+
+  5. 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 Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program 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 to
+this License.
+
+  7. 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 Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+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.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program 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.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the 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 Program
+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 Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, 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
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), 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 Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  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 program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..f77dede
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,836 @@
+ver 1.11:
+	Fix issue with agent reference counting imbalance.
+	Fix issue with handling max number of SSID for scanning.
+	Fix issue with missing notification of online state changes.
+	Fix issue with not properly triggering auto-connect behavior.
+	Fix issue with disabling IPv6 in lower up interface states.
+	Fix issue with spurious error messages for interface handling.
+	Fix issue with wrong answer count in DNS responses.
+	Fix issue with crash in DNS lookup function.
+	Add support for BlueZ 5.x network interfaces.
+	Remove deprecated WiMAX support.
+
+ver 1.10:
+	Fix issue with not skipping service if settings loading fails.
+	Fix issue with not clearing address before starting DHCP.
+	Fix issue with not handling removal of GPRS context.
+	Fix issue with not closing UDP socket on error condition.
+	Fix issue with race condition when removing WiFi device.
+	Add support for separate VPN daemon.
+
+ver 1.9:
+	Fix issue with WISPr portal context handling.
+	Fix issue with DNS lookup from wrong queue.
+	Fix issue with DNS data reception after disconnect.
+	Fix issue with missing DNS host part length checking.
+	Fix issue with RFKILL and technology interaction.
+	Fix issue with tethering and disabled technologies.
+	Add support for single connected technology setting.
+
+ver 1.8:
+	Fix issue with NTP transmit time calculation.
+	Fix issue with WiFi Tethering and newer kernels.
+	Fix issue with Netlink messages from Wireless Extensions.
+	Fix issue with IPv6 nameserver refresh beeing applied to IPv4.
+	Fix issue with overwriting DNS proxy address information.
+	Fix issue with missing handling of RFKILL hard blocking.
+	Add support for disabling internal backtrace functionality.
+
+ver 1.7:
+	Fix issue with IPv4 address removal when setting interface down.
+	Fix issue with wrong error when setting tethering support option.
+	Fix issue with errors reported twice via agent to the client.
+	Fix issue with missing serialization of agent callbacks.
+	Add initial version of command line client tool.
+
+ver 1.6:
+	Fix issue with Bluetooth networking support.
+	Fix issue with technology enabling method returns.
+	Fix issue with wrong IP address for fixed configurations.
+	Fix issue with IP address setting when interface is down.
+	Fix issue with handling duplicate hidden WiFi networks.
+	Fix issue with missing scanning for hidden WiFi networks.
+	Fix issue with missing update of service properties.
+	Fix issue with missing clearing of service errors.
+	Add manual pages for daemon and configuration file.
+
+ver 1.5:
+	Fix issue with detecting Bluetooth networks when powered off.
+	Fix issue with connection attempts of non-favorite services.
+	Fix issue with connection attempts of disabled IP configurations.
+	Fix issue with missing auto-connection after changing IP method.
+	Fix issue with setting service state when changing IPv4 method.
+	Fix issue with IPv6 usage and static/manual configuration.
+	Add support for configuration option to disable hostname updates.
+	Add support for storing WiFi Tethering identifier and passphrase.
+	Add support for signaling changes of error property.
+
+ver 1.4:
+	Fix issue with WiFi scanning in Tethering mode.
+	Fix issue with WISPr operation and disconnects.
+	Fix issue with DHCP client and restart behavior.
+	Fix issue with DNS resolving and failing IPv6 records.
+	Fix issue with incorrect NTP leap-not-in-sync flag.
+	Fix issue with incorrect NTP transmit time value.
+	Fix issue with failing NTP server due to routing.
+	Fix issue with missing gateway change notification.
+	Fix issue with stale network interfaces at startup.
+	Fix issue with pending method reply and agent errors.
+	Add support for providing previous WPS PIN to agent.
+	Add support for WPA supplicant based auto-scanning.
+	Add support for per device regulatory domain setting.
+	Add support for provisioning hidden WiFi networks.
+
+ver 1.3:
+	Fix issue with default configuration values.
+	Fix issue with timeserver canonical name entries.
+	Fix issue with crash from cellular dummy context.
+	Fix issue with incorrect index for private networks.
+
+ver 1.2:
+	Fix issue with not handling WiFi security changes.
+	Fix issue with not stopping WiFi scanning on shutdown.
+	Fix issue with auto-scanning and network discovery.
+	Fix issue with D-Bus reply for hidden WiFi networks.
+	Fix issue with overlapping memory areas and DNS requests.
+	Add support for randomized DNS transaction identifiers.
+	Add support for DNS caching over TCP connections.
+	Add support for using default IPv6 privacy setting.
+	Add support for providing previous passphrase to agent.
+	Add support for configuration unprovisioning handling.
+	Add support for NetworkInterfaceBlacklist configuration.
+	Add support for Bluetooth DUN daemon (dundee).
+
+ver 1.1:
+	Fix issue with missing message type and DHCPv4 support.
+	Fix issue with potential NULL pointer in DHCPv6 handling.
+	Fix issue with potential NULL pointer in VPN handling.
+	Fix issue with potential NULL pointer for WiFi SSID.
+	Fix issue with missing conversion of raw WiFi PSK input.
+	Fix issue with missing stop for WiFi auto-scanning handling.
+	Fix issue with uninitialized IPv6 prefix length in oFono plugin.
+	Fix issue with domain search list handling according to RFC 6106.
+	Fix issue with domain name list notifications.
+	Fix issue with nameserver list notifications.
+	Fix issue with incorrect fixed IP configuration.
+	Fix issue with incorrect cleanup of resolver timers.
+	Fix issue with handling of RDNSS lifetime expiration.
+	Fix issue with crash on wrong domain length information.
+	Add support for favorite service database migration.
+	Add support for disabling WISPr functionality.
+	Add support for configurable agent timeouts.
+
+ver 1.0:
+	Fix issue with missing WiFi disconnecting flag.
+	Fix issue with missing GPRS context attached check.
+	Fix issue with potential crash and supplicant handling.
+	Fix issue with potential crash and VPN provider.
+	Fix issue with potential crash and host routes.
+
+ver 0.85:
+	Fix issue with duplicate service timeservers.
+	Fix issue with failure state when aborting agent request.
+	Fix issue with automatic scanning for hidden WiFi networks.
+	Fix issue with missing hostname/domainname validity checks.
+	Fix issue with missing DHCP packet length checks.
+	Add support for browser launching from WISPr login.
+
+ver 0.84:
+	Fix issue with handling changed WiFi security of access points.
+	Fix issue with state notification of NetworkManager compatibility.
+
+ver 0.83:
+	Fix issue with Ethernet not being enabled by default.
+	Fix issue with missing host routes for WISPr request.
+	Fix issue with missing HTTPS handling for WISPr support.
+	Fix issue with agent asking for passphrase for open service.
+	Fix issue with endless online check for preferred technology.
+	Fix issue with IPv6 RDNSS and DNS server creation.
+	Fix issue with WiFi roaming state change handling.
+	Fix issue with broken handling of WPS PBC method.
+
+ver 0.82:
+	Fix issue with global online state handling.
+	Fix issue with timeserver handling in case of VPN.
+	Fix issue with automatic WiFi scanning handling.
+	Fix issue with WPS PIN length of zero and PBC.
+
+ver 0.81:
+	Update default configuration options.
+	Add support for WPS PBC advertising handling.
+	Add support for wpa_supplicant background scanning.
+	Fix issue with showing cellular services without APN.
+	Fix issue with missing timeservers changed signal.
+
+ver 0.80:
+	Update to support additional D-Bus API changes.
+	Add support for preferred technologies switching.
+	Add support for default auto connect technologies option.
+	Add support for service specific timeserver configuration.
+	Add support for extended timeserver fallback functionality.
+	Add support for extended nameserver fallback functionality.
+	Add support for user supplied routes for providers.
+	Add support for checking WiFi passphrase validity.
+	Fix issue with WISPr support and proxy handling.
+	Fix issue with Ethernet and auto connect handling.
+	Fix issue with too early IPv6 auto connection.
+	Fix issue with too early 6to4 connection checks.
+	Fix issue with oFono interaction on disconnect.
+	Fix issue with DNS servers behind point-to-point links.
+	Fix issue with pending DNS proxy requests.
+	Fix multiple issues with VPN handling.
+	Fix multiple issues with default gateway handling.
+
+ver 0.79:
+	Update to support changed D-Bus API.
+	Add support for WiFi background scanning.
+	Add support for showing hidden WiFi networks as services.
+	Add support for generic stateless DHCPv6 handling.
+	Add support for DHCPv4 client identifier handling.
+	Add support for generic IP address pool handling.
+	Add support for global DNS cache handling.
+	Add support for internal NTP time handling.
+	Add support for updated oFono handling.
+
+ver 0.78:
+	Fix multiple issues with service connection states.
+	Fix multiple issues with technology handling.
+	Fix issue with DHCP file descriptor leakage.
+	Fix issue with open access points and WPS.
+	Fix issue with handling of cellular devices.
+	Fix issue with DNS proxy hostname resolving.
+	Add support for PPTP and L2TP VPN tunneling.
+	Add support for organized settings storage.
+	Add support for WiFi fast connect handling.
+	Add support for better WiFi error handling.
+	Add support for integrated WISPr handling.
+
+ver 0.77:
+	Fix issue with iptables API breakage.
+	Fix issue with agent input handling.
+	Fix issue with empty cellular operator name.
+	Fix issue with reference counting for network objects.
+	Fix issue with missing D-Bus signals for proxy changes.
+	Fix issue with group identifier and hidden WiFi networks.
+	Fix issue with setting wrong gateway for PPP connections.
+	Fix issue with mismatch of stored IP configuration settings.
+	Fix issue with not stopping DHCP for IPv4 configuration.
+	Add support for remembering last IP address from DHCP.
+	Add support for EAP-GTC authentication method.
+
+ver 0.76:
+	Fix issue with loopback interface setup.
+	Fix issue with /etc/localtime being a symlink.
+	Fix issue with not handling dummy network devices.
+	Fix issue with not provisioning existing services.
+	Fix issue with running WPAD on IPv6 connections.
+	Fix issue with client certificate for TTLS/PEAP.
+	Remove internal element infrastructure.
+
+ver 0.75:
+	Fix issue with 3G connect timeout handling.
+	Fix issue with WiFi raw key PSK handling.
+	Fix issue with DHCP renewal timeout handling.
+	Fix issue with DHCP and empty nameserver list.
+	Add support for unit testing.
+
+ver 0.74:
+	Fix issue with race condition in ready/online handling.
+	Fix issue with DHCP release callback handling.
+	Fix multiple issues with session API handling.
+	Add support for using DNS proxy for Tethering.
+	Add support for Private Network API.
+	Add support for Clock API.
+
+ver 0.73:
+	Update support for session API handling.
+	Add support for more advanced roaming policies.
+	Add support for EAP identity and passphrase queries.
+	Add support for IPv6 handling with cellular bearer.
+	Add support for main configuration file.
+	Remove deprecated profile interface.
+
+ver 0.72:
+	Fix issue with overwriting DNS servers from DHCP.
+	Fix issue with DHCP renewal with same configuration.
+	Fix issue with multiple memory leaks.
+	Add support for 6to4 tunneling.
+
+ver 0.71:
+	Fix issue with not storing IPv6 privacy settings.
+	Fix issue with storing fixed and manual IP settings.
+	Fix issue with service state when PAN connection fails.
+	Fix issue with tethering and WiFi bridge handling.
+	Fix issue with autonomously activated contexts.
+	Fix issue with nameserver array for PACrunner.
+	Fix issue with network information memory leak.
+	Fix issue with double-free in statistics handling.
+	Fix issue with handling malformed profiles.
+	Fix issue with pending DHCP client requests.
+	Add initial support for TI shared transport handling.
+
+ver 0.70:
+	Add support for reporting invalid WiFi passphrases.
+	Add support for IPv6 privacy extension.
+	Add support for IPv6 advanced features.
+	Add support for IPv6 nameserver settings.
+	Remove deprecated APN service settings.
+
+ver 0.69:
+	Fix issue with not handling DNS proxy failures gracefully.
+	Fix issue with double free in statistics handling.
+	Fix issue with early tethering bridge creation.
+	Add support for tethering property per technology.
+	Add support for initial WiFi tethering feature.
+	Add support for using PACrunner as proxy driver.
+	Add support for WPS as part of the security property.
+
+ver 0.68:
+	Fix issue with wrong name of PolicyKit configuration file.
+	Fix issue with inconsistency of WiFi scan states.
+	Fix issue with missing auto-reconnect and oFono.
+	Add support for vpnc based private networks.
+	Add support for WiFi Protected Setup handling.
+	Remove legacy WiFi plugin.
+
+ver 0.67:
+	Fix issue with oFono plugin and multiple online calls.
+	Fix issue with checking for AutoConnect service property.
+	Remove deprecated MCC and MNC service properties.
+
+ver 0.66:
+	Fix multiple set of memory leaks.
+	Fix issue with WPA supplicant phase2 values.
+	Fix issue with WiFi access points after kill/restart.
+	Fix issue with correct PACrunner configuration loading.
+	Add support for loading provision files at runtime.
+	Add support for setting proxy auto-configuration.
+	Add support for IPv6 auto-configured addresses.
+
+ver 0.65:
+	Use new WiFi plugin by default.
+	Fix issue with handling already powered devices.
+	Fix issue with handling proxy PAC option from DHCP.
+	Add support for handling regulatory domain settings.
+	Add support for handling IPv6 router advertisements.
+	Add support for handling IPv6 nameservers.
+	Add support for handling multiple search domains.
+	Add support for handling oFono modem lockdown.
+	Add support for handling IPv6 DNS connections.
+	Add support for IPv4 Link-Local negotiation.
+	Add support for USB CDC Tethering functionality.
+
+ver 0.64:
+	Update service name to net.connman domain.
+	Fix issue with disabling a technology twice.
+	Fix issue with using wrong string for Proxy.Method.
+	Fix issue with TCP connection lookup and DNS proxy.
+	Fix issue with TCP receive busy waits and DNS proxy.
+	Fix various issues with WPA Supplicant interaction.
+	Add support for chunk encoding to HTTP client.
+	Add support for internal HTTP client for portal detection.
+	Add support for internal DHCP server setup.
+	Add support for internal NAT and IP forwarding setup.
+	Add support for Bluetooth Tethering functionality.
+	Remove deprecated device and network D-Bus interfaces.
+	Remove support for dhclient plugin.
+
+ver 0.63:
+	Change to use nl80211/cfg80211 WiFi management by default.
+	Fix various issues with new WPA Supplicant interface.
+	Fix issue with not connecting failed networks at boot.
+	Fix issue with properly tracking RFKILL blocked state.
+	Fix issue with missing signals for IPv4/IPv6 gateway details.
+	Add support for using RTNL for setting IPv4/IPv6 details.
+	Add support for using PHONET_PIPE GPRS interfaces.
+	Add support for setting manual proxy configurations.
+	Add support for exporting proxy configurations to PACrunner.
+	Add support for combined home and roaming statistics.
+	Add support for OpenVPN connections.
+	Remove dependency on udev.
+
+ver 0.62:
+	Fix crash with non-existent or extra DHCP result options.
+	Fix crash when doing PEAP/TTLS authentication.
+	Fix issue with handling multiple data counters.
+	Fix issue with Bluetooth adapters without address.
+	Fix issue with multiple scanning attempts after disconnects.
+	Fix issue with VPN services when switching into offline mode.
+	Add support for storing statistics information in separate files.
+	Add support for verification of configuration file parameters.
+	Add support for handling time server values from DHCP.
+	Add support for allowing DNS over TCP within the DNS proxy.
+	Add support for loading proxy configurations into PACrunner.
+	Add support for WiFi plugin using new WPA Supplicant D-Bus API.
+	Add support for requesting passphrases via agents.
+	Remove default support for EDNS0 option.
+
+ver 0.61:
+	Add support for using the internal DHCP client by default.
+	Add support for latest PolicyKit framework.
+	Add support for new oFono D-Bus interfaces.
+
+ver 0.60:
+	Fix issue with missing reset of proxy settings.
+	Fix issue with missing Ethernet property changed signal.
+	Fix issue with offline operation on already blocked devices.
+	Fix issue with offline mode and device powered changes.
+	Fix issue with portal detection and DHCP renewals.
+	Fix issue with connection attempts for removed networks.
+	Fix issue with stale pointers of networks.
+
+ver 0.59:
+	Fix issue with D-Bus object paths of VPN providers.
+
+ver 0.58:
+	Fix various issues around offline mode.
+	Fix various issues with VPN nameserver handling.
+	Add support for home/roaming network statistics.
+	Add support for EAP-TTLS WiFi configuration.
+	Add support for creating backtraces.
+
+ver 0.57:
+	Fix missing default profile creation.
+	Fix missing service integration of VPN providers.
+	Fix missing export of PAC information retrieved from DHCP.
+	Fix issue with detection of new Bluetooth devices.
+	Fix issue with offline mode handling.
+	Fix issue with device power handling.
+
+ver 0.56:
+	Fix issues with offline mode handling.
+	Fix service integration with VPN providers.
+	Add internal asynchronous resolver library.
+	Add internal DHCP client library.
+	Add support for using internal DHCP client.
+	Add support for WPAD proxy auto-configuration.
+	Add support for static IPv6 configuration.
+	Add support for DHCP provided domain names.
+	Add initial support for on-demand connections.
+	Remove uDHCP and resolvconf plugins.
+
+ver 0.55:
+	Fix issue with 3G roaming status indication.
+	Fix issue with using -H option with dhclient.
+	Fix issue with loading WiFi SSID details for scanning.
+	Add support for setting host routes for DNS servers.
+	Add support for more detailed statistics counters.
+	Add support for internal DHCP client library.
+
+ver 0.54:
+	Fix issue with root requests and EDNS0 OPT records.
+	Fix issue with default gateway when route deletion fails.
+	Fix issue with group identifiers for cellular networks.
+	Fix issue with fixed IP settings from cellular networks.
+	Fix issue with nameserver settings and manual configuration.
+	Add support for cellular network name changes.
+	Add support for cellular signal strength changes.
+	Add support for actively scanning for hidden networks.
+	Add support for ASCII based WEP keys.
+	Add support for NTP timeserver updates.
+	Add support for PPP default route settings.
+
+ver 0.53:
+	Fix issue with supplicant and device scanning state cleaning.
+	Fix issue with Bluetooth PAN networks stay in connected state.
+	Fix issue with reference counting and connected state.
+	Fix issue with technology disabling on device removal.
+	Fix issue with two default gateways when using VPN.
+	Fix issue with static IPv4 configuration and signals.
+	Add support for splitting DHCP provided nameserver results.
+	Add support multiple nameservers in /etc/resolv.conf.
+	Add support for setting manual DNS server configuration.
+	Add support for exporting IPv4 gateway information.
+	Add support for newer versions of oFono API.
+
+ver 0.52:
+	Fix issue with new "connected" states.
+	Fix issue with hidden networks and PSK.
+	Fix issue with DHCP and Bluetooth PAN.
+	Fix issue when disconnecting PAN networks.
+	Add support for application sessions.
+	Add plugin for hh2serial GPS support.
+
+ver 0.51:
+	Fix issue with missing device power toggling.
+	Fix issue with D-Bus object path on device removal.
+	Add support for WiFi portal detection.
+	Add support for configuring static gateways.
+	Remove unneeded plugin for Option HSO support.
+	Remove unneeded plugin for Ericsson MBM support.
+
+ver 0.50:
+	Fix configuration loading for unknown services.
+	Fix IP method setting of Ethernet plugin.
+
+ver 0.49:
+	Fix issue with WiFi power changes.
+	Fix issue with Bluetooth device startup.
+	Fix issue with host route settings for VPN.
+	Fix issue with processing of RFKILL events.
+	Fix some WPA Enterprise privacy issues.
+	Add support for basic Ethernet information.
+	Add support for static IP settings.
+
+ver 0.48:
+	Fix signal strength calculation when quality is not provided.
+	Fix issues with wpa_supplicant state tracking.
+	Fix faulty removal of IP address from interface.
+	Fix permissions of newly created /etc/resolv.conf file.
+	Fix DNS proxy handling when in offline mode.
+	Add support for EDNS0 resolver option.
+	Add workaround for large EDNS0 queries.
+	Add workaround for DHCP startup failures with WiFi networks.
+	Add support for handling hostnames and domainnames.
+	Add support for IPv4 configuration via service interface.
+	Add support for fixed and manual IPv4 configuration.
+	Add support for default service changed notifier.
+	Add support for clearing failure state via service removal.
+	Add support for OpenConnect VPN connections.
+	Add support for IEEE 802.1x WiFi networks.
+	Add support for roaming between WPA and WPA2 networks.
+	Add various generic D-Bus helpers and use them.
+	Remove special handling of Ethernet devices.
+
+ver 0.47:
+	Fix segmentation fault on resolver shutdown.
+	Fix issue with adding nameserver that doesn't exist.
+	Fix issue when no broadcast address is given.
+	Fix issue with missing property changed signal.
+	Add checks for invalid supplicant state transitions.
+	Add initial version of oFono GPRS support.
+	Add support for dynamic debug framework.
+
+ver 0.46:
+	Fix reconnect issue when power off or disabling the device.
+	Remove problematic retry on failure code path.
+
+ver 0.45:
+	Fix crash with connect timeout and second connect attempt.
+	Fix reconnect issues after suspend or roaming attempt.
+
+ver 0.44:
+	Fix command line options for device filtering.
+	Fix issue with network reference in MBM support.
+	Fix handling when losing network access in MBM plugin.
+	Fix broken libiWmxSDK callback parameter handling.
+	Add work around Intel WiMAX SDK API breakage.
+
+ver 0.43:
+	Fix issue with missing scanning after power up.
+	Fix issue with udev versus /dev/rfkill event processing.
+	Fix issue with powered down device on connection attempt.
+	Add support for multiple connection attempts.
+	Add support for tracking the operation state.
+	Add full support for Ericsson MBM cellular devices.
+
+ver 0.42:
+	Fix issue with switching between hidden WiFi networks.
+	Fix issue with missing scanning after disconnect.
+	Fix issue with not triggering auto-connect in some cases.
+
+ver 0.41:
+	Fix race condition with WiFi devices and RFKILL.
+	Fix issue with WiFi connect/disconnect and some drivers.
+	Fix issue with WEP encryption and staging drivers.
+	Fix issue with wrong setup of loopback interfaces.
+
+ver 0.40:
+	Fix issue with wrong setting of initial AutoConnect value.
+	Fix issue with IP configuration and loopback devices.
+	Fix issue with build system and include directory.
+	Fix wrong variable for dhclient-script location.
+	Fix disconnect race condition with Bluetooth service.
+	Add support for ignoring bonding Ethernet interfaces.
+
+ver 0.39:
+	Fix file permissions for profile storage.
+	Fix service resorting when they are in different states.
+	Fix support for handling Bluetooth PAN devices.
+	Add support for AutoConnect property of services.
+	Add support for creating, modifying and removing profiles.
+	Add support for fully flexible task handling framework.
+	Add support for more generic RTNL handling and notifications.
+	Add support for full non-recursive build.
+
+ver 0.38:
+	Fix broken check for security modes.
+	Fix requirement of inotify when loopback support is disabled.
+
+ver 0.37:
+	Fix missing update of signal strength from scan results.
+	Fix error handling in case when passphrase is required.
+	Add support for PassphraseRequired property.
+	Add missing check for WiFi security modes.
+
+ver 0.36:
+	Fix missing reset of network reference when disconnecting.
+	Fix wrong variable reference when sending technology replies.
+	Fix wrong identifiers of D-Bus error names.
+
+ver 0.35:
+	Fix missing auto-connect trigger on Ethernet device removal.
+	Fix availability listing for devices without attached drivers.
+	Fix signals for connected and default technologies.
+	Fix notification to use service types instead of device types.
+	Fix potential pending scan result reply messages after removal.
+	Add support for blocking enable and disable technology changes.
+
+ver 0.34:
+	Fix setup of udev context before loading any plugins.
+	Fix rearming the scan trigger if a device got disabled.
+	Fix device power state changes tracking with RFKILL notifications.
+	Fix wrong usage of device types instead of service types.
+	Fix connect method to handle non-WiFi services.
+
+ver 0.33:
+	Add support for RFKILL changes of the WiFi subsystem.
+	Fix state value of Network Manager compatibility support.
+
+ver 0.32:
+	Fix broken device unregistration on removal.
+	Fix WiMAX device detection handling.
+
+ver 0.31:
+	Fix missing enforcement of offline mode for new devices.
+	Add support for persistent storage of offline mode.
+	Add support for persistent storage of device power state.
+	Remove deprecated and unused network storage callbacks.
+
+ver 0.30:
+	Fix issue where hidden network could show up in service list.
+	Fix issue with asynchronous notification of scan requests.
+	Fix message reference leak when adding interface fails.
+	Fix problem when removing network during inactive state.
+	Remove broken and unused callback for joining networks.
+	Remove deprecated device and network interface methods.
+	Remove test scripts for deprecated interface methods.
+
+ver 0.29:
+	Fix missing signal emission for offline mode changes.
+	Fix signal emission for changes in technology properties.
+	Rename Technologies property to AvailableTechnologies.
+
+ver 0.28:
+	Fix another reference counting imbalance when adding networks.
+	Revert supplicant change to always reset scanning after results.
+
+ver 0.27:
+	Fix missing disarming of the connection timeout.
+	Fix handling of multiple supplicant disconnect attempts.
+	Fix simultaneous connects from different technologies limitation.
+
+ver 0.26:
+	Fix broken handling of auto-connect logic.
+	Fix handling of out-of-range access points.
+	Fix support for connecting to hidden networks.
+	Fix reference counting for networks with same SSID.
+	Fix issue with WiFi interfaces not getting switched off.
+	Fix problems with delayed service list updates.
+	Fix disconnect/abort of connection attempts.
+
+ver 0.25:
+	Fix showing of WiFi networks with less than 25% signal strength.
+	Fix potential segmentation fault with network passphrases.
+
+ver 0.24:
+	Fix handling of initial device powered state.
+	Fix missing Powered property changed signals.
+	Fix canceling of a network connection attempt.
+	Fix stalled configuration issue with supplicant.
+	Fix detection of association errors from supplicant.
+	Fix issue with wrong scanning state information.
+	Fix hidden SSID detection routines.
+	Fix visible Ethernet services even without carrier.
+	Add global method call to request scanning.
+	Add support for global technologies list.
+	Add support for delaying service list updates.
+	Update the overall D-Bus API documentation.
+
+ver 0.23:
+	Fix dhclient probe/remove race condition.
+	Fix handling of disconnected services during auto-connect.
+	Add support for proper group name of hidden networks.
+	Add support for storing SSID details of hidden networks.
+
+ver 0.22:
+	Fix wrong auto-connect procedure after user connection.
+	Fix invalid update of already connected network.
+	Fix idle state handling after disconnecting device.
+	Fix disconnect race condition in WiFi supplicant.
+	Fix WiFi signal strength reporting.
+
+ver 0.21:
+	Add udev based network device detection.
+	Add support for global auto-connect feature.
+	Add support for basic service drag and drop.
+	Fix missing passphrase cleanup on service removal.
+	Fix potential duplicate network creation.
+	Fix handling of WEP shared keys.
+
+ver 0.20:
+	Add plugin for Intel WiMAX SDK support.
+	Add special handling for default vendor SSIDs.
+	Add support for default gateway in different network.
+	Add support for automatic switching of default gateway.
+	Add support for asynchronous handling of Powered property.
+	Add support for connecting/disconnecting Ethernet services.
+	Add support for more detailed error states of services.
+	Add support for clearing error state via ClearProperty.
+	Fix error code for invalid or unknown properties.
+	Fix various timeout handling issues.
+	Remove Policy and Priority device and network properties.
+
+ver 0.19:
+	Add hidden networks to the service list.
+	Add support for storing the service name.
+	Fix service list sorting for connected services.
+	Fix missing cancel command when operation times out.
+	Fix various issues with service favorite handling.
+	Remove Available and Remember network properties.
+
+ver 0.18:
+	Add support for asynchronous service connect method.
+	Fix broken storage of service favorite details.
+
+ver 0.17:
+	Add AT chat library implementation.
+	Fix service lookup for WiFi and WiMAX devices.
+	Fix service state signal emission and error handling.
+	Fix storing and loading of configured passphrases for services.
+
+ver 0.16:
+	Update Intel OSPM support to latest specification.
+	Add initial support for new service interface.
+	Add support for builtin plugins.
+	Add extra warning if no nameserver is defined.
+	Add error reporting for state and storage directory creation.
+	Add error message for network and device storing failures
+	Fix stale entry in gateway list after connection changes.
+	Fix handling of DHCP results with no nameserver.
+	Fix infinite loop for service lookup.
+	Fix various format string warnings.
+
+ver 0.15:
+	Detect VMware network interface and ignore them.
+	Fix setting of scan_ssid for hidden networks.
+	Fix empty network name property.
+
+ver 0.14:
+	Add support for detecting DHCP failures.
+	Add support for joining hidden WiFi networks.
+	Add support for device and network address property.
+	Add support for default /etc/resolv.conf generation.
+	Fix issue with wrong address setting for loopback.
+	Fix detection of WiFi access point changes.
+	Fix crash with blob properties.
+
+ver 0.13:
+	Add support for notification infrastructure.
+	Add fully dynamic property storage capabilities.
+	Fix broken loading of last network on bootup.
+	Fix crash when unplugging WiFi devices.
+	Rename OSPM plugin to Intel OSPM plugin.
+	Rename WiMAX plugin to Intel WiMAX SDK plugin.
+
+ver 0.12:
+	Fix connection state change handling.
+	Fix network list enumeration.
+	Fix broken driver matching for devices.
+	Fix issue with network identifier lookup.
+
+ver 0.11:
+	Add plugin priority handling.
+	Add network type for WiMAX.
+	Fix network protocol selection for Bluetooth PAN.
+	Fix parameters for Bluetooth PAN disconnect method.
+
+ver 0.10:
+	Fix races with connection signals.
+	Fix automatic switching of default connection.
+
+ver 0.9:
+	Rename FlightMode to OfflineMode.
+	Add static IPv4 setting support for Ethernet devices.
+	Add extra options to exclude devices and plugins.
+	Add support for toggling debug output.
+	Add support for ScanInterval property.
+	Fix handling of disconnect commands from applications.
+	Fix detection of networks that are out of range.
+	Fix setting network remember status.
+	Fix argument type checking of properties.
+
+ver 0.8:
+	Add Device and Network property to connection interface.
+	Add option to disable installation of data files.
+	Add command line option to show version number.
+	Fix signal emission for network changes.
+
+ver 0.7:
+	Add basic support for flight mode.
+	Add support for multiple storage drivers.
+	Add support for RTNL newlink watch API.
+	Add support for different security privileges.
+	Add support for device and network priorities.
+	Add functions for setting network properties.
+	Fix issue with listing devices without a driver.
+	Fix issue with WiFi scanning indication.
+	Fix detection of WiFi security changes.
+	Update WiFi driver to use new network helpers.
+	Install different D-Bus configuration for PolicyKit.
+
+ver 0.6:
+	Add CONNMAN_API_SUBJECT_TO_CHANGE definition.
+	Add detailed configuration options.
+	Add various D-Bus helper functions.
+	Add generic device driver infrastructure.
+	Add generic network driver infrastructure.
+	Add property for WiFi network mode.
+	Add property for network interface name.
+	Add property for global connection policy.
+	Add support for verbose compiler warnings.
+	Add support for device detection via udev.
+	Add support for systems with udhcpc.
+	Add support for Bluetooth PAN networks.
+	Fix WiFi issue with DHCP restart after handshake.
+	Fix exported symbols list creation.
+	Remove deprecated and unused plugins.
+
+ver 0.5:
+	Add support for handling Bluetooth adapters.
+	Add support for activating wpa_supplicant on demand.
+	Add Device property to network objects.
+	Add Scanning property to device objects.
+	Fix Name property of device objects.
+	Fix WiFi SSID to object path conversion.
+	Fix duplicate wireless scan results.
+	Fix built issue with libudev and uClibc.
+	Fix issues with element registration failures.
+
+ver 0.4:
+	Add DNS proxy resolver plugin.
+	Add support for default connections.
+	Add support for gateway change notifications.
+	Add signal strength property for connections.
+	Add property for connection type.
+	Fix issue with carrier detection.
+	Fix broken resolvconf plugin.
+
+ver 0.3:
+	Add support for automatically connecting known networks.
+	Add improved framework for handling resolver details.
+	Add generic signal strength property.
+	Fix bridge and WiMAX device detection.
+	Fix network listing for Ethernet devices.
+
+ver 0.2:
+	Add support for indicating network changes.
+	Add support for signal strength property.
+	Add support for unique device names.
+	Fix broken device enumeration.
+	Fix issue with device removal callback.
+	Fix issue with wpa_supplicant disconnecting.
+	Fix D-Bus access policy configuration.
+
+ver 0.1:
+	Initial public release.
diff --git a/HACKING b/HACKING
new file mode 100644
index 0000000..05fb69c
--- /dev/null
+++ b/HACKING
@@ -0,0 +1,144 @@
+Hacking on Connection Manager
+*****************************
+
+
+Build tools requirements
+========================
+
+When building and testing directly from the repository it is important to
+have at least automake version 1.10 or later installed. All modern
+distributions should default to the latest version, but it seems that
+Debian's default is still an earlier version:
+
+  Check version
+    # dpkg -l '*automake*'
+
+  Install new version
+    # apt-get install automake1.10
+    # update-alternatives --config automake
+
+
+Working with the source code repository
+=======================================
+
+The repository contains two extra scripts that accomplish the bootstrap
+process. One is called "bootstrap" which is the basic scripts that uses the
+autotools scripts to create the needed files for building and installing.
+It makes sure to call the right programs depending on the usage of shared or
+static libraries or translations etc.
+
+The second program is called "bootstrap-configure". This program will make
+sure to properly clean the repository, call the "bootstrap" script and then
+call configure with proper settings for development. It will use the best
+options and pass them over to configure. These options normally include
+the enabling the maintainer mode and the debugging features.
+
+So while in a normal source project the call "./configure ..." is used to
+configure the project with its settings like prefix and extra options. In
+case of bare repositories call "./bootstrap-configure" and it will bootstrap
+the repository and calls configure with all the correct options to make
+development easier.
+
+In case of preparing for a release with "make distcheck", don't use
+bootstrap-configure since it could export development specific settings.
+
+So the normal steps to checkout, build and install such a repository is
+like this:
+
+  Checkout repository
+    # git clone git://git.kernel.org/pub/scm/network/connman/connman.git
+    # cd connman
+
+  Configure and build
+    # ./bootstrap-configure
+    # make
+
+  Check installation
+    # make install DESTDIR=$PWD/x
+    # find x
+    # rm -rf x
+
+  Check distribution
+    # make distcheck
+
+  Final installation
+    # sudo make install
+
+  Remove autogenerated files
+    # make maintainer-clean
+
+
+Running from within the source code repository
+==============================================
+
+When using "./configure --enable-maintainer-mode" the automake scripts will
+use the plugins directly from within the repository. This removes the need
+to use "make install" when testing "connmand". The "bootstrap-configure"
+automatically includes this option.
+
+  Run daemon in foreground with debugging
+    # sudo ./src/connmand -n -d 'plugins/*'
+
+The debugging option -d takes an argument. This argument can be a comma
+separated list of file names like 'plugins/wifi.c,plugins/ethernet.c' to
+enable debugs in these files. Simple glob style pattern matching is
+supported in this list.
+
+For production installations or distribution packaging it is important that
+the "--enable-maintainer-mode" option is NOT used.
+
+Some times it is important to restrict the available interfaces. For example
+in cases where testing happens over a network connection. The "-i" command
+line switch allows to specify a glob pattern for the interface names.
+
+  Run daemon for wireless interfaces
+    # sudo ./src/connmand -n -i wlan*
+
+
+Debugging the D-Bus interface during runtime
+============================================
+
+Running the daemon with debugging information in the foreground is quite
+verbose and sometimes not really helpful. The "monitor-connman" script
+allows to monitor "PropertyChanged" D-Bus signals from various interfaces.
+
+Every "PropertyChanged" signal will generate a line of output. Some of them
+can get very complex. The first detail inside "{ ... }" is the interface
+name (without its service name prefix). The second detail inside "[ ... ]"
+is the object path. And after that it is followed by a key and value of
+the property that changed.
+
+
+Generating source code documentation
+====================================
+
+The source code is annotated using the gtk-doc style documentation. This
+allows an easy way of generating API documentation. The "bootstrap-configure"
+script will use the "--enable-gtk-doc" configure to enable the generation of
+the documentation.
+
+To make the gtk-doc process work, the gtk-doc tools need to be installed.
+Every distribution should provide a package for this, but the naming of the
+package might be different:
+
+  Debian
+    # apt-get install gtk-doc-tools
+
+  Ubuntu
+    # apt-get install gtk-doc-utils
+
+  Fedora
+    # yum install gtk-doc
+
+In case "bootstrap-configure" is not used, the manual steps for generating
+the documentation files are like this:
+
+  Configuring the repository
+    # ./configure --enable-gtk-doc
+
+  Generate the documentation
+    # cd doc && make
+
+  View documentation
+    # firefox doc/html/index.html
+
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..56b077d
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,236 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free
+Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about.  Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory.  After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PREFIX'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PREFIX', the package will
+use PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the `--target=TYPE' option to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).  Here is a another example:
+
+     /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent
+configuration-related scripts to be executed by `/bin/bash'.
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+     Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..a88e987
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,407 @@
+
+AM_MAKEFLAGS = --no-print-directory
+
+includedir = @includedir@/connman
+
+include_HEADERS = include/types.h include/log.h include/plugin.h \
+			include/notifier.h include/service.h \
+			include/resolver.h include/ipconfig.h \
+			include/device.h include/network.h include/inet.h \
+			include/storage.h include/provision.h \
+			include/session.h include/ipaddress.h include/agent.h \
+			include/inotify.h include/technology.h include/dbus.h
+
+nodist_include_HEADERS = include/version.h
+
+noinst_HEADERS = include/rtnl.h include/task.h \
+			include/option.h \
+			include/provider.h include/vpn-dbus.h \
+			include/utsname.h include/timeserver.h include/proxy.h \
+			include/setting.h
+
+local_headers = $(foreach file,$(include_HEADERS) $(nodist_include_HEADERS) \
+			$(noinst_HEADERS), include/connman/$(notdir $(file)))
+
+
+gdbus_sources = gdbus/gdbus.h gdbus/mainloop.c gdbus/watch.c \
+				gdbus/object.c gdbus/client.c gdbus/polkit.c
+
+gdhcp_sources = gdhcp/gdhcp.h gdhcp/common.h gdhcp/common.c gdhcp/client.c \
+		gdhcp/server.c gdhcp/ipv4ll.h gdhcp/ipv4ll.c gdhcp/timer.h \
+		gdhcp/timer.c gdhcp/unaligned.h
+
+gweb_sources = gweb/gweb.h gweb/gweb.c gweb/gresolv.h gweb/gresolv.c
+
+if WISPR
+gweb_sources += gweb/giognutls.h gweb/giognutls.c
+else
+gweb_sources += gweb/giognutls.h gweb/gionotls.c
+endif
+
+if DATAFILES
+
+if NMCOMPAT
+nmcompat_conf = plugins/connman-nmcompat.conf
+endif
+
+dbusconfdir = @DBUS_CONFDIR@
+
+dbusconf_DATA = src/connman.conf $(nmcompat_conf)
+
+if VPN
+dbusconf_DATA += vpn/connman-vpn-dbus.conf
+dbusservicedir = @DBUS_DATADIR@
+dbusservice_DATA = vpn/net.connman.vpn.service
+endif
+
+if SYSTEMD
+systemdunitdir = @SYSTEMD_UNITDIR@
+
+systemdunit_DATA = src/connman.service
+
+if VPN
+systemdunit_DATA += vpn/connman-vpn.service
+endif
+endif
+endif
+
+plugin_LTLIBRARIES =
+
+plugin_objects =
+
+builtin_modules =
+builtin_sources =
+builtin_libadd =
+builtin_cflags =
+
+noinst_PROGRAMS =
+
+unit_objects =
+
+MANUAL_PAGES =
+
+sbin_PROGRAMS = src/connmand
+
+src_connmand_SOURCES = $(gdbus_sources) $(gdhcp_sources) $(gweb_sources) \
+			$(builtin_sources) src/connman.ver \
+			src/main.c src/connman.h src/log.c \
+			src/error.c src/plugin.c src/task.c \
+			src/device.c src/network.c src/connection.c \
+			src/manager.c src/service.c \
+			src/clock.c src/timezone.c src/agent-connman.c \
+			src/agent.c src/notifier.c src/provider.c \
+			src/resolver.c src/ipconfig.c src/detect.c src/inet.c \
+			src/dhcp.c src/dhcpv6.c src/rtnl.c src/proxy.c \
+			src/utsname.c src/timeserver.c src/rfkill.c \
+			src/storage.c src/dbus.c src/config.c \
+			src/technology.c src/counter.c src/ntp.c \
+			src/session.c src/tethering.c src/wpad.c src/wispr.c \
+			src/stats.c src/iptables.c src/dnsproxy.c src/6to4.c \
+			src/ippool.c src/bridge.c src/nat.c src/ipaddress.c \
+			src/inotify.c \
+			src/rlimits.c
+
+src_connmand_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@ \
+				@XTABLES_LIBS@ @GNUTLS_LIBS@ -lresolv -ldl -lrt
+
+src_connmand_LDFLAGS = -Wl,--export-dynamic \
+				-Wl,--version-script=$(srcdir)/src/connman.ver
+
+if VPN
+vpn_plugin_LTLIBRARIES =
+
+vpn_plugin_objects =
+
+builtin_vpn_modules =
+builtin_vpn_sources =
+builtin_vpn_libadd =
+builtin_vpn_cflags =
+
+sbin_PROGRAMS += vpn/connman-vpnd
+
+vpn_connman_vpnd_SOURCES = $(gdbus_sources) $(builtin_vpn_sources) \
+			$(gweb_sources) vpn/vpn.ver vpn/main.c vpn/vpn.h \
+			src/log.c src/error.c src/plugin.c src/task.c \
+			vpn/vpn-manager.c vpn/vpn-provider.c \
+			vpn/vpn-provider.h vpn/vpn-rtnl.h \
+			vpn/vpn-ipconfig.c src/inet.c vpn/vpn-rtnl.c \
+			src/dbus.c src/storage.c src/ipaddress.c src/agent.c \
+			vpn/vpn-agent.c vpn/vpn-agent.h
+
+vpn_connman_vpnd_LDADD = $(builtin_vpn_libadd) @GLIB_LIBS@ @DBUS_LIBS@ \
+				@GNUTLS_LIBS@ -lresolv -ldl
+
+vpn_connman_vpnd_LDFLAGS = -Wl,--export-dynamic \
+				-Wl,--version-script=$(srcdir)/vpn/vpn.ver
+endif
+
+BUILT_SOURCES = $(local_headers) src/builtin.h
+
+if VPN
+BUILT_SOURCES += vpn/builtin.h
+endif
+
+CLEANFILES = src/connman.conf $(BUILT_SOURCES)
+
+statedir = $(localstatedir)/run/connman
+
+if VPN
+vpn_plugindir = $(libdir)/connman/plugins-vpn
+endif
+
+plugindir = $(libdir)/connman/plugins
+
+scriptdir = $(libdir)/connman/scripts
+
+storagedir = $(localstatedir)/lib/connman
+
+configdir = ${sysconfdir}/connman
+
+if MAINTAINER_MODE
+if VPN
+build_vpn_plugindir = $(abs_top_srcdir)/vpn/plugins/.libs
+endif
+build_plugindir = $(abs_top_srcdir)/plugins/.libs
+build_scriptdir = $(abs_top_srcdir)/scripts
+else
+build_plugindir = $(plugindir)
+build_scriptdir = $(scriptdir)
+if VPN
+build_vpn_plugindir = $(vpn_plugindir)
+endif
+endif
+
+AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ @XTABLES_CFLAGS@ \
+				@GNUTLS_CFLAGS@ $(builtin_cflags) \
+				-DCONNMAN_PLUGIN_BUILTIN \
+				-DSTATEDIR=\""$(statedir)"\" \
+				-DPLUGINDIR=\""$(build_plugindir)"\" \
+				-DSCRIPTDIR=\""$(build_scriptdir)"\" \
+				-DSTORAGEDIR=\""$(storagedir)\"" \
+				-DCONFIGDIR=\""$(configdir)\""
+
+if VPN
+AM_CPPFLAGS = -I$(builddir)/include -I$(srcdir)/gdbus
+else
+AM_CPPFLAGS = -I$(builddir)/include -I$(builddir)/src -I$(srcdir)/gdbus
+endif
+
+src_connmand_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ @XTABLES_CFLAGS@ \
+				@GNUTLS_CFLAGS@ $(builtin_cflags) \
+				-DCONNMAN_PLUGIN_BUILTIN \
+				-DSTATEDIR=\""$(statedir)"\" \
+				-DPLUGINDIR=\""$(build_plugindir)"\" \
+				-DSCRIPTDIR=\""$(build_scriptdir)"\" \
+				-DSTORAGEDIR=\""$(storagedir)\"" \
+				-DCONFIGDIR=\""$(configdir)\"" \
+				-I$(builddir)/src
+
+EXTRA_DIST = src/genbuiltin src/connman-dbus.conf src/connman-polkit.conf \
+						plugins/connman-nmcompat.conf
+
+if VPN
+vpn_connman_vpnd_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ \
+				$(builtin_vpn_cflags) \
+				-DCONNMAN_PLUGIN_BUILTIN \
+				-DSTATEDIR=\""$(statedir)"\" \
+				-DPLUGINDIR=\""$(build_vpn_plugindir)"\" \
+				-DSCRIPTDIR=\""$(build_scriptdir)"\" \
+				-DSTORAGEDIR=\""$(storagedir)\"" \
+				-DCONFIGDIR=\""$(configdir)\"" \
+				-I$(builddir)/vpn
+
+endif
+
+EXTRA_DIST += vpn/vpn-dbus.conf vpn/vpn-polkit.conf
+
+script_DATA =
+script_PROGRAMS =
+script_LTLIBRARIES =
+
+include Makefile.plugins
+
+if CLIENT
+sbin_PROGRAMS += client/connmanctl
+
+MANUAL_PAGES += doc/connmanctl.1
+
+client_connmanctl_SOURCES =  $(gdbus_sources) src/connman.h \
+			client/dbus.h client/dbus.c \
+			client/data_manager.h client/data_manager.c \
+			client/services.h client/services.c \
+			client/technology.h client/technology.c \
+			client/interactive.h client/interactive.c \
+			client/monitor.h client/monitor.c \
+			client/commands.c client/main.c
+
+client_connmanctl_LDADD = @DBUS_LIBS@ @GLIB_LIBS@ -lreadline -ldl
+endif
+
+if WISPR
+noinst_PROGRAMS += tools/wispr
+
+tools_wispr_SOURCES = $(gweb_sources) tools/wispr.c
+tools_wispr_LDADD = @GLIB_LIBS@ @GNUTLS_LIBS@ -lresolv
+endif
+
+if TOOLS
+noinst_PROGRAMS += tools/supplicant-test \
+			tools/dhcp-test tools/dhcp-server-test \
+			tools/addr-test tools/web-test tools/resolv-test \
+			tools/dbus-test tools/polkit-test \
+			tools/iptables-test tools/tap-test tools/wpad-test \
+			tools/stats-tool tools/private-network-test \
+			unit/test-session unit/test-ippool unit/test-nat
+
+tools_supplicant_test_SOURCES = $(gdbus_sources) tools/supplicant-test.c \
+			tools/supplicant-dbus.h tools/supplicant-dbus.c \
+			tools/supplicant.h tools/supplicant.c
+tools_supplicant_test_LDADD = @GLIB_LIBS@ @DBUS_LIBS@
+
+tools_web_test_SOURCES = $(gweb_sources) tools/web-test.c
+tools_web_test_LDADD = @GLIB_LIBS@ @GNUTLS_LIBS@ -lresolv
+
+tools_resolv_test_SOURCES = gweb/gresolv.h gweb/gresolv.c tools/resolv-test.c
+tools_resolv_test_LDADD = @GLIB_LIBS@ -lresolv
+
+tools_wpad_test_SOURCES = gweb/gresolv.h gweb/gresolv.c tools/wpad-test.c
+tools_wpad_test_LDADD = @GLIB_LIBS@ -lresolv
+
+tools_stats_tool_LDADD = @GLIB_LIBS@
+
+tools_dhcp_test_SOURCES = $(gdhcp_sources) tools/dhcp-test.c
+tools_dhcp_test_LDADD = @GLIB_LIBS@
+
+tools_dhcp_server_test_SOURCES = $(gdhcp_sources) tools/dhcp-server-test.c
+tools_dhcp_server_test_LDADD = @GLIB_LIBS@
+
+tools_dbus_test_SOURCES = $(gdbus_sources) tools/dbus-test.c
+tools_dbus_test_LDADD = @GLIB_LIBS@ @DBUS_LIBS@
+
+tools_polkit_test_LDADD = @DBUS_LIBS@
+
+tools_iptables_test_LDADD = @GLIB_LIBS@ @XTABLES_LIBS@
+
+tools_private_network_test_LDADD = @GLIB_LIBS@ @DBUS_LIBS@
+
+unit_test_session_SOURCES = $(gdbus_sources) src/log.c src/dbus.c \
+		unit/test-session.c unit/utils.c unit/manager-api.c \
+		unit/session-api.c unit/test-connman.h
+unit_test_session_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ -ldl
+unit_objects += $(unit_test_session_OBJECTS)
+
+unit_test_ippool_SOURCES = $(gdbus_sources) src/log.c src/dbus.c \
+		 src/ippool.c unit/test-ippool.c
+unit_test_ippool_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ -ldl
+unit_objects += $(unit_test_ippool_OBJECTS)
+
+unit_test_nat_SOURCES = $(gdbus_sources) src/log.c src/dbus.c \
+		src/iptables.c  src/nat.c unit/test-nat.c
+unit_test_nat_LDADD = @GLIB_LIBS@ @DBUS_LIBS@  @XTABLES_LIBS@ -ldl
+unit_objects += $(unit_nat_ippool_OBJECTS)
+endif
+
+test_scripts = test/get-state test/list-services \
+		test/monitor-services test/test-clock \
+		test/simple-agent test/show-introspection test/test-compat \
+		test/test-manager test/test-connman test/monitor-connman \
+		test/connect-provider test/remove-provider \
+		test/test-counter test/set-ipv4-method test/set-ipv6-method \
+		test/get-services test/get-proxy-autoconfig test/set-proxy \
+		test/enable-tethering test/disable-tethering test/backtrace \
+		test/test-session test/test-supplicant \
+		test/test-new-supplicant test/service-move-before \
+		test/set-global-timeservers test/get-global-timeservers \
+		test/set-nameservers test/set-domains test/set-timeservers
+
+test_scripts += test/vpn-connect test/vpn-disconnect test/vpn-get \
+		test/monitor-vpn
+
+if TEST
+testdir = $(pkglibdir)/test
+test_SCRIPTS = $(test_scripts)
+endif
+
+EXTRA_DIST += $(test_scripts)
+
+EXTRA_DIST += doc/overview-api.txt doc/behavior-api.txt \
+				doc/ipconfig-api.txt doc/plugin-api.txt \
+				doc/manager-api.txt doc/agent-api.txt \
+				doc/service-api.txt doc/technology-api.txt \
+				doc/counter-api.txt doc/config-format.txt \
+				doc/clock-api.txt doc/session-api.txt \
+				doc/session-overview.txt doc/backtrace.txt \
+				doc/advanced-configuration.txt \
+				doc/vpn-connection-api.txt \
+				doc/vpn-manager-api.txt doc/vpn-overview.txt
+
+MANUAL_PAGES += doc/connman.8 doc/connman.conf.5
+
+noinst_dist_man_MANS = $(MANUAL_PAGES)
+
+pkgconfigdir = $(libdir)/pkgconfig
+
+pkgconfig_DATA = connman.pc
+
+DISTCHECK_CONFIGURE_FLAGS = --disable-gtk-doc \
+				--disable-datafiles \
+				--enable-hh2serial-gps \
+				--enable-openconnect \
+				--enable-openvpn \
+				--enable-vpnc \
+				--enable-session-policy-local \
+				--enable-nmcompat \
+				--enable-polkit
+
+DISTCLEANFILES = $(pkgconfig_DATA)
+
+MAINTAINERCLEANFILES = Makefile.in \
+	aclocal.m4 configure config.h.in config.sub config.guess \
+	ltmain.sh depcomp compile missing install-sh mkinstalldirs
+
+
+src/builtin.h: src/genbuiltin $(builtin_sources)
+	$(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@
+
+vpn/builtin.h: src/genbuiltin $(builtin_vpn_sources)
+	$(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_vpn_modules) > $@
+
+src/connman.conf: src/connman-dbus.conf src/connman-polkit.conf
+if POLKIT
+	$(AM_V_GEN)cp $(srcdir)/src/connman-polkit.conf $@
+else
+	$(AM_V_GEN)cp $(srcdir)/src/connman-dbus.conf $@
+endif
+
+if VPN
+vpn/connman-vpn-dbus.conf: vpn/vpn-dbus.conf vpn/vpn-polkit.conf
+if POLKIT
+	$(AM_V_GEN)cp $(srcdir)/vpn/vpn-polkit.conf $@
+else
+	$(AM_V_GEN)cp $(srcdir)/vpn/vpn-dbus.conf $@
+endif
+endif
+
+if SELINUX
+if VPN
+EXTRA_DIST += connman-task.pp
+CLEANFILES += connman-task.pp
+endif
+
+connman-task.pp: vpn/connman-task.te
+	make -f /usr/share/selinux/devel/Makefile
+endif
+
+EXTRA_DIST += vpn/connman-task.te
+
+$(abs_top_builddir)/include/connman:
+	$(AM_V_at)$(MKDIR_P) $@
+
+include/connman/version.h: $(abs_top_builddir)/include/version.h | $(abs_top_builddir)/include/connman
+	$(AM_V_GEN)$(LN_S) $< $@
+
+include/connman/%.h: $(abs_top_srcdir)/include/%.h | $(abs_top_builddir)/include/connman
+	$(AM_V_GEN)$(LN_S) $< $@
+
+clean-local:
+	@$(RM) -rf include/connman
diff --git a/Makefile.plugins b/Makefile.plugins
new file mode 100644
index 0000000..2986b6b
--- /dev/null
+++ b/Makefile.plugins
@@ -0,0 +1,265 @@
+
+plugin_cflags = -fvisibility=hidden -I$(srcdir)/gdbus \
+					@DBUS_CFLAGS@ @GLIB_CFLAGS@
+plugin_ldflags = -no-undefined -module -avoid-version
+
+script_cflags = -fvisibility=hidden -I$(srcdir)/gdbus \
+					@DBUS_CFLAGS@
+
+if LOOPBACK
+builtin_modules += loopback
+builtin_sources += plugins/loopback.c
+endif
+
+if ETHERNET
+builtin_modules += ethernet
+builtin_sources += plugins/ethernet.c
+endif
+
+gsupplicant_sources = gsupplicant/gsupplicant.h gsupplicant/dbus.h \
+			gsupplicant/supplicant.c gsupplicant/dbus.c
+
+if WIFI
+builtin_modules += wifi
+builtin_sources += plugins/wifi.c $(gsupplicant_sources)
+endif
+
+if SLEEP
+plugin_LTLIBRARIES += plugins/sleepplugin.la
+plugin_objects += $(plugins_sleepplugin_la_OBJECTS)
+plugins_sleepplugin_la_CFLAGS = $(plugin_cflags)
+plugins_sleepplugin_la_LDFLAGS = $(plugin_ldflags)
+endif
+
+if BLUETOOTH
+builtin_modules += bluetooth_legacy
+builtin_sources += plugins/bluetooth_legacy.c
+builtin_modules += bluetooth
+builtin_sources += plugins/bluetooth.c
+endif
+
+if HH2SERIAL_GPS
+if HH2SERIAL_GPS_BUILTIN
+builtin_modules += hh2serial_gps
+builtin_sources += plugins/hh2serial-gps.c
+else
+plugin_LTLIBRARIES += plugins/hh2serial-gps.la
+plugin_objects += $(plugins_hh2serial_gps_la_OBJECTS)
+plugins_hh2serial_gps_la_CFLAGS = $(plugin_cflags)
+plugins_hh2serial_gps_la_LDFLAGS = $(plugin_ldflags)
+endif
+endif
+
+if OFONO
+builtin_modules += ofono
+builtin_sources += plugins/mcc.h plugins/ofono.c
+endif
+
+if DUNDEE
+builtin_modules += dundee
+builtin_sources += plugins/dundee.c
+endif
+
+if VPN
+builtin_modules += vpn
+builtin_sources += plugins/vpn.c
+
+if OPENCONNECT
+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@\"
+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_CFLAGS = $(plugin_cflags) \
+					-DOPENCONNECT=\"@OPENCONNECT@\" \
+					-DSTATEDIR=\""$(statedir)"\" \
+					-DSCRIPTDIR=\""$(build_scriptdir)"\"
+vpn_plugins_openconnect_la_LDFLAGS = $(plugin_ldflags)
+endif
+endif
+
+if OPENVPN
+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_CFLAGS = $(plugin_cflags) -DOPENVPN=\"@OPENVPN@\" \
+					-DSTATEDIR=\""$(statedir)"\" \
+					-DSCRIPTDIR=\""$(build_scriptdir)"\"
+vpn_plugins_openvpn_la_LDFLAGS = $(plugin_ldflags)
+endif
+endif
+
+if VPNC
+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_CFLAGS = $(plugin_cflags) -DVPNC=\"@VPNC@\" \
+					-DSTATEDIR=\""$(statedir)"\" \
+					-DSCRIPTDIR=\""$(build_scriptdir)"\"
+vpn_plugins_vpnc_la_LDFLAGS = $(plugin_ldflags)
+endif
+endif
+
+if L2TP
+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_CFLAGS = $(plugin_cflags) -DL2TP=\"@L2TP@\" \
+					-DSTATEDIR=\""$(statedir)"\" \
+					-DSCRIPTDIR=\""$(build_scriptdir)"\"
+vpn_plugins_l2tp_la_LDFLAGS = $(plugin_ldflags)
+endif
+endif
+
+if PPTP
+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_CFLAGS = $(plugin_cflags) -DPPPD=\"@PPPD@\" \
+					-DPPTP=\"@PPTP@\" \
+					-DSTATEDIR=\""$(statedir)"\" \
+					-DSCRIPTDIR=\""$(build_scriptdir)"\"
+vpn_plugins_pptp_la_LDFLAGS = $(plugin_ldflags)
+endif
+endif
+
+if PPTP
+script_LTLIBRARIES += scripts/libppp-plugin.la
+scripts_libppp_plugin_la_LDFLAGS = $(script_cflags) @DBUS_CFLAGS@
+scripts_libppp_plugin_la_LIBADD = @DBUS_LIBS@
+else
+if L2TP
+script_LTLIBRARIES += scripts/libppp-plugin.la
+scripts_libppp_plugin_la_LDFLAGS = $(script_cflags) @DBUS_CFLAGS@
+scripts_libppp_plugin_la_LIBADD = @DBUS_LIBS@
+endif
+endif
+
+if VPN
+builtin_vpn_sources += $(builtin_vpn_source)
+endif
+endif
+
+if PACRUNNER
+builtin_modules += pacrunner
+builtin_sources += plugins/pacrunner.c
+endif
+
+if POLKIT
+builtin_modules += polkit
+builtin_sources += plugins/polkit.c
+
+if DATAFILES
+policydir = @POLKIT_DATADIR@
+
+policy_DATA = plugins/net.connman.policy
+
+if VPN
+policy_DATA += vpn/net.connman.vpn.policy
+endif
+endif
+endif
+
+if IOSPM
+plugin_LTLIBRARIES += plugins/iospm.la
+plugin_objects += $(plugins_iospm_la_OBJECTS)
+plugins_iospm_la_CFLAGS = $(plugin_cflags)
+plugins_iospm_la_LDFLAGS = $(plugin_ldflags)
+endif
+
+if OPENCONNECT
+script_PROGRAMS += scripts/openconnect-script
+
+scripts_openconnect_script_LDADD = @DBUS_LIBS@
+else
+if VPNC
+script_PROGRAMS += scripts/openconnect-script
+
+scripts_openconnect_script_LDADD = @DBUS_LIBS@
+endif
+endif
+
+if OPENVPN
+script_PROGRAMS += scripts/openvpn-script
+
+scripts_openvpn_script_LDADD = @DBUS_LIBS@
+endif
+
+if NMCOMPAT
+builtin_modules += nmcompat
+builtin_sources += plugins/nmcompat.c
+endif
+
+if TIST
+if TIST_BUILTIN
+builtin_modules += tist
+builtin_sources += plugins/tist.c
+else
+plugin_LTLIBRARIES += plugins/tist.la
+plugin_objects += $(plugins_tist_la_OBJECTS)
+plugins_tist_la_CFLAGS = $(plugin_cflags)
+plugins_tist_la_LDFLAGS = $(plugin_ldflags)
+endif
+endif
+
+if SESSION_POLICY_LOCAL
+if SESSION_POLICY_LOCAL_BUILTIN
+builtin_modules += session_policy_local
+builtin_sources += plugins/session_policy_local.c
+else
+plugin_LTLIBRARIES += plugins/session_policy_local.la
+plugin_objects += $(plugins_session_policy_local_la_OBJECTS)
+plugins_session_policy_local_la_CFLAGS = $(plugin_cflags) \
+				-DSTORAGEDIR=\""$(storagedir)\""
+plugins_session_policy_local_la_LDFLAGS = $(plugin_ldflags)
+endif
+endif
+
+EXTRA_DIST += plugins/polkit.policy
+
+plugins/net.connman.policy: plugins/polkit.policy
+if POLKIT
+	$(AM_V_GEN)cp $< $@
+endif
+
+EXTRA_DIST += vpn/vpn-polkit.policy
+
+if VPN
+vpn/net.connman.vpn.policy: vpn/vpn-polkit.policy
+if POLKIT
+	$(AM_V_GEN)cp $< $@
+endif
+endif
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..0f86bc1
--- /dev/null
+++ b/README
@@ -0,0 +1,276 @@
+Connection Manager
+******************
+
+Copyright (C) 2007-2012  Intel Corporation. All rights reserved.
+
+
+Functionality and features
+==========================
+
+The following features are built-in into Connection Manager:
+	- Generic plugin infrastructure
+	- Device and network abstraction (with basic storage support)
+	- IPv4, IPv4-LL (link-local) and DHCP
+	- IPv6, DHCPv6 and 6to4 tunnels
+	- Advanced routing and DNS configuration
+	- Built-in DNS proxy and intelligent caching
+	- Built-in WISPr hotspot logins and portal detection
+	- Time and timezone configuration (manual and automatic with NTP)
+	- Proxy handling (manual and automatic with WPAD)
+	- Tethering support (USB, Bluetooth and WiFi AP mode)
+	- Detailed statistics handling (home and roaming)
+
+Various plugins can be enabled for networking support:
+	- Ethernet plugin
+	- WiFi plugin with WEP40/WEP128 and WPA/WPA2 (personal and enterprise)
+	- Bluetooth plugin (using BlueZ)
+	- 2G/3G/4G plugin (using oFono)
+
+Also plugins with additional features are available:
+	- Loopback interface setup
+	- PACrunner proxy handling
+	- PolicyKit authorization support
+
+Note that when ConnMan starts, it clears all network interfaces that are
+going to be used. If this is not desired, network interfaces can be ignored
+either by setting NetworkInterfaceBlacklist in the main.conf config file or
+by using the -I command line option.
+
+
+Compilation and installation
+============================
+
+In order to compile Connection Manager you need following software packages:
+	- GCC compiler
+	- GLib library
+	- D-Bus library
+	- IP-Tables library
+	- GnuTLS library (optional)
+	- PolicyKit (optional)
+	- readline (command line client)
+
+To configure run:
+	./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var
+
+Configure automatically searches for all required components and packages.
+
+To compile and install run:
+	make && make install
+
+
+Configuration and options
+=========================
+
+For a working system, certain configuration options need to be enabled:
+
+	--disable-ethernet
+
+		Disable support for Ethernet network cards
+
+		By default Ethernet technology support is built-in and
+		enabled. This option can be used to build a small daemon
+		for a specific system if Ethernet support is not required.
+
+	--disable-wifi
+
+		Disable support for WiFi devices
+
+		By default WiFi technology support is built-in and
+		enabled. This option can be used to build a small daemon
+		for a specific system if WiFi support is not required.
+
+		It is safe to build a daemon with WiFi support and no
+		running wpa_supplicant. The start of wpa_supplicant is
+		automatically detected and only a runtime dependency. It
+		is not needed to build ConnMan.
+
+	--disable-bluetooth
+
+		Disable support for Bluetooth devices
+
+		By default Bluetooth technology support is built-in and
+		enabled. This option can be used to build a small daemon
+		for a specific system if Bluetooth support is not required.
+
+		It is safe to build a daemon with Bluetooth support and no
+		running bluetoothd. The start of bluetoothd is automatically
+		detected and only a runtime dependency. It is not needed to
+		build ConnMan.
+
+	--disable-ofono
+
+		Disable support for cellular 2G/3G/4G devices
+
+		By default oFono technology support is built-in and
+		enabled. This option can be used to build a small daemon
+		for a specific system where oFono is not used.
+
+		It is safe to build a daemon with oFono support and no
+		running ofonod. That start of ofonod is automatically
+		detected and only a runtime dependency. It is not needed to
+		build ConnMan.
+
+	--disable-dundee
+
+		Disable support for Bluetooth DUN devices
+
+		By default Bluetooth DUN technology (dundee) support is
+		built-in and enabled. This option can be used to build a
+		small daemon for a specific system where dundee is not used.
+
+		It is safe to build a daemon with dundee support and no
+		running dundee. That start of dundee is automatically
+		detected and only a runtime dependency. It is not needed to
+		build ConnMan.
+
+	--disable-pacrunner
+
+		Disable support for PACrunner proxy handling
+
+		By default PACrunner support is built-in and enabled. This
+		option can be used to build a small daemon for a specific
+		system where PACrunner is not used.
+
+		It is safe to build a daemon with PACrunner support and no
+		pacrunner daemon. It will detect and start a PACrunner
+		process if needed at runtime. The presence is not needed
+		to build ConnMan.
+
+	--disable-loopback
+
+		Disable setup of loopback device
+
+		For distributions with a really minimal init system and no
+		networking scripts this can take care of setting up the
+		loopback device and enabling it.
+
+		It is safe to leave this selected even if networking
+		scripts are in place. It detects an already configured
+		loopback device and leaves it as it is.
+
+	--disable-wispr
+
+		Disable support for WISPr hotspot logins
+
+		For systems with really minimal memory requirements, this
+		will disable the support for WISPr hotspot logins. The code
+		for WISPr will be still compiled into the daemon, but its
+		requirement on GnuTLS for secure connections will be lifted.
+
+		The missing GnuTLS support shrinks the memory requirements
+		by about 30% and for systems that are more stationary and do
+		not log into hotspots this might be a better trade off.
+
+		Disabling WISPr support is not disabling the portal detection
+		support. A portal will still be detected, but instead of being
+		asked for login credentials, the request for a browser session
+		will be made through the agent.
+
+	--enable-polkit
+
+		Enable support for PolicyKit authorization
+
+		This allows to check every D-Bus access against a security
+		policy and so restrict access to certain functionality.
+
+	--enable-nmcompat
+
+		Enable support for NetworkManager compatibility interfaces
+
+		This allows to expose a minimal set of NetworkManager
+		interfaces. It is useful for systems with applications
+		written to use NetworkManager to detect online/offline
+		status and have not yet been converted to use ConnMan.
+
+	--disable-client
+
+		Disable support for the command line client
+
+		By default the command line client is enabled and uses the
+		readline library. For specific systems where ConnMan is
+		configured by other means, the command line client can be
+		disabled and the dependency on readline is removed.
+
+	--enable-selinux
+
+		Enable support for compiling SElinux type enforcement rules
+
+		The TE rules are needed if host environment is in enforcing
+		mode. Without this option, the VPN client process cannot
+		send notification to connman-vpnd via net.connman.Task
+		interface. The compiled connman-task.pp module needs to
+		also installed using this command
+			# semodule -i connman-task.pp
+		in order to enable the dbus access.
+
+
+Kernel configuration
+====================
+
+In order to support tethering, the following kernel configuration options
+need to be enabled either as modules (m) or builtin (y):
+
+CONFIG_BRIDGE
+CONFIG_IP_NF_TARGET_MASQUERADE
+
+In order to enable CONFIG_IP_NF_TARGET_MASQUERADE, the following options need
+to be enabled also as modules (m) or builtin (y):
+
+CONFIG_NETFILTER
+CONFIG_NF_CONNTRACK_IPV4
+CONFIG_NF_NAT_IPV4
+
+
+wpa_supplicant configuration
+============================
+
+In order to get wpa_supplicant and Connection Manager working properly
+together you should edit wpa_supplicant .config file and set:
+
+CONFIG_WPS=y
+CONFIG_AP=y
+CONFIG_CTRL_IFACE_DBUS_NEW=y
+
+and, add:
+
+CONFIG_BGSCAN_SIMPLE=y
+
+This last option will enable the support of background scanning while being
+connected, which is necessary when roaming on wifi.
+
+It is recommended to use wpa_supplicant 0.8.x or 1.x or later.
+
+
+VPN
+===
+
+In order to compile pptp and l2tp VPN plugins, you need ppp development
+package.
+
+To run l2tp you will need
+	- xl2tpd, http://www.xelerance.com/services/software/xl2tpd
+
+To run pptp you will need
+	- pptp client, http://pptpclient.sourceforge.net
+
+Both l2tp and pptp also need pppd.
+
+
+OpenVPN
+=======
+
+Up to version 2.2 of OpenVPN, pushing additional routes from the
+server will not always work. Some of the symptons are that additional
+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.
+
+
+Information
+===========
+
+Mailing list:
+	connman@connman.net
+
+For additional information about the project visit ConnMan web site:
+	http://www.connman.net
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..77ab29e
--- /dev/null
+++ b/TODO
@@ -0,0 +1,210 @@
+Background
+==========
+
+- Priority scale: High, Medium and Low
+
+- Complexity scale: C1, C2, C4 and C8.
+   The complexity scale is exponential, with complexity 1 being the
+   lowest complexity. Complexity is a function of both task 'complexity'
+   and task 'scope'.
+
+
+Core
+====
+
+- Session API implementation
+
+   Priority: High
+   Complexity: C4
+   Owner: Daniel Wagner <daniel.wagner@bmw-carit.de>
+   Owner: Patrik Flykt <patrik.flykt@linux.intel.com>
+
+   The session API should provide a connection abstraction in order to
+   prioritize applications network accesses, prevent or allow network
+   and bearer roaming, or provide applications with a way to request
+   for periodic network connections. On-demand connections will be
+   implemented through this API as well.
+   See http://www.mail-archive.com/connman@connman.net/msg01653.html
+
+
+- Personal firewall
+
+   Priority: Low
+   Complexity: C8
+   Owner: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
+
+   Discuss and implement a basic and safe firewalling strategy into
+   Connman. Provide a D-Bus API for personal firewalling.
+
+
+- PACRunner extensions
+
+   Priority: Low
+   Complexity: C4
+
+   Support more URI schemes, support multiple connections, tighter
+   security integration.
+
+
+- Check logging produced by connman_info()
+
+   Priority: Medium
+   Complexity: C1
+
+   Check that logging produced by connman_info() contains meaningful messages
+   and get rid of the unnecessary ones.
+
+
+- Support for multiple agents
+
+  Priority: Medium
+  Complexity: C2
+
+  Allow to register multiple agents. Each unique system bus name owner
+  however is only allowed to register one agent.
+
+  The selection of which agents is used  should be matched by bus name
+  owner if possible or first come first serve. A graceful fallback to
+  the next agent should be also used in case of malfunctional agents.
+
+- Remove --nobacktrace option
+
+ Priority: Medium
+ Complexity: C1
+ When: 2.0
+
+ Remove the --nobacktrace option or change it to --backtrace depending on the
+ level of systemd integration or other factors.
+
+
+- Clean up type definitions
+
+   Priority: Medium
+   Complexity: C1
+
+   Go through variable types and use the following:
+   * uint8_t instead of connman_uint8_t, unsigned char
+   * uint16_t instead of connman_uint16_t, unsigned short
+   * bool from <stdbool.h> instead of connman_bool_t and gboolean, in the
+     latter case in those places it makes sense
+
+
+- Clean up data structure usage
+
+   Priority: Medium
+   Complexity: C4
+
+   Use hash tables, queues and lists in the code. Replace GSequences with
+   simpler structures. At the same time do a check on the currently used
+   data structures and see if something can be simplified.
+
+
+- Unit tests for DHCP, DNS and HTTP
+
+   Priority: Medium
+   Complexity: C4
+
+   Create unit tests for these components starting with DHCP. Use gtest
+   from GLib for this task similarly to what has been done for OBEX in Bluez
+   and oFono in general.
+
+
+WiFi
+====
+
+- Clean up WiFi data structure usage
+
+   Priority: Medium
+   Complexity: C2
+
+   Struct wifi_data is passed as a pointer in some of the wifi plugin
+   callbacks. For example removing a WiFi USB stick causes RTNL and
+   wpa_supplicant to call the wifi plugin at the same time causing the
+   freeing of the wifi data structure. Fix up the code to have proper
+   reference counting or other handling in place for the shared wifi data
+   and the members in the data structure.
+
+
+- EAP-AKA/SIM
+
+   Priority: Medium
+   Complexity: C2
+   Owner: Samuel Ortiz <sameo@linux.intel.com>
+
+   This EAP is needed for SIM card based network authentication.
+   ConnMan here plays a minor role: Once wpa_supplicant is set up for
+   starting and EAP-AKA/SIM authentication, it will talk to a SIM card
+   through its pcsc-lite API.
+
+
+- EAP-FAST
+
+   Priority: Low
+   Complexity: C1
+
+
+- WiFi p2p
+
+   Priority: Medium
+   Complexity: C2
+
+
+- Removing wpa_supplicant 0.7.x legacy support
+
+  Priority: Low
+  Complexity: C1
+  Owner: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
+
+  Removing global country property setter in gsupplicant, and removing
+  wifi's technology set_regdom implementation. Removing autoscan fallback.
+  (Note: should be done around the end 2012)
+
+Bluetooth
+=========
+
+- Remove Bluez 4.x support
+
+  Priority: Low
+  Complexity: C1
+
+  Remove plugins/bluetooth-legacy.c support in about 6 month (July 2013) or
+  when Bluez 4.x usage becomes minimal.
+
+Cellular
+========
+
+
+VPN
+===
+
+- IPsec
+
+   Priority: Medium
+   Complexity: C4
+   Owner: Jukka Rissanen <jukka.rissanen@linux.intel.com>
+
+
+Tools
+=====
+
+- Add Agent mode to connmanctl command line tool
+
+   Priority: Medium
+   Complexity: C2
+
+   connmanctl should implement agent prompting when started with a suitable
+   command line option. Agent mode should also be enabled when in interactive
+   mode.
+
+
+User Interface
+==============
+
+- GNOME3 UI
+
+   Priority: Low
+   Complexity: C4
+   Owner: Alok Barsode <alok.barsode@linux.intel.com>
+
+   A GNOME3 shell user interface would make it easier for mainstream distros
+   users to use ConnMan.
diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644
index 0000000..0a59871
--- /dev/null
+++ b/acinclude.m4
@@ -0,0 +1,61 @@
+AC_DEFUN([AC_PROG_CC_PIE], [
+	AC_CACHE_CHECK([whether ${CC-cc} accepts -fPIE], ac_cv_prog_cc_pie, [
+		echo 'void f(){}' > conftest.c
+		if test -z "`${CC-cc} -fPIE -pie -c conftest.c 2>&1`"; then
+			ac_cv_prog_cc_pie=yes
+		else
+			ac_cv_prog_cc_pie=no
+		fi
+		rm -rf conftest*
+	])
+])
+
+AC_DEFUN([COMPILER_FLAGS], [
+	if (test "${CFLAGS}" = ""); then
+		CFLAGS="-Wall -O2 -D_FORTIFY_SOURCE=2"
+	fi
+	if (test "$USE_MAINTAINER_MODE" = "yes"); then
+		CFLAGS+=" -Werror -Wextra"
+		CFLAGS+=" -Wno-unused-parameter"
+		CFLAGS+=" -Wno-missing-field-initializers"
+		CFLAGS+=" -Wdeclaration-after-statement"
+		CFLAGS+=" -Wmissing-declarations"
+		CFLAGS+=" -Wredundant-decls"
+		CFLAGS+=" -Wcast-align"
+		CFLAGS="$CFLAGS -DG_DISABLE_DEPRECATED"
+	fi
+])
+
+AC_DEFUN([GTK_DOC_CHECK],
+[
+  AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first
+  AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first
+  dnl for overriding the documentation installation directory
+  AC_ARG_WITH([html-dir],
+    AS_HELP_STRING([--with-html-dir=PATH], [path to installed docs]),,
+    [with_html_dir='${datadir}/gtk-doc/html'])
+  HTML_DIR="$with_html_dir"
+  AC_SUBST([HTML_DIR])
+
+  dnl enable/disable documentation building
+  AC_ARG_ENABLE([gtk-doc],
+    AS_HELP_STRING([--enable-gtk-doc],
+                   [use gtk-doc to build documentation [[default=no]]]),,
+    [enable_gtk_doc=no])
+
+  if test x$enable_gtk_doc = xyes; then
+    ifelse([$1],[],
+      [PKG_CHECK_EXISTS([gtk-doc],,
+                        AC_MSG_ERROR([gtk-doc not installed and --enable-gtk-doc requested]))],
+      [PKG_CHECK_EXISTS([gtk-doc >= $1],,
+                        AC_MSG_ERROR([You need to have gtk-doc >= $1 installed to build gtk-doc]))])
+  fi
+
+  AC_MSG_CHECKING([whether to build gtk-doc documentation])
+  AC_MSG_RESULT($enable_gtk_doc)
+
+  AC_PATH_PROGS(GTKDOC_CHECK,gtkdoc-check,)
+
+  AM_CONDITIONAL([ENABLE_GTK_DOC], [test x$enable_gtk_doc = xyes])
+  AM_CONDITIONAL([GTK_DOC_USE_LIBTOOL], [test -n "$LIBTOOL"])
+])
diff --git a/bootstrap b/bootstrap
new file mode 100755
index 0000000..fb2c692
--- /dev/null
+++ b/bootstrap
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+cd "`dirname $0`"
+
+aclocal && \
+    autoheader && \
+        libtoolize --automake --copy --force && \
+	    automake --add-missing --copy && \
+		autoconf
diff --git a/bootstrap-configure b/bootstrap-configure
new file mode 100755
index 0000000..0741bcd
--- /dev/null
+++ b/bootstrap-configure
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+if [ -f config.status ]; then
+	make maintainer-clean
+fi
+
+if [ ! -f doc/gtk-doc.make ]; then
+	gtkdocize --copy --docdir doc
+fi
+
+./bootstrap && \
+    ./configure --enable-maintainer-mode \
+		--enable-debug \
+		--prefix=/usr \
+		--mandir=/usr/share/man \
+		--localstatedir=/var \
+		--sysconfdir=/etc \
+		--disable-datafiles \
+		--enable-openconnect=builtin \
+		--enable-openvpn=builtin \
+		--enable-vpnc=builtin \
+		--enable-session-policy-local=builtin \
+		--enable-nmcompat \
+		--enable-polkit $*
diff --git a/client/commands.c b/client/commands.c
new file mode 100644
index 0000000..75856cd
--- /dev/null
+++ b/client/commands.c
@@ -0,0 +1,538 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 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 as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "services.h"
+#include "technology.h"
+#include "data_manager.h"
+#include "monitor.h"
+#include "interactive.h"
+
+#define MANDATORY_ARGS 3
+
+static char *ipv4[] = {
+	"Method",
+	"Address",
+	"Netmask",
+	"Gateway",
+	NULL
+};
+
+static char *ipv6[] = {
+	"Method",
+	"Address",
+	"PrefixLength",
+	"Gateway",
+	"Privacy",
+	NULL
+};
+
+static char *proxy_simple[] = {
+	"Method",
+	"URL",
+	NULL
+};
+
+void show_help(void)
+{
+	printf("Usage: connmanctl <command> [args]\n"
+	"  enable                             Enables given technology\n"
+	"        <technology>\n"
+	"        offlinemode                  Enables OfflineMode\n"
+	"  disable                            Disables given technology\n"
+	"        <technology>\n"
+	"        offlinemode                  Disables OfflineMode\n"
+	"  state                              Shows if the system is online or offline\n"
+	"  services                           Display list of all services\n"
+	"        --properties <service name>  Show properties of service\n"
+	"  technologies                       Current technology on the system\n"
+	"  scan <technology>                  Scans for new services on the given technology\n"
+	"  connect <service>                  Connect to a given service\n"
+	"  disconnect <service>               Disconnect from service\n"
+	"  config <service> [arg]             Set certain config options\n"
+	"        --autoconnect=y/n            Set autoconnect to service\n"
+	"        --nameservers <names>        Set manual name servers\n"
+	"        --timeservers <names>        Set manual time servers\n"
+	"        --domains <domains>          Set manual domains\n"
+	"        --ipv4                       Set ipv4 configuration\n"
+	"          [METHOD|DHCP|AUTO|MANUAL] [IP] [NETMASK] [GATEWAY]\n"
+	"        --ipv6                       Set ipv6 configuration\n"
+	"          [METHOD|AUTO|MANUAL|OFF] [IP] [PREFIXLENGTH] [GATEWAY]\n"
+	"          [PRIVACY|DISABLED|ENABLED|PREFERED]\n"
+	"        --proxy                      Set proxy configuration\n"
+	"          [METHOD|URL|SERVERS|EXCLUDES]\n"
+	"          if METHOD = manual, enter 'servers' then the list of servers\n"
+	"                         then enter 'excludes' then the list of excludes\n"
+	"        --remove                     Remove the service from favorite\n"
+	"  monitor                            Monitor signals from all Connman interfaces\n"
+	"        --services                   Monitor signals from the Service interface\n"
+	"        --tech                       Monitor signals from the Technology interface\n"
+	"        --manager                    Monitor signals from the Manager interface\n"
+	"  help, --help, (no arguments)       Show this dialogue\n"
+	"  exit, quit, q                      Quit interactive mode\n"
+	"\nNote: arguments and output are considered EXPERIMENTAL for now.\n\n");
+}
+
+int service_switch(int argc, char *argv[], int c, DBusConnection *conn,
+						struct service_data *service)
+{
+	const char *name;
+	DBusMessage *message;
+	int error = 0;
+
+	message = get_message(conn, "GetServices");
+	if (message == NULL)
+		return -ENOMEM;
+
+	switch (c) {
+	case 'p':
+		name = find_service(conn, message, argv[2], service);
+		if (name == NULL) {
+			error = -ENXIO;
+			break;
+		}
+
+		error = list_properties(conn, "GetServices", (char *) name);
+		break;
+	default:
+		fprintf(stderr, "Command not recognized, please check help\n");
+		error = -EINVAL;
+		break;
+	}
+
+	dbus_message_unref(message);
+
+	return error;
+}
+
+int config_switch(int argc, char *argv[], int c, DBusConnection *conn)
+{
+	DBusMessage *message;
+	int num_args = argc - MANDATORY_ARGS;
+	int error = 0;
+	dbus_bool_t val;
+
+	message = get_message(conn, "GetServices");
+	if (message == NULL)
+		return -ENOMEM;
+
+	switch (c) {
+	case 'a':
+		switch (*optarg) {
+		case 'y':
+		case '1':
+		case 't':
+			val = TRUE;
+			break;
+		case 'n':
+		case '0':
+		case 'f':
+			val = FALSE;
+			break;
+		default:
+			return -EINVAL;
+		}
+		error = set_service_property(conn, message, argv[1],
+						"AutoConnect", NULL,
+						&val, 0);
+		break;
+	case 'i':
+		error = set_service_property(conn, message, argv[1],
+					"IPv4.Configuration", ipv4,
+					argv + MANDATORY_ARGS, num_args);
+		break;
+	case 'v':
+		error = set_service_property(conn, message, argv[1],
+					"IPv6.Configuration", ipv6,
+					argv + MANDATORY_ARGS, num_args);
+		break;
+	case 'n':
+		error = set_service_property(conn, message, argv[1],
+					"Nameservers.Configuration", NULL,
+					argv + MANDATORY_ARGS, num_args);
+		break;
+	case 't':
+		error = set_service_property(conn, message, argv[1],
+					"Timeservers.Configuration", NULL,
+					argv + MANDATORY_ARGS, num_args);
+		break;
+	case 'd':
+		error = set_service_property(conn, message, argv[1],
+					"Domains.Configuration", NULL,
+					argv + MANDATORY_ARGS, num_args);
+		break;
+	case 'x':
+		if ((strcmp(argv[3], "direct") == 0 && argc < 5) ||
+			(strcmp(argv[3], "auto") == 0 && argc < 6)) {
+			error = set_service_property(conn, message, argv[1],
+					"Proxy.Configuration", proxy_simple,
+					argv + MANDATORY_ARGS, num_args);
+		} else if (strcmp(argv[3], "manual") == 0
+				  && strcmp(argv[4], "servers") == 0
+				  && argc > 5) {
+			argc -= 5;
+			error = store_proxy_input(conn, message, argv[1],
+								argc, &argv[5]);
+		} else {
+			fprintf(stderr, "Incorrect arguments\n");
+			error = -EINVAL;
+		}
+		break;
+	case 'r':
+		error = remove_service(conn, message, argv[1]);
+		break;
+	default:
+		fprintf(stderr, "Command not recognized, please check help\n");
+		error = -EINVAL;
+		break;
+	}
+
+	dbus_message_unref(message);
+
+	return error;
+}
+
+int monitor_switch(int argc, char *argv[], int c, DBusConnection *conn)
+{
+	int error;
+
+	switch (c) {
+	case 's':
+		error = monitor_connman(conn, "Service", "PropertyChanged");
+		if (error != 0)
+			return error;
+		if (dbus_connection_add_filter(conn, service_property_changed,
+							NULL, NULL) == FALSE)
+			return -ENOMEM;
+		printf("Now monitoring the service interface.\n");
+		break;
+	case 'c':
+		error = monitor_connman(conn, "Technology", "PropertyChanged");
+		if (error != 0)
+			return error;
+		if (dbus_connection_add_filter(conn, tech_property_changed,
+							NULL, NULL) == FALSE)
+			return -ENOMEM;
+		printf("Now monitoring the technology interface.\n");
+		break;
+	case 'm':
+		error = monitor_connman(conn, "Manager", "PropertyChanged");
+		if (error != 0)
+			return error;
+		error = monitor_connman(conn, "Manager", "TechnologyAdded");
+		if (error != 0)
+			return error;
+		error = monitor_connman(conn, "Manager", "TechnologyRemoved");
+		if (error != 0)
+			return error;
+		error = monitor_connman(conn, "Manager", "ServicesChanged");
+		if (error != 0)
+			return error;
+		if (dbus_connection_add_filter(conn, manager_property_changed,
+							NULL, NULL) == FALSE)
+			return -ENOMEM;
+		if (dbus_connection_add_filter(conn, tech_added_removed,
+							NULL, NULL) == FALSE)
+			return -ENOMEM;
+		if (dbus_connection_add_filter(conn, manager_services_changed,
+							NULL, NULL) == FALSE)
+			return -ENOMEM;
+		printf("Now monitoring the manager interface.\n");
+		break;
+	default:
+		fprintf(stderr, "Command not recognized, please check help\n");
+		return -EINVAL;
+		break;
+	}
+	return 0;
+}
+
+int commands_no_options(DBusConnection *connection, char *argv[], int argc)
+{
+	DBusMessage *message = NULL;
+	int error = 0;
+
+
+	if (strcmp(argv[0], "--help") == 0 || strcmp(argv[0], "help") == 0  ||
+						strcmp(argv[0], "h") == 0) {
+		show_help();
+	} else if (strcmp(argv[0], "state") == 0) {
+		if (argc != 1) {
+			fprintf(stderr, "State cannot accept an argument, "
+								"see help\n");
+			error = -EINVAL;
+		} else
+			error = list_properties(connection,
+						"GetProperties", NULL);
+	} else if (strcmp(argv[0], "technologies") == 0) {
+		if (argc != 1) {
+			fprintf(stderr, "Tech cannot accept an argument, "
+								"see help\n");
+			error = -EINVAL;
+		} else
+			error = list_properties(connection,
+						"GetTechnologies", NULL);
+	} else if (strcmp(argv[0], "connect") == 0) {
+		if (argc != 2) {
+			fprintf(stderr, "Connect requires a service name or "
+							"path, see help\n");
+			error = -EINVAL;
+		} else
+			error = connect_service(connection,
+						strip_service_path(argv[1]));
+		if (error == 0)
+			printf("Connected to: %s\n",
+						strip_service_path(argv[1]));
+	} else if (strcmp(argv[0], "disconnect") == 0) {
+		if (argc != 2) {
+			fprintf(stderr, "Disconnect requires a service name or "
+							"path, see help\n");
+			error = -EINVAL;
+		} else
+			error = disconnect_service(connection,
+						strip_service_path(argv[1]));
+		if (error == 0)
+			printf("Disconnected from: %s\n",
+						strip_service_path(argv[1]));
+	} else if (strcmp(argv[0], "scan") == 0) {
+		if (argc != 2) {
+			fprintf(stderr, "Scan requires a service name or path, "
+								"see help\n");
+			error = -EINVAL;
+		}
+		message = get_message(connection, "GetTechnologies");
+		if (message == NULL)
+			error = -ENOMEM;
+		else
+			error = scan_technology(connection, message, argv[1]);
+	} else if (strcmp(argv[0], "enable") == 0) {
+		if (argc != 2) {
+			fprintf(stderr, "Enable requires a technology name or "
+				"the argument 'offlinemode', see help\n");
+			error = -EINVAL;
+		} else if (strcmp(argv[1], "offlinemode") == 0) {
+			error = set_manager(connection, "OfflineMode", TRUE);
+			if (error == 0)
+				printf("OfflineMode is now enabled\n");
+		} else {
+			message = get_message(connection, "GetTechnologies");
+			if (message == NULL)
+				error = -ENOMEM;
+			else
+				error = set_technology(connection, message,
+						"Powered", argv[1], TRUE);
+			if (error == 0)
+				printf("Enabled %s technology\n", argv[1]);
+		}
+	} else if (strcmp(argv[0], "disable") == 0) {
+		if (argc != 2) {
+			fprintf(stderr, "Disable requires a technology name or "
+				"the argument 'offlinemode' see help\n");
+			error = -EINVAL;
+		} else if (strcmp(argv[1], "offlinemode") == 0) {
+			error = set_manager(connection, "OfflineMode", FALSE);
+			if (error == 0)
+				printf("OfflineMode is now disabled\n");
+		} else {
+			message = get_message(connection, "GetTechnologies");
+			if (message == NULL)
+				error = -ENOMEM;
+			else
+				error = set_technology(connection, message,
+						"Powered", argv[1], FALSE);
+			if (error == 0)
+				printf("Disabled %s technology\n", argv[1]);
+		}
+	} else
+		return -1;
+
+	if (message != NULL)
+		dbus_message_unref(message);
+
+	return error;
+}
+
+int commands_options(DBusConnection *connection, char *argv[], int argc)
+{
+	int error, c;
+	int option_index = 0;
+	struct service_data service;
+
+	static struct option service_options[] = {
+		{"properties", required_argument, 0, 'p'},
+		{0, 0, 0, 0}
+	};
+
+	static struct option config_options[] = {
+		{"nameservers", required_argument, 0, 'n'},
+		{"timeservers", required_argument, 0, 't'},
+		{"domains", required_argument, 0, 'd'},
+		{"ipv6", required_argument, 0, 'v'},
+		{"proxy", required_argument, 0, 'x'},
+		{"autoconnect", required_argument, 0, 'a'},
+		{"ipv4", required_argument, 0, 'i'},
+		{"remove", 0, 0, 'r'},
+		{0, 0, 0, 0}
+	};
+
+	static struct option monitor_options[] = {
+		{"services", no_argument, 0, 's'},
+		{"tech", no_argument, 0, 'c'},
+		{"manager", no_argument, 0, 'm'},
+		{0, 0, 0, 0}
+	};
+
+	if (strcmp(argv[0], "services") == 0) {
+		if (argc > 3) {
+			fprintf(stderr, "Too many arguments for services, "
+								"see help\n");
+			return -EINVAL;
+		}
+		if (argc < 2) {
+			printf("List of all services:\n");
+			error = list_properties(connection, "GetServices", NULL);
+			if (error != 0)
+				return error;
+		} else {
+			while ((c = getopt_long(argc, argv, "", service_options,
+						&option_index))) {
+				if (c == -1) {
+					if (option_index == 0) {
+						printf("Services takes an "
+							"option, see help.\n");
+						return -EINVAL;
+					}
+					break;
+				}
+				error = service_switch(argc, argv, c,
+								connection,
+								&service);
+				if (error != 0)
+					return error;
+				option_index++;
+			}
+		}
+	} else if (strcmp(argv[0], "config") == 0) {
+		if (argc < 3) {
+			fprintf(stderr, "Config requires an option, "
+								"see help\n");
+			return -EINVAL;
+		}
+		while ((c = getopt_long(argc, argv, "", config_options,
+							&option_index))) {
+			if (c == -1) {
+				if (option_index == 0) {
+					printf("Config requires an option, "
+							"see help\n");
+					return -EINVAL;
+				}
+				break;
+			}
+			error = config_switch(argc, argv, c, connection);
+			if (error != 0)
+				return error;
+			option_index++;
+		}
+	} else if (strcmp(argv[0], "monitor") == 0) {
+		if (argc > 2) {
+			fprintf(stderr, "Too many arguments for monitor, "
+								"see help\n");
+			return -EINVAL;
+		}
+		if (argc < 2) {
+			error = monitor_connman(connection, "Service",
+							"PropertyChanged");
+			if (error != 0)
+				return error;
+			error = monitor_connman(connection, "Technology",
+							"PropertyChanged");
+			if (error != 0)
+				return error;
+			error = monitor_connman(connection, "Manager",
+							"PropertyChanged");
+			if (error != 0)
+				return error;
+			error = monitor_connman(connection, "Manager",
+							"TechnologyAdded");
+			if (error != 0)
+				return error;
+			error = monitor_connman(connection, "Manager",
+							"TechnologyRemoved");
+			if (error != 0)
+				return error;
+			error = monitor_connman(connection, "Manager",
+							"ServicesChanged");
+			if (error != 0)
+				return error;
+			if (dbus_connection_add_filter(connection,
+					service_property_changed, NULL, NULL)
+								== FALSE)
+				return -ENOMEM;
+			if (dbus_connection_add_filter(connection,
+					tech_property_changed, NULL, NULL)
+								== FALSE)
+				return -ENOMEM;
+			if (dbus_connection_add_filter(connection,
+					tech_added_removed, NULL, NULL)
+								== FALSE)
+				return -ENOMEM;
+			if (dbus_connection_add_filter(connection,
+					manager_property_changed, NULL, NULL)
+								== FALSE)
+				return -ENOMEM;
+			if (dbus_connection_add_filter(connection,
+					manager_services_changed, NULL, NULL)
+								== FALSE)
+				return -ENOMEM;
+			printf("Now monitoring all interfaces.\n");
+		} else
+			while ((c = getopt_long(argc, argv, "", monitor_options,
+							&option_index))) {
+				if (c == -1) {
+					if (option_index == 0) {
+						printf("Monitor takes an "
+							"option, see help\n");
+						return -EINVAL;
+					}
+					break;
+				}
+				error = monitor_switch(argc, argv, c, connection);
+				if (error != 0)
+					return error;
+				option_index++;
+			}
+	} else
+		return -1;
+	return 0;
+}
diff --git a/client/data_manager.c b/client/data_manager.c
new file mode 100644
index 0000000..8dae718
--- /dev/null
+++ b/client/data_manager.c
@@ -0,0 +1,274 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 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 as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "services.h"
+#include "technology.h"
+#include "data_manager.h"
+#include "dbus.h"
+
+static void extract_manager_properties(DBusMessage *message)
+{
+	DBusMessageIter iter, array;
+
+	dbus_message_iter_init(message, &iter);
+	dbus_message_iter_recurse(&iter, &array);
+	extract_properties(&array);
+}
+
+int store_proxy_input(DBusConnection *connection, DBusMessage *message,
+				char *name, int num_args, char *argv[])
+{
+	int i, j, k;
+	int error = 0;
+	gchar **servers = NULL;
+	gchar **excludes = NULL;
+
+	for (i = 0; strcmp(argv[i], "excludes") != 0; i++) {
+		servers = g_try_realloc(servers, (i + 1) * sizeof(char *));
+		if (servers == NULL) {
+			fprintf(stderr, "Could not allocate memory for list\n");
+			return -ENOMEM;
+		}
+		servers[i] = g_strdup(argv[i]);
+		/* In case the user doesn't enter "excludes" */
+		if (i + 1 == num_args) {
+			i++;
+			j = 0;
+			goto free_servers;
+		}
+	}
+	for (j = 0; j + (i + 1) != num_args; j++) {
+		excludes = g_try_realloc(excludes, (j + 1) * sizeof(char *));
+		if (excludes == NULL) {
+			fprintf(stderr, "Could not allocate memory for list\n");
+			return -ENOMEM;
+		}
+		excludes[j] = g_strdup(argv[j + (i + 1)]);
+	}
+
+free_servers:
+	error = set_proxy_manual(connection, message, name, servers, excludes,
+									i, j);
+
+	for (k = 0; k < j - 1; k++)
+		g_free(excludes[k]);
+	g_free(excludes);
+
+	for (k = 0; k < i - 1; k++)
+		g_free(servers[k]);
+	g_free(servers);
+
+	return error;
+}
+
+int connect_service(DBusConnection *connection, char *name)
+{
+	DBusMessage *message, *message_connect = NULL;
+	struct service_data service;
+	char *path = NULL;
+	const char *path_name;
+	DBusError err;
+	int err_ret = 0;
+
+	message = get_message(connection, "GetServices");
+	if (message == NULL)
+		return -ENOMEM;
+
+	path_name = find_service(connection, message, name, &service);
+	if (path_name == NULL) {
+		err_ret = -ENXIO;
+		goto error;
+	}
+
+	path = g_strdup_printf("/net/connman/service/%s", path_name);
+	message_connect = dbus_message_new_method_call("net.connman", path,
+						"net.connman.Service",
+						"Connect");
+	if (message_connect == NULL) {
+		err_ret = -ENOMEM;
+		goto error;
+	}
+
+	dbus_error_init(&err);
+	dbus_connection_send_with_reply_and_block(connection, message_connect,
+								-1, &err);
+
+	if (dbus_error_is_set(&err)) {
+		printf("Connection failed; error: '%s'\n", err.message);
+		err_ret = -EINVAL;
+		goto error;
+	}
+
+	dbus_connection_send(connection, message_connect, NULL);
+	dbus_connection_flush(connection);
+
+error:
+	if (message != NULL)
+		dbus_message_unref(message);
+	if (message_connect != NULL)
+		dbus_message_unref(message_connect);
+	g_free(path);
+
+	return err_ret;
+}
+
+int disconnect_service(DBusConnection *connection, char *name)
+{
+	DBusMessage *message, *message_disconnect = NULL;
+	struct service_data service;
+	char *path = NULL;
+	const char *path_name;
+	DBusError err;
+	int err_ret = 0;
+
+	message = get_message(connection, "GetServices");
+	if (message == NULL)
+		return -ENOMEM;
+
+	path_name = find_service(connection, message, name, &service);
+	if (path_name == NULL) {
+		err_ret = -ENXIO;
+		goto error;
+	}
+
+	path = g_strdup_printf("/net/connman/service/%s", path_name);
+	printf("%s\n", path);
+	message_disconnect = dbus_message_new_method_call("net.connman", path,
+							  "net.connman.Service",
+							  "Disconnect");
+	if (message_disconnect == NULL) {
+		err_ret = -ENOMEM;
+		goto error;
+	}
+
+	dbus_error_init(&err);
+	dbus_connection_send_with_reply_and_block(connection,
+						  message_disconnect,
+						  -1, &err);
+
+	if (dbus_error_is_set(&err)) {
+		printf("Connection failed; error: '%s'\n", err.message);
+		err_ret = -EINVAL;
+		goto error;
+	}
+
+	dbus_connection_send(connection, message_disconnect, NULL);
+	dbus_connection_flush(connection);
+
+error:
+	if (message != NULL)
+		dbus_message_unref(message);
+	if (message_disconnect != NULL)
+		dbus_message_unref(message_disconnect);
+	g_free(path);
+
+	return err_ret;
+}
+
+int set_manager(DBusConnection *connection, char *key, dbus_bool_t value)
+{
+	DBusMessage *message;
+	DBusMessageIter iter;
+
+	message = dbus_message_new_method_call("net.connman", "/",
+						"net.connman.Manager",
+						"SetProperty");
+	if (message == NULL)
+		return -ENOMEM;
+
+	dbus_message_iter_init_append(message, &iter);
+	dbus_property_append_basic(&iter, (const char *) key,
+						DBUS_TYPE_BOOLEAN, &value);
+	dbus_connection_send(connection, message, NULL);
+	dbus_connection_flush(connection);
+	dbus_message_unref(message);
+
+	return 0;
+}
+
+/* Call with any given function we want connman to respond to */
+DBusMessage *get_message(DBusConnection *connection, char *function)
+{
+	DBusMessage *message, *reply;
+	DBusError error;
+
+	message = dbus_message_new_method_call(CONNMAN_SERVICE,
+						CONNMAN_MANAGER_PATH,
+						CONNMAN_MANAGER_INTERFACE,
+						function);
+	if (message == NULL)
+		return NULL;
+
+	dbus_error_init(&error);
+
+	reply = dbus_connection_send_with_reply_and_block(connection,
+							   message, -1, &error);
+	if (dbus_error_is_set(&error) == TRUE) {
+		fprintf(stderr, "%s\n", error.message);
+		dbus_error_free(&error);
+	} else if (reply == NULL)
+		fprintf(stderr, "Failed to receive message\n");
+
+	dbus_message_unref(message);
+
+	return reply;
+}
+
+int list_properties(DBusConnection *connection, char *function,
+			char *service_name)
+{
+	DBusMessage *message;
+
+	message = get_message(connection, function);
+	if (message == NULL)
+		return -ENOMEM;
+
+	if (strcmp(function, "GetProperties") == 0)
+		extract_manager_properties(message);
+
+	else if (strcmp(function, "GetServices") == 0 && service_name != NULL)
+		extract_services(message, service_name);
+
+	else if (strcmp(function, "GetServices") == 0 && service_name == NULL)
+		get_services(message);
+
+	else if (strcmp(function, "GetTechnologies") == 0)
+		extract_tech(message);
+
+	dbus_message_unref(message);
+
+	return 0;
+}
diff --git a/client/data_manager.h b/client/data_manager.h
new file mode 100644
index 0000000..211eeb3
--- /dev/null
+++ b/client/data_manager.h
@@ -0,0 +1,45 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 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 as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <dbus/dbus.h>
+
+#define SIGNAL_LISTEN_TIMEOUT 10
+
+struct signal_args {
+	DBusConnection *connection;
+	const char *signal_name;
+};
+
+struct proxy_input {
+	char *servers;
+	char *excludes;
+};
+
+DBusMessage *get_message(DBusConnection *connection, char *function);
+int store_proxy_input(DBusConnection *connection, DBusMessage *message,
+				char *name, int num_args, char *argv[]);
+int list_properties(DBusConnection *connection, char *function,
+			char *service_name);
+int connect_service(DBusConnection *connection, char *name);
+int disconnect_service(DBusConnection *connection, char *name);
+int set_manager(DBusConnection *connection, char *key, dbus_bool_t value);
+void listen_for_manager_signal(void *args);
diff --git a/client/dbus.c b/client/dbus.c
new file mode 100644
index 0000000..002d858
--- /dev/null
+++ b/client/dbus.c
@@ -0,0 +1,80 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 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 as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <dbus/dbus.h>
+
+#include "dbus.h"
+
+void dbus_property_append_basic(DBusMessageIter *iter,
+					const char *key, int type, void *val)
+{
+	DBusMessageIter value;
+	const char *signature;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key);
+
+	switch (type) {
+	case DBUS_TYPE_BOOLEAN:
+		signature = DBUS_TYPE_BOOLEAN_AS_STRING;
+		break;
+	case DBUS_TYPE_STRING:
+		signature = DBUS_TYPE_STRING_AS_STRING;
+		break;
+	case DBUS_TYPE_BYTE:
+		signature = DBUS_TYPE_BYTE_AS_STRING;
+		break;
+	case DBUS_TYPE_UINT16:
+		signature = DBUS_TYPE_UINT16_AS_STRING;
+		break;
+	case DBUS_TYPE_INT16:
+		signature = DBUS_TYPE_INT16_AS_STRING;
+		break;
+	case DBUS_TYPE_UINT32:
+		signature = DBUS_TYPE_UINT32_AS_STRING;
+		break;
+	case DBUS_TYPE_INT32:
+		signature = DBUS_TYPE_INT32_AS_STRING;
+		break;
+	case DBUS_TYPE_UINT64:
+		signature = DBUS_TYPE_UINT64_AS_STRING;
+		break;
+	case DBUS_TYPE_INT64:
+		signature = DBUS_TYPE_INT64_AS_STRING;
+		break;
+	case DBUS_TYPE_OBJECT_PATH:
+		signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
+		break;
+	default:
+		signature = DBUS_TYPE_VARIANT_AS_STRING;
+		break;
+	}
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+							signature, &value);
+	dbus_message_iter_append_basic(&value, type, val);
+	dbus_message_iter_close_container(iter, &value);
+}
+
diff --git a/client/dbus.h b/client/dbus.h
new file mode 100644
index 0000000..3cde017
--- /dev/null
+++ b/client/dbus.h
@@ -0,0 +1,65 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 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 as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <dbus/dbus.h>
+
+#define CONNMAN_SERVICE			"net.connman"
+
+#define CONNMAN_MANAGER_INTERFACE	CONNMAN_SERVICE ".Manager"
+#define CONNMAN_MANAGER_PATH		"/"
+
+#define CONNMAN_SERVICE_INTERFACE	CONNMAN_SERVICE ".Service"
+
+void dbus_property_append_basic(DBusMessageIter *iter,
+					const char *key, int type, void *val);
+
+static inline void dbus_dict_open(DBusMessageIter *iter, DBusMessageIter *dict)
+{
+	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, dict);
+}
+
+static inline void dbus_dict_open_variant(DBusMessageIter *iter,
+							DBusMessageIter *dict)
+{
+	dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+			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, dict);
+}
+
+static inline void dbus_array_open(DBusMessageIter *iter, DBusMessageIter *dict)
+{
+	dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+			DBUS_TYPE_ARRAY_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING,
+			dict);
+}
+
+static inline void dbus_dict_close(DBusMessageIter *iter, DBusMessageIter *dict)
+{
+	dbus_message_iter_close_container(iter, dict);
+}
+
diff --git a/client/interactive.c b/client/interactive.c
new file mode 100644
index 0000000..485ae0f
--- /dev/null
+++ b/client/interactive.c
@@ -0,0 +1,148 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 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 as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "services.h"
+#include "technology.h"
+#include "data_manager.h"
+#include "monitor.h"
+#include "interactive.h"
+
+static DBusConnection *interactive_conn;
+
+static char **parse_long(char *input, int *num_args)
+{
+	int i;
+	char **token = NULL;
+
+	for (i = 0; input != NULL; i++) {
+		token = realloc(token, (i + 1) * sizeof(char *));
+		if (token == NULL)
+			return NULL;
+		token[i] = strdup(input);
+		input = strtok(NULL, " ");
+	}
+	*num_args = i;
+
+	return token;
+}
+
+static gboolean rl_handler(char *input)
+{
+	char **long_args;
+	int num_args, i, error=FALSE;
+	num_args = 0;
+
+	if (input == NULL) {
+		rl_newline(1, '\n');
+		exit(EXIT_FAILURE);
+	}
+
+	add_history(input);
+	input = strtok(input, " ");
+
+	if (input == NULL)
+		goto bail;
+	long_args = parse_long(input, &num_args);
+
+	if (long_args == NULL) {
+		free(input);
+		exit(EXIT_FAILURE);
+	} else {
+		error = commands_no_options(interactive_conn,
+						long_args, num_args);
+		if (error == -1)
+			error = commands_options(interactive_conn, long_args,
+						num_args);
+		else
+			goto bail;
+	}
+	if ((strcmp(long_args[0], "quit") == 0)
+					|| (strcmp(long_args[0], "exit") == 0)
+					|| (strcmp(long_args[0], "q") == 0)) {
+		for (i = 0; i < num_args; i++)
+			free(long_args[i]);
+		free(long_args);
+		exit(EXIT_SUCCESS);
+	}
+	if (error == -1) {
+		fprintf(stderr, "%s is not a valid command, check help.\n",
+			long_args[0]);
+	}
+
+	for (i = 0; i < num_args; i++)
+		free(long_args[i]);
+	free(long_args);
+	optind = 0;
+
+	error = TRUE;
+bail:
+	rl_callback_handler_install("connmanctl> ", (void *)rl_handler);
+	return error;
+}
+
+static gboolean readmonitor(GIOChannel *channel, GIOCondition condition,
+							gpointer user_data){
+	if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+		g_io_channel_unref(channel);
+		return FALSE;
+	}
+	rl_callback_read_char();
+	return TRUE;
+}
+
+void show_interactive(DBusConnection *connection, GMainLoop *mainloop)
+{
+	GIOChannel *gchan;
+	int events;
+	gchan = g_io_channel_unix_new(fileno(stdin));
+	events = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+	interactive_conn = connection;
+
+	while (TRUE) {
+		g_io_add_watch(gchan, events, readmonitor, NULL);
+		rl_callback_handler_install("connmanctl> ", (void *)rl_handler);
+		g_main_loop_run(mainloop);
+
+		rl_callback_handler_remove();
+		g_io_channel_unref(gchan);
+	}
+}
diff --git a/client/interactive.h b/client/interactive.h
new file mode 100644
index 0000000..a2bd051
--- /dev/null
+++ b/client/interactive.h
@@ -0,0 +1,32 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 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 as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <dbus/dbus.h>
+
+void show_interactive(DBusConnection *connection, GMainLoop *mainloop);
+int commands_no_options(DBusConnection *connection, char *argv[], int argc);
+int commands_options(DBusConnection *connection, char *argv[], int argc);
+void show_help(void);
+int monitor_switch(int argc, char *argv[], int c, DBusConnection *conn);
+int config_switch(int argc, char *argv[], int c, DBusConnection *conn);
+int service_switch(int argc, char *argv[], int c, DBusConnection *conn,
+						struct service_data *service);
diff --git a/client/main.c b/client/main.c
new file mode 100644
index 0000000..ab64277
--- /dev/null
+++ b/client/main.c
@@ -0,0 +1,126 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+#include <readline/readline.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "data_manager.h"
+#include "services.h"
+#include "technology.h"
+#include "interactive.h"
+#include "monitor.h"
+
+static GMainLoop *main_loop;
+
+static gboolean timeout_wait(gpointer data)
+{
+	static int i;
+	i++;
+	/* Set to whatever number of retries is wanted/needed */
+	if (i == 1) {
+		g_main_loop_quit(data);
+		return FALSE;
+	}
+	return TRUE;
+}
+
+static void rl_handler(char *input)
+{
+
+	if (input == NULL)
+		exit(EXIT_FAILURE);
+	else
+		printf("Use ctrl-d to exit\n");
+}
+
+static gboolean readmonitor(GIOChannel *channel, GIOCondition condition,
+						gpointer user_data){
+	rl_callback_read_char();
+	return TRUE;
+}
+
+int main(int argc, char *argv[])
+{
+	DBusConnection *connection;
+	DBusError err;
+	int events, error;
+	GIOChannel *gchan;
+	main_loop = g_main_loop_new(NULL, FALSE);
+
+	dbus_error_init(&err);
+
+	connection = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, &err);
+
+	if (dbus_error_is_set(&err)) {
+		fprintf(stderr, "Connection Error: %s\n", err.message);
+		dbus_error_free(&err);
+	}
+
+	if (connection == NULL) {
+		fprintf(stderr, "Could not connect to system bus...exiting\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (argc < 2)
+		show_interactive(connection, main_loop);
+
+	error = commands_no_options(connection, argv + 1, argc - 1);
+	if (error == -1) {
+		error = commands_options(connection, argv + 1, argc - 1);
+		if (strcmp(argv[1], "monitor") != 0)
+			return error;
+	} else {
+		return error;
+	}
+
+	if (error == -1) {
+		fprintf(stderr, "%s is not a valid command, check help.\n",
+							argv[1]);
+		return -EINVAL;
+	}
+	gchan = g_io_channel_unix_new(fileno(stdin));
+	events = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+	g_io_add_watch(gchan, events, readmonitor, NULL);
+	rl_callback_handler_install("", rl_handler);
+
+	if (strcmp(argv[1], "monitor") != 0)
+		g_timeout_add_full(G_PRIORITY_DEFAULT, 100, timeout_wait,
+							       main_loop, NULL);
+	g_main_loop_run(main_loop);
+	rl_callback_handler_remove();
+	g_io_channel_unref(gchan);
+	if (main_loop != NULL)
+		g_main_loop_unref(main_loop);
+	return 0;
+}
diff --git a/client/monitor.c b/client/monitor.c
new file mode 100644
index 0000000..5e8b392
--- /dev/null
+++ b/client/monitor.c
@@ -0,0 +1,254 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 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 as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "monitor.h"
+#include "services.h"
+#include "technology.h"
+#include "data_manager.h"
+
+static const char *get_service_name(DBusMessage *message, char *dbus_path)
+{
+	DBusMessageIter iter, array;
+
+	dbus_message_iter_init(message, &iter);
+	dbus_message_iter_recurse(&iter, &array);
+
+	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
+		DBusMessageIter entry, dict;
+		struct service_data service;
+		char *path;
+
+		dbus_message_iter_recurse(&array, &entry);
+		dbus_message_iter_get_basic(&entry, &path);
+
+		if (g_strcmp0(path, dbus_path) == 0) {
+			dbus_message_iter_next(&entry);
+			dbus_message_iter_recurse(&entry, &dict);
+			extract_service_name(&dict, &service);
+			return service.name;
+		} else {
+			dbus_message_iter_next(&array);
+		}
+	}
+	return NULL;
+}
+
+static void extract_tech_signal(DBusMessage *message)
+{
+	DBusMessageIter iter, dict;
+	char *path;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_OBJECT_PATH) {
+		dbus_message_iter_get_basic(&iter, &path);
+		printf(" { %s }\n", path);
+	}
+	dbus_message_iter_next(&iter);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID) {
+		dbus_message_iter_recurse(&iter, &dict);
+		extract_properties(&dict);
+	}
+}
+
+static void extract_signal_args(DBusMessage *message)
+{
+	DBusMessageIter iter, array, dict;
+	char *string, *value;
+	uint16_t key_int;
+	dbus_bool_t bvalue;
+
+	value = NULL;
+	key_int = 0;
+
+	dbus_message_iter_init(message, &iter);
+
+	while (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID) {
+		if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
+			dbus_message_iter_get_basic(&iter, &string);
+			printf("\n[%s] = ",
+			string);
+		}
+		dbus_message_iter_next(&iter);
+		if (dbus_message_iter_get_arg_type(&iter) !=
+							DBUS_TYPE_INVALID) {
+			dbus_message_iter_recurse(&iter, &array);
+			if (dbus_message_iter_get_arg_type(&array) ==
+							DBUS_TYPE_STRING) {
+				dbus_message_iter_get_basic(&array, &value);
+				printf("%s\n", value);
+				continue;
+			} else if (dbus_message_iter_get_arg_type(&array) ==
+							DBUS_TYPE_BOOLEAN) {
+				dbus_message_iter_get_basic(&array, &bvalue);
+				printf("%s\n", bvalue == TRUE ?
+							"True" : "False");
+				continue;
+			} else if (dbus_message_iter_get_arg_type(&array) ==
+							DBUS_TYPE_ARRAY)
+				dbus_message_iter_recurse(&array, &dict);
+			if (dbus_message_iter_get_arg_type(&dict) ==
+						DBUS_TYPE_DICT_ENTRY) {
+				iterate_dict(&dict, value, key_int);
+				printf("\n");
+			} else {
+				iterate_array(&array);
+				printf("\n");
+			}
+			dbus_message_iter_next(&iter);
+		}
+	}
+}
+
+int monitor_connman(DBusConnection *connection, char *interface,
+				char *signal_name)
+{
+	char *rule = g_strdup_printf("type='signal',interface='net.connman.%s',"
+					"member='%s'", interface, signal_name);
+	DBusError err;
+
+	dbus_error_init(&err);
+	g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, &err);
+	if (dbus_error_is_set(&err)) {
+		fprintf(stderr, "Bus setup error:%s\n", err.message);
+		return -1;
+	}
+	dbus_bus_add_match(connection, rule, &err);
+
+	if (dbus_error_is_set(&err)) {
+		fprintf(stderr, "Match Error: %s\n", err.message);
+		return -1;
+	}
+	return 0;
+}
+
+DBusHandlerResult service_property_changed(DBusConnection *connection,
+						DBusMessage *message,
+						void *user_data)
+{
+	DBusMessage *service_message;
+	struct service_data service;
+
+	if (dbus_message_is_signal(message, "net.connman.Service",
+					    "PropertyChanged")) {
+		service_message = get_message(connection, "GetServices");
+		if (service_message == NULL)
+			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+		service.name = get_service_name(service_message,
+				(char *) dbus_message_get_path(message));
+		printf("\n");
+		g_message("Path = %s, Interface = %s\nService = %s",
+				dbus_message_get_path(message),
+				dbus_message_get_interface(message),
+				service.name);
+		extract_signal_args(message);
+
+		dbus_message_unref(service_message);
+	}
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+DBusHandlerResult tech_property_changed(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	if (dbus_message_is_signal(message, "net.connman.Technology",
+					    "PropertyChanged")) {
+		printf("\n");
+		g_message("Path = %s, Interface = %s",
+				dbus_message_get_path(message),
+				dbus_message_get_interface(message));
+		extract_signal_args(message);
+	}
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+DBusHandlerResult tech_added_removed(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	if (dbus_message_is_signal(message, "net.connman.Manager",
+					    "TechnologyAdded")) {
+		printf("\n");
+		g_message("Path = %s, Interface = %s",
+				dbus_message_get_path(message),
+				dbus_message_get_interface(message));
+		printf("New technology added:\n");
+		extract_tech_signal(message);
+	} else if (dbus_message_is_signal(message, "net.connman.Manager",
+						   "TechnologyRemoved")) {
+		printf("\n");
+		g_message("Path = %s, Interface = %s",
+				dbus_message_get_path(message),
+				dbus_message_get_interface(message));
+		printf("Technology was removed:\n");
+		extract_tech_signal(message);
+	}
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+DBusHandlerResult manager_services_changed(DBusConnection *connection,
+				DBusMessage *message, void *user_data)
+{
+	if (dbus_message_is_signal(message, "net.connman.Manager",
+						"ServicesChanged")) {
+		printf("\n");
+		g_message("Path = %s, Interface = %s",
+				dbus_message_get_path(message),
+				dbus_message_get_interface(message));
+		printf("Services Changed, displaying updated "
+							"list of services:\n");
+		list_properties(connection, "GetServices", NULL);
+	}
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+DBusHandlerResult manager_property_changed(DBusConnection *connection,
+				DBusMessage *message, void *user_data)
+{
+	if (dbus_message_is_signal(message, "net.connman.Manager",
+					    "PropertyChanged")) {
+		printf("\n");
+		g_message("Path = %s, Interface = %s",
+				dbus_message_get_path(message),
+				dbus_message_get_interface(message));
+		extract_signal_args(message);
+	}
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
diff --git a/client/monitor.h b/client/monitor.h
new file mode 100644
index 0000000..db64aa1
--- /dev/null
+++ b/client/monitor.h
@@ -0,0 +1,41 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 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 as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <dbus/dbus.h>
+
+int monitor_connman(DBusConnection *connection, char *interface,
+				char *signal_name);
+
+DBusHandlerResult service_property_changed(DBusConnection *connection,
+				DBusMessage *message, void *user_data);
+
+DBusHandlerResult tech_property_changed(DBusConnection *connection,
+				DBusMessage *message, void *user_data);
+
+DBusHandlerResult tech_added_removed(DBusConnection *connection,
+				DBusMessage *message, void *user_data);
+
+DBusHandlerResult manager_property_changed(DBusConnection *connection,
+				DBusMessage *message, void *user_data);
+
+DBusHandlerResult manager_services_changed(DBusConnection *connection,
+				DBusMessage *message, void *user_data);
diff --git a/client/services.c b/client/services.c
new file mode 100644
index 0000000..7e6424f
--- /dev/null
+++ b/client/services.c
@@ -0,0 +1,535 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 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 as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "services.h"
+#include "dbus.h"
+
+static void append_property_array(DBusMessageIter *iter, char *property,
+						char **data, int num_args)
+{
+	DBusMessageIter value, array;
+	int i;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &property);
+
+	dbus_array_open(iter, &value);
+	dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
+					 DBUS_TYPE_STRING_AS_STRING, &array);
+
+	for (i = 0; i < num_args; i++) {
+		dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
+						&data[i]);
+		printf("Added: %s\n", data[i]);
+	}
+	dbus_message_iter_close_container(&value, &array);
+	dbus_message_iter_close_container(iter, &value);
+}
+
+static void append_property_dict(DBusMessageIter *iter, char *property,
+					char **keys, char **data, int num_args)
+{
+	DBusMessageIter value, dict, entry, dict_key;
+	int i;
+	unsigned char prefix;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &property);
+
+	/* Top most level is a{sv} */
+	dbus_dict_open_variant(iter, &value);
+
+	dbus_dict_open(&value, &dict);
+
+	for (i = 0; i < num_args; i++) {
+		dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
+							NULL, &entry);
+		dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
+							&keys[i]);
+
+		if (strcmp(property, "IPv6.Configuration") == 0 &&
+					   g_strcmp0(keys[i], "PrefixLength")) {
+			if (data[i] == NULL) {
+				fprintf(stderr, "No values entered!\n");
+				exit(EXIT_FAILURE);
+			}
+			prefix = atoi(data[i]);
+
+			dbus_message_iter_open_container(&entry,
+						DBUS_TYPE_VARIANT,
+						DBUS_TYPE_BYTE_AS_STRING,
+						&dict_key);
+			dbus_message_iter_append_basic(&dict_key,
+						       DBUS_TYPE_BYTE, &prefix);
+		} else {
+			dbus_message_iter_open_container(&entry,
+						 DBUS_TYPE_VARIANT,
+						 DBUS_TYPE_STRING_AS_STRING,
+						 &dict_key);
+			dbus_message_iter_append_basic(&dict_key,
+							DBUS_TYPE_STRING,
+							&data[i]);
+		}
+		dbus_message_iter_close_container(&entry, &dict_key);
+		dbus_message_iter_close_container(&dict, &entry);
+	}
+	/* Close {sv}, then close a{sv} */
+	dbus_dict_close(&value, &dict);
+	dbus_dict_close(iter, &value);
+}
+
+void iterate_array(DBusMessageIter *iter)
+{
+	DBusMessageIter array_item;
+	dbus_bool_t key_bool;
+	char *key_str;
+
+	dbus_message_iter_recurse(iter, &array_item);
+	/* Make sure the entry is not NULL! */
+	printf("[ ");
+	while (dbus_message_iter_get_arg_type(&array_item) !=
+					DBUS_TYPE_INVALID) {
+		if (dbus_message_iter_get_arg_type(&array_item) ==
+					DBUS_TYPE_STRING) {
+			dbus_message_iter_get_basic(&array_item,
+						&key_str);
+			printf("%s ", key_str);
+		} else if (dbus_message_iter_get_arg_type(&array_item) ==
+					DBUS_TYPE_BOOLEAN) {
+			dbus_message_iter_get_basic(&array_item, &key_bool);
+			printf("%s ", key_bool == TRUE ? "True"
+						: "False");
+		}
+		dbus_message_iter_next(&array_item);
+	}
+	if (dbus_message_iter_get_arg_type(&array_item) ==
+					DBUS_TYPE_INVALID)
+		printf("] ");
+}
+
+void iterate_dict(DBusMessageIter *dict, char *string, uint16_t key_int)
+{
+	DBusMessageIter dict_entry, sub_dict_entry;
+
+	printf("{ ");
+	while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
+		dbus_message_iter_recurse(dict, &dict_entry);
+		dbus_message_iter_get_basic(&dict_entry, &string);
+		printf("%s=", string);
+		dbus_message_iter_next(&dict_entry);
+		while (dbus_message_iter_get_arg_type(&dict_entry)
+							!= DBUS_TYPE_INVALID) {
+			dbus_message_iter_recurse(&dict_entry, &sub_dict_entry);
+			if (dbus_message_iter_get_arg_type(&sub_dict_entry)
+							== DBUS_TYPE_UINT16) {
+				dbus_message_iter_get_basic(&sub_dict_entry,
+								&key_int);
+				printf("%d ", key_int);
+			} else if (dbus_message_iter_get_arg_type(&sub_dict_entry)
+							== DBUS_TYPE_STRING) {
+				dbus_message_iter_get_basic(&sub_dict_entry,
+								&string);
+				printf("%s ", string);
+			} else if (dbus_message_iter_get_arg_type(&sub_dict_entry)
+							== DBUS_TYPE_ARRAY) {
+				iterate_array(&sub_dict_entry);
+			}
+			dbus_message_iter_next(&dict_entry);
+		}
+		dbus_message_iter_next(dict);
+	}
+	printf("}");
+}
+
+/* Get dictionary info about the current service and store it */
+static void extract_service_properties(DBusMessageIter *dict,
+				struct service_data *service)
+{
+	DBusMessageIter entry, value, array_item;
+	char *key;
+	char *key_str;
+	uint16_t key_uint16;
+	dbus_bool_t key_bool;
+
+	while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
+		dbus_message_iter_recurse(dict, &entry);
+		dbus_message_iter_get_basic(&entry, &key);
+		printf("\n  %s = ", key);
+		if (strcmp(key, "Name") == 0 && strlen(key) < 5)
+			service->name = key;
+
+		dbus_message_iter_next(&entry);
+		dbus_message_iter_recurse(&entry, &value);
+		/* Check if entry is a dictionary itself */
+		if (strcmp(key, "Ethernet") == 0 ||
+			/* if just strcmp, the .Configuration names don't match
+			 * and they are iterated with iterate_array instead*/
+				strncmp(key, "IPv4", 4) == 0 ||
+				strncmp(key, "IPv6", 4) == 0 ||
+				strncmp(key, "Proxy", 5) == 0 ||
+				strcmp(key, "Provider") == 0) {
+			dbus_message_iter_recurse(&value, &array_item);
+			iterate_dict(&array_item, key_str, key_uint16);
+		} else
+		switch (dbus_message_iter_get_arg_type(&value)) {
+		case DBUS_TYPE_ARRAY:
+			iterate_array(&value);
+			break;
+		case DBUS_TYPE_BOOLEAN:
+			dbus_message_iter_get_basic(&value, &key_bool);
+			printf("%s", key_bool == TRUE ? "True" : "False");
+			break;
+		case DBUS_TYPE_BYTE:
+			dbus_message_iter_get_basic(&value, &key_uint16);
+			printf("%d", key_uint16);
+			break;
+		case DBUS_TYPE_STRING:
+			dbus_message_iter_get_basic(&value, &key_str);
+			printf("%s", key_str);
+			break;
+		}
+		dbus_message_iter_next(dict);
+	}
+	printf("\n\n");
+}
+
+static void match_service_name(DBusMessage *message, char *service_name,
+						struct service_data *service)
+{
+	DBusMessageIter iter, array;
+
+	dbus_message_iter_init(message, &iter);
+	dbus_message_iter_recurse(&iter, &array);
+
+	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
+		DBusMessageIter entry, dict;
+		char *path;
+
+		dbus_message_iter_recurse(&array, &entry);
+		dbus_message_iter_get_basic(&entry, &path);
+
+		service->path = strip_service_path(path);
+		dbus_message_iter_next(&entry);
+		dbus_message_iter_recurse(&entry, &dict);
+		extract_service_name(&dict, service);
+		if (g_strcmp0(service_name, service->name) == 0) {
+			printf("    Matched %s with %s\n\n", service->name,
+								service->path);
+			break;
+		}
+		dbus_message_iter_next(&array);
+	}
+}
+
+void extract_service_name(DBusMessageIter *dict, struct service_data *service)
+{
+	DBusMessageIter dict_entry, value;
+	const char *key;
+	const char *state;
+
+	while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
+		dbus_message_iter_recurse(dict, &dict_entry);
+		dbus_message_iter_get_basic(&dict_entry, &key);
+		if (strcmp(key, "Name") == 0) {
+			dbus_message_iter_next(&dict_entry);
+			dbus_message_iter_recurse(&dict_entry, &value);
+			dbus_message_iter_get_basic(&value, &service->name);
+		}
+		if (strcmp(key, "AutoConnect") == 0) {
+			dbus_message_iter_next(&dict_entry);
+			dbus_message_iter_recurse(&dict_entry, &value);
+			dbus_message_iter_get_basic(&value, &service->autoconn);
+		}
+		if (strcmp(key, "State") == 0) {
+			dbus_message_iter_next(&dict_entry);
+			dbus_message_iter_recurse(&dict_entry, &value);
+			dbus_message_iter_get_basic(&value, &state);
+			if (strcmp(state, "ready") == 0) {
+				service->connected = TRUE;
+				service->online = FALSE;
+			} else if (strcmp(state, "online") == 0) {
+				service->connected = FALSE;
+				service->online = TRUE;
+			} else {
+				service->connected = FALSE;
+				service->online = FALSE;
+			}
+		}
+		if (strcmp(key, "Favorite") == 0) {
+			dbus_message_iter_next(&dict_entry);
+			dbus_message_iter_recurse(&dict_entry, &value);
+			dbus_message_iter_get_basic(&value, &service->favorite);
+		}
+		dbus_message_iter_next(dict);
+	}
+}
+
+/* Show detailed information about a service */
+void extract_services(DBusMessage *message, char *service_name)
+{
+	DBusMessageIter iter, array;
+
+	dbus_message_iter_init(message, &iter);
+	dbus_message_iter_recurse(&iter, &array);
+
+	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
+		DBusMessageIter entry, dict;
+		struct service_data service;
+		char *path;
+
+		dbus_message_iter_recurse(&array, &entry);
+		dbus_message_iter_get_basic(&entry, &path);
+
+		service.path = strip_service_path(path);
+		if (g_strcmp0(service.path, service_name) == 0) {
+			printf("[ %s ]\n", service.path);
+			dbus_message_iter_next(&entry);
+			dbus_message_iter_recurse(&entry, &dict);
+			extract_service_properties(&dict, &service);
+		}
+		dbus_message_iter_next(&array);
+	}
+}
+
+/* Support both string names and path names for connecting to services */
+char *strip_service_path(char *service)
+{
+	char *service_name;
+	service_name = strrchr(service, '/');
+	if (service_name == NULL)
+		return service;
+	else
+		return service_name + 1;
+}
+
+/* Show a simple list of service names only */
+void get_services(DBusMessage *message)
+{
+	DBusMessageIter iter, array;
+
+	dbus_message_iter_init(message, &iter);
+	dbus_message_iter_recurse(&iter, &array);
+
+	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
+		DBusMessageIter entry, dict;
+		struct service_data service;
+		char *path;
+
+		dbus_message_iter_recurse(&array, &entry);
+		dbus_message_iter_get_basic(&entry, &path);
+
+		service.path = strip_service_path(path);
+		dbus_message_iter_next(&entry);
+		dbus_message_iter_recurse(&entry, &dict);
+		extract_service_name(&dict, &service);
+		printf("%-1s%-1s%-1s %-20s { %s }\n",
+			service.favorite ? "*" : "",
+			service.autoconn ? "A" : "",
+			service.online ? "O" : (service.connected ? "R" : ""),
+			service.name, service.path);
+		dbus_message_iter_next(&array);
+	}
+}
+
+const char *find_service(DBusConnection *connection, DBusMessage *message,
+			  char *service_name, struct service_data *service)
+{
+	DBusMessageIter iter, array, entry;
+	char *path;
+
+	service_name = strip_service_path(service_name);
+	match_service_name(message, service_name, service);
+	/* Service name did not match, so check if entry is a path */
+	if (g_strcmp0(service_name, service->name)) {
+		dbus_message_iter_init(message, &iter);
+		dbus_message_iter_recurse(&iter, &array);
+
+		while (dbus_message_iter_get_arg_type(&array) ==
+							DBUS_TYPE_STRUCT) {
+			dbus_message_iter_recurse(&array, &entry);
+			dbus_message_iter_get_basic(&entry, &path);
+
+			service->path = strip_service_path(path);
+			if (g_strcmp0(service->path, service_name) == 0)
+				return service->path;
+			dbus_message_iter_next(&array);
+		}
+		fprintf(stderr, "'%s' is not a valid service name or path.\n",
+								service_name);
+		fprintf(stderr, "Use the 'services' command to find available "
+							"services.\n");
+		return NULL;
+	} else
+		return service->path;
+}
+
+int set_proxy_manual(DBusConnection *connection, DBusMessage *message,
+				char *name, char **servers, char **excludes,
+				int num_servers, int num_excludes)
+{
+	DBusMessage *message_send;
+	DBusMessageIter iter, value, dict, entry, data;
+	struct service_data service;
+	char *path;
+	const char *path_name;
+	char *property = "Proxy.Configuration";
+	char *method = "Method";
+	char *manual = "manual";
+
+	path_name = find_service(connection, message, name, &service);
+	if (path_name == NULL)
+		return -ENXIO;
+
+	path = g_strdup_printf("/net/connman/service/%s", path_name);
+	message_send = dbus_message_new_method_call("net.connman", path,
+							"net.connman.Service",
+							"SetProperty");
+
+	if (message_send == NULL) {
+		g_free(path);
+		return -ENOMEM;
+	}
+
+	dbus_message_iter_init_append(message_send, &iter);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &property);
+	dbus_dict_open_variant(&iter, &value);
+	dbus_dict_open(&value, &dict);
+	dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL,
+							&entry);
+	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &method);
+	dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+						DBUS_TYPE_STRING_AS_STRING,
+						&data);
+	dbus_message_iter_append_basic(&data, DBUS_TYPE_STRING, &manual);
+	dbus_message_iter_close_container(&entry, &data);
+	dbus_message_iter_close_container(&dict, &entry);
+	dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL,
+							&entry);
+	append_property_array(&entry, "Servers", servers, num_servers);
+	dbus_message_iter_close_container(&dict, &entry);
+
+	if (num_excludes != 0) {
+		dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
+							NULL, &entry);
+		append_property_array(&entry, "Excludes", excludes,
+							num_excludes);
+		dbus_message_iter_close_container(&dict, &entry);
+	}
+
+	dbus_message_iter_close_container(&value, &dict);
+	dbus_message_iter_close_container(&iter, &value);
+	dbus_connection_send(connection, message_send, NULL);
+	dbus_connection_flush(connection);
+	dbus_message_unref(message_send);
+
+	g_free(path);
+
+	return 0;
+}
+
+int set_service_property(DBusConnection *connection, DBusMessage *message,
+				char *name, char *property, char **keys,
+				void *data, int num_args)
+{
+	DBusMessage *message_send;
+	DBusMessageIter iter;
+	struct service_data service;
+	char *path;
+	const char *path_name;
+
+	path_name = find_service(connection, message, name, &service);
+	if (path_name == NULL)
+		return -ENXIO;
+
+	path = g_strdup_printf("/net/connman/service/%s", path_name);
+	message_send = dbus_message_new_method_call("net.connman", path,
+							"net.connman.Service",
+							"SetProperty");
+
+	if (message_send == NULL) {
+		g_free(path);
+		return -ENOMEM;
+	}
+
+	dbus_message_iter_init_append(message_send, &iter);
+
+	if (strcmp(property, "AutoConnect") == 0)
+		dbus_property_append_basic(&iter, (const char *) property,
+						DBUS_TYPE_BOOLEAN, data);
+	else if ((strcmp(property, "Domains.Configuration") == 0)
+			|| (strcmp(property, "Timeservers.Configuration") == 0)
+			|| (strcmp(property, "Nameservers.Configuration") == 0))
+		append_property_array(&iter, property, data, num_args);
+	else if ((strcmp(property, "IPv4.Configuration") == 0)
+			|| (strcmp(property, "IPv6.Configuration") == 0)
+			|| (strcmp(property, "Proxy.Configuration") == 0))
+		append_property_dict(&iter, property, keys, data, num_args);
+
+	dbus_connection_send(connection, message_send, NULL);
+	dbus_connection_flush(connection);
+	dbus_message_unref(message_send);
+	g_free(path);
+
+	return 0;
+}
+
+int remove_service(DBusConnection *connection, DBusMessage *message,
+								char *name)
+{
+	struct service_data service;
+	DBusMessage *message_send;
+	const char *path_name;
+	char *path;
+
+	path_name = find_service(connection, message, name, &service);
+	if (path_name == NULL)
+		return -ENXIO;
+
+	if (service.favorite == FALSE)
+		return 0;
+
+	path = g_strdup_printf("/net/connman/service/%s", path_name);
+	message_send = dbus_message_new_method_call(CONNMAN_SERVICE, path,
+						CONNMAN_SERVICE_INTERFACE,
+						"Remove");
+	if (message_send == NULL) {
+		g_free(path);
+		return -ENOMEM;
+	}
+
+	dbus_connection_send(connection, message_send, NULL);
+	dbus_message_unref(message_send);
+	g_free(path);
+
+	return 0;
+}
diff --git a/client/services.h b/client/services.h
new file mode 100644
index 0000000..eccc60a
--- /dev/null
+++ b/client/services.h
@@ -0,0 +1,57 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 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 as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdint.h>
+
+#include <dbus/dbus.h>
+
+struct service_data {
+	const char *path;
+	const char *name;
+	dbus_bool_t autoconn;
+	dbus_bool_t favorite;
+	dbus_bool_t connected;
+	dbus_bool_t online;
+};
+
+char *strip_service_path(char *service);
+void extract_service_name(DBusMessageIter *dict, struct service_data *service);
+int set_service_property(DBusConnection *connection, DBusMessage *message,
+				char *name, char *property, char **keys,
+				void *data, int num_args);
+int remove_service(DBusConnection *connection, DBusMessage *message,
+								char *name);
+int set_proxy_manual(DBusConnection *connection, DBusMessage *message,
+				char *name, char **servers, char **excludes,
+				int num_servers, int num_excludes);
+
+const char *find_service(DBusConnection *connection, DBusMessage *message,
+			  char *service_name, struct service_data *service);
+void extract_services(DBusMessage *message, char *service_name);
+void get_services(DBusMessage *message);
+void iterate_dict(DBusMessageIter *dict, char *string, uint16_t key_int);
+int list_services(DBusConnection *connection, char *function);
+int list_services_properties(DBusConnection *connection, char *function,
+				char *service_name);
+int listen_for_service_signal(DBusConnection *connection, char *signal_name,
+			char *service_name);
+void iterate_array(DBusMessageIter *iter);
diff --git a/client/technology.c b/client/technology.c
new file mode 100644
index 0000000..1832a1d
--- /dev/null
+++ b/client/technology.c
@@ -0,0 +1,189 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 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 as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "technology.h"
+#include "dbus.h"
+
+void extract_properties(DBusMessageIter *dict)
+{
+	while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
+		DBusMessageIter entry, value;
+		const char *key, *sdata;
+		dbus_bool_t bdata;
+
+		dbus_message_iter_recurse(dict, &entry);
+		dbus_message_iter_get_basic(&entry, &key);
+		printf("  [%s] = ", key);
+
+		dbus_message_iter_next(&entry);
+
+		dbus_message_iter_recurse(&entry, &value);
+
+		if (dbus_message_iter_get_arg_type(&value) ==
+							DBUS_TYPE_BOOLEAN) {
+			dbus_message_iter_get_basic(&value, &bdata);
+			printf("%s\n", bdata ? "True" : "False");
+		} else if (dbus_message_iter_get_arg_type(&value) ==
+							DBUS_TYPE_STRING) {
+			dbus_message_iter_get_basic(&value, &sdata);
+			printf("%s\n", sdata);
+		}
+		dbus_message_iter_next(dict);
+	}
+}
+
+void match_tech_name(DBusMessage *message, char *tech_name,
+						struct tech_data *tech)
+{
+	DBusMessageIter iter, array;
+
+	dbus_message_iter_init(message, &iter);
+	dbus_message_iter_recurse(&iter, &array);
+	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
+		DBusMessageIter entry;
+		const char *path;
+		const char *name;
+
+		dbus_message_iter_recurse(&array, &entry);
+		dbus_message_iter_get_basic(&entry, &path);
+		tech->path = g_strdup(path);
+		name = strrchr(path, '/') + 1;
+		tech->name = g_strdup(name);
+		if (g_strcmp0(tech_name, tech->name) == 0) {
+			printf("    %-20s { %s } exists\n", tech->name,
+								tech->path);
+			break;
+		} else
+			dbus_message_iter_next(&array);
+	}
+
+}
+
+void extract_tech(DBusMessage *message)
+{
+	DBusMessageIter iter, array;
+
+	dbus_message_iter_init(message, &iter);
+	dbus_message_iter_recurse(&iter, &array);
+	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
+		DBusMessageIter entry, dict;
+
+		const char *path;
+
+		dbus_message_iter_recurse(&array, &entry);
+		dbus_message_iter_get_basic(&entry, &path);
+
+		printf("{ %s }\n", path);
+
+		dbus_message_iter_next(&entry);
+
+		dbus_message_iter_recurse(&entry, &dict);
+		extract_properties(&dict);
+
+		dbus_message_iter_next(&array);
+	}
+}
+
+int scan_technology(DBusConnection *connection, DBusMessage *message,
+								char *tech)
+{
+	DBusMessage *message_send;
+	struct tech_data technology;
+	DBusError err;
+
+	match_tech_name(message, tech, &technology);
+	if (g_strcmp0(tech, technology.name) != 0) {
+		fprintf(stderr, "%s does not exist on the system\n", tech);
+		fprintf(stderr, "Use the 'tech' command to find available "
+					"technologies on your system.\n");
+		return -ENXIO;
+	}
+
+	message_send = dbus_message_new_method_call("net.connman",
+						technology.path,
+						"net.connman.Technology",
+						"Scan");
+	if (message_send == NULL)
+		return -ENOMEM;
+
+	dbus_error_init(&err);
+	dbus_connection_send_with_reply_and_block(connection, message_send, -1,
+									&err);
+
+	if (dbus_error_is_set(&err)) {
+		printf("Scan failed; error: '%s'\n", err.message);
+		return -EINVAL;
+	}
+
+	dbus_message_unref(message_send);
+	printf("Scanned for new services on %s.\n", technology.name);
+	g_free(technology.name);
+	g_free(technology.path);
+
+	return 0;
+}
+
+int set_technology(DBusConnection *connection, DBusMessage *message, char *key,
+						char *tech, dbus_bool_t value)
+{
+	DBusMessage *message_send;
+	DBusMessageIter iter;
+	struct tech_data technology;
+
+	match_tech_name(message, tech, &technology);
+	if (g_strcmp0(tech, technology.name) != 0) {
+		fprintf(stderr, "%s does not exist on the system\n", tech);
+		fprintf(stderr, "Use the 'tech' command to find available "
+					"technologies on your system.\n");
+		return -ENXIO;
+	}
+
+	message_send = dbus_message_new_method_call("net.connman",
+							technology.path,
+							"net.connman.Technology",
+							"SetProperty");
+	if (message_send == NULL)
+		return -ENOMEM;
+
+	dbus_message_iter_init_append(message_send, &iter);
+	dbus_property_append_basic(&iter, (const char *) key,
+						DBUS_TYPE_BOOLEAN, &value);
+	dbus_connection_send(connection, message_send, NULL);
+	dbus_connection_flush(connection);
+	dbus_message_unref(message_send);
+	g_free(technology.name);
+	g_free(technology.path);
+
+	return 0;
+}
diff --git a/client/technology.h b/client/technology.h
new file mode 100644
index 0000000..75d1a84
--- /dev/null
+++ b/client/technology.h
@@ -0,0 +1,40 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 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 as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <dbus/dbus.h>
+
+struct tech_data {
+	char *path;
+	char *name;
+	dbus_bool_t powered;
+	dbus_bool_t connected;
+};
+
+void extract_properties(DBusMessageIter *dict);
+void match_tech_name(DBusMessage *message, char *tech_name,
+			struct tech_data *tech);
+void extract_tech(DBusMessage *message);
+int list_tech(DBusConnection *connection, char *function);
+int set_technology(DBusConnection *connection, DBusMessage *message, char *key,
+						char *tech, dbus_bool_t value);
+int scan_technology(DBusConnection *connection, DBusMessage *message,
+						char *tech);
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..442b8a6
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,390 @@
+AC_PREREQ(2.60)
+AC_INIT(connman, 1.11)
+
+AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
+AC_CONFIG_HEADERS([config.h])
+
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+AM_MAINTAINER_MODE
+
+AC_PREFIX_DEFAULT(/usr/local)
+
+PKG_PROG_PKG_CONFIG
+
+COMPILER_FLAGS
+
+AC_SUBST(abs_top_srcdir)
+AC_SUBST(abs_top_builddir)
+
+AC_LANG_C
+
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_CC_PIE
+AC_PROG_INSTALL
+AC_PROG_MKDIR_P
+
+m4_define([_LT_AC_TAGCONFIG], [])
+m4_ifdef([AC_LIBTOOL_TAGS], [AC_LIBTOOL_TAGS([])])
+
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
+
+AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization],
+			[disable code optimization through compiler]), [
+	if (test "${enableval}" = "no"); then
+		CFLAGS="$CFLAGS -O0 -U_FORTIFY_SOURCE"
+	fi
+])
+
+GTK_DOC_CHECK
+
+AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],
+			[enable compiling with debugging information]), [
+	if (test "${enableval}" = "yes" &&
+				test "${ac_cv_prog_cc_g}" = "yes"); then
+		CFLAGS="$CFLAGS -g"
+		AC_DEFINE(CONNMAN_DEBUG, 1, [Enable connman debugging code?])
+	fi
+])
+
+AC_ARG_ENABLE(pie, AC_HELP_STRING([--enable-pie],
+			[enable position independent executables flag]), [
+	if (test "${enableval}" = "yes" &&
+				test "${ac_cv_prog_cc_pie}" = "yes"); then
+		CFLAGS="$CFLAGS -fPIE"
+		LDFLAGS="$LDFLAGS -pie"
+	fi
+])
+
+AC_ARG_ENABLE(threads,
+	AC_HELP_STRING([--enable-threads], [enable threading support]),
+			[enable_threads=${enableval}], [enable_threads="no"])
+
+AC_ARG_ENABLE(hh2serial-gps,
+	AC_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_WITH(openconnect, AC_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]),
+			[enable_openconnect=${enableval}], [enable_openconnect="no"])
+if (test "${enable_openconnect}" != "no"); then
+	if (test -z "${path_openconnect}"); then
+		AC_PATH_PROG(OPENCONNECT, [openconnect], [], $PATH:/sbin:/usr/sbin)
+		if (test -z "${OPENCONNECT}"); then
+			AC_MSG_ERROR(openconnect binary not found)
+		fi
+	else
+		OPENCONNECT="${path_openconnect}"
+		AC_SUBST(OPENCONNECT)
+	fi
+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],
+        [specify location of openvpn binary]), [path_openvpn=${withval}])
+
+AC_ARG_ENABLE(openvpn,
+	AC_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
+		AC_PATH_PROG(OPENVPN, [openvpn], [], $PATH:/sbin:/usr/sbin)
+		if (test -z "${OPENVPN}"); then
+			AC_MSG_ERROR(openvpn binary not found)
+		fi
+	else
+		OPENVPN="${path_openvpn}"
+		AC_SUBST(OPENVPN)
+	fi
+fi
+AM_CONDITIONAL(OPENVPN, test "${enable_openvpn}" != "no")
+AM_CONDITIONAL(OPENVPN_BUILTIN, test "${enable_openvpn}" = "builtin")
+
+AC_ARG_WITH(vpnc, AC_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]),
+		[enable_vpnc=${enableval}], [enable_vpnc="no"])
+if (test "${enable_vpnc}" != "no"); then
+	if (test -z "${path_vpnc}"); then
+		AC_PATH_PROG(VPNC, [vpnc], [], $PATH:/sbin:/usr/sbin)
+		if (test -z "${VPNC}"); then
+			AC_MSG_ERROR(vpnc binary not found)
+		fi
+	else
+		VPNC="${path_vpnc}"
+		AC_SUBST(VPNC)
+	fi
+fi
+AM_CONDITIONAL(VPNC, test "${enable_vpnc}" != "no")
+AM_CONDITIONAL(VPNC_BUILTIN, test "${enable_vpnc}" = "builtin")
+
+AC_ARG_ENABLE(l2tp,
+	AC_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
+		AC_PATH_PROG(PPPD, [pppd], [/usr/sbin/pppd], $PATH:/sbin:/usr/sbin)
+	else
+		PPPD="${path_pppd}"
+		AC_SUBST(PPPD)
+	fi
+	AC_CHECK_HEADERS(pppd/pppd.h, dummy=yes,
+			AC_MSG_ERROR(ppp header files are required))
+	if (test -z "${path_l2tp}"); then
+		AC_PATH_PROG(L2TP, [xl2tpd], [/usr/sbin/xl2tpd], $PATH:/sbin:/usr/sbin)
+	else
+		L2TP="${path_l2tp}"
+		AC_SUBST(L2TP)
+	fi
+fi
+AM_CONDITIONAL(L2TP, test "${enable_l2tp}" != "no")
+AM_CONDITIONAL(L2TP_BUILTIN, test "${enable_l2tp}" = "builtin")
+
+AC_ARG_ENABLE(pptp,
+	AC_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
+		AC_PATH_PROG(PPPD, [pppd], [/usr/sbin/pppd], $PATH:/sbin:/usr/sbin)
+	else
+		PPPD="${path_pppd}"
+		AC_SUBST(PPPD)
+	fi
+	AC_CHECK_HEADERS(pppd/pppd.h, dummy=yes,
+			AC_MSG_ERROR(ppp header files are required))
+	if (test -z "${path_pptp}"); then
+		AC_PATH_PROG(PPTP, [pptp], [/usr/sbin/pptp], $PATH:/sbin:/usr/sbin)
+	else
+		PPTP="${path_pptp}"
+		AC_SUBST(PPTP)
+	fi
+fi
+AM_CONDITIONAL(PPTP, test "${enable_pptp}" != "no")
+AM_CONDITIONAL(PPTP_BUILTIN, test "${enable_pptp}" = "builtin")
+
+AC_CHECK_HEADERS(resolv.h, dummy=yes,
+	AC_MSG_ERROR(resolver header files are required))
+AC_CHECK_LIB(resolv, ns_initparse, dummy=yes, [
+	AC_CHECK_LIB(resolv, __ns_initparse, dummy=yes,
+		AC_MSG_ERROR(resolver library support is required))
+])
+
+AC_CHECK_FUNC(signalfd, dummy=yes,
+			AC_MSG_ERROR(signalfd support is required))
+
+AC_CHECK_LIB(dl, dlopen, dummy=yes,
+			AC_MSG_ERROR(dynamic linking loader is required))
+
+AC_ARG_ENABLE(iospm, AC_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]),
+			[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]),
+			[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],
+			[Maximal size of a statistics round robin file]),
+			[stats_max_file_size=${withval}])
+
+if (test -z "${stats_max_file_size}"); then
+   # default size is 16 kByte
+   stats_max_file_size="16 * 8 * 128"
+fi
+
+AC_DEFINE_UNQUOTED([STATS_MAX_FILE_SIZE], (${stats_max_file_size}), [Maximal size of a statistics round robin file])
+
+PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.28, dummy=yes,
+				AC_MSG_ERROR(GLib >= 2.28 is required))
+AC_SUBST(GLIB_CFLAGS)
+AC_SUBST(GLIB_LIBS)
+
+if (test "${enable_threads}" = "yes"); then
+	AC_DEFINE(NEED_THREADS, 1, [Define if threading support is required])
+	PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
+				AC_MSG_ERROR(GThread >= 2.16 is required))
+	GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
+	GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
+fi
+
+PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.4, dummy=yes,
+				AC_MSG_ERROR(D-Bus >= 1.4 is required))
+AC_SUBST(DBUS_CFLAGS)
+AC_SUBST(DBUS_LIBS)
+
+AC_ARG_WITH(dbusconfdir, AC_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
+	DBUS_CONFDIR="${sysconfdir}/dbus-1/system.d"
+else
+	DBUS_CONFDIR="${path_dbusconf}/dbus-1/system.d"
+fi
+AC_SUBST(DBUS_CONFDIR)
+
+AC_ARG_WITH(dbusdatadir, AC_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
+	DBUS_DATADIR="${datadir}/dbus-1/system-services"
+else
+	DBUS_DATADIR="${path_dbusdata}/dbus-1/system-services"
+fi
+AC_SUBST(DBUS_DATADIR)
+
+AC_ARG_WITH([systemdunitdir], AC_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
+	SYSTEMD_UNITDIR="${path_systemdunit}"
+	AC_SUBST(SYSTEMD_UNITDIR)
+fi
+AM_CONDITIONAL(SYSTEMD, test -n "${path_systemdunit}")
+
+PKG_CHECK_MODULES(XTABLES, xtables, dummy=yes,
+				AC_MSG_ERROR(Xtables library is required))
+AC_SUBST(XTABLES_CFLAGS)
+AC_SUBST(XTABLES_LIBS)
+
+AC_ARG_ENABLE(test, AC_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],
+				[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],
+				[enable PolicyKit support]),
+			[enable_polkit=${enableval}], [enable_polkit="no"])
+if (test "${enable_polkit}" != "no"); then
+	POLKIT_DATADIR="`$PKG_CONFIG --variable=actiondir polkit`"
+	POLKIT_DATADIR=""
+	if (test -z "${POLKIT_DATADIR}"); then
+		POLKIT_DATADIR="${datadir}/polkit-1/actions"
+	fi
+	AC_SUBST(POLKIT_DATADIR)
+fi
+AM_CONDITIONAL(POLKIT, test "${enable_polkit}" != "no")
+
+AC_ARG_ENABLE(selinux, AC_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],
+				[disable loopback support]),
+					[enable_loopback=${enableval}])
+AM_CONDITIONAL(LOOPBACK, test "${enable_loopback}" != "no")
+
+AC_ARG_ENABLE(sleep, AC_HELP_STRING([--enable-sleep],
+			   [enable system sleep]),
+				   [enable_sleep=${enableval}])
+AM_CONDITIONAL(SLEEP, test "${enable_sleep}" != "no")
+
+AC_ARG_ENABLE(ethernet, AC_HELP_STRING([--disable-ethernet],
+				[disable Ethernet support]),
+					[enable_ethernet=${enableval}])
+AM_CONDITIONAL(ETHERNET, test "${enable_ethernet}" != "no")
+
+AC_ARG_ENABLE(wifi, AC_HELP_STRING([--disable-wifi],
+				[disable WiFi support]),
+					[enable_wifi=${enableval}])
+AM_CONDITIONAL(WIFI, test "${enable_wifi}" != "no")
+
+AC_ARG_ENABLE(bluetooth, AC_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],
+				[disable oFono support]),
+					[enable_ofono=${enableval}])
+AM_CONDITIONAL(OFONO, test "${enable_ofono}" != "no")
+
+AC_ARG_ENABLE(dundee, AC_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],
+				[disable PACrunner support]),
+					[enable_pacrunner=${enableval}])
+AM_CONDITIONAL(PACRUNNER, test "${enable_pacrunner}" != "no")
+
+AC_ARG_ENABLE(wispr, AC_HELP_STRING([--disable-wispr],
+				[disable WISPr support]),
+					[enable_wispr=${enableval}])
+AM_CONDITIONAL(WISPR, test "${enable_wispr}" != "no")
+
+AC_ARG_ENABLE(tools, AC_HELP_STRING([--disable-tools],
+				[disable testing tools]),
+					[enable_tools=${enableval}])
+AM_CONDITIONAL(TOOLS, test "${enable_tools}" != "no")
+
+AC_ARG_ENABLE(client, AC_HELP_STRING([--disable-client],
+				[disable command line client]),
+					[enable_client=${enableval}])
+AM_CONDITIONAL(CLIENT, test "${enable_client}" != "no")
+
+if (test "${enable_wispr}" != "no"); then
+	PKG_CHECK_MODULES(GNUTLS, gnutls, dummy=yes,
+				AC_MSG_ERROR(GnuTLS library is required))
+else
+	GNUTLS_CFLAGS=""
+	GNUTLS_LIBS=""
+fi
+AC_SUBST(GNUTLS_CFLAGS)
+AC_SUBST(GNUTLS_LIBS)
+
+if (test "${enable_loopback}" != "no"); then
+	AC_CHECK_HEADERS(sys/inotify.h, dummy=yes,
+			AC_MSG_ERROR(inotify header files are required))
+
+	AC_CHECK_LIB(c, inotify_init, dummy=yes,
+			AC_MSG_ERROR(inotify library support is required))
+fi
+
+if (test "${enable_wifi}" != "no"); then
+	AC_PATH_PROG(WPASUPPLICANT, [wpa_supplicant], [],
+						$PATH:/sbin:/usr/sbin)
+fi
+
+AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--disable-datafiles],
+			[don't install configuration and data files]),
+					[enable_datafiles=${enableval}])
+AM_CONDITIONAL(DATAFILES, test "${enable_datafiles}" != "no")
+
+if (test "${enable_client}" != "no"); then
+	AC_CHECK_HEADERS(readline/readline.h, dummy=yes,
+		AC_MSG_ERROR(readline header files are required))
+fi
+
+AM_CONDITIONAL(VPN, test "${enable_openconnect}" != "no" -o \
+			"${enable_openvpn}" != "no" -o \
+			"${enable_vpnc}" != "no" -o \
+			"${enable_l2tp}" != "no" -o \
+			"${enable_pptp}" != "no")
+
+AC_OUTPUT(Makefile include/version.h src/connman.service
+		vpn/connman-vpn.service	vpn/net.connman.vpn.service
+		scripts/connman	doc/version.xml connman.pc)
diff --git a/connman.pc.in b/connman.pc.in
new file mode 100644
index 0000000..2af3c2b
--- /dev/null
+++ b/connman.pc.in
@@ -0,0 +1,14 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+ 
+plugindir=${libdir}/connman/plugins
+scriptdir=${libdir}/connman/scripts
+
+Name: connman
+Description: Connection Manager
+Requires: glib-2.0 dbus-1
+Version: @VERSION@
+Libs: -module -avoid-version -export-symbols-regex connman_plugin_desc
+Cflags: -I${includedir}
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..ce3e433
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,38 @@
+
+DOC_MODULE = connman
+
+DOC_MAIN_SGML_FILE = $(DOC_MODULE)-docs.xml
+
+DOC_SOURCE_DIR = ../src
+
+SCAN_OPTIONS = --rebuild-sections --source-dir=../include
+
+MKDB_OPTIONS = --sgml-mode --output-format=xml --tmpl-dir=. \
+						--ignore-files=connman \
+						--source-dir=../include \
+						--source-suffixes=c,h
+
+MKTMPL_OPTIONS = --output-dir=.
+
+HFILE_GLOB = $(top_srcdir)/include/*.h
+CFILE_GLOB = $(top_srcdir)/src/*.c $(top_srcdir)/src/*.h
+
+IGNORE_HFILES = connman connman.h
+
+HTML_IMAGES =
+
+content_files = connman-introduction.xml
+
+INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/gdbus \
+	$(GTHREAD_CFLAGS) $(GMODULE_CFLAGS) $(GLIB_CFLAGS) $(DBUS_CFLAGS)
+
+GTKDOC_LIBS = $(DBUS_LIBS) $(GLIB_LIBS) $(GMODULE_LIBS) $(GTHREAD_LIBS)
+
+MAINTAINERCLEANFILES = Makefile.in \
+	$(DOC_MODULE).types $(DOC_MODULE)-*.txt *.sgml *.bak
+
+if ENABLE_GTK_DOC
+include $(top_srcdir)/doc/gtk-doc.make
+else
+EXTRA_DIST = $(DOC_MAIN_SGML_FILE) connman-introduction.xml
+endif
diff --git a/doc/advanced-configuration.txt b/doc/advanced-configuration.txt
new file mode 100644
index 0000000..3c08c8f
--- /dev/null
+++ b/doc/advanced-configuration.txt
@@ -0,0 +1,61 @@
+Advanced configuration interface
+********************************
+
+
+Configuration basics
+====================
+
+The default configuration method for all servers is automatic or something
+like DHCP. In almost every case that should be just good enough, but if it
+is not, Connection Manager supports manual configuration for Ethernet and
+IP settings.
+
+
+Configuration interface
+=======================
+
+Every service contains two properties. One represents the current active
+configuration and the other one allows manual configuration via the user.
+
+For IPv4 they are named "IPv4" and IPv4.Configuration".
+
+[ /profile/default/wifi_001122334455_42696720696e204a6170616e_managed_psk ]
+    Type = wifi
+    Name = Big in Japan
+    Mode = managed
+    Strength = 82
+    Security = rsn
+    Favorite = true
+    State = ready
+    IPv4.Configuration = { Method=dhcp }
+    IPv4 = { Netmask=255.255.255.0 Method=dhcp Address=192.168.1.198 }
+
+The above WiFi network shows how the default configuration would look like
+with a connected service. The configuration method is DHCP and the current
+IP address is 192.168.1.198.
+
+The "IPv4" property is read-only and will emit PropertyChanged signals in
+case the IP address of this interface changes. The "IPv4.Configuration"
+property is read-write and allows changes. For example to use a static IP
+configuration this call could be used:
+
+    service.SetProperty("IPv4.Configuration", { "Method": "manual",
+    						"Address": "192.168.1.100",
+    						"Netmask": "255.255.255.0" })
+
+The configuration itself is a dictionary with various fields. Not all of
+them need to present. A lot of combinations are valid.
+
+For example the "Method" field has valid settings of "off", "fixed", "manual"
+and "dhcp". The "fixed" value however can not be set by any user program. It
+is an internal value that some 3G cards require. Switching to "off" will
+remove and IP configuration from the interface. The "manual" method allows
+for static address configuration. And "dhcp" will use DHCP to retrieve all
+required information automatically.
+
+With a manual configuration, the fields "Address" and "Netmask" should be
+given. In case "Netmask" is left out, the best netmask will be calculated.
+
+The "Gateway" field can be used to indicate the default route/gateway for
+this interface.
+
diff --git a/doc/agent-api.txt b/doc/agent-api.txt
new file mode 100644
index 0000000..a98343f
--- /dev/null
+++ b/doc/agent-api.txt
@@ -0,0 +1,256 @@
+Agent hierarchy
+===============
+
+Service		unique name
+Interface	net.connman.Agent
+Object path	freely definable
+
+Methods		void Release()
+
+			This method gets called when the service daemon
+			unregisters the agent. An agent can use it to do
+			cleanup tasks. There is no need to unregister the
+			agent, because when this method gets called it has
+			already been unregistered.
+
+		void ReportError(object service, string error)
+
+			This method gets called when an error has to be
+			reported to the user.
+
+			A special return value can be used to trigger a
+			retry of the failed transaction.
+
+			Possible Errors: net.connman.Agent.Error.Retry
+
+		void RequestBrowser(object service, string url)
+
+			This method gets called when it is required
+			to ask the user to open a website to procceed
+			with login handling.
+
+			This can happen if connected to a hotspot portal
+			page without WISPr support.
+
+			Possible Errors: net.connman.Agent.Error.Canceled
+
+		dict RequestInput(object service, dict fields)
+
+			This method gets called when trying to connect to
+			a service and some extra input is required. For
+			example a passphrase or the name of a hidden network.
+
+			The return value should be a dictionary where the
+			keys are the field names and the values are the
+			actual fields. Alternatively an error indicating that
+			the request got canceled can be returned.
+
+			Most common return field names are "Name" and of
+			course "Passphrase".
+
+			The dictionary arguments contains field names with
+			their input parameters.
+
+			In case of WISPr credentials requests and if the user
+			prefers to login through the browser by himself, agent
+			will have to return a LaunchBrowser error (see below).
+
+			Possible Errors: net.connman.Agent.Error.Canceled
+					 net.connman.Agent.Error.LaunchBrowser
+
+		void Cancel()
+
+			This method gets called to indicate that the agent
+			request failed before a reply was returned.
+
+Fields		string Name
+
+			The name of a network. This field will be requested
+			when trying to connect to a hidden network.
+
+		array{byte} SSID
+
+			This field is an alternative to "Name" for WiFi
+			networks and can be used to return the exact binary
+			representation of a network name.
+
+			Normally returning the "Name" field is the better
+			option here.
+
+		string Identity
+
+			Identity (username) for EAP authentication methods.
+
+		string Passphrase
+
+			The passphrase for authentication. For example a WEP
+			key, a PSK passphrase or a passphrase for EAP
+			authentication methods.
+
+		string PreviousPassphrase
+
+			The previous passphrase successfully saved, i.e.
+			which lead to a successfull 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
+			a RequestInput is raised after a retry. In case of WPS
+			association through PIN method: when retrying, the
+			previous wpspin will be provided.
+
+		string WPS
+
+			This field requests the use of WPS to get associated.
+			This is an alternate choice against Passphrase when
+			requested service supports WPS. The reply can contain
+			either empty pin, if user wants to use push-button
+			method, or a pin code if user wants to use the pin
+			method.
+
+		string Username
+
+			Username for WISPr authentication. This field will be
+			requested when connecting to a WISPr-enabled hotspot.
+
+		string Password
+
+			Password for WISPr authentication. This field will be
+			requested when connecting to a WISPr-enabled hotspot.
+
+Arguments	string Type
+
+			Contains the type of a field. For example "psk", "wep"
+			"passphrase", "response", "ssid", "wpspin" or plain
+			"string".
+
+		string Requirement
+
+			Contains the requirement option. Valid values are
+			"mandatory", "optional", "alternate" or
+			"informational".
+
+			The "alternate" value specifies that this field can be
+			returned as an alternative to another one. An example
+			would be the network name or SSID.
+
+			All "mandatory" fields must be returned, while the
+			"optional" can be returned if available.
+
+			Nothing needs to be returned for "informational", as it
+			is here only to provide an information so a value is
+			attached to it.
+
+		array{string} Alternates
+
+			Contains the list of alternate field names this
+			field can be represented by.
+
+		string Value
+
+			Contains data as a string, relatively to an
+			"informational" argument.
+
+Examples	Requesting a passphrase for WPA2 network
+
+			RequestInput("/service1",
+				{ "Passphrase" : { "Type"        : "psk",
+						   "Requirement" : "mandatory"
+						 }
+				}
+			==> { "Passphrase" : "secret123" }
+
+		Requesting a passphrase after an error on the previous one:
+
+			RequestInput("/service1",
+				{ "Passphrase" : { "Type"        : "psk",
+						   "Requirement" : "mandatory"
+						 },
+				  "PreviousPassphrase" :
+					{ "Type"       : "psk",
+					  "Requirement : "informational",
+					  "Value"      : "secret123"
+					}
+				}
+
+		Requesting name for hidden network
+
+			RequestInput("/service2",
+				{ "Name" : { "Type"        : "string",
+					     "Requirement" : "mandatory",
+					     "Alternates"  : [ "SSID" ]
+					   },
+				  "SSID" : { "Type"        : "ssid",
+					     "Requirement" : "alternate"
+					   }
+				}
+			==> { "Name" : "My hidden network" }
+
+		Requesting a passphrase for a WPA2 network with WPS alternative:
+
+			RequestInput("/service3",
+				{ "Passphrase" : { "Type"        : "psk",
+						   "Requirement" : "mandatory",
+						   "Alternates"  : [ "WPS" ]
+						 },
+				  "WPS"        : { "Type"        : "wpspin",
+						   "Requirement" : "alternate"
+						 }
+				}
+
+			==> { "WPS" : "123456" }
+
+		Requesting a passphrase for a WPA2 network with WPS alternative
+		after an error on the previous one:
+
+			RequestInput("/service3",
+				{ "Passphrase" : { "Type"        : "psk",
+						   "Requirement" : "mandatory",
+						   "Alternates"  : [ "WPS" ]
+					         },
+				"WPS"          : { "Type"        : "wpspin",
+						   "Requirement" : "alternate"
+						 }
+				"PreviousPassphrase" :
+						{ "Type"       : "wpspin",
+					  	"Requirement : "informational",
+					  	"Value"      : "123456"
+						}
+
+		Requesting passphrase for a WPA-Enterprise network:
+
+			RequestInput("/service4",
+				{ "Identity"   : { "Type"        : "string",
+						   "Requirement" : "mandatory"
+						 },
+				  "Passphrase" : { "Type"        : "passphrase",
+						   "Requirement" : "mandatory"
+						 }
+				}
+
+			==> { "Identity" : "alice", "Passphrase": "secret123" }
+
+		Requesting challenge response for a WPA-Enterprise network:
+
+			RequestInput("/service4",
+				{ "Identity"   : { "Type"        : "string",
+						   "Requirement" : "mandatory"
+						 },
+				  "Passphrase" : { "Type"        : "response",
+						   "Requirement" : "mandatory"
+						 }
+				}
+
+			==> { "Identity" : "bob", "Passphrase": "secret123" }
+
+		Requesting username and password for a WISPr-enabled hotspot:
+
+			RequestInput("/service5",
+				{ "Username"   : { "Type"        : "string",
+						   "Requirement" : "mandatory"
+						 },
+				  "Password"   : { "Type"        : "passphrase",
+						   "Requirement" : "mandatory"
+						 }
+				}
+
+			==> { "Username" : "foo", "Password": "secret" }
diff --git a/doc/backtrace.txt b/doc/backtrace.txt
new file mode 100644
index 0000000..ac8472c
--- /dev/null
+++ b/doc/backtrace.txt
@@ -0,0 +1,28 @@
+ConnMan backtraces
+******************
+
+ConnMan dumps backtraces upon segmentation faults, bus errors and other
+crashing signals. Regardless of the debug level you started connmand with, the
+backtrace will be dumped to syslog.
+
+The ConnMan backtraces start with the following line:
+	-------- backtrace --------
+and will try to display function names if those can be resolved from the stack
+addresses. All static functions name will not appear for example.
+
+For a more complete and useful stack frame output you can use the
+test/backtrace script. It takes the actual binary that crashed and the
+connmand logs. The logs can contain any connman debug strings on top of the
+backtrace.
+
+Here is an example of the backtrace script usage:
+
+me@localhost:[~]$ backtrace /sbin/connmand connman.log
+-------- backtrace --------
+[0]: __connman_debug_list_available() [log.c:117]
+[1]: connman_driver_register() [element.c:515]
+[2]: __connman_driver_rescan() [element.c:490]
+[3]: disable_technology() [manager.c:391]
+[4]: generic_message() [object.c:262]
+-----------------------------------
+
diff --git a/doc/behavior-api.txt b/doc/behavior-api.txt
new file mode 100644
index 0000000..5feea76
--- /dev/null
+++ b/doc/behavior-api.txt
@@ -0,0 +1,11 @@
+Interface behavior description
+******************************
+
+
+Ethernet service
+================
+
+The Ethernet based service is a special case since it has no children, but
+still can be manually connected and disconnected while also has an implicit
+behavior when physically plugging in or removing an Ethernet cable.
+
diff --git a/doc/clock-api.txt b/doc/clock-api.txt
new file mode 100644
index 0000000..6818f5a
--- /dev/null
+++ b/doc/clock-api.txt
@@ -0,0 +1,87 @@
+Clock hierarchy
+===============
+
+Service		net.connman
+Interface	net.connman.Clock
+Object path	/
+
+Methods		dict GetProperties()  [experimental]
+
+			Returns all system clock properties. See the
+			properties section for available properties.
+
+			Possible Errors: [service].Error.InvalidArguments
+
+		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.
+
+			Possible Errors: [service].Error.InvalidArguments
+					 [service].Error.InvalidProperty
+
+Signals		PropertyChanged(string name, variant value)  [experimental]
+
+			This signal indicates a changed value of the given
+			property.
+
+
+Properties	uint64 Time [readonly or readwrite]  [experimental]
+
+			Current system time in seconds since epoch.
+
+			This value is present for changing the system time
+			if TimeUpdates is set to manual.
+
+			It is not present for driving an updated display
+			of the system time. PropertyChanged signal for this
+			value are only send out if it gets changed or jumps
+			unexpectedly.
+
+			In general application interested in the current
+			time should be using gettimeofday() and related
+			system calls.
+
+		string TimeUpdates [readwrite]  [experimental]
+
+			Possible values are "manual" and "auto" to indicate
+			time update policy.
+
+			With the "auto" setting the system tries to use as
+			many sources as possible to determine the correct
+			and updated time.
+
+		string Timezone [readonly or readwrite]  [experimental]
+
+			Current system timezone string. Allowed values
+			are from the standard timezone data (tzdata)
+			package under /usr/share/zoneinfo. For example
+			strings like "America/Vancouver" or "Europe/Berlin".
+
+			This value is present for changing the timezone
+			if TimezoneUpdates is set to manual.
+
+			When the timezone gets changed a PropertyChanged
+			signal will be send out.
+
+		string TimezoneUpdates [readwrite]  [experimental]
+
+			Possible values are "manual" and "auto" to indicate
+			timezone update policy.
+
+			With the "auto" setting the system tries to use as
+			many sources as possible to determine the correct
+			timezone.
+
+		array{string} Timeservers [readwrite]  [experimental]
+
+			List of global default NTP servers. The list should
+			be sorted in order of preference.
+
+			If a service configuration provides NTP servers,
+			then they are preferred over the global ones.
+
+			This list of servers is used when TimeUpdates is set
+			to auto.
diff --git a/doc/coding-style.txt b/doc/coding-style.txt
new file mode 100644
index 0000000..30690b7
--- /dev/null
+++ b/doc/coding-style.txt
@@ -0,0 +1,344 @@
+Every project has its coding style, and ConnMan is not an exception. This
+document describes the preferred coding style for ConnMan code, in order to keep
+some level of consistency among developers so that code can be easily
+understood and maintained, and also to help your code survive under
+maintainer's fastidious eyes so that you can get a passport for your patch
+ASAP.
+
+First of all, ConnMan coding style must follow every rule for Linux kernel
+(http://www.kernel.org/doc/Documentation/CodingStyle). There also exists a tool
+named checkpatch.pl to help you check the compliance with it. Just type
+"checkpatch.pl --no-tree patch_name" to check your patch. In theory, you need
+to clean up all the warnings and errors except this one: "ERROR: Missing
+Signed-off-by: line(s)". ConnMan does not used Signed-Off lines, so including
+them is actually an error.  In certain circumstances one can ignore the 80
+character per line limit.  This is generally only allowed if the alternative
+would make the code even less readable.
+
+Besides the kernel coding style above, ConnMan has special flavors for its own.
+Some of them are mandatory (marked as 'M'), while some others are optional
+(marked as 'O'), but generally preferred.
+
+M1: Blank line before and after an if/while/do/for statement
+============================================================
+There should be a blank line before if statement unless the if is nested and
+not preceded by an expression or variable declaration.
+
+Example:
+1)
+a = 1;
+if (b) {  // wrong
+
+2)
+a = 1
+
+if (b) {
+}
+a = 2;	// wrong
+
+3)
+if (a) {
+	if (b)  // correct
+
+4)
+b = 2;
+
+if (a) {	// correct
+
+}
+
+b = 3;
+
+The only exception to this rule applies when a variable is being allocated:
+array = g_try_new0(int, 20);
+if (array == NULL)	// Correct
+	return;
+
+
+M2: Multiple line comment
+=========================
+If your comments have more then one line, please start it from the second line.
+
+Example:
+/*
+ * first line comment	// correct
+ * ...
+ * last line comment
+ */
+
+
+M3: Space before and after operator
+===================================
+There should be a space before and after each operator.
+
+Example:
+a + b;  // correct
+
+
+M4: Wrap long lines
+===================
+If your condition in if, while, for statement or a function declaration is too
+long to fit in one line, the new line needs to be indented not aligned with the
+body.
+
+Example:
+1)
+if (call->status == CALL_STATUS_ACTIVE ||
+	call->status == CALL_STATUS_HELD) {  // wrong
+	connman_dbus_dict_append();
+
+2)
+if (call->status == CALL_STATUS_ACTIVE ||
+		call->status == CALL_STATUS_HELD) {  // correct
+	connman_dbus_dict_append();
+
+3)
+gboolean sim_ust_is_available(unsigned char *service_ust, unsigned char len,
+	num sim_ust_service index) // wrong
+{
+	int a;
+	...
+}
+
+4)
+gboolean sim_ust_is_available(unsigned char *service_ust, unsigned char len,
+					enum sim_ust_service index) // correct
+{
+	int a;
+	...
+}
+
+If the line being wrapped is a function call or function declaration, the
+preferred style is to indent at least past the opening parenthesis. Indenting
+further is acceptable as well (as long as you don't hit the 80 character
+limit).
+
+If this is not possible due to hitting the 80 character limit, then indenting
+as far as possible to the right without hitting the limit is preferred.
+
+Example:
+
+1)
+gboolean sim_ust_is_available(unsigned char *service_ust, unsigned char len,
+		enum sim_ust_service index); // worse
+
+2)
+gboolean sim_ust_is_available(unsigned char *service_ust, unsigned char len,
+						enum sim_ust_service index);
+						// better
+
+M5: Git commit message 50/72 formatting
+=======================================
+The commit message header should be within 50 characters. And if you have
+detailed explanatory text, wrap it to 72 character.
+
+
+M6: Space when doing type casting
+=================================
+There should be a space between new type and variable.
+
+Example:
+1)
+a = (int *)b;  // wrong
+2)
+a = (int *) b;  // correct
+
+
+M7: Don't initialize variable unnecessarily
+===========================================
+When declaring a variable, try not to initialize it unless necessary.
+
+Example:
+int i = 1;  // wrong
+
+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.
+
+Example:
+additional = g_try_malloc(len - 1);  // correct
+if (additional == NULL)
+	return FALSE;
+
+
+M9: Follow the order of include header elements
+===============================================
+When writing an include header the various elements should be in the following
+order:
+	- #includes
+	- forward declarations
+	- #defines
+	- enums
+	- typedefs
+	- function declarations and inline function definitions
+
+
+M10: Internal headers must not use include guards
+=================================================
+Any time when creating a new header file with non-public API, that header
+must not contain include guards.
+
+
+M11: Naming of enums
+====================
+
+Enums must have a descriptive name.  The enum type should be small caps and
+it should not be typedef-ed.  Enum contents should be in CAPITAL letters and
+prefixed by the enum type name.
+
+Example:
+
+enum animal_type {
+	ANIMAL_TYPE_FOUR_LEGS,
+	ANIMAL_TYPE_EIGHT_LEGS,
+	ANIMAL_TYPE_TWO_LEGS,
+};
+
+If the enum contents have values (e.g. from specification) the formatting
+should be as follows:
+
+enum animal_type {
+	ANIMAL_TYPE_FOUR_LEGS =		4,
+	ANIMAL_TYPE_EIGHT_LEGS =	8,
+	ANIMAL_TYPE_TWO_LEGS =		2,
+};
+
+M12: Enum as switch variable
+====================
+
+If the variable of a switch is an enum, you must not include a default in
+switch body. The reason for this is: If later on you modify the enum by adding
+a new type, and forget to change the switch accordingly, the compiler will
+complain the new added type hasn't been handled.
+
+Example:
+
+enum animal_type {
+	ANIMAL_TYPE_FOUR_LEGS =		4,
+	ANIMAL_TYPE_EIGHT_LEGS =	8,
+	ANIMAL_TYPE_TWO_LEGS =		2,
+};
+
+enum animal_type t;
+
+switch (t) {
+case ANIMAL_TYPE_FOUR_LEGS:
+	...
+	break;
+case ANIMAL_TYPE_EIGHT_LEGS:
+	...
+	break;
+case ANIMAL_TYPE_TWO_LEGS:
+	...
+	break;
+default:  // wrong
+	break;
+}
+
+However if the enum comes from an external header file outside ConnMan
+we cannot make any assumption of how the enum is defined and this
+rule might not apply.
+
+M13: Check for pointer being NULL
+=================================
+
+When checking if a pointer or a return value is NULL, explicitly compare to
+NULL rather than use the shorter check with "!" operator.
+
+Example:
+1)
+array = g_try_new0(int, 20);
+if (!array)	// Wrong
+	return;
+
+2)
+if (!g_at_chat_get_slave(chat))	// Wrong
+	return -EINVAL;
+
+3)
+array = g_try_new0(int, 20);
+if (array == NULL)	// Correct
+	return;
+
+
+M14: Always use parenthesis with sizeof
+=======================================
+The expression argument to the sizeof operator should always be in
+parenthesis, too.
+
+Example:
+1)
+memset(stuff, 0, sizeof(*stuff));
+
+2)
+memset(stuff, 0, sizeof *stuff); // Wrong
+
+
+M15: Use void if function has no parameters
+===========================================================
+A function with no parameters must use void in the parameter list.
+
+Example:
+1)
+void foo(void)
+{
+}
+
+2)
+void foo()	// Wrong
+{
+}
+
+M16: Don't use hex value with shift operators
+==============================================
+The expression argument to the shift operators should not be in hex.
+
+Example:
+
+1)
+1 << y
+
+2)
+0x1 << y	// Wrong
+
+O1: Shorten the name
+====================
+Better to use abbreviation, rather than full name, to name a variable,
+function, struct, etc.
+
+Example:
+supplementary_service  // too long
+ss  // better
+
+O2: Try to avoid complex if body
+================================
+It's better not to have a complicated statement for if. You may judge its
+contrary condition and return | break | continue | goto ASAP.
+
+Example:
+1)
+if (a) {  // worse
+	struct voicecall *v;
+	call = synthesize_outgoing_call(vc, vc->pending);
+	v = voicecall_create(vc, call);
+	v->detect_time = time(NULL);
+	DBG("Registering new call: %d", call->id);
+	voicecall_dbus_register(v);
+} else
+	return;
+
+2)
+if (!a)
+	return;
+
+struct voicecall *v;
+call = synthesize_outgoing_call(vc, vc->pending);
+v = voicecall_create(vc, call);
+v->detect_time = time(NULL);
+DBG("Registering new call: %d", call->id);
+voicecall_dbus_register(v);
diff --git a/doc/config-format.txt b/doc/config-format.txt
new file mode 100644
index 0000000..d8146be
--- /dev/null
+++ b/doc/config-format.txt
@@ -0,0 +1,101 @@
+Connman configuration file format
+*********************************
+
+Connman uses configuration files to provision existing services. Connman will
+be looking for its configuration files at STORAGEDIR which by default points
+to /var/lib/connman/. Configuration file names must not include other
+characters than letters or numbers and must have a .config suffix.
+Those configuration files are text files with a simple format and we typically
+have one file per provisioned network.
+
+If the config file is removed, then Connman tries to remove the
+provisioned service. If individual service entry inside config is removed,
+then the corresponding provisioned service is removed. If service
+entry is changed, then corresponding service is removed and then
+immediately re-provisioned.
+
+
+Global entry [global]
+=====================
+
+These files can have an optional global entry describing the actual file.
+The 2 allowed fields for that entry are:
+- Name: Name of the network.
+- Description: Description of the network.
+- Protected: Configuration protection against being removed, modified or
+overwritten by a Manager.ProvisionService() call. If unset, this value defaults
+to TRUE, i.e. configs are protected by default.
+
+
+Service entry [service_*]
+=========================
+
+Each provisioned service must start with the [service_*] tag. Replace * with
+an identifier unique to the config file.
+
+Allowed fields:
+- Type: Service type. We currently only support wifi.
+- Name: A string representation of an 802.11 SSID. If the SSID field is
+  present, the Name field is ignored.
+- SSID: A hexadecimal representation of an 802.11 SSID. If the SSID field is
+  omitted, the Name field is used instead.
+- EAP: EAP type. We currently only support tls, ttls or peap.
+- CACertFile: File path to CA certificate file (PEM/DER).
+- ClientCertFile: File path to client certificate file (PEM/DER).
+- PrivateKeyFile: File path to client private key file (PEM/DER/PFX).
+- PrivateKeyPassphrase: Password/passphrase for private key file.
+- PrivateKeyPassphraseType: We only support the fsid passphrase type for now.
+  This is for private keys generated by using their own filesystem UUID as the
+  passphrase. The PrivateKeyPassphrase field is ignored when this field is set
+  to fsid.
+- Identity: Identity string for EAP.
+- Phase2: Phase2 (inner authentication with TLS tunnel) authentication method.
+  Prefix the value with "EAP-" to indicate the usage of an EAP-based inner
+  authentication method (should only be used with EAP = TTLS).
+- Passphrase: RSN/WPA/WPA2 Passphrase
+- Hidden: If set to true, then this AP is hidden. If missing or set to false,
+  then AP is not hidden.
+
+
+Example
+=======
+
+This is a configuration file for a network providing EAP-TLS, EAP-TTLS and
+EAP-PEAP services.
+The respective SSIDs are tls_ssid, ttls_ssid and peap_ssid and the file name
+is example.config.
+Please note that the SSID entry is for hexadecimal encoded SSID (e.g. "SSID =
+746c735f73736964"). If your SSID does not contain any exotic character then
+you should use the Name entry instead (e.g. "Name = tls_ssid").
+
+
+example@example:[~]$ cat /var/lib/connman/example.config
+[global]
+Name = Example
+Description = Example network configuration
+
+[service_tls]
+Type = wifi
+SSID = 746c735f73736964
+EAP = tls
+CACertFile = /home/user/.certs/ca.pem
+ClientCertFile = /home/user/devlp/.certs/client.pem
+PrivateKeyFile = /home/user/.certs/client.fsid.pem
+PrivateKeyPassphraseType = fsid
+Identity = user
+
+[service_ttls]
+Type = wifi
+Name = ttls_ssid
+EAP = ttls
+CACertFile = /home/user/.cert/ca.pem
+Phase2 = MSCHAPV2
+Identity = user
+
+[service_peap]
+Type = wifi
+Name = peap_ssid
+EAP = peap
+CACertFile = /home/user/.cert/ca.pem
+Phase2 = MSCHAPV2
+Identity = user
diff --git a/doc/connman-docs.xml b/doc/connman-docs.xml
new file mode 100644
index 0000000..d4059a4
--- /dev/null
+++ b/doc/connman-docs.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+               "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+<!ENTITY version SYSTEM "version.xml">
+]>
+<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
+  <bookinfo>
+    <title>Connection Manager Reference Manual</title>
+    <releaseinfo>Version &version;</releaseinfo>
+    <authorgroup>
+      <author>
+	<firstname>Marcel</firstname>
+	<surname>Holtmann</surname>
+	<affiliation>
+	  <address>
+	    <email>marcel@holtmann.org</email>
+	  </address>
+	</affiliation>
+      </author>
+    </authorgroup>
+
+    <copyright>
+      <year>2007-2008</year>
+      <holder>Intel Corporation. All rights reserved.</holder>
+    </copyright>
+
+    <legalnotice>
+      <para>
+	Permission is granted to copy, distribute and/or modify this
+	document under the terms of the <citetitle>GNU Free
+	Documentation License</citetitle>, Version 1.1 or any later
+	version published by the Free Software Foundation with no
+	Invariant Sections, no Front-Cover Texts, and no Back-Cover
+	Texts. You may obtain a copy of the <citetitle>GNU Free
+	Documentation License</citetitle> from the Free Software
+	Foundation by visiting <ulink type="http"
+	url="http://www.fsf.org">their Web site</ulink> or by writing
+	to:
+
+	<address>
+	  The Free Software Foundation, Inc.,
+	  <street>59 Temple Place</street> - Suite 330,
+	  <city>Boston</city>, <state>MA</state> <postcode>02111-1307</postcode>,
+	  <country>USA</country>
+	</address>
+      </para>
+    </legalnotice>
+  </bookinfo>
+
+  <reference id="design">
+    <title>Design Overview</title>
+    <partintro>
+      <para>
+	This part presents the design documentation for Connection Manager.
+      </para>
+    </partintro>
+    <xi:include href="connman-introduction.xml" />
+  </reference>
+
+  <reference id="manager">
+    <title>Manager interface</title>
+    <para>
+<programlisting><xi:include href="manager-api.txt" parse="text" /></programlisting>
+    </para>
+  </reference>
+
+  <reference id="device">
+    <title>Device interface</title>
+    <para>
+<programlisting><xi:include href="device-api.txt" parse="text" /></programlisting>
+    </para>
+  </reference>
+
+  <reference id="network">
+    <title>Network interface</title>
+    <para>
+<programlisting><xi:include href="network-api.txt" parse="text" /></programlisting>
+    </para>
+  </reference>
+
+  <reference id="service">
+    <title>Service interface</title>
+    <para>
+<programlisting><xi:include href="service-api.txt" parse="text" /></programlisting>
+    </para>
+  </reference>
+
+  <reference id="connection">
+    <title>Connection interface</title>
+    <para>
+<programlisting><xi:include href="connection-api.txt" parse="text" /></programlisting>
+    </para>
+  </reference>
+
+  <reference id="reference">
+    <title>Plugin API Reference</title>
+    <partintro>
+      <para>
+	This part presents the function reference for Connection Manager.
+      </para>
+    </partintro>
+    <xi:include href="xml/log.xml" />
+    <xi:include href="xml/plugin.xml" />
+    <xi:include href="xml/storage.xml" />
+    <xi:include href="xml/security.xml" />
+    <xi:include href="xml/resolver.xml" />
+    <!-- <xi:include href="xml/device.xml" /> -->
+    <!-- <xi:include href="xml/network.xml" /> -->
+  </reference>
+
+  <appendix id="license">
+    <title>License</title>
+    <para>
+<programlisting><xi:include href="../COPYING" parse="text" /></programlisting>
+    </para>
+  </appendix>
+
+  <index>
+    <title>Index</title>
+  </index>
+</book>
diff --git a/doc/connman-introduction.xml b/doc/connman-introduction.xml
new file mode 100644
index 0000000..4672c2c
--- /dev/null
+++ b/doc/connman-introduction.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+               "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">
+
+<chapter id="introduction">
+  <title>Introduction</title>
+  
+  <sect1 id="intro-about">
+    <title>About</title>
+    
+    <para>
+    </para>
+  </sect1>
+
+</chapter>
diff --git a/doc/connman.8 b/doc/connman.8
new file mode 100644
index 0000000..7297cf8
--- /dev/null
+++ b/doc/connman.8
@@ -0,0 +1,79 @@
+.\" connman(8) manual page
+.\"
+.\" Copyright (C) 2012 Intel Corporation
+.\"
+.TH CONNMAN "8" "21 August 2012"
+.SH NAME
+ConnMan \- network management daemon
+.SH SYNOPSIS
+.B connmand [\-\-version] | [\-\-help]
+.PP
+.B connmand [\-\-config=<filename>] [\-\-debug=<file1>:<file2>:...] [\-\-device=<interface1>,<interface2>,...] [\-\-nodevice=<interface1>,<interface2>,..] [\-\-wifi=<driver1>,<driver2>,...] [\-\-plugin=<plugin1>,<plugin2>,...] [\-\-noplugin=<plugin1>,<plugin2>,...] [\-\-nodaemon] [\-\-nodnsproxy]
+.SH DESCRIPTION
+The \fIConnMan\fP provides a daemon for managing internet connections
+within devices running the Linux operating system. The Connection Manager is
+designed to be slim and to use as few resources as possible.
+It is a fully modular system that can be extended, through plug-ins,
+to support all kinds of wired or wireless technologies.
+Also, configuration methods, like DHCP and domain name resolving,
+are implemented using plug-ins.
+The plug-in approach allows for easy adaption and modification for various
+use cases.
+.P
+.SH OPTIONS
+The following options are supported:
+.TP
+.I "\-\-version"
+Print the ConnMan software version and exit.
+.TP
+.I "\-\-help"
+Print ConnMan's available options and exit.
+.TP
+.I "\-\-config=<filename>"
+Specify configuration file to set up various settings for ConnMan.  If not
+specified, the default value of '<SYSCONFDIR>/connman/main.conf'
+is used; where <SYSCONFDIR> is dependent on your distribution (usually
+it's /etc).  See \fBconnman.conf\fP(5) for more information on configuration
+file. The use of config file is optional and sane default values
+are used if config file is missing.
+.TP
+.I "\-\-debug=<file1>:<file2>:..."
+Sets how much information ConnMan sends to the log destination (usually
+syslog's "daemon" facility).  If the file options are omitted, then debugging
+information from all the source files are printed. If file options are
+present, then only debug prints from that source file are printed.
+Example: --debug=src/service.c:plugins/wifi.c
+.TP
+.I "\-\-device=<interface1>,<interface2>,..."
+Only manage these network interfaces. By default all network interfaces
+are managed.
+.TP
+.I "\-\-nodevice=<interface1>,<interface2>,..."
+Never manage these network interfaces.
+.TP
+.I "\-\-plugin=<plugin1>,<plugin2>,..."
+Load these plugins only. The option can be a pattern containing
+"*" and "?" characters.
+.TP
+.I "\-\-noplugin=<plugin1>,<plugin2>,..."
+Never load these plugins. The option can be a pattern containing
+"*" and "?" characters.
+.TP
+.I "\-\-wifi=<driver1>,<driver2>,..."
+Wifi driver that WiFi/Supplicant should use. If omitted, then the value
+of "nl80211,wext" is used by default.
+.TP
+.I "\-\-nodaemon"
+Do not daemonize. This is useful for debugging, and directs log output to
+the controlling terminal in addition to syslog.
+.TP
+.I "\-\-nodnsproxy"
+Do not act as a DNS proxy. By default ConnMan will direct all DNS traffic
+to itself by setting nameserver to 127.0.0.1 in \fBresolv.conf\fP(5) file.
+If this is not desired and you want that all programs call directly some
+DNS server, then you can use the --nodnsproxy option.
+If this option is used, then ConnMan is not able to cache the DNS queries
+because the DNS traffic is not going through ConnMan and that can cause
+some extra network traffic.
+.SH SEE ALSO
+.BR connman.conf (5).
diff --git a/doc/connman.conf.5 b/doc/connman.conf.5
new file mode 100644
index 0000000..5500a17
--- /dev/null
+++ b/doc/connman.conf.5
@@ -0,0 +1,100 @@
+.\" connman.conf(5) manual page
+.\"
+.\" Copyright (C) 2012 Intel Corporation
+.\"
+.TH "connman.conf" "5" "21 August 2012" ""
+.SH NAME
+main.conf \- ConnMan configuration file
+.SH SYNOPSIS
+/etc/connman/main.conf
+.br
+or
+.br
+\fI<SYSCONFDIR>\fP/connman/main.conf
+.br
+where <SYSCONFDIR> depends on your distribution or build.
+.SH DESCRIPTION
+.P
+.I main.conf
+is a configuration file for ConnMan. The configuration file is
+optional but it can be used to set up various aspects of ConnMan's
+behavior. The location of the file may be changed through use of
+the "\-\-config=" argument for \fBconnman\fP (8).
+.SH "FILE FORMAT"
+.P
+The configuration file format is key file format.
+It consists of sections (groups) of key-value pairs.
+Lines beginning with a '#' and blank lines are considered comments.
+Sections are started by a header line containing the section enclosed
+in '[' and ']', and ended implicitly by the start of the next section
+or the end of the file. Each key-value pair must be contained in a section.
+.P
+Description of sections and available keys follows:
+.SS [General]
+This section is the only mandatory section of the configuration file.
+.TP
+.B InputRequestTimeout=\fPsecs\fP
+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.
+.TP
+.B BrowserLaunchTimeout=\fPsecs\fP
+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.
+.TP
+.B BackgroundScanning=\fPtrue|false\fP
+Enable background scanning. Default is true.
+Background scanning will start every 5 minutes unless
+the scan list is empty. In that case, a simple backoff
+mechanism starting from 10s up to 5 minutes will run.
+.TP
+.B FallbackTimeservers=\fPserver1,server2,...\fP
+List of Fallback timeservers separated by ",".
+These timeservers are used for NTP sync when there are
+no timeserver set by the user or by the service.
+These can contain mixed combination of fully qualified
+domain names, IPv4 and IPv6 addresses.
+.TP
+.B FallbackNameservers=\fPserver1,server2,...\fP
+List of fallback nameservers separated by "," appended
+to the list of nameservers given by the service. The
+nameserver entries must be in numeric format, host
+names are ignored.
+.TP
+.B DefaultAutoConnectTechnologies=\fPtechnology1,technology2,...\fP
+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.
+.TP
+.B PreferredTechnologies=\fPtechnology1,technology2,...\fP
+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
+with state 'online' or they are all tried. A service of a
+preferred technology type in state 'ready' will get the
+default route when compared to 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 in state 'ready'.
+.TP
+.B NetworkInterfaceBlacklist=\fPinterface1,interface2,...\fP
+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.
+.TP
+.B AllowHostnameUpdates=\fPtrue|false\fP
+Allow connman to change the system hostname. This can
+happen for example if we receive DHCP hostname option.
+Default value is true.
+.SH "SEE ALSO"
+.BR Connman (8)
diff --git a/doc/connmanctl.1 b/doc/connmanctl.1
new file mode 100644
index 0000000..b71c6e6
--- /dev/null
+++ b/doc/connmanctl.1
@@ -0,0 +1,190 @@
+.TH connmanctl 1 07/31/2012 "" "User Commands for Connman CLI"
+.SH
+NAME
+connmanctl \- Connman CLI
+.SH
+SYNOPSIS
+.BR connmanctl " ["
+.BR enable " <technology> | "
+.BR offlinemode "] ["
+.BR disable " <technology> | "
+.BR offlinemode "] ["
+.BR technologies "] ["
+.BR state "] ["
+.BR services " [\-\-properties <service>]] ["
+.BR scan " <technology>] ["
+.BR connect " <service>] ["
+.BR config " <service> \-\-<option> ARGS...] ["
+.BR help " | \-\-help]"
+.PP
+.SH
+DESCRIPTION
+Connmanctl is a Connman command line interface which can be run in two modes:
+a plain synchronous command input, and an asynchronous interactive shell.
+To run a specific command the user may enter connmanctl <command> [options]
+[args], or enter connmanctl; in this case, the program will drop into the
+interactive shell.
+.PP
+Connmantl can handle most simple network connections. It is able to enable/
+disable any technology that exists on the system, display a list of
+services available, connect to/disconnect from any unsecured networks,
+show properties of the system, the technologies, and any individual
+service, and configure all of the properties. It is also able to monitor
+changes in the properties of the services, technologies, and the system.
+.PP
+In the interactive shell, all of the same commands can be used. It
+provides quicker usage when needing to use connmanctl more extensively.
+.SH
+COMMANDS AND OPTIONS
+.TP
+.BR "help | \-\-help | " "(no arguments)"
+Shows the abbreviated help menu in the terminal.
+.PP
+.TP
+.BR enable " <technology>"
+Enables the given technology type (e.g. ethernet, wifi, 3g, etc.)
+Turns power on to the technology, but doesn't connect unless
+there is a service with autoconnect set to True.
+.PP
+.TP
+.BR disable " <technology>"
+Disables the given technology type. Turns power off to the
+technology and disconnects if it is already connected.
+.PP
+.TP
+.B enable offlinemode
+Enables offline mode. Disconnects and powers down all
+technologies system-wide, however each technology can be powered
+back on individually.
+.PP
+.TP
+.B disable offlinemode
+Disables offline mode. Technologies are powered back on according
+to their individual policies.
+.PP
+.TP
+.B technologies
+Shows a list of all technology types existing on the system and
+their properties. See the properties section of the Technology
+API for explanations of each property.
+.PP
+.TP
+.B state
+Shows the system properties. Includes ths online state of the
+system, offline mode, and session mode.
+.PP
+.TP
+.BR scan " <technology>"
+Scans for new services on the given technology.
+.PP
+.TP
+.B services
+Shows a list of all available service names. This includes the
+names of wifi networks, the wired ethernet connection, names of
+bluetooth devices, etc. These are the names used when a
+<service> command is called for. The service name
+(e.g. Joes-wifi), the service path (e.g.
+wifi_6834534139723_managed_none), or the full service path (e.g.
+/net/connman/Service/wifi_5467631...) are all accepted as valid
+input. An asterisk in front of the service indicates that the
+service is favorited, and a "C" indicates a service that is
+already connected.
+.PP
+.TP
+.BR "services \-\-properties" " <service>"
+Shows a list of all properties for that service. See the
+properties section of the Service API for explanations of each
+property.
+.PP
+.TP
+.BR connect " <service>"
+Connects to the given service if it is unsecured.
+.PP
+.TP
+.BR disconnect " <service>"
+Disconnects from the given service.
+.PP
+.TP
+.BR config " <service> " \-\-<option>
+Configures a writable property of the given service to the
+value(s) entered after --<option>.
+.PP
+.TP
+.BR monitor " [\-\-<option>]"
+Listens for and displays DBus signals sent by Connman. The option indicates
+which signals you want to subscribe to. If no option is entered, it displays
+all signals from all interfaces.
+.PP
+.SS
+Config Options:
+.PP
+.TP
+.B \-\-autoconnect=y/n
+Sets the autoconnect property of the service.
+.PP
+.TP
+.B \-\-ipv4
+Configures the IPv4 settings for the service. Enter the settings
+in the order "Method", "Address", "Netmask", then "Gateway"
+after the argument. See the properties section of the Service
+API for more information on these settings and the values
+accepted for them. It also displays a list of changes to both the
+IPv4 settings, and incidental changes to other values related to
+it.
+.PP
+.TP
+.B \-\-ipv6
+Configures the IPv6 settings for the service. Enter the settings
+in the order "Method", "Address", "PrefixLength", "Gateway", then
+"Privacy". See the properties section of the Service API for more
+information on these settings and the values accepted for them.
+It also displays a list of entered changes to the IPv6 settings,
+and incidental changes to other values related to it.
+.PP
+.TP
+.B \-\-nameservers
+Adds to the list of manually configured domain name servers.
+Enter the name servers after the argument separated by spaces.
+.PP
+.TP
+.B \-\-timeservers
+Adds to the list of manually configured time servers. Enter the
+time servers after the argument separated by spaces.
+.PP
+.TP
+.B \-\-domains
+Adds to the list of manually configured search domains. Enter
+the domains after the argument, separated by spaces.
+.PP
+.TP
+.B \-\-proxy
+Configures the IPv6 settings for the service. Enter the settings in the
+order "Method", "URL". If the Method is set to "direct", no other arguments
+are taken. If the Method is set to "auto", the URL is optional. To set the
+Servers and Excludes manually, enter "manual" followed by "servers" with a
+list of servers separated by spaces. Then, optionally, the word "excludes"
+followed by a list of excludes separated by spaces. e.g. "./connmanctl config
+joes-wifi \-\-proxy manual servers serv1 serv2 serv3 excludes excl1 excl2"
+.PP
+.SS
+Monitor Options:
+.PP
+.TP
+.B \-\-services
+Listens for and displays the PropertyChanged signal from the Service interface.
+Also displays the service name (e.g. Joes-wifi) that the property is part of.
+More information, including a list of possible properties can be found in the
+Service API.
+.PP
+.TP
+.B \-\-tech
+Listens for and displays the PropertyChanged signal from the Technology
+interface. More information, including a list of possible properties can be
+found in the Technology API.
+.PP
+.TP
+.B \-\-manager
+Listens for and displays the PropertyChanged, ServicesChanged, TechnologyAdded,
+and TechnologyRemoved signals from the Manager interface. More information on
+these signals and a list of possible properties can be found in the Manager API.
+.PP
diff --git a/doc/counter-api.txt b/doc/counter-api.txt
new file mode 100644
index 0000000..32411d5
--- /dev/null
+++ b/doc/counter-api.txt
@@ -0,0 +1,70 @@
+Counter hierarchy
+=================
+
+Service		unique name
+Interface	net.connman.Counter
+Object path	freely definable
+
+Methods		void Release()
+
+			This method gets called when the service daemon
+			unregisters the counter. A counter can use it to do
+			cleanup tasks. There is no need to unregister the
+			counter, because when this method gets called it has
+			already been unregistered.
+
+		void Usage(object service, dict home, dict roaming)
+
+			This signal indicates a change in the counter values
+			for the service object. The counter is reset by calling
+			the service ResetCounters method.
+
+			When registering a new counter this method will be
+			called once with all details for "home" and "roaming"
+			counters filled in. Every further method call will
+			only include the changed values.
+
+			When "home" counter is active, then "roaming" counter
+			will contain an empty dictionary and vise-versa.
+
+			The dictionary argument contains the following entries:
+
+				RX.Packets
+
+					Total number of packets received.
+
+				TX.Bytes
+
+					Total number of packets sent.
+
+				RX.Bytes
+
+					Total number of bytes received.
+
+				TX.Bytes
+
+					Total number of bytes sent.
+
+				RX.Errors
+
+					Total number of erronous packets
+					received.
+
+				TX.Errors
+
+					Total number of erronous packets
+					sent.
+
+				RX.Dropped
+
+					Total number of dropped packets
+					while receiving.
+
+				TX.Dropped
+
+					Total number of dropped packets
+					while sending.
+
+				Time
+
+					Total number of seconds online.
diff --git a/doc/gtk-doc.make b/doc/gtk-doc.make
new file mode 100644
index 0000000..354ffb7
--- /dev/null
+++ b/doc/gtk-doc.make
@@ -0,0 +1,173 @@
+# -*- mode: makefile -*-
+
+####################################
+# Everything below here is generic #
+####################################
+
+if GTK_DOC_USE_LIBTOOL
+GTKDOC_CC = $(LIBTOOL) --mode=compile $(CC) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+GTKDOC_LD = $(LIBTOOL) --mode=link $(CC) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS)
+else
+GTKDOC_CC = $(CC) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+GTKDOC_LD = $(CC) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS)
+endif
+
+# We set GPATH here; this gives us semantics for GNU make
+# which are more like other make's VPATH, when it comes to
+# whether a source that is a target of one rule is then
+# searched for in VPATH/GPATH.
+#
+GPATH = $(srcdir)
+
+TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE)
+
+EXTRA_DIST = 				\
+	$(content_files)		\
+	$(HTML_IMAGES)			\
+	$(DOC_MAIN_SGML_FILE)		\
+	$(DOC_MODULE)-sections.txt	\
+	$(DOC_MODULE)-overrides.txt
+
+DOC_STAMPS=scan-build.stamp tmpl-build.stamp sgml-build.stamp html-build.stamp \
+	   $(srcdir)/tmpl.stamp $(srcdir)/sgml.stamp $(srcdir)/html.stamp
+
+SCANOBJ_FILES = 		 \
+	$(DOC_MODULE).args 	 \
+	$(DOC_MODULE).hierarchy  \
+	$(DOC_MODULE).interfaces \
+	$(DOC_MODULE).prerequisites \
+	$(DOC_MODULE).signals
+
+REPORT_FILES = \
+	$(DOC_MODULE)-undocumented.txt \
+	$(DOC_MODULE)-undeclared.txt \
+	$(DOC_MODULE)-unused.txt
+
+CLEANFILES = $(SCANOBJ_FILES) $(REPORT_FILES) $(DOC_STAMPS)
+
+if ENABLE_GTK_DOC
+all-local: html-build.stamp
+else
+all-local:
+endif
+
+docs: html-build.stamp
+
+#### scan ####
+
+scan-build.stamp: $(HFILE_GLOB) $(CFILE_GLOB)
+	@echo 'gtk-doc: Scanning header files'
+	@-chmod -R u+w $(srcdir)
+	cd $(srcdir) && \
+	  gtkdoc-scan --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --ignore-headers="$(IGNORE_HFILES)" $(SCAN_OPTIONS) $(EXTRA_HFILES)
+	if grep -l '^..*$$' $(srcdir)/$(DOC_MODULE).types > /dev/null 2>&1 ; then \
+	    CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" CFLAGS="$(GTKDOC_CFLAGS)" LDFLAGS="$(GTKDOC_LIBS)" gtkdoc-scangobj $(SCANGOBJ_OPTIONS) --module=$(DOC_MODULE) --output-dir=$(srcdir) ; \
+	else \
+	    cd $(srcdir) ; \
+	    for i in $(SCANOBJ_FILES) ; do \
+               test -f $$i || touch $$i ; \
+	    done \
+	fi
+	touch scan-build.stamp
+
+$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt: scan-build.stamp
+	@true
+
+#### templates ####
+
+tmpl-build.stamp: $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt
+	@echo 'gtk-doc: Rebuilding template files'
+	@-chmod -R u+w $(srcdir)
+	cd $(srcdir) && gtkdoc-mktmpl --module=$(DOC_MODULE) $(MKTMPL_OPTIONS)
+	touch tmpl-build.stamp
+
+tmpl.stamp: tmpl-build.stamp
+	@true
+
+tmpl/*.sgml:
+	@true
+
+
+#### xml ####
+
+sgml-build.stamp: tmpl.stamp $(HFILE_GLOB) $(CFILE_GLOB) $(DOC_MODULE)-sections.txt $(srcdir)/tmpl/*.sgml $(expand_content_files)
+	@echo 'gtk-doc: Building XML'
+	@-chmod -R u+w $(srcdir)
+	cd $(srcdir) && \
+	gtkdoc-mkdb --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --output-format=xml --expand-content-files="$(expand_content_files)" --main-sgml-file=$(DOC_MAIN_SGML_FILE) $(MKDB_OPTIONS)
+	touch sgml-build.stamp
+
+sgml.stamp: sgml-build.stamp
+	@true
+
+#### html ####
+
+html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files)
+	@echo 'gtk-doc: Building HTML'
+	@-chmod -R u+w $(srcdir)
+	rm -rf $(srcdir)/html
+	mkdir $(srcdir)/html
+	cd $(srcdir)/html && gtkdoc-mkhtml $(DOC_MODULE) ../$(DOC_MAIN_SGML_FILE)
+	test "x$(HTML_IMAGES)" = "x" || ( cd $(srcdir) && cp $(HTML_IMAGES) html )
+	@echo 'gtk-doc: Fixing cross-references'
+	cd $(srcdir) && gtkdoc-fixxref --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS)
+	touch html-build.stamp
+
+##############
+
+clean-local:
+	rm -f *~ *.bak
+	rm -rf .libs
+
+distclean-local:
+	cd $(srcdir) && \
+	  rm -rf xml $(REPORT_FILES) \
+	         $(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt
+
+maintainer-clean-local: clean
+	cd $(srcdir) && rm -rf xml html
+
+install-data-local:
+	-installfiles=`echo $(srcdir)/html/*`; \
+	if test "$$installfiles" = '$(srcdir)/html/*'; \
+	then echo '-- Nothing to install' ; \
+	else \
+	  $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR); \
+	  for i in $$installfiles; do \
+	    echo '-- Installing '$$i ; \
+	    $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \
+	  done; \
+	  echo '-- Installing $(srcdir)/html/index.sgml' ; \
+	  $(INSTALL_DATA) $(srcdir)/html/index.sgml $(DESTDIR)$(TARGET_DIR) || :; \
+	  which gtkdoc-rebase >/dev/null && \
+	    gtkdoc-rebase --relative --dest-dir=$(DESTDIR) --html-dir=$(DESTDIR)$(TARGET_DIR) ; \
+	fi
+	
+
+uninstall-local:
+	rm -f $(DESTDIR)$(TARGET_DIR)/*
+
+#
+# Require gtk-doc when making dist
+#
+if ENABLE_GTK_DOC
+dist-check-gtkdoc:
+else
+dist-check-gtkdoc:
+	@echo "*** gtk-doc must be installed and enabled in order to make dist"
+	@false
+endif
+
+dist-hook: dist-check-gtkdoc dist-hook-local
+	mkdir $(distdir)/tmpl
+	mkdir $(distdir)/xml
+	mkdir $(distdir)/html
+	-cp $(srcdir)/tmpl/*.sgml $(distdir)/tmpl
+	-cp $(srcdir)/xml/*.xml $(distdir)/xml
+	cp $(srcdir)/html/* $(distdir)/html
+	-cp $(srcdir)/$(DOC_MODULE).types $(distdir)/
+	-cp $(srcdir)/$(DOC_MODULE)-sections.txt $(distdir)/
+	cd $(distdir) && rm -f $(DISTCLEANFILES)
+	-gtkdoc-rebase --online --relative --html-dir=$(distdir)/html
+
+.PHONY : dist-hook-local docs
diff --git a/doc/ipconfig-api.txt b/doc/ipconfig-api.txt
new file mode 100644
index 0000000..080fdac
--- /dev/null
+++ b/doc/ipconfig-api.txt
@@ -0,0 +1,41 @@
+IP configuration handling
+*************************
+
+
+IP basics
+=========
+
+The core IP handling is designed around network interfaces or more precisely
+what the Linux kernel handles as struct net_device. Via RTNL every interface
+is tracked and an IP device created for it.
+
+	+--------+           +---- eth0 -----+
+	|        |           |               |
+	|  RTNL  +-----+---->|   IP device   |
+	|        |     |     |               |
+	+--------+     |     +---------------+
+                       |
+                       |     +---- wlan0 ----+
+	               |     |               |
+	               +---->|   IP device   |
+	                     |               |
+	                     +---------------+
+
+The IP device tracks link configuration, IP address setting and routing
+information for that interface. Every IP device also contains a configuration
+element. That element contains an operation table for callbacks based on
+different events.
+
+	struct connman_ipconfig_ops {
+		void (*up)         (struct connman_ipconfig *);
+		void (*down)       (struct connman_ipconfig *);
+		void (*lower_up)   (struct connman_ipconfig *);
+		void (*lower_down) (struct connman_ipconfig *);
+		void (*ip_bound)   (struct connman_ipconfig *);
+		void (*ip_release) (struct connman_ipconfig *);
+	};
+
+All configuration objects created directly by RTNL are tightly bound to the
+IP device. They will trigger DHCP or other configuration helpers.
+
+
diff --git a/doc/manager-api.txt b/doc/manager-api.txt
new file mode 100644
index 0000000..ed23c8d
--- /dev/null
+++ b/doc/manager-api.txt
@@ -0,0 +1,238 @@
+Manager hierarchy
+=================
+
+Service		net.connman
+Interface	net.connman.Manager
+Object path	/
+
+Methods		dict GetProperties()
+
+			Returns all global system properties. See the
+			properties section for available properties.
+
+			Possible Errors: [service].Error.InvalidArguments
+
+		void SetProperty(string name, variant value)
+
+			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.
+
+			Possible Errors: [service].Error.InvalidArguments
+					 [service].Error.InvalidProperty
+
+		array{object,dict} GetTechnologies()
+
+			Returns a list of tuples with technology object
+			path and dictionary of technology properties.
+
+			Possible Errors: [service].Error.InvalidArguments
+
+		array{object,dict} GetServices()
+
+			Returns a sorted list of tuples with service
+			object path and dictionary of service properties.
+
+			This list will not contain sensitive information
+			like passphrases etc.
+
+			Possible Errors: [service].Error.InvalidArguments
+
+		object ConnectProvider(dict provider)	[deprecated]
+
+			Connect to a VPN specified by the given provider
+			properties.
+
+			When successful this method will return the object
+			path of the VPN service object.
+
+			This method can also be used to connect to an
+			already existing VPN.
+
+			This method call will only return in case of an
+			error or when the service is fully connected. So
+			setting a longer D-Bus timeout might be a really
+			good idea.
+
+			When 'SessionMode' property is enabled, this method
+			call is disallowed.
+
+			This API is deprecated and should not be used.
+			The VPN configuration API is provided by ConnMan
+			VPN daemon and user should use that one instead.
+
+			Possible Errors: [service].Error.InvalidArguments
+
+		void RegisterAgent(object path)
+
+			Register new agent for handling user requests.
+
+			Possible Errors: [service].Error.InvalidArguments
+
+		void UnregisterAgent(object path)
+
+			Unregister an existing agent.
+
+			Possible Errors: [service].Error.InvalidArguments
+
+		void RegisterCounter(object path, uint32 accuracy, uint32 period)  [experimental]
+
+			Register a new counter for user notifications.
+
+			The accuracy is specified in kilo-bytes and defines
+			a threshold for counter updates. Together with the
+			period value it defines how often user space needs
+			to be updated. The period value is in seconds.
+
+			This interface is not meant for time tracking. If
+			the time needs to be tracked down to the second, it
+			is better to have a real timer running inside the
+			application than using this interface.
+
+			Also getting notified for every kilo-byte is a bad
+			choice (even if the interface supports it). Something
+			like 10 kilo-byte units or better 1 mega-byte seems
+			to be a lot more reasonable and better for the user.
+
+			Possible Errors: [service].Error.InvalidArguments
+
+		void UnregisterCounter(object path)  [experimental]
+
+			Unregister an existing counter.
+
+			Possible Errors: [service].Error.InvalidArguments
+
+		object CreateSession(dict settings, object notifier)  [experimental]
+
+			Create a new session for the application. Every
+			application can create multiple session with
+			different settings. The settings are described
+			as part of the session interface.
+
+			The notifier allows asynchronous notification about
+			session specific changes. These changes can be
+			for online/offline state or IP address changes or
+			similar things the application is required to
+			handle.
+
+			Every application should at least create one session
+			to inform about its requirements and it purpose.
+
+		void DestroySession(object session)  [experimental]
+
+			Remove the previously created session.
+
+			If an application exits unexpectatly the session
+			will be automatically destroyed.
+
+		object path, dict, fd RequestPrivateNetwork(dict options)
+								[experimental]
+
+			Request a new Private Network, which includes the
+			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
+			with IP settings are returned.
+
+			Possible Errors: [service].Error.InvalidArguments
+					 [service].Error.NotSupported
+
+		void ReleasePrivateNetwork(object path) [experimental]
+
+			Releases a private network.
+
+			Possible Errors: [service].Error.InvalidArguments
+
+Signals		TechnologyAdded(object path, dict properties)
+
+			Signal that is sent when a new technology is added.
+
+			It contains the object path of the technology and
+			also its properties.
+
+		TechnologyRemoved(object path)
+
+			Signal that is sent when a technology has been removed.
+
+			The object path is no longer accessible after this
+			signal and only emitted for reference.
+
+		ServicesChanged(array{object, dict}, array{object})
+
+			Signals a list of services that have been changed
+			via the first array. And a list of service that
+			have been removed via the second array.
+
+			The list of added services is sorted. The dictionary
+			with the properties might be empty in case none of
+			the properties have changed. Or only contains the
+			properties that have changed.
+
+			For newly added services the whole set of properties
+			will be present.
+
+			The list of removed services can be empty.
+
+			This signal will only be triggered when the sort
+			order of the service list or the number of services
+			changes. It will not be emitted if only a property
+			of the service object changes. For that it is
+			required to watch the PropertyChanged signal of
+			the service object.
+
+		PropertyChanged(string name, variant value)
+
+			This signal indicates a changed value of the given
+			property.
+
+Properties	string State [readonly]
+
+			The global connection state of a system. Possible
+			values are "offline", "idle", "ready" and "online".
+
+			If the device is in offline mode, the value "offline"
+			indicates this special global state. It can also be
+			retrieved via the OfflineMode property, but is kept
+			here for consistency and to differentiate from "idle".
+
+			However when OfflineMode property is true, the State
+			property can still be "idle", "ready" or "online"
+			since it is possible by the end user to re-enable
+			individual technologies like WiFi and Bluetooth while
+			in offline mode.
+
+			The states "idle", "ready" and "online" match to
+			states from the services. If no service is in
+			either "ready" or "online" state it will indicate
+			the "idle" state.
+
+			If at least one service is in "ready" state and no
+			service is in "online" state, then it will indicate
+			the "ready" state.
+
+			When at least one service is in "online" state,
+			this property will indicate "online" as well.
+
+		boolean OfflineMode [readwrite]
+
+			The offline mode indicates the global setting for
+			switching all radios on or off. Changing offline mode
+			to true results in powering down all devices. When
+			leaving offline mode the individual policy of each
+			device decides to switch the radio back on or not.
+
+			During offline mode, it is still possible to switch
+			certain technologies manually back on. For example
+			the limited usage of WiFi or Bluetooth devices might
+			be allowed in some situations.
+
+		boolean SessionMode [readwrite]  [experminental]
+
+			This disables the auto connect feature. It should be
+			enabled when the Session API is used. When SessionMode
+			is enabled, 'ConnectService' and 'ConnectProvider'
+			method calls are disallowed.
+
+			The default value is false.
diff --git a/doc/overview-api.txt b/doc/overview-api.txt
new file mode 100644
index 0000000..14fec14
--- /dev/null
+++ b/doc/overview-api.txt
@@ -0,0 +1,392 @@
+Application programming interface
+*********************************
+
+
+Service basics
+==============
+
+Inside Connection Manager there exists one advanced interface to allow the
+user interface an easy access to networking details and user chosen
+preferences. This is the service list and interface.
+
+The basic idea is that Connection Manager maintains a single flat and sorted
+list of all available, preferred or previously used services. A service here
+can be either a Ethernet device, a WiFi network or a remote Bluetooth device
+(for example a mobile phone).
+
+This list of service is sorted by Connection Manager and there is no need
+for the user interface to implement its own sorting. User decisions will
+need to be done via Connection Manager and it is then responsible to update
+the order of services in this list.
+
+	+---------------------------------------+
+	| Ethernet                              |
+	+---------------------------------------+
+	| Bluetooth phone                       |
+	+---------------------------------------+
+	| Guest            (strength 90, none)  |
+	+---------------------------------------+
+	| My WiFi AP       (strength 80, rsn)   |
+	+---------------------------------------+
+	| Other AP         (strength 70, rsn)   |
+	+---------------------------------------+
+	| Friends AP       (strength 70, wep)   |
+	+---------------------------------------+
+
+If none of the services has been used before the sorting order will be done
+with these priorities:
+
+	1. Ethernet	(lower index numbers first)
+	2. Bluetooth	(last used devices first)
+	3. GSM/UTMS/3G	(if SIM card is present, activated and not roaming)
+	3. WiFi		(signal strength first, then more secure network
+			first)
+
+The Ethernet devices are always sorted first since they are physically built
+into the system and will be always present. In cases they are switched off
+manually they will not be showing in this list.
+
+Since every Bluetooth device has to be configured/paired first, the user
+already made a choice here that these are important. Connection Manager will
+only show devices with PAN or DUN profile support. While Bluetooth devices
+do have a signal strength, it is mostly unknown since background scanning
+in Bluetooth is too expensive. The choice here is to sort the last used
+Bluetooth device before the others.
+
+WiFi networks closer in the proximity should be shown first since it is more
+likely they are selected. The signal strength value is normalized to 0-100
+(effectively a percentage) and allows an easy sorting.
+
+WiFi networks with the same signal strength are then sorted by their security
+setting. WPA2 encrypted networks should be preferred over WPA/WEP and also
+unencrypted ones. After that they will be sorted by the SSID in alphabetical
+order.
+
+In the case the WiFi network uses WPS for setup and it is clearly detectable
+that a network waits for Connection Manager to connect to it (for example via
+a push-to-connect button press on the AP), then this network should be shown
+first before any other WiFi networks. The reason here is that the user already
+made a choice via the access point. However this depends on technical details
+if it is possible to detect these situations.
+
+
+Service order
+=============
+
+All unused services will have the internal order number of 0 and then will
+be sorted according to the rules above. For Bluetooth the user already made
+the decision to setup their device and by that means select it. However
+until the first connection attempt it might have been setup for total
+different reason (like audio usage) and thus it still counts as unused from
+a networking point of view.
+
+Selecting the "My WiFi AP" and successfully connecting to it makes it a
+favorite device and it will become an order number bigger than 0. All
+order numbers are internally. They are given only to service that are marked
+as favorite. For WiFi and Bluetooth a successful connection attempt makes
+these services automatically a favorite. For Ethernet the plugging of a cable
+makes it a favorite. Disconnecting from a network doesn't remove the favorite
+setting. It is a manual operation and is equal to users pressing
+delete/remove button.
+
+	+---------------------------------------+
+	| My WiFi AP       (strength 80, rsn)   |  order=1 - favorite=yes
+	+---------------------------------------+
+	| Ethernet                              |  order=0
+	+---------------------------------------+
+	| Guest            (strength 90, none)  |  order=0
+	+---------------------------------------+
+	|                                       |
+
+Ethernet is special here since the unplugging of the network cable will
+remove the favorite selection.
+
+	+---------------------------------------+
+	| Ethernet with cable                   |  order=1 - favorite=yes
+	+---------------------------------------+
+	| Ethernet without cable                |  order=0 - favorite=no
+	+---------------------------------------+
+	| Guest            (strength 90, none)  |  order=0
+	+---------------------------------------+
+	|                                       |
+
+This means that all services with an order > 0 have favorite=yes and all
+others have favorite=no setting. The favorite setting is exposed via a
+property over the service interface. As mentioned above, the order number
+is only used internally.
+
+Within Connection Manager many services can be connected at the same time and
+also have an IP assignment. However only one can have the default route. The
+service with the default route will always be sorted at the top of the
+list.
+
+	+---------------------------------------+
+	| Ethernet                              |  order=2 - connected=yes
+	+---------------------------------------+
+	| My WiFi AP       (strength 80, rsn)   |  order=1 - connected=yes
+	+---------------------------------------+
+	| Guest            (strength 90, none)  |  order=0
+	+---------------------------------------+
+	|                                       |
+
+To change the default connection to your access point, the user needs to
+manually drag the access point service to the top of the list. Connection
+Manager will not take down default routes if there is no reason to do so.
+A working connection is considered top priority.
+
+	+---------------------------------------+
+	| My WiFi AP       (strength 80, rsn)   |  order=2 - connected=yes
+	+---------------------------------------+
+	| Ethernet                              |  order=1 - connected=yes
+	+---------------------------------------+
+	| Guest            (strength 90, none)  |  order=0
+	+---------------------------------------+
+	|                                       |
+
+Another possible user interaction would be to unplug the Ethernet cable and
+in this case the favorite setting will be removed and the service falls back
+down in the list.
+
+	+---------------------------------------+
+	| My WiFi AP       (strength 80, rsn)   |  order=1 - connected=yes
+	+---------------------------------------+
+	| Ethernet                              |  order=0
+	+---------------------------------------+
+	| Guest            (strength 90, none)  |  order=0
+	+---------------------------------------+
+	|                                       |
+
+If the service on the top of the list changes the default route will be
+automatically adjusted as needed. The user can trigger this by disconnecting
+from a network, if the network becomes unavailable (out of range) or if the
+cable gets unplugged.
+
+As described above, the pure case of disconnecting from a network will not
+remove the favorite setting. So previously selected networks are still present
+and are sorted above all others.
+
+	+---------------------------------------+
+	| Ethernet                              |  order=2 - connected=yes
+	+---------------------------------------+
+	| My WiFi AP       (strength 80, rsn)   |  order=1 - connected=no
+	+---------------------------------------+
+	| Guest            (strength 90, none)  |  order=0
+	+---------------------------------------+
+	|                                       |
+
+Unplugging the Ethernet cable will remove the favorite setting, but due to
+the basic ordering of services it will be at the top of the services with an
+order number of 0 (directly after all favorite services).
+
+	+---------------------------------------+
+	| My WiFi AP       (strength 80, rsn)   |  order=1 - connected=no
+	+---------------------------------------+
+	| Ethernet                              |  order=0 - connected=no
+	+---------------------------------------+
+	| Guest            (strength 90, none)  |  order=0
+	+---------------------------------------+
+	|                                       |
+
+
+Service tweaks
+==============
+
+The interfaces of Connection Manager will always export all services that are
+currently known. The Ethernet devices with no cable plugged are actually not
+included in this list. They will only show up once a carrier is detected.
+
+The service interface is not meant for basic device configuration task. So
+switching a device on and off (via RFKILL for example) should be done via
+the device interface.
+
+Due to limited screen size of small devices and the big amount of WiFi
+access points that are deployed right now it might be sensible to not show
+certain WiFi networks in the user interface.
+
+The choice to hide a WiFi network from the user interface should be purely
+done by the signal strength. The optimal cut-off value here still has to be
+determined, but in the end that is a user interface policy.
+
+
+Service naming
+==============
+
+Every service will have a name property that allows the user interface to
+display them directly. All names will be already converted into UTF-8. It
+derives from the netork details.
+
+In case of WiFi this will be the SSID value. The SSID is a binary array and
+will be converted into printable form. Unprintable characters are replaced
+with spaces.
+
+For Bluetooth the device alias is used. The alias is different since it
+can be overwritten by the user via the Bluetooth service. The identification
+is still done based on its address, but the display name might change. In
+most cases the alias is equal to the Bluetooth remote friendly name.
+
+For Ethernet device no name will be provided. The type property will indicate
+that this service is Ethernet and then it is up to the user interface to
+provide a proper localized name for it.
+
+
+Service states
+==============
+
+Every service can have multiple states that indicate what is currently
+going on with it. The choice to have multiple states instead of a simple
+connected yes/no value comes from the fact that it is important to let the
+user interface name if a service is in process of connecting/disconnecting.
+
+The basic state of every service is "idle". This means that this service
+is not in use at all at the moment. It also is not attempting to connect
+or do anything else.
+
+The "association" state indicates that this service tries to establish a
+low-level connection to the network. For example associating/connecting
+with a WiFi access point.
+
+With the "configuration" state the service indicates that it is trying
+to retrieve/configure IP settings.
+
+The "ready" state signals a successful connected device. This doesn't mean
+it has the default route, but basic IP operations will succeed.
+
+With the "disconnect" state a service indicates that it is going to terminate
+the current connection and will return to the "idle" state.
+
+In addition a "failure" state indicates a wrong behavior. It is similar to
+the "idle" state since the service is not connected.
+
+		+---------------+
+		| idle          |<-------------------------------+
+		+---------------+                                |
+		      |                                          |
+		      |                      +-------------+     |
+		      +----------------------| failure     |     |
+		      | service.Connect()    +-------------+     |
+		      V                           A              |
+		+---------------+                 |              |
+		| association   |-----------------+              |
+		+---------------+      error      |              |
+		      |                           |              |
+		      | success                   |              |
+		      V                           |              |
+		+---------------+                 |              |
+		| configuration |-----------------+              |
+		+---------------+      error                     |
+		      |                                          |
+		      | success                                  |
+		      V                                          |
+		+---------------+                                |
+		| ready         |                                |
+		+---------------+                                |
+		      |                                          |
+		      | success                                  |
+		      |                                          |
+		      V                                          |
+		+---------------+                                |
+		| online        |<----------------+              |
+		+---------------+                 |              |
+		      |                           |              |
+		      | service.Disconnect()      |              |
+		      V                           |              |
+		+---------------+                 |              |
+		| disconnect    |-----------------+              |
+		+---------------+      error                     |
+		      |                                          |
+		      +------------------------------------------+
+
+The different states should no be used by the user interface to trigger
+advanced actions. The state transitions are provided for the sole purpose
+to give the user feedback on what is currently going on. Especially in
+cases where networks are flaky or DHCP servers take a long time these
+information are helpful for the user.
+
+Some services might require special authentication procedure like a web
+based confirmation. The LoginRequired property should be used to check
+for this.
+
+
+Application basics
+==================
+
+All applications should use D-Bus to communicate with Connection Manager. The
+main entry point is the manager object. Currently the manager object is
+located at "/", but this might change to allow full namespacing of the API
+in the future. The manager interface is documented in manager-api.txt and
+contains a set of global properties and methods.
+
+A simple way to retrieve all global properties looks like this:
+
+	bus = dbus.SystemBus()
+
+	manager = dbus.Interface(bus.get_object("net.connman", "/"),
+						"net.connman.Manager")
+
+	properties = manager.GetProperties()
+
+Changing a global property is also pretty simple. For example enabling the
+so called offline mode (aka flight mode) it is enough to just set that
+property:
+
+	manager.SetProperty("OfflineMode", dbus.Boolean(1))
+
+The manager object contains references to profiles, devices, services and
+connections. All these references represent other interfaces that allow
+detailed control of Connection Manager. The profiles and devices interfaces
+are more for advanced features and most applications don't need them at all.
+
+The services are represented as a list of object paths. Every of these object
+paths contains a service interface. A service is a global collection for
+Ethernet devices, WiFi networks, Bluetooth services etc. and all these
+different types are treated equally.
+
+Every local Ethernet card will show up as exactly one service. WiFi networks
+will be grouped by SSID, mode and security setting. Bluetooth PAN and DUN
+service will show up per remote device. This creates a simple list that can
+be directly displayed to the users since these are the exact details users
+should care about.
+
+	properties = manager.GetProperties()
+
+	for path in properties["Services"]:
+		service = dbus.Interface(bus.get_object("net.connman", path),
+							"net.connman.Service")
+
+		service_properties = service.GetProperties()
+
+The service interface is documented in service-api.txt and contains common
+properties valid for all services. It also contains method to connect or
+disconnect a specific service. This allows users to select a specific service.
+Connection Manager can also auto-connect services based on his policies or
+via external events (like plugging in an Ethernet cable).
+
+Connecting (or disconnecting) a specific service manually is as simple as
+just telling it to actually connect:
+
+	service.Connect()  or  service.Disconnect()
+
+It is possible to connect multiple services if the underlying technology
+allows it. For example it would be possible to connect to a WiFi network
+and a Bluetooth service at the same time. Trying to connect to a second WiFi
+network with the same WiFi hardware would result in an automatic disconnect
+of the currently connected network. Connection Manager handles all of this
+for the applications in the background. Trying to connect an Ethernet service
+will result in an error if no cable is plugged in. All connection attempts
+can fail for one reason or another. Application should be able to handle
+such errors and will also be notified of changes via signals.
+
+In future versions Connection Manager will interact with an agent to confirm
+certain transactions with the user. This functionality is currently not
+implemented.
+
+To monitor the current status of a service the state property can be used. It
+gives detailed information about the current progress.
+
+	properties = service.GetProperties()
+
+	print properties["State"]
+
+All state changes are also sent via the PropertyChanged signal on the
+service interface. This allows asynchronous monitoring without having to poll
+Connection Manager for changes.
diff --git a/doc/plugin-api.txt b/doc/plugin-api.txt
new file mode 100644
index 0000000..b39c043
--- /dev/null
+++ b/doc/plugin-api.txt
@@ -0,0 +1,24 @@
+Plugin programming interface
+****************************
+
+
+Plugin basics
+=============
+
+The Connection Manager supports plugins for various actions. The basic plugin
+contains of plugin description via CONNMAN_PLUGIN_DEFINE and also init/exit
+callbacks defined through that description.
+
+#include <connman/plugin.h>
+
+static int example_init(void)
+{
+	return 0;
+}
+
+static void example_exit(void)
+{
+}
+
+CONNMAN_PLUGIN_DEFINE(example, "Example plugin", CONNMAN_VERSION,
+						example_init, example_exit)
diff --git a/doc/service-api.txt b/doc/service-api.txt
new file mode 100644
index 0000000..b33eb6f
--- /dev/null
+++ b/doc/service-api.txt
@@ -0,0 +1,488 @@
+Service hierarchy
+=================
+
+Service		net.connman
+Interface	net.connman.Service
+Object path	[variable prefix]/{service0,service1,...}
+
+Methods		dict GetProperties()  [deprecated]
+
+			Returns properties for the service object. See
+			the properties section for available properties.
+
+			Usage of this method is highly discouraged. Use
+			the Manager.GetServices() method instead.
+
+			Possible Errors: [service].Error.InvalidArguments
+
+		void SetProperty(string name, variant value)
+
+			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.
+
+			Possible Errors: [service].Error.InvalidArguments
+					 [service].Error.InvalidProperty
+
+		void ClearProperty(string name)
+
+			Clears the value of the specified property.
+
+			Possible Errors: [service].Error.InvalidArguments
+					 [service].Error.InvalidProperty
+
+		void Connect()
+
+			Connect this service. It will attempt to connect
+			WiFi or Bluetooth services.
+
+			For Ethernet devices this method can only be used
+			if it has previously been disconnected. Otherwise
+			the plugging of a cable will trigger connecting
+			automatically. If no cable is plugged in this method
+			will fail.
+
+			This method call will only return in case of an
+			error or when the service is fully connected. So
+			setting a longer D-Bus timeout might be a really
+			good idea.
+
+			Possible Errors: [service].Error.InvalidArguments
+
+		void Disconnect()
+
+			Disconnect this service. If the service is not
+			connected an error message will be generated.
+
+			On Ethernet devices this will disconnect the IP
+			details from the service. It will not magically
+			unplug the cable. When no cable is plugged in this
+			method will fail.
+
+			This method can also be used to abort a previous
+			connectiong attempt via the Connect method.
+
+			Possible Errors: [service].Error.InvalidArguments
+
+		void Remove()
+
+			A successfully connected service with Favorite=true
+			can be removed this way. If it is connected, it will
+			be automatically disconnected first.
+
+			If the service requires a passphrase it will be
+			cleared and forgotten when removing.
+
+			This is similar to setting the Favorite property
+			to false, but that is currently not supported.
+
+			In the case a connection attempt failed and the
+			service is in the State=failure, this method can
+			also be used to reset the service.
+
+			Calling this method on Ethernet devices will cause
+			an error message. It is not possible to remove these
+			kind of devices.
+
+			Possible Errors: [service].Error.InvalidArguments
+
+		void MoveBefore(object service)
+
+			If a service has been used before, this allows a
+			reorder of the favorite services.
+
+			The target service object must be part of this
+			profile. Moving between profiles is not supported.
+
+			Possible Errors: [service].Error.InvalidArguments
+
+		void MoveAfter(object service)
+
+			If a service has been used before, this allows a
+			reorder of the favorite services.
+
+			The target service object must be part of this
+			profile. Moving between profiles is not supported.
+
+			Possible Errors: [service].Error.InvalidArguments
+
+		void ResetCounters()  [experimental]
+
+			Reset the counter statistics.
+
+			Possible Errors: None
+
+Signals		PropertyChanged(string name, variant value)
+
+			This signal indicates a changed value of the given
+			property.
+
+Properties	string State [readonly]
+
+			The service state information.
+
+			Valid states are "idle", "failure", "association",
+			"configuration", "ready", "disconnect" and "online".
+
+			The "ready" state signals a successfully
+			connected device. "online" signals that an
+			Internet connection is available and has been
+			verified.
+
+			See doc/overview-api.txt for more information about
+			state transitions.
+
+		string Error [readonly]
+
+			The service error status details.
+
+			When error occur during connection or disconnection
+			the detailed information is represented in this
+			property to help the user interface to present the
+			user with alternate options.
+
+			This property is only valid when the service is in
+			the "failure" state. Otherwise it might be empty or
+			not present at all.
+
+			Current defined error code is "dhcp-failed".
+
+		string Name [readonly]
+
+			The service name (for example "Wireless" etc.)
+
+			This name can be used for directly displaying it in
+			the application. It has pure informational purpose
+			and no attempt should be made to translate it.
+
+			For Ethernet devices and hidden WiFi networks this
+			property is not present.
+
+		string Type [readonly]
+
+			The service type (for example "ethernet", "wifi" etc.)
+
+			This information should only be used to determine
+			advanced properties or showing the correct icon
+			to the user.
+
+			Together with a missing Name property, this can
+			be used to identify hidden WiFi networks.
+
+		array{string} Security [readonly]
+
+			If the service type is WiFi, then this property is
+			present and contains the list of security methods
+			or key management settings.
+
+			Possible values are "none", "wep", "psk", "ieee8021x"
+			and also "wps".
+
+			This property might be only present for WiFi
+			services.
+
+		uint8 Strength [readonly]
+
+			Indicates the signal strength of the service. This
+			is a normalized value between 0 and 100.
+
+			This property will not be present for Ethernet
+			devices.
+
+		boolean Favorite [readonly]
+
+			Will be true if a cable is plugged in or the user
+			selected and successfully connected to this service.
+
+			This value is automatically changed and to revert
+			it back to false the Remove() method needs to be
+			used.
+
+		boolean Immutable [readonly]
+
+			This value will be set to true if the service is
+			configured externally via a configuration file.
+
+			The only valid operation are Connect() and of
+			course Disconnect(). The Remove() method will
+			result in an error.
+
+		boolean AutoConnect [readwrite]
+
+			If set to true, this service will auto-connect
+			when no other connection is available.
+
+			The service won't auto-connect while roaming.
+
+			For favorite services it is possible to change
+			this value to prevent or permit automatic
+			connection attempts.
+
+		boolean Roaming [readonly]
+
+			This property indicates if this service is roaming.
+
+			In the case of Cellular services this normally
+			indicates connections to a foreign provider when
+			traveling abroad.
+
+		array{string} Nameservers [readonly]
+
+			The list of currently active nameservers for this
+			service. If the server is not in READY or ONLINE
+			state than this list will be empty.
+
+			Global nameservers are automatically added to this
+			list. The array represents a sorted list of the
+			current nameservers. The first one has the highest
+			priority and is used by default.
+
+			When using DHCP this array represents the nameservers
+			provided by the network. In case of manual settings,
+			the ones from Nameservers.Configuration are used.
+
+		array{string} Nameservers.Configuration [readwrite]
+
+			The list of manually configured domain name
+			servers. Some cellular networks don't provide
+			correct name servers and this allows for an
+			override.
+
+			This array is sorted by priority and the first
+			entry in the list represents the nameserver with
+			the highest priority.
+
+			When using manual configuration and no global
+			nameservers are configured, then it is useful
+			to configure this setting.
+
+			Changes to the domain name servers can be done
+			at any time. It will not cause a disconnect of
+			the service. However there might be small window
+			where name resolution might fail.
+
+		array{string} Timeservers [readonly]
+
+			The list of currently active timeservers for this
+			service. If the server is not in READY or ONLINE
+			state than this list will be empty.
+
+		array{string} Timeservers.Configuration [readwrite]
+
+			The list of manually configured time servers.
+
+			The first entry in the list represents the
+			timeserver with the highest priority.
+
+			When using manual configuration this setting
+			is useful to override all the other timeserver
+			settings. This is service specific, hence only
+			the values for the default service are used.
+
+			Changes to this property will result in restart
+			of NTP query.
+
+		array{string} Domains [readonly]
+
+			The list of currently used search domains taken
+			from Domains.Configurations if set, otherwise a
+			domain name if provided by DHCP or VPNs.
+
+		array{string} Domains.Configuration [readwrite]
+
+			The list of manually configured search domains.
+
+		dict IPv4 [readonly]
+
+			string Method [readonly]
+
+				Possible values are "dhcp", "manual"
+				and "off".
+
+				The value "fixed" indicates an IP address
+				that can not be modified. For example
+				cellular networks return fixed information.
+
+			string Address [readonly]
+
+				The current configured IPv4 address.
+
+			string Netmask [readonly]
+
+				The current configured IPv4 netmask.
+
+			string Gateway [readonly]
+
+				The current configured IPv4 gateway.
+
+		dict IPv4.Configuration [readwrite]
+
+			Same values as IPv4 property. The IPv4 represents
+			the actual system configuration while this allows
+			user configuration.
+
+			Changing these settings will cause a state change
+			of the service. The service will become unavailable
+			until the new configuration has been successfully
+			installed.
+
+		dict IPv6 [readonly]
+
+			string Method [readonly]
+
+				Possible values are "auto", "manual", "6to4"
+				and "off".
+
+				The value "fixed" indicates an IP address
+				that can not be modified. For example
+				cellular networks return fixed information.
+				The value "6to4" is returned if 6to4 tunnel
+				is created by connman. The tunnel can only be
+				created if method was set to "auto" by the
+				user. User cannot set the method to "6to4".
+
+			string Address [readonly]
+
+				The current configured IPv6 address.
+
+			uint8 PrefixLength [readonly]
+
+				The prefix length of the IPv6 address.
+
+			string Gateway [readonly]
+
+				The current configured IPv6 gateway.
+
+			string Privacy [readonly]
+
+				Enable or disable IPv6 privacy extension
+				that is described in RFC 4941. The value
+				has only meaning if Method is set to "auto".
+
+				Value "disabled" means that privacy extension
+				is disabled and normal autoconf addresses are
+				used.
+
+				Value "enabled" means that privacy extension is
+				enabled and system prefers to use public
+				addresses over temporary addresses.
+
+				Value "prefered" means that privacy extension is
+				enabled and system prefers temporary addresses
+				over public addresses.
+
+				Default value is "disabled".
+
+		dict IPv6.Configuration [readwrite]
+
+			Same values as IPv6 property. The IPv6 represents
+			the actual system configuration while this allows
+			user configuration.
+
+			Changing these settings will cause a state change
+			of the service. The service will become unavailable
+			until the new configuration has been successfully
+			installed.
+
+		dict Proxy [readonly]
+
+			string Method [readonly]
+
+				Possible values are "direct", "auto" and
+				"manual".
+
+				In case of "auto" method, the URL file can be
+				provided unless you want to let DHCP/WPAD
+				auto-discover to be tried. In such case if DHCP
+				and WPAD auto-discover methods fails then
+				method will be "direct".
+
+				In case of "direct" no additional information
+				are provided. For the "manual" method the
+				Servers have to be set, Excludes is optional.
+
+			string URL [readonly]
+
+				Automatic proxy configuration URL. Used by
+				"auto" method.
+
+			array{string} Servers [readonly]
+
+				Used when "manual" method is set.
+
+				List of proxy URIs. The URI without a protocol
+				will be interpreted as the generic proxy URI.
+				All others will target a specific protocol and
+				only once.
+
+				Example for generic proxy server entry would
+				be like this: "server.example.com:911".
+
+			array{string} Excludes [readonly]
+
+				Used when "manual" method is set.
+
+				List of hosts which can be accessed directly.
+
+		dict Proxy.Configuration [readwrite]
+
+			Same values as Proxy property. The Proxy represents
+			the actual system configuration while this allows
+			user configuration.
+
+			If "auto" method is set with an empty URL, then
+			DHCP/WPAD auto-discover will be tried. Otherwise the
+			specified URL will be used.
+
+		dict Provider [readonly]
+
+			string Host [readonly]
+
+				VPN host IP.
+
+			string Domain [readonly]
+
+				VPN Domain.
+
+			string Name [readonly]
+
+				VPN provider Name.
+
+			string Type [readonly]
+
+				VPN provider type.
+
+		dict Ethernet [readonly]
+
+			string Method [readonly]
+
+				Possible values are "auto" and "manual".
+
+			string Interface [readonly]
+
+				Interface name (for example eth0).
+
+			string Address [readonly]
+
+				Ethernet device address (MAC address).
+
+			uint16 MTU [readonly]
+
+				The Ethernet MTU (default is 1500).
+
+			uint16 Speed [readonly]
+
+				Selected speed of the line.
+
+				This information might not always be
+				available.
+
+			string Duplex [readonly]
+
+				Selected duplex settings of the line.
+
+				Possible values are "half" and "full".
+
+				This information might not always be
+				available.
diff --git a/doc/session-api.txt b/doc/session-api.txt
new file mode 100644
index 0000000..a0a328d
--- /dev/null
+++ b/doc/session-api.txt
@@ -0,0 +1,184 @@
+Service		unique name
+Interface	net.connman.Notification
+Object path	freely definable
+
+Methods		void Release()
+
+			This method gets called when the service daemon
+			unregisters the session. A counter can use it to do
+			cleanup tasks. There is no need to unregister the
+			session, because when this method gets called it has
+			already been unregistered.
+
+		void Update(dict settings)
+
+			Sends an update of changed settings. Only settings
+			that are changed will be included.
+
+			Initially on every session creation this method is
+			called once to inform about the current settings.
+
+
+Service		net.connman
+Interface	net.connman.Session
+Object path	variable
+
+Methods		void Destroy()
+
+			Close the current session. This is similar to
+			DestroySession method on the manager interface. It
+			is just provided for convenience depending on how
+			the application wants to track the session.
+
+		void Connect()
+
+			If not connected, then attempt to connect this
+			session.
+
+			The usage of this method depends a little bit on
+			the model of the application. Some application
+			should not try to call Connect on any session at
+			all. They should just monitor if it becomes online
+			or gets back offline.
+
+			Others might require an active connection right now.
+			So for example email notification should only check
+			for new emails when a connection is available. However
+			if the user presses the button for get email or wants
+			to send an email it should request to get online with
+			this method.
+
+			Depending on the bearer settings the current service
+			is used or a new service will be connected.
+
+			This method returns immediately after it has been
+			called. The application is informed through the update
+			notification about the state of the session.
+
+			It is also not guaranteed that a session stays online
+			after this method call. It can be taken offline at any
+			time. This might happen because of idle timeouts or
+			other reasons.
+
+			It is safe to call this method multiple times. The
+			actual usage will be sorted out for the application.
+
+		void Disconnect()
+
+			This method indicates that the current session does
+			not need a connection anymore.
+
+			This method returns immediately. The application is
+			informed through the update notification about the
+			state of the session.
+
+		void Change(string name, variant value)
+
+			Change the value of certain settings. Not all
+			settings can be changed. Normally this should not
+			be needed or an extra session should be created.
+			However in some cases it makes sense to change
+			a value and trigger different behavior.
+
+			A change of a setting will cause an update notification
+			to be sent. Some changes might cause the session to
+			be moved to offline state.
+
+Settings	string State [readonly]
+
+			This indicates if the connection is disconnected,
+			connected or online. It is updated according to the
+			selected ConnectionType. The session will not be
+			in a useful shape (i.e.: providing a network connection
+			to the owner) until its State gets updated to connected
+			and/or online.
+
+			This maps to the useful port of the  service state.
+			And it is only valid for the selected bearer
+			configuration. Otherwise it will be reported as
+			disconnected even if connected services are present.
+
+			In addition the State settings notification might
+			not happen right away. Notifications of this state
+			can be delayed based on the speed of the bearer. It
+			is done to avoid congestion on bearers like cellular
+			etc.
+
+		string Name [readonly]
+
+			The Service name to which the system is connected.
+			It should only be used for displaying it in the UI
+			and not for getting hold on session object.
+
+		string  Bearer [readonly]
+
+			This indicates the current bearer that is used
+			for this session. Or an empty string if no bearer
+			if available.
+
+		string  Interface [readonly]
+
+			Interface name used by the service object to connect.
+			This name can be used for SO_BINDTODEVICE in the
+			application.
+
+		dict IPv4 [readonly]
+
+			Current IPv4 configuration.
+
+		dict IPv6 [readonly]
+
+			Current IPv6 configuration.
+
+		array{string} AllowedBearers [readwrite]
+
+			A list of bearers that can be used for this session.
+			In general this list should be empty to indicate that
+			any bearer is acceptable.
+
+			The order of the entries in AllowedBearers matters.
+			The services are sorted in the order of the bearer
+			entries in this list.
+
+			Also "*" matches any bearer. This is usefull to prefer
+			certain bearers such as 'wifi' with a fallback to any
+			other available bearer.
+
+			Invalid bearer names will be ignored and removed
+			from the list. And empty AllowedBearers will
+			not match to any bearer, therefore the session
+			will never go online.
+
+			When a session is created and the provided settings
+			dictionary does not contain AllowedBearers, a default
+			session with "*" will be created.
+
+		string ConnectionType [readwrite]
+
+			This is used to indicate which connection is requested
+			from the session. The state of the session will be
+			updated accordingly. Values can be 'local',
+			'internet' or 'any'.
+
+			'local' means the session requests to be connected,
+			but does not require specifically to be online.
+			Therefore State property will be set to 'connected' if
+			underlying service gets ready and/or online.
+
+			'online' means the session requests to be connected,
+			and online. State property will never get 'connected'
+			but instead will switch to 'online' if underlying
+			service gets online.
+
+			'any' means either 'local' or 'internet'.
+
+			Invalid values will be ignored and removed. An
+			empty ConnectionType is an invalid configuration.
+
+			When a session is created and the provided settings
+			dictionary does not contain ConnectionType, a default
+			session with 'any' will be created.
+
+			(This setting will be removed when the unique process
+			identifaction problem is solved.)
+
diff --git a/doc/session-overview.txt b/doc/session-overview.txt
new file mode 100644
index 0000000..d42c6d1
--- /dev/null
+++ b/doc/session-overview.txt
@@ -0,0 +1,78 @@
+Session API
+***********
+
+
+Connection management algorithm basics
+======================================
+
+When a session is created, a sorted list of services is added to the
+session. The services are filtered and sorted according AllowedBearers.
+
+There are three triggers which lead to evaluate the connect
+algorithm:
+
+ - Session.Connect()
+ - Offline
+
+Connect algorithm:
+
+              Session.Connect()
+                       |
+                +------+-------+
+          +-----+ECall Session ?+-----+
+       Yes|     +--------------+      |No
+          |                           |
+        Connect to            +--------------+
+        first available   +---+AvoidHandover?+---+
+        Service           |   +--------------+   |
+                       Yes|                      |No
+                 +----------------+              |
+             +---+In service_list +---+          |
+          Yes|   |and online?     |   |No        |
+             |   +----------------+   |          |
+             |                        |          |
+         Take that one                Take first in
+                                      the service list
+
+Disconnect algorithm
+
+ - Session.Disconnect()
+
+Disconnect algorithm:
+
+  Session.Disconnect()
+       |
+       +--- Session.Change()
+       |
++-----------------+    Yes
+|service not used +-------------+
+|by other session?|             |
++------.----------+             |
+       |No                      |
+       |                        |
+    Service.Disconnect()   Do nothing
+
+Session.Disconnect() will be blocked whenever a ongoing
+emergency call is active.
+
+
+Session States and Transitions
+==============================
+
+There is only one state which is called Free Ride.
+
+The Free Ride state means that a session will go online if a matching
+service goes online without calling Service.Connect() itself. The idea
+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()
+ +------+
+ |      v
++------------+
+|  Free Ride |
++------------+
+  |     ^
+  +-----+
+ Disconnect()
diff --git a/doc/technology-api.txt b/doc/technology-api.txt
new file mode 100644
index 0000000..9fe66b3
--- /dev/null
+++ b/doc/technology-api.txt
@@ -0,0 +1,103 @@
+Technology hierarchy
+====================
+
+Service		net.connman
+Interface	net.connman.Technology
+Object path	[variable prefix]/{technology0,technology1,...}
+
+Methods		dict GetProperties()  [deprecated]
+
+			Returns properties for the technology object. See
+			the properties section for available properties.
+
+			Usage of this method is highly discouraged. Use
+			the Manager.GetTechnologies() method instead.
+
+			Possible Errors: [service].Error.InvalidArguments
+
+		void SetProperty(string name, variant value)
+
+			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.
+
+			Possible Errors: [service].Error.InvalidArguments
+					 [service].Error.InvalidProperty
+
+		void Scan()
+
+			Trigger a scan for this specific technology. The
+			method call will return when a scan has been
+			finished and results are available. So setting
+			a longer D-Bus timeout might be a really good
+			idea.
+
+			Results will be signaled via the ServicesChanged
+			signal from the manager interface.
+
+Signals		PropertyChanged(string name, variant value)
+
+			This signal indicates a changed value of the given
+			property.
+
+Properties	boolean Powered [readwrite]
+
+			Boolean representing the power state of the
+			technology. False means that the technology is
+			off (and is available RF-Killed) while True means
+			that the technology is enabled.
+
+		boolean Connected [readonly]
+
+			Boolean representing if a technolgy is connected.
+
+			This is just a convience property for allowing the
+			UI to easily show if this technolgy has an active
+			connection or not.
+
+			If this property is True it means that at least one
+			service of this technology is in ready state.
+
+		string Name [readonly]
+
+			Name of this technology.
+
+		string Type [readonly]
+
+			The technology type (for example "ethernet" etc.)
+
+			This information should only be used to determine
+			advanced properties or showing the correct icon
+			to the user.
+
+		boolean Tethering [readwrite]
+
+			This option allows to enable or disable the support
+			for tethering. When tethering is enabled then the
+			default service is bridged to all clients connected
+			through the technology.
+
+		string TetheringIdentifier [readwrite]
+
+			The tethering broadcasted identifier.
+
+			This property is only valid for the WiFi technology,
+			and is then mapped to the WiFi AP SSID clients will
+			have to join in order to gain internet connectivity.
+
+		string TetheringPassphrase [readwrite]
+
+			The tethering connection passphrase.
+
+			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.
+
+		uint32  IdleTimeout [readwrite] [experimental]
+
+			If the technology is idle for given period then it
+			will go offline if no Service with this technology
+			has AutoConnect set to True.
+
+			If the timeout is 0, this feature is disabled.
diff --git a/doc/valgrind.suppressions b/doc/valgrind.suppressions
new file mode 100644
index 0000000..c1c7bca
--- /dev/null
+++ b/doc/valgrind.suppressions
@@ -0,0 +1,235 @@
+{
+   <syslog error>
+   Memcheck:Cond
+   obj:/lib/libc-*.so
+   ...
+   fun:localtime_r
+   fun:__vsyslog_chk
+   fun:__syslog_chk
+   fun:__connman_log_init
+   ...
+}
+{
+   <iconv open>
+   Memcheck:Addr4
+   obj:/lib/libc-*.so
+   obj:/lib/libglib-2.0.so*
+   fun:g_iconv_open
+   ...
+   fun:g_convert
+   fun:g_locale_to_utf8
+   fun:g_strerror
+   fun:g_key_file_load_from_file
+   ...
+}
+{
+   <ioctl ADDRT/DELRT>
+   Memcheck:Param
+   ioctl(SIOCADDRT/DELRT)
+   obj:/lib/ld-*.so
+   ...
+}
+{
+   <g_main_loop>
+   Memcheck:Leak
+   fun:memalign
+   ...
+   fun:g_slice_alloc
+   ...
+   fun:g_main_loop_new
+   ...
+}
+{
+   <g_option_context_parse>
+   Memcheck:Leak
+   ...
+   fun:g_slice_alloc
+   ...
+   fun:g_option_context_parse
+   ...
+}
+{
+   <g_key_file_load_from_data>
+   Memcheck:Leak
+   ...
+   fun:g_slice_alloc
+   ...
+   fun:g_key_file_load_from_data
+   ...
+}
+{
+   <g_key_file_new 1>
+   Memcheck:Leak
+   ...
+   fun:g_slice_alloc
+   ...
+   fun:g_key_file_new
+   ...
+}
+{
+   <g_key_file_new 2>
+   Memcheck:Leak
+   fun:*alloc
+   ...
+   fun:g_key_file_new
+   fun:main
+}
+{
+   <connman plugin cleanup>
+   Memcheck:Leak
+   ...
+   fun:__connman_plugin_cleanup
+   ...
+}
+{
+   <cmd line option parsing>
+   Memcheck:Leak
+   fun:malloc
+   fun:g_malloc
+   fun:g_strdup
+   fun:g_set_prgname
+   fun:g_option_context_parse
+   fun:main
+}
+{
+   <dbus system bus setup 1>
+   Memcheck:Leak
+   ...
+   fun:dbus_malloc*
+   ...
+   fun:g_dbus_setup_bus
+   fun:main
+}
+{
+   <dbus system bus setup 2>
+   Memcheck:Leak
+   ...
+   fun:g_malloc*
+   ...
+   fun:dbus_connection_set_watch_functions
+   fun:setup_bus
+   ...
+}
+{
+   <key file get charset>
+   Memcheck:Leak
+   ...
+   fun:g_*alloc*
+   ...
+   fun:g_strerror
+   fun:g_key_file_load_from_file
+   fun:main
+}
+{
+   <dbus disconnect func set>
+   Memcheck:Leak
+   ...
+   fun:filter_data_get
+   fun:g_dbus_add_signal_watch
+   fun:g_dbus_set_disconnect_function
+   fun:main
+}
+{
+   <plugin dlopen>
+   Memcheck:Leak
+   ...
+   fun:dlopen
+   fun:__connman_plugin_init
+   fun:main
+}
+{
+   <dbus system bus setup 3>
+   Memcheck:Leak
+   ...
+   fun:dbus_malloc0
+   ...
+   fun:dbus_parse_address
+   ...
+   fun:g_dbus_setup_bus
+   fun:main
+}
+{
+   <libdbus internals 1>
+   Memcheck:Leak
+   fun:*malloc
+   ...
+   obj:/lib/libdbus-1.so.3.5.3
+}
+{
+   <dbus system bus setup 4>
+   Memcheck:Leak
+   fun:*alloc
+   ...
+   fun:dbus_*alloc*
+   ...
+   fun:g_dbus_setup_bus
+   fun:main
+}
+{
+   <dbus system bus setup 5>
+   Memcheck:Leak
+   fun:calloc
+   fun:g_malloc0
+   ...
+   fun:g_dbus_set_disconnect_function
+   fun:main
+}
+{
+   <dbus bus remove match>
+   Memcheck:Leak
+   fun:malloc
+   fun:g_malloc
+   fun:g_source_set_callback
+   fun:g_timeout_add_full
+   fun:g_timeout_add
+   ...
+   fun:dbus_pending_call_block
+   fun:dbus_connection_send_with_reply_and_block
+   ...
+   fun:dbus_bus_remove_match
+}
+{
+   <g_main_loop_run/new>
+   Memcheck:Leak
+   fun:*alloc
+   ...
+   fun:g_main_loop_*
+   fun:main
+}
+{
+   <g_main_context_dispatch>
+   Memcheck:Leak
+   fun:*alloc
+   ...
+   fun:g_main_context_dispatch
+}
+{
+   <libdbus internals 2>
+   Memcheck:Leak
+   fun:realloc
+   fun:dbus_realloc
+   ...
+   fun:dbus_message_set_reply_serial
+   fun:dbus_message_new_error
+   ...
+}
+{
+   <libdbus internals 3>
+   Memcheck:Leak
+   fun:realloc
+   fun:dbus_realloc
+   ...
+   fun:dbus_message_new_signal
+   ...
+}
+{
+   <dbus_bus_register>
+   Memcheck:Leak
+   fun:malloc
+   fun:realloc
+   fun:dbus_realloc
+   ...
+   fun:dbus_pending_call_block
+   fun:dbus_connection_send_with_reply_and_block
+   fun:dbus_bus_register
+}
diff --git a/doc/version.xml.in b/doc/version.xml.in
new file mode 100644
index 0000000..d78bda9
--- /dev/null
+++ b/doc/version.xml.in
@@ -0,0 +1 @@
+@VERSION@
diff --git a/doc/vpn-agent-api.txt b/doc/vpn-agent-api.txt
new file mode 100644
index 0000000..bdef9f3
--- /dev/null
+++ b/doc/vpn-agent-api.txt
@@ -0,0 +1,137 @@
+Agent hierarchy
+===============
+
+Service		unique name
+Interface	net.connman.vpn.Agent
+Object path	freely definable
+
+Methods		void Release()
+
+			This method gets called when the service daemon
+			unregisters the agent. An agent can use it to do
+			cleanup tasks. There is no need to unregister the
+			agent, because when this method gets called it has
+			already been unregistered.
+
+		void ReportError(object service, string error)
+
+			This method gets called when an error has to be
+			reported to the user.
+
+			A special return value can be used to trigger a
+			retry of the failed transaction.
+
+			Possible Errors: net.connman.vpn.Agent.Error.Retry
+
+		dict RequestInput(object service, dict fields)
+
+			This method gets called when trying to connect to
+			a service and some extra input is required. For
+			example a password or username.
+
+			The return value should be a dictionary where the
+			keys are the field names and the values are the
+			actual fields. Alternatively an error indicating that
+			the request got canceled can be returned.
+
+			Most common return field names are "Username" and of
+			course "Password".
+
+			The dictionary arguments contains field names with
+			their input parameters.
+
+			Possible Errors: net.connman.vpn.Agent.Error.Canceled
+
+		void Cancel()
+
+			This method gets called to indicate that the agent
+			request failed before a reply was returned.
+
+Fields		string Username
+
+			Username for authentication. This field will be
+			requested when connecting to L2TP and PPTP.
+
+		string Password
+
+			Password for authentication.
+
+		boolean SaveCredentials
+
+			Tells if the user wants the user credentials
+			be saved by connman-vpnd.
+
+		string Host
+
+			End point of this VPN link i.e., the VPN gateway
+			we are trying to connect to.
+
+		string Name
+
+			Name of the VPN connection we are trying to connect to.
+
+		string OpenConnect.Cookie
+
+			Return the OpenConnect cookie value that is used to
+			authenticate the user and is specific to this user.
+
+Arguments	string Type
+
+			Contains the type of a field. For example "password",
+			"response", "boolean" or plain "string".
+
+		string Requirement
+
+			Contains the requirement option. Valid values are
+			"mandatory", "optional", "alternate" or
+			"informational".
+
+			The "alternate" value specifies that this field can be
+			returned as an alternative to another one.
+
+			All "mandatory" fields must be returned, while the
+			"optional" can be returned if available.
+
+			Nothing needs to be returned for "informational", as it
+			is here only to provide an information so a value is
+			attached to it.
+
+		array{string} Alternates
+
+			Contains the list of alternate field names this
+			field can be represented by.
+
+		string Value
+
+			Contains data as a string, relatively to an
+			"informational" argument.
+
+Examples	Requesting a username and password for L2TP network
+
+			RequestInput("/vpn1",
+				{ "Username" : { "Type"        : "string",
+						 "Requirement" : "mandatory"
+						} }
+				{ "Password" : { "Type"        : "password",
+						 "Requirement" : "mandatory"
+						} }
+				{ "SaveCredentials" : { "Type" : "boolean",
+						"Requirement" : "optional"
+						}
+				}
+			==> { "Username" : "foo", "Password" : "secret123",
+				"SaveCredentials" : true }
+
+		Requesting a OpenConnect cookie
+
+			RequestInput("/vpn2",
+				{ "OpenConnect.Cookie" : { "Type" : "string",
+						 "Requirement" : "mandatory"
+							} }
+				{ "Host" : { "Type" : "string",
+					 "Requirement" : "informational"
+							} }
+				{ "Name" : { "Type" : "string",
+					 "Requirement" : "informational"
+							} }
+			==> { "OpenConnect.Cookie" : "0123456@adfsf@asasdf" }
diff --git a/doc/vpn-connection-api.txt b/doc/vpn-connection-api.txt
new file mode 100644
index 0000000..9faed8a
--- /dev/null
+++ b/doc/vpn-connection-api.txt
@@ -0,0 +1,166 @@
+vpn connection
+==============
+
+Service		net.connman.vpn
+Interface	net.connman.vpn.Connection
+Object path	[variable prefix]/{connection0,connection1,...}
+
+Method		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.
+
+			Possible Errors: [connection].Error.InvalidArguments
+					 [connection].Error.InvalidProperty
+
+		void ClearProperty(string name) [experimental]
+
+			Clears the value of the specified property.
+
+			Possible Errors: [connection].Error.InvalidArguments
+					 [connection].Error.InvalidProperty
+
+		void Connect() [experimental]
+
+			Connect this VPN connection. It will attempt to connect
+			to the VPN connection. The Connect() will wait until
+			the connection is created or there is an error. The
+			error description is returned in dbus error.
+
+			Possible Errors: [connection].Error.InvalidArguments
+					[connection].Error.InProgress
+
+		void Disconnect() [experimental]
+
+			Disconnect this VPN connection. If the connection is
+			not connected an error message will be generated.
+
+			Possible Errors: [connection].Error.InvalidArguments
+
+Signals		PropertyChanged(string name, variant value) [experimental]
+
+			This signal indicates a changed value of the given
+			property.
+
+Properties	string State [readonly]
+
+			The connection state information.
+
+			Valid states are "idle", "failure", "configuration",
+			"ready", "disconnect".
+
+		string Type [readonly]
+
+			The VPN type (for example "openvpn", "vpnc" etc.)
+
+		string Name [readonly]
+
+			The VPN name.
+
+		string Domain [readonly]
+
+			The domain name used behind the VPN connection.
+			This is optional for most VPN technologies.
+
+		string Host [readonly]
+
+		       The VPN host (server) address.
+
+		int Index [readonly]
+
+			The index of the VPN network tunneling interface.
+			If there is no tunneling device, then this value
+			is not returned.
+
+		dict IPv4 [readonly]
+
+			string Address
+
+			        The current configured IPv4 address.
+
+			string Netmask
+
+			       The current configured IPv4 netmask.
+
+			string Gateway
+
+			       The current configured IPv4 gateway.
+
+			string Peer
+
+			       The current configured VPN tunnel endpoint
+			       IPv4 address.
+
+		dict IPv6 [readonly]
+
+			string Address
+
+			        The current configured IPv6 address.
+
+			string PrefixLength
+
+			       The prefix length of the IPv6 address.
+
+			string Gateway
+
+			       The current configured IPv6 gateway.
+
+			string Peer
+
+			       The current configured VPN tunnel endpoint
+			       IPv6 address.
+
+		array{string} Nameservers [readonly]
+
+			The list of nameservers set by VPN.
+
+		array{dict} UserRoutes [readwrite]
+
+			int ProtocolFamily
+
+				Protocol family of the route. Set to 4
+				if IPv4 and 6 if IPv6 route.
+
+			string Network
+
+				The network part of the route.
+
+			string Netmask
+
+				The netmask of the route.
+
+			string Gateway
+
+				Gateway address of the route.
+
+			The list of currently active user activated
+			routes.
+
+		array{dict} ServerRoutes [readonly]
+
+			int ProtocolFamily
+
+				Protocol family of the route. Set to 4
+				if IPv4 and 6 if IPv6 route.
+
+			string Network
+
+				The network part of the route.
+
+			string Netmask
+
+				The netmask of the route.
+
+			string Gateway
+
+				Gateway address of the route.
+
+			The VPN server activated route. These routes
+			are pushed to connman by VPN server.
+
+		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
+		are mentioned in this document.
diff --git a/doc/vpn-manager-api.txt b/doc/vpn-manager-api.txt
new file mode 100644
index 0000000..66c5bee
--- /dev/null
+++ b/doc/vpn-manager-api.txt
@@ -0,0 +1,50 @@
+vpn manager
+===========
+
+Service		net.connman.vpn
+Interface	net.connman.vpn.Manager
+Object path	/
+
+Method		object Create(dict settings) [experimental]
+
+			Create a new VPN connection and configuration using
+			the supplied settings.
+
+		void Remove(object vpn)  [experimental]
+
+			Remove the previously created VPN configuration.
+
+		array{object,dict} GetConnections()  [experimental]
+
+			Returns a list of tuples with VPN connection object
+			path and dictionary of their properties.
+
+			Possible Errors: [manager].Error.InvalidArguments
+
+		void RegisterAgent(object path)  [experimental]
+
+			Register new agent for handling user requests.
+
+			Possible Errors: [manager].Error.InvalidArguments
+
+		void UnregisterAgent(object path)  [experimental]
+
+			Unregister an existing agent.
+
+			Possible Errors: [manager].Error.InvalidArguments
+
+Signals		ConnectionAdded(object path, dict properties)  [experimental]
+
+			Signal that is sent when a new VPN connection
+			is added.
+
+			It contains the object path of the VPN connection
+			and also its properties.
+
+		ConnectionRemoved(object path)  [experimental]
+
+			Signal that is sent when a VPN connection
+			has been removed.
+
+			The object path is no longer accessible after this
+			signal and only emitted for reference.
diff --git a/doc/vpn-overview.txt b/doc/vpn-overview.txt
new file mode 100644
index 0000000..42b6e94
--- /dev/null
+++ b/doc/vpn-overview.txt
@@ -0,0 +1,60 @@
+VPN daemon overview
+*******************
+
+
+Manager interface
+=================
+
+Manager interface described in vpn-manager-api.txt is to be used
+by both the connectivity UI and by ConnMan. The Create(),
+Remove(), RegisterAgent() and UnregisterAgent() functions are for
+UI usage. The GetConnections() method and ConnectionAdded() and
+ConnectionRemoved() signals are for ConnMan VPN plugin to use.
+
+The UI should use the methods like this:
+- Ask VPN properties (like certs, usernames etc) from the user.
+- Call Manager.Create() to create a VPN connection (note that
+  the system does not yet try to connect to VPN at this point)
+- Register an agent to vpnd so that vpnd can ask any extra
+  parameters etc from the user if needed.
+- If the user wants to connect to VPN gateway, then the
+  connection attempt should be done in ConnMan side as
+  there will be a service created there.
+- If the user wishes to remove the VPN configuration, the UI
+  can call the Manager.Remove() which removes the VPN connection.
+  If the VPN was in use, the VPN connection is also disconnected.
+- When UI is terminated, the UI should call the UnregisterAgent()
+
+The ConnMan calls VPN daemon like this:
+- There is a VPN plugin which at startup starts to listen the
+  ConnectionAdded() and ConnectionRemoved() signals.
+- The VPN plugin will call GetConnections() in order to get
+  available VPN connections. It will then create a provider service
+  for each VPN connection that is returned.
+- User can then connect to the VPN by calling the service Connect()
+  method
+- The existing ConnMan Manager.ConnectProvider() interface can still
+  work by calling vpn.Manager.Create() and then call vpn.Connection.Connect()
+  but this ConnectProvider() interface will be deprecated at some
+  point.
+
+
+
+Connection interface
+====================
+
+The Manager.Create() will return the object path of the created
+vpn.Connection object and place it in idle state. Note that
+vpn.Connection.PropertyChanged signal is not called when Connection
+object is created because the same parameters are returned via
+vpn.Manager.ConnectionAdded() signal.
+The vpn.Connection object can be connected using the Connect() method
+and disconnected by calling Disconnect() method. When the connection
+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
+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.
diff --git a/gdbus/client.c b/gdbus/client.c
new file mode 100644
index 0000000..c03e3a4
--- /dev/null
+++ b/gdbus/client.c
@@ -0,0 +1,1350 @@
+/*
+ *
+ *  D-Bus helper library
+ *
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <dbus/dbus.h>
+
+#include "gdbus.h"
+
+#define METHOD_CALL_TIMEOUT (300 * 1000)
+
+struct GDBusClient {
+	gint ref_count;
+	DBusConnection *dbus_conn;
+	char *service_name;
+	char *unique_name;
+	char *base_path;
+	GPtrArray *match_rules;
+	DBusPendingCall *pending_call;
+	GDBusWatchFunction connect_func;
+	void *connect_data;
+	GDBusWatchFunction disconn_func;
+	void *disconn_data;
+	GDBusMessageFunction signal_func;
+	void *signal_data;
+	GDBusProxyFunction proxy_added;
+	GDBusProxyFunction proxy_removed;
+	GDBusPropertyFunction property_changed;
+	void *user_data;
+	GList *proxy_list;
+};
+
+struct GDBusProxy {
+	gint ref_count;
+	GDBusClient *client;
+	char *obj_path;
+	char *interface;
+	GHashTable *prop_list;
+	char *match_rule;
+	GDBusPropertyFunction prop_func;
+	void *prop_data;
+};
+
+struct prop_entry {
+	char *name;
+	int type;
+	DBusMessage *msg;
+};
+
+static void modify_match_reply(DBusPendingCall *call, void *user_data)
+{
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError error;
+
+	dbus_error_init(&error);
+
+	if (dbus_set_error_from_message(&error, reply) == TRUE)
+		dbus_error_free(&error);
+
+	dbus_message_unref(reply);
+}
+
+static gboolean modify_match(DBusConnection *conn, const char *member,
+							const char *rule)
+{
+	DBusMessage *msg;
+	DBusPendingCall *call;
+
+	msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+					DBUS_INTERFACE_DBUS, member);
+	if (msg == NULL)
+		return FALSE;
+
+	dbus_message_append_args(msg, DBUS_TYPE_STRING, &rule,
+						DBUS_TYPE_INVALID);
+
+	if (dbus_connection_send_with_reply(conn, msg, &call, -1) == FALSE) {
+		dbus_message_unref(msg);
+		return FALSE;
+	}
+
+	dbus_pending_call_set_notify(call, modify_match_reply, NULL, NULL);
+	dbus_pending_call_unref(call);
+
+	dbus_message_unref(msg);
+
+	return TRUE;
+}
+
+static void iter_append_iter(DBusMessageIter *base, DBusMessageIter *iter)
+{
+	int type;
+
+	type = dbus_message_iter_get_arg_type(iter);
+
+	if (dbus_type_is_basic(type)) {
+		const void *value;
+
+		dbus_message_iter_get_basic(iter, &value);
+		dbus_message_iter_append_basic(base, type, &value);
+	} else if (dbus_type_is_container(type)) {
+		DBusMessageIter iter_sub, base_sub;
+		char *sig;
+
+		dbus_message_iter_recurse(iter, &iter_sub);
+
+		switch (type) {
+		case DBUS_TYPE_ARRAY:
+		case DBUS_TYPE_VARIANT:
+			sig = dbus_message_iter_get_signature(&iter_sub);
+			break;
+		default:
+			sig = NULL;
+			break;
+		}
+
+		dbus_message_iter_open_container(base, type, sig, &base_sub);
+
+		if (sig != NULL)
+			dbus_free(sig);
+
+		while (dbus_message_iter_get_arg_type(&iter_sub) !=
+							DBUS_TYPE_INVALID) {
+			iter_append_iter(&base_sub, &iter_sub);
+			dbus_message_iter_next(&iter_sub);
+		}
+
+		dbus_message_iter_close_container(base, &base_sub);
+	}
+}
+
+static void prop_entry_update(struct prop_entry *prop, DBusMessageIter *iter)
+{
+	DBusMessage *msg;
+	DBusMessageIter base;
+
+	msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &base);
+	iter_append_iter(&base, iter);
+
+	if (prop->msg != NULL)
+		dbus_message_unref(prop->msg);
+
+	prop->msg = dbus_message_copy(msg);
+	dbus_message_unref(msg);
+}
+
+static struct prop_entry *prop_entry_new(const char *name,
+						DBusMessageIter *iter)
+{
+	struct prop_entry *prop;
+
+	prop = g_try_new0(struct prop_entry, 1);
+	if (prop == NULL)
+		return NULL;
+
+	prop->name = g_strdup(name);
+	prop->type = dbus_message_iter_get_arg_type(iter);
+
+	prop_entry_update(prop, iter);
+
+	return prop;
+}
+
+static void prop_entry_free(gpointer data)
+{
+	struct prop_entry *prop = data;
+
+	if (prop->msg != NULL)
+		dbus_message_unref(prop->msg);
+
+	g_free(prop->name);
+
+	g_free(prop);
+}
+
+static void add_property(GDBusProxy *proxy, const char *name,
+						DBusMessageIter *iter)
+{
+	DBusMessageIter value;
+	struct prop_entry *prop;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
+		return;
+
+	dbus_message_iter_recurse(iter, &value);
+
+	prop = g_hash_table_lookup(proxy->prop_list, name);
+	if (prop != NULL) {
+		GDBusClient *client = proxy->client;
+
+		prop_entry_update(prop, &value);
+
+		if (proxy->prop_func)
+			proxy->prop_func(proxy, name, &value, proxy->prop_data);
+
+		if (client == NULL)
+			return;
+
+		if (client->property_changed)
+			client->property_changed(proxy, name, &value,
+							client->user_data);
+		return;
+	}
+
+	prop = prop_entry_new(name, &value);
+	if (prop == NULL)
+		return;
+
+	g_hash_table_replace(proxy->prop_list, prop->name, prop);
+
+	if (proxy->prop_func)
+		proxy->prop_func(proxy, name, &value, proxy->prop_data);
+}
+
+static void update_properties(GDBusProxy *proxy, DBusMessageIter *iter)
+{
+	DBusMessageIter dict;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+		return;
+
+	dbus_message_iter_recurse(iter, &dict);
+
+	while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+		DBusMessageIter entry;
+		const char *name;
+
+		dbus_message_iter_recurse(&dict, &entry);
+
+		if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+			break;
+
+		dbus_message_iter_get_basic(&entry, &name);
+		dbus_message_iter_next(&entry);
+
+		add_property(proxy, name, &entry);
+
+		dbus_message_iter_next(&dict);
+	}
+}
+
+static void get_all_properties_reply(DBusPendingCall *call, void *user_data)
+{
+	GDBusProxy *proxy = user_data;
+	GDBusClient *client = proxy->client;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusMessageIter iter;
+	DBusError error;
+
+	dbus_error_init(&error);
+
+	if (dbus_set_error_from_message(&error, reply) == TRUE) {
+		dbus_error_free(&error);
+		goto done;
+	}
+
+	dbus_message_iter_init(reply, &iter);
+
+	update_properties(proxy, &iter);
+
+done:
+	if (g_list_find(client->proxy_list, proxy) == NULL) {
+		if (client->proxy_added)
+			client->proxy_added(proxy, client->user_data);
+
+		client->proxy_list = g_list_append(client->proxy_list, proxy);
+	}
+
+	dbus_message_unref(reply);
+
+	g_dbus_client_unref(client);
+}
+
+static void get_all_properties(GDBusProxy *proxy)
+{
+	GDBusClient *client = proxy->client;
+	const char *service_name = client->service_name;
+	DBusMessage *msg;
+	DBusPendingCall *call;
+
+	msg = dbus_message_new_method_call(service_name, proxy->obj_path,
+					DBUS_INTERFACE_PROPERTIES, "GetAll");
+	if (msg == NULL)
+		return;
+
+	dbus_message_append_args(msg, DBUS_TYPE_STRING, &proxy->interface,
+							DBUS_TYPE_INVALID);
+
+	if (dbus_connection_send_with_reply(client->dbus_conn, msg,
+							&call, -1) == FALSE) {
+		dbus_message_unref(msg);
+		return;
+	}
+
+	g_dbus_client_ref(client);
+
+	dbus_pending_call_set_notify(call, get_all_properties_reply,
+							proxy, NULL);
+	dbus_pending_call_unref(call);
+
+	dbus_message_unref(msg);
+}
+
+static GDBusProxy *proxy_lookup(GDBusClient *client, const char *path,
+						const char *interface)
+{
+	GList *list;
+
+	for (list = g_list_first(client->proxy_list); list;
+						list = g_list_next(list)) {
+		GDBusProxy *proxy = list->data;
+
+		if (g_str_equal(proxy->interface, interface) == TRUE &&
+				g_str_equal(proxy->obj_path, path) == TRUE)
+			return proxy;
+        }
+
+	return NULL;
+}
+
+static GDBusProxy *proxy_new(GDBusClient *client, const char *path,
+						const char *interface)
+{
+	GDBusProxy *proxy;
+
+	proxy = g_try_new0(GDBusProxy, 1);
+	if (proxy == NULL)
+		return NULL;
+
+	proxy->client = client;
+	proxy->obj_path = g_strdup(path);
+	proxy->interface = g_strdup(interface);
+
+	proxy->prop_list = g_hash_table_new_full(g_str_hash, g_str_equal,
+							NULL, prop_entry_free);
+
+	proxy->match_rule = g_strdup_printf("type='signal',"
+				"sender='%s',path='%s',interface='%s',"
+				"member='PropertiesChanged',arg0='%s'",
+				client->service_name, proxy->obj_path,
+				DBUS_INTERFACE_PROPERTIES, proxy->interface);
+
+	modify_match(client->dbus_conn, "AddMatch", proxy->match_rule);
+
+	return g_dbus_proxy_ref(proxy);
+}
+
+static void proxy_free(gpointer data)
+{
+	GDBusProxy *proxy = data;
+
+	if (proxy->client) {
+		GDBusClient *client = proxy->client;
+
+		if (client->proxy_removed)
+			client->proxy_removed(proxy, client->user_data);
+
+		modify_match(client->dbus_conn, "RemoveMatch",
+							proxy->match_rule);
+
+		g_free(proxy->match_rule);
+		proxy->match_rule = NULL;
+
+		g_hash_table_remove_all(proxy->prop_list);
+
+		proxy->client = NULL;
+	}
+
+	g_dbus_proxy_unref(proxy);
+}
+
+static void proxy_remove(GDBusClient *client, const char *path,
+						const char *interface)
+{
+	GList *list;
+
+	for (list = g_list_first(client->proxy_list); list;
+						list = g_list_next(list)) {
+		GDBusProxy *proxy = list->data;
+
+		if (g_str_equal(proxy->interface, interface) == TRUE &&
+				g_str_equal(proxy->obj_path, path) == TRUE) {
+			client->proxy_list =
+				g_list_delete_link(client->proxy_list, list);
+			proxy_free(proxy);
+			break;
+		}
+	}
+}
+
+GDBusProxy *g_dbus_proxy_new(GDBusClient *client, const char *path,
+							const char *interface)
+{
+	GDBusProxy *proxy;
+
+	if (client == NULL)
+		return NULL;
+
+	proxy = proxy_lookup(client, path, interface);
+	if (proxy)
+		return g_dbus_proxy_ref(proxy);
+
+	proxy = proxy_new(client, path, interface);
+	if (proxy == NULL)
+		return NULL;
+
+	get_all_properties(proxy);
+
+	return g_dbus_proxy_ref(proxy);
+}
+
+GDBusProxy *g_dbus_proxy_ref(GDBusProxy *proxy)
+{
+	if (proxy == NULL)
+		return NULL;
+
+	g_atomic_int_inc(&proxy->ref_count);
+
+	return proxy;
+}
+
+void g_dbus_proxy_unref(GDBusProxy *proxy)
+{
+	if (proxy == NULL)
+		return;
+
+	if (g_atomic_int_dec_and_test(&proxy->ref_count) == FALSE)
+		return;
+
+	g_hash_table_destroy(proxy->prop_list);
+
+	g_free(proxy->obj_path);
+	g_free(proxy->interface);
+
+	g_free(proxy);
+}
+
+const char *g_dbus_proxy_get_path(GDBusProxy *proxy)
+{
+	if (proxy == NULL)
+		return NULL;
+
+	return proxy->obj_path;
+}
+
+const char *g_dbus_proxy_get_interface(GDBusProxy *proxy)
+{
+	if (proxy == NULL)
+		return NULL;
+
+	return proxy->interface;
+}
+
+gboolean g_dbus_proxy_get_property(GDBusProxy *proxy, const char *name,
+                                                        DBusMessageIter *iter)
+{
+	struct prop_entry *prop;
+
+	if (proxy == NULL || name == NULL)
+		return FALSE;
+
+	prop = g_hash_table_lookup(proxy->prop_list, name);
+	if (prop == NULL)
+		return FALSE;
+
+	if (prop->msg == NULL)
+		return FALSE;
+
+	if (dbus_message_iter_init(prop->msg, iter) == FALSE)
+		return FALSE;
+
+	return TRUE;
+}
+
+struct refresh_property_data {
+	GDBusProxy *proxy;
+	char *name;
+};
+
+static void refresh_property_free(gpointer user_data)
+{
+	struct refresh_property_data *data = user_data;
+
+	g_free(data->name);
+	g_free(data);
+}
+
+static void refresh_property_reply(DBusPendingCall *call, void *user_data)
+{
+	struct refresh_property_data *data = user_data;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError error;
+
+	dbus_error_init(&error);
+
+	if (dbus_set_error_from_message(&error, reply) == FALSE) {
+		DBusMessageIter iter;
+
+		dbus_message_iter_init(reply, &iter);
+
+		add_property(data->proxy, data->name, &iter);
+	} else
+		dbus_error_free(&error);
+
+	dbus_message_unref(reply);
+}
+
+gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name)
+{
+	struct refresh_property_data *data;
+	GDBusClient *client;
+	DBusMessage *msg;
+	DBusMessageIter iter;
+	DBusPendingCall *call;
+
+	if (proxy == NULL || name == NULL)
+		return FALSE;
+
+	client = proxy->client;
+	if (client == NULL)
+		return FALSE;
+
+	data = g_try_new0(struct refresh_property_data, 1);
+	if (data == NULL)
+		return FALSE;
+
+	data->proxy = proxy;
+	data->name = g_strdup(name);
+
+	msg = dbus_message_new_method_call(client->service_name,
+			proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Get");
+	if (msg == NULL) {
+		refresh_property_free(data);
+		return FALSE;
+	}
+
+	dbus_message_iter_init_append(msg, &iter);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
+							&proxy->interface);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
+
+	if (dbus_connection_send_with_reply(client->dbus_conn, msg,
+							&call, -1) == FALSE) {
+		dbus_message_unref(msg);
+		refresh_property_free(data);
+		return FALSE;
+	}
+
+	dbus_pending_call_set_notify(call, refresh_property_reply,
+						data, refresh_property_free);
+	dbus_pending_call_unref(call);
+
+	dbus_message_unref(msg);
+
+	return TRUE;
+}
+
+struct set_property_data {
+	GDBusResultFunction function;
+	void *user_data;
+	GDBusDestroyFunction destroy;
+};
+
+static void set_property_reply(DBusPendingCall *call, void *user_data)
+{
+	struct set_property_data *data = user_data;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError error;
+
+	dbus_error_init(&error);
+
+	dbus_set_error_from_message(&error, reply);
+
+	if (data->function)
+		data->function(&error, data->user_data);
+
+	if (data->destroy)
+		data->destroy(data->user_data);
+
+	dbus_error_free(&error);
+
+	dbus_message_unref(reply);
+}
+
+gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
+				const char *name, int type, const void *value,
+				GDBusResultFunction function, void *user_data,
+				GDBusDestroyFunction destroy)
+{
+	struct set_property_data *data;
+	GDBusClient *client;
+	DBusMessage *msg;
+	DBusMessageIter iter, variant;
+	DBusPendingCall *call;
+	char type_as_str[2];
+
+	if (proxy == NULL || name == NULL || value == NULL)
+		return FALSE;
+
+	if (dbus_type_is_basic(type) == FALSE)
+		return FALSE;
+
+	client = proxy->client;
+	if (client == NULL)
+		return FALSE;
+
+	data = g_try_new0(struct set_property_data, 1);
+	if (data == NULL)
+		return FALSE;
+
+	data->function = function;
+	data->user_data = user_data;
+	data->destroy = destroy;
+
+	msg = dbus_message_new_method_call(client->service_name,
+			proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Set");
+	if (msg == NULL) {
+		g_free(data);
+		return FALSE;
+	}
+
+	type_as_str[0] = (char) type;
+	type_as_str[1] = '\0';
+
+	dbus_message_iter_init_append(msg, &iter);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
+							&proxy->interface);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+						type_as_str, &variant);
+	dbus_message_iter_append_basic(&variant, type, value);
+	dbus_message_iter_close_container(&iter, &variant);
+
+	if (dbus_connection_send_with_reply(client->dbus_conn, msg,
+							&call, -1) == FALSE) {
+		dbus_message_unref(msg);
+		g_free(data);
+		return FALSE;
+	}
+
+	dbus_pending_call_set_notify(call, set_property_reply, data, g_free);
+	dbus_pending_call_unref(call);
+
+	dbus_message_unref(msg);
+
+	return TRUE;
+}
+
+struct method_call_data {
+	GDBusReturnFunction function;
+	void *user_data;
+	GDBusDestroyFunction destroy;
+};
+
+static void method_call_reply(DBusPendingCall *call, void *user_data)
+{
+	struct method_call_data *data = user_data;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+
+	if (data->function)
+		data->function(reply, data->user_data);
+
+	if (data->destroy)
+		data->destroy(data->user_data);
+
+	dbus_message_unref(reply);
+}
+
+gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method,
+				GDBusSetupFunction setup,
+				GDBusReturnFunction function, void *user_data,
+				GDBusDestroyFunction destroy)
+{
+	struct method_call_data *data;
+	GDBusClient *client;
+	DBusMessage *msg;
+	DBusPendingCall *call;
+
+	if (proxy == NULL || method == NULL)
+		return FALSE;
+
+	client = proxy->client;
+	if (client == NULL)
+		return FALSE;
+
+	data = g_try_new0(struct method_call_data, 1);
+	if (data == NULL)
+		return FALSE;
+
+	data->function = function;
+	data->user_data = user_data;
+	data->destroy = destroy;
+
+	msg = dbus_message_new_method_call(client->service_name,
+				proxy->obj_path, proxy->interface, method);
+	if (msg == NULL) {
+		g_free(data);
+		return FALSE;
+	}
+
+	if (setup) {
+		DBusMessageIter iter;
+
+		dbus_message_iter_init_append(msg, &iter);
+		setup(&iter, data->user_data);
+	}
+
+	if (dbus_connection_send_with_reply(client->dbus_conn, msg,
+					&call, METHOD_CALL_TIMEOUT) == FALSE) {
+		dbus_message_unref(msg);
+		g_free(data);
+		return FALSE;
+	}
+
+	dbus_pending_call_set_notify(call, method_call_reply, data, g_free);
+	dbus_pending_call_unref(call);
+
+	dbus_message_unref(msg);
+
+	return TRUE;
+}
+
+gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy,
+			GDBusPropertyFunction function, void *user_data)
+{
+	if (proxy == NULL)
+		return FALSE;
+
+	proxy->prop_func = function;
+	proxy->prop_data = user_data;
+
+	return TRUE;
+}
+
+static void refresh_properties(GDBusClient *client)
+{
+	GList *list;
+
+	for (list = g_list_first(client->proxy_list); list;
+						list = g_list_next(list)) {
+		GDBusProxy *proxy = list->data;
+
+		get_all_properties(proxy);
+        }
+}
+
+static void properties_changed(GDBusClient *client, const char *path,
+							DBusMessage *msg)
+{
+	GDBusProxy *proxy = NULL;
+	DBusMessageIter iter, entry;
+	const char *interface;
+	GList *list;
+
+	if (dbus_message_iter_init(msg, &iter) == FALSE)
+		return;
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+		return;
+
+	dbus_message_iter_get_basic(&iter, &interface);
+	dbus_message_iter_next(&iter);
+
+	for (list = g_list_first(client->proxy_list); list;
+						list = g_list_next(list)) {
+		GDBusProxy *data = list->data;
+
+		if (g_str_equal(data->interface, interface) == TRUE &&
+				g_str_equal(data->obj_path, path) == TRUE) {
+			proxy = data;
+			break;
+		}
+	}
+
+	if (proxy == NULL)
+		return;
+
+	update_properties(proxy, &iter);
+
+	dbus_message_iter_next(&iter);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+		return;
+
+	dbus_message_iter_recurse(&iter, &entry);
+
+	while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
+		const char *name;
+
+		dbus_message_iter_get_basic(&entry, &name);
+
+		g_hash_table_remove(proxy->prop_list, name);
+
+		if (proxy->prop_func)
+			proxy->prop_func(proxy, name, NULL, proxy->prop_data);
+
+		if (client->property_changed)
+			client->property_changed(proxy, name, NULL,
+							client->user_data);
+
+		dbus_message_iter_next(&entry);
+	}
+}
+
+static void parse_properties(GDBusClient *client, const char *path,
+				const char *interface, DBusMessageIter *iter)
+{
+	GDBusProxy *proxy;
+
+	if (g_str_equal(interface, DBUS_INTERFACE_INTROSPECTABLE) == TRUE)
+		return;
+
+	if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE)
+		return;
+
+	proxy = proxy_lookup(client, path, interface);
+	if (proxy) {
+		update_properties(proxy, iter);
+		return;
+	}
+
+	proxy = proxy_new(client, path, interface);
+	if (proxy == NULL)
+		return;
+
+	update_properties(proxy, iter);
+
+	if (client->proxy_added)
+		client->proxy_added(proxy, client->user_data);
+
+	client->proxy_list = g_list_append(client->proxy_list, proxy);
+}
+
+static void parse_interfaces(GDBusClient *client, const char *path,
+						DBusMessageIter *iter)
+{
+	DBusMessageIter dict;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+		return;
+
+	dbus_message_iter_recurse(iter, &dict);
+
+	while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+		DBusMessageIter entry;
+		const char *interface;
+
+		dbus_message_iter_recurse(&dict, &entry);
+
+		if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+			break;
+
+		dbus_message_iter_get_basic(&entry, &interface);
+		dbus_message_iter_next(&entry);
+
+		parse_properties(client, path, interface, &entry);
+
+		dbus_message_iter_next(&dict);
+	}
+}
+
+static void interfaces_added(GDBusClient *client, DBusMessage *msg)
+{
+	DBusMessageIter iter;
+	const char *path;
+
+	if (dbus_message_iter_init(msg, &iter) == FALSE)
+		return;
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
+		return;
+
+	dbus_message_iter_get_basic(&iter, &path);
+	dbus_message_iter_next(&iter);
+
+	g_dbus_client_ref(client);
+
+	parse_interfaces(client, path, &iter);
+
+	g_dbus_client_unref(client);
+}
+
+static void interfaces_removed(GDBusClient *client, DBusMessage *msg)
+{
+	DBusMessageIter iter, entry;
+	const char *path;
+
+	if (dbus_message_iter_init(msg, &iter) == FALSE)
+		return;
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
+		return;
+
+	dbus_message_iter_get_basic(&iter, &path);
+	dbus_message_iter_next(&iter);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+		return;
+
+	dbus_message_iter_recurse(&iter, &entry);
+
+	g_dbus_client_ref(client);
+
+	while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
+		const char *interface;
+
+		dbus_message_iter_get_basic(&entry, &interface);
+		proxy_remove(client, path, interface);
+		dbus_message_iter_next(&entry);
+	}
+
+	g_dbus_client_unref(client);
+}
+
+static void parse_managed_objects(GDBusClient *client, DBusMessage *msg)
+{
+	DBusMessageIter iter, dict;
+
+	if (dbus_message_iter_init(msg, &iter) == FALSE)
+		return;
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+		return;
+
+	dbus_message_iter_recurse(&iter, &dict);
+
+	while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+		DBusMessageIter entry;
+		const char *path;
+
+		dbus_message_iter_recurse(&dict, &entry);
+
+		if (dbus_message_iter_get_arg_type(&entry) !=
+							DBUS_TYPE_OBJECT_PATH)
+			break;
+
+		dbus_message_iter_get_basic(&entry, &path);
+		dbus_message_iter_next(&entry);
+
+		parse_interfaces(client, path, &entry);
+
+		dbus_message_iter_next(&dict);
+	}
+}
+
+static void get_managed_objects_reply(DBusPendingCall *call, void *user_data)
+{
+	GDBusClient *client = user_data;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError error;
+
+	dbus_error_init(&error);
+
+	if (dbus_set_error_from_message(&error, reply) == TRUE) {
+		dbus_error_free(&error);
+		goto done;
+	}
+
+	parse_managed_objects(client, reply);
+
+done:
+	dbus_message_unref(reply);
+
+	g_dbus_client_unref(client);
+}
+
+static void get_managed_objects(GDBusClient *client)
+{
+	DBusMessage *msg;
+	DBusPendingCall *call;
+
+	if (!client->proxy_added && !client->proxy_removed) {
+		refresh_properties(client);
+		return;
+	}
+
+	msg = dbus_message_new_method_call(client->service_name, "/",
+					DBUS_INTERFACE_DBUS ".ObjectManager",
+							"GetManagedObjects");
+	if (msg == NULL)
+		return;
+
+	dbus_message_append_args(msg, DBUS_TYPE_INVALID);
+
+	if (dbus_connection_send_with_reply(client->dbus_conn, msg,
+							&call, -1) == FALSE) {
+		dbus_message_unref(msg);
+		return;
+	}
+
+	g_dbus_client_ref(client);
+
+	dbus_pending_call_set_notify(call, get_managed_objects_reply,
+							client, NULL);
+	dbus_pending_call_unref(call);
+
+	dbus_message_unref(msg);
+}
+
+static void get_name_owner_reply(DBusPendingCall *call, void *user_data)
+{
+	GDBusClient *client = user_data;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError error;
+	const char *name;
+
+	g_dbus_client_ref(client);
+
+	dbus_error_init(&error);
+
+	if (dbus_set_error_from_message(&error, reply) == TRUE) {
+		dbus_error_free(&error);
+		goto done;
+	}
+
+	if (dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &name,
+						DBUS_TYPE_INVALID) == FALSE)
+		goto done;
+
+	if (client->unique_name == NULL) {
+		client->unique_name = g_strdup(name);
+
+		if (client->connect_func)
+			client->connect_func(client->dbus_conn,
+							client->connect_data);
+
+		get_managed_objects(client);
+	}
+
+done:
+	dbus_message_unref(reply);
+
+	dbus_pending_call_unref(client->pending_call);
+	client->pending_call = NULL;
+
+	g_dbus_client_unref(client);
+}
+
+static void get_name_owner(GDBusClient *client, const char *name)
+{
+	DBusMessage *msg;
+
+	msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+					DBUS_INTERFACE_DBUS, "GetNameOwner");
+	if (msg == NULL)
+		return;
+
+	dbus_message_append_args(msg, DBUS_TYPE_STRING, &name,
+						DBUS_TYPE_INVALID);
+
+	if (dbus_connection_send_with_reply(client->dbus_conn, msg,
+					&client->pending_call, -1) == FALSE) {
+		dbus_message_unref(msg);
+		return;
+	}
+
+	dbus_pending_call_set_notify(client->pending_call,
+					get_name_owner_reply, client, NULL);
+
+	dbus_message_unref(msg);
+}
+
+static DBusHandlerResult message_filter(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	GDBusClient *client = user_data;
+	const char *sender;
+
+	if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+	sender = dbus_message_get_sender(message);
+
+	if (g_str_equal(sender, DBUS_SERVICE_DBUS) == TRUE) {
+		const char *interface, *member;
+		const char *name, *old, *new;
+
+		interface = dbus_message_get_interface(message);
+
+		if (g_str_equal(interface, DBUS_INTERFACE_DBUS) == FALSE)
+			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+		member = dbus_message_get_member(message);
+
+		if (g_str_equal(member, "NameOwnerChanged") == FALSE)
+			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+		if (dbus_message_get_args(message, NULL,
+						DBUS_TYPE_STRING, &name,
+						DBUS_TYPE_STRING, &old,
+						DBUS_TYPE_STRING, &new,
+						DBUS_TYPE_INVALID) == FALSE)
+			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+		if (g_str_equal(name, client->service_name) == FALSE)
+			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+		if (*new == '\0' && client->unique_name != NULL &&
+				g_str_equal(old, client->unique_name) == TRUE) {
+			if (client->disconn_func)
+				client->disconn_func(client->dbus_conn,
+							client->disconn_data);
+
+			g_free(client->unique_name);
+			client->unique_name = NULL;
+		} else if (*old == '\0' && client->unique_name == NULL) {
+			client->unique_name = g_strdup(new);
+
+			if (client->connect_func)
+				client->connect_func(client->dbus_conn,
+							client->connect_data);
+
+			get_managed_objects(client);
+		}
+
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+	}
+
+	if (client->unique_name == NULL)
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+	if (g_str_equal(sender, client->unique_name) == TRUE) {
+		const char *path, *interface, *member;
+
+		path = dbus_message_get_path(message);
+		interface = dbus_message_get_interface(message);
+		member = dbus_message_get_member(message);
+
+		if (g_str_equal(path, "/") == TRUE) {
+			if (g_str_equal(interface, DBUS_INTERFACE_DBUS
+						".ObjectManager") == FALSE)
+				return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+			if (g_str_equal(member, "InterfacesAdded") == TRUE) {
+				interfaces_added(client, message);
+				return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+			}
+
+			if (g_str_equal(member, "InterfacesRemoved") == TRUE) {
+				interfaces_removed(client, message);
+				return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+			}
+
+			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+		}
+
+		if (g_str_has_prefix(path, client->base_path) == FALSE)
+			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+		if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE) {
+			if (g_str_equal(member, "PropertiesChanged") == TRUE)
+				properties_changed(client, path, message);
+
+			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+		}
+
+		if (client->signal_func)
+			client->signal_func(client->dbus_conn,
+					message, client->signal_data);
+	}
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+GDBusClient *g_dbus_client_new(DBusConnection *connection,
+					const char *service, const char *path)
+{
+	GDBusClient *client;
+	unsigned int i;
+
+	if (connection == NULL)
+		return NULL;
+
+	client = g_try_new0(GDBusClient, 1);
+	if (client == NULL)
+		return NULL;
+
+	if (dbus_connection_add_filter(connection, message_filter,
+						client, NULL) == FALSE) {
+		g_free(client);
+		return NULL;
+	}
+
+	client->dbus_conn = dbus_connection_ref(connection);
+	client->service_name = g_strdup(service);
+	client->base_path = g_strdup(path);
+
+	get_name_owner(client, client->service_name);
+
+	client->match_rules = g_ptr_array_sized_new(4);
+	g_ptr_array_set_free_func(client->match_rules, g_free);
+
+	g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
+				"sender='%s',path='%s',interface='%s',"
+				"member='NameOwnerChanged',arg0='%s'",
+				DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+				DBUS_INTERFACE_DBUS, client->service_name));
+	g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
+				"sender='%s',"
+				"path='/',interface='%s.ObjectManager',"
+				"member='InterfacesAdded'",
+				client->service_name, DBUS_INTERFACE_DBUS));
+	g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
+				"sender='%s',"
+				"path='/',interface='%s.ObjectManager',"
+				"member='InterfacesRemoved'",
+				client->service_name, DBUS_INTERFACE_DBUS));
+	g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
+				"sender='%s',path_namespace='%s'",
+				client->service_name, client->base_path));
+
+	for (i = 0; i < client->match_rules->len; i++) {
+		modify_match(client->dbus_conn, "AddMatch",
+				g_ptr_array_index(client->match_rules, i));
+	}
+
+	return g_dbus_client_ref(client);
+}
+
+GDBusClient *g_dbus_client_ref(GDBusClient *client)
+{
+	if (client == NULL)
+		return NULL;
+
+	g_atomic_int_inc(&client->ref_count);
+
+	return client;
+}
+
+void g_dbus_client_unref(GDBusClient *client)
+{
+	unsigned int i;
+
+	if (client == NULL)
+		return;
+
+	if (g_atomic_int_dec_and_test(&client->ref_count) == FALSE)
+		return;
+
+	if (client->pending_call != NULL) {
+		dbus_pending_call_cancel(client->pending_call);
+		dbus_pending_call_unref(client->pending_call);
+	}
+
+	for (i = 0; i < client->match_rules->len; i++) {
+		modify_match(client->dbus_conn, "RemoveMatch",
+				g_ptr_array_index(client->match_rules, i));
+	}
+
+	g_ptr_array_free(client->match_rules, TRUE);
+
+	dbus_connection_remove_filter(client->dbus_conn,
+						message_filter, client);
+
+	g_list_free_full(client->proxy_list, proxy_free);
+
+	if (client->disconn_func)
+		client->disconn_func(client->dbus_conn, client->disconn_data);
+
+	dbus_connection_unref(client->dbus_conn);
+
+	g_free(client->service_name);
+	g_free(client->unique_name);
+	g_free(client->base_path);
+
+	g_free(client);
+}
+
+gboolean g_dbus_client_set_connect_watch(GDBusClient *client,
+				GDBusWatchFunction function, void *user_data)
+{
+	if (client == NULL)
+		return FALSE;
+
+	client->connect_func = function;
+	client->connect_data = user_data;
+
+	return TRUE;
+}
+
+gboolean g_dbus_client_set_disconnect_watch(GDBusClient *client,
+				GDBusWatchFunction function, void *user_data)
+{
+	if (client == NULL)
+		return FALSE;
+
+	client->disconn_func = function;
+	client->disconn_data = user_data;
+
+	return TRUE;
+}
+
+gboolean g_dbus_client_set_signal_watch(GDBusClient *client,
+				GDBusMessageFunction function, void *user_data)
+{
+	if (client == NULL)
+		return FALSE;
+
+	client->signal_func = function;
+	client->signal_data = user_data;
+
+	return TRUE;
+}
+
+gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
+					GDBusProxyFunction proxy_added,
+					GDBusProxyFunction proxy_removed,
+					GDBusPropertyFunction property_changed,
+					void *user_data)
+{
+	if (client == NULL)
+		return FALSE;
+
+	client->proxy_added = proxy_added;
+	client->proxy_removed = proxy_removed;
+	client->property_changed = property_changed;
+	client->user_data = user_data;
+
+	get_managed_objects(client);
+
+	return TRUE;
+}
diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h
new file mode 100644
index 0000000..6f5a012
--- /dev/null
+++ b/gdbus/gdbus.h
@@ -0,0 +1,367 @@
+/*
+ *
+ *  D-Bus helper library
+ *
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __GDBUS_H
+#define __GDBUS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <dbus/dbus.h>
+#include <glib.h>
+
+typedef enum GDBusMethodFlags GDBusMethodFlags;
+typedef enum GDBusSignalFlags GDBusSignalFlags;
+typedef enum GDBusPropertyFlags GDBusPropertyFlags;
+typedef enum GDBusSecurityFlags GDBusSecurityFlags;
+
+typedef struct GDBusArgInfo GDBusArgInfo;
+typedef struct GDBusMethodTable GDBusMethodTable;
+typedef struct GDBusSignalTable GDBusSignalTable;
+typedef struct GDBusPropertyTable GDBusPropertyTable;
+typedef struct GDBusSecurityTable GDBusSecurityTable;
+
+typedef void (* GDBusWatchFunction) (DBusConnection *connection,
+							void *user_data);
+
+typedef void (* GDBusMessageFunction) (DBusConnection *connection,
+					 DBusMessage *message, void *user_data);
+
+typedef gboolean (* GDBusSignalFunction) (DBusConnection *connection,
+					DBusMessage *message, void *user_data);
+
+DBusConnection *g_dbus_setup_bus(DBusBusType type, const char *name,
+							DBusError *error);
+
+DBusConnection *g_dbus_setup_private(DBusBusType type, const char *name,
+							DBusError *error);
+
+gboolean g_dbus_request_name(DBusConnection *connection, const char *name,
+							DBusError *error);
+
+gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
+				GDBusWatchFunction function,
+				void *user_data, DBusFreeFunction destroy);
+
+typedef void (* GDBusDestroyFunction) (void *user_data);
+
+typedef DBusMessage * (* GDBusMethodFunction) (DBusConnection *connection,
+					DBusMessage *message, void *user_data);
+
+typedef gboolean (*GDBusPropertyGetter)(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data);
+
+typedef guint32 GDBusPendingPropertySet;
+
+typedef void (*GDBusPropertySetter)(const GDBusPropertyTable *property,
+			DBusMessageIter *value, GDBusPendingPropertySet id,
+			void *data);
+
+typedef gboolean (*GDBusPropertyExists)(const GDBusPropertyTable *property,
+								void *data);
+
+typedef guint32 GDBusPendingReply;
+
+typedef void (* GDBusSecurityFunction) (DBusConnection *connection,
+						const char *action,
+						gboolean interaction,
+						GDBusPendingReply pending);
+
+enum GDBusFlags {
+	G_DBUS_FLAG_ENABLE_EXPERIMENTAL = (1 << 0),
+};
+
+enum GDBusMethodFlags {
+	G_DBUS_METHOD_FLAG_DEPRECATED   = (1 << 0),
+	G_DBUS_METHOD_FLAG_NOREPLY      = (1 << 1),
+	G_DBUS_METHOD_FLAG_ASYNC        = (1 << 2),
+	G_DBUS_METHOD_FLAG_EXPERIMENTAL = (1 << 3),
+};
+
+enum GDBusSignalFlags {
+	G_DBUS_SIGNAL_FLAG_DEPRECATED   = (1 << 0),
+	G_DBUS_SIGNAL_FLAG_EXPERIMENTAL = (1 << 1),
+};
+
+enum GDBusPropertyFlags {
+	G_DBUS_PROPERTY_FLAG_DEPRECATED   = (1 << 0),
+	G_DBUS_PROPERTY_FLAG_EXPERIMENTAL = (1 << 1),
+};
+
+enum GDBusSecurityFlags {
+	G_DBUS_SECURITY_FLAG_DEPRECATED        = (1 << 0),
+	G_DBUS_SECURITY_FLAG_BUILTIN           = (1 << 1),
+	G_DBUS_SECURITY_FLAG_ALLOW_INTERACTION = (1 << 2),
+};
+
+struct GDBusArgInfo {
+	const char *name;
+	const char *signature;
+};
+
+struct GDBusMethodTable {
+	const char *name;
+	GDBusMethodFunction function;
+	GDBusMethodFlags flags;
+	unsigned int privilege;
+	const GDBusArgInfo *in_args;
+	const GDBusArgInfo *out_args;
+};
+
+struct GDBusSignalTable {
+	const char *name;
+	GDBusSignalFlags flags;
+	const GDBusArgInfo *args;
+};
+
+struct GDBusPropertyTable {
+	const char *name;
+	const char *type;
+	GDBusPropertyGetter get;
+	GDBusPropertySetter set;
+	GDBusPropertyExists exists;
+	GDBusPropertyFlags flags;
+};
+
+struct GDBusSecurityTable {
+	unsigned int privilege;
+	const char *action;
+	GDBusSecurityFlags flags;
+	GDBusSecurityFunction function;
+};
+
+#define GDBUS_ARGS(args...) (const GDBusArgInfo[]) { args, { } }
+
+#define GDBUS_METHOD(_name, _in_args, _out_args, _function) \
+	.name = _name, \
+	.in_args = _in_args, \
+	.out_args = _out_args, \
+	.function = _function
+
+#define GDBUS_ASYNC_METHOD(_name, _in_args, _out_args, _function) \
+	.name = _name, \
+	.in_args = _in_args, \
+	.out_args = _out_args, \
+	.function = _function, \
+	.flags = G_DBUS_METHOD_FLAG_ASYNC
+
+#define GDBUS_DEPRECATED_METHOD(_name, _in_args, _out_args, _function) \
+	.name = _name, \
+	.in_args = _in_args, \
+	.out_args = _out_args, \
+	.function = _function, \
+	.flags = G_DBUS_METHOD_FLAG_DEPRECATED
+
+#define GDBUS_DEPRECATED_ASYNC_METHOD(_name, _in_args, _out_args, _function) \
+	.name = _name, \
+	.in_args = _in_args, \
+	.out_args = _out_args, \
+	.function = _function, \
+	.flags = G_DBUS_METHOD_FLAG_ASYNC | G_DBUS_METHOD_FLAG_DEPRECATED
+
+#define GDBUS_EXPERIMENTAL_METHOD(_name, _in_args, _out_args, _function) \
+	.name = _name, \
+	.in_args = _in_args, \
+	.out_args = _out_args, \
+	.function = _function, \
+	.flags = G_DBUS_METHOD_FLAG_EXPERIMENTAL
+
+#define GDBUS_EXPERIMENTAL_ASYNC_METHOD(_name, _in_args, _out_args, _function) \
+	.name = _name, \
+	.in_args = _in_args, \
+	.out_args = _out_args, \
+	.function = _function, \
+	.flags = G_DBUS_METHOD_FLAG_ASYNC | G_DBUS_METHOD_FLAG_EXPERIMENTAL
+
+#define GDBUS_NOREPLY_METHOD(_name, _in_args, _out_args, _function) \
+	.name = _name, \
+	.in_args = _in_args, \
+	.out_args = _out_args, \
+	.function = _function, \
+	.flags = G_DBUS_METHOD_FLAG_NOREPLY
+
+#define GDBUS_SIGNAL(_name, _args) \
+	.name = _name, \
+	.args = _args
+
+#define GDBUS_DEPRECATED_SIGNAL(_name, _args) \
+	.name = _name, \
+	.args = _args, \
+	.flags = G_DBUS_SIGNAL_FLAG_DEPRECATED
+
+#define GDBUS_EXPERIMENTAL_SIGNAL(_name, _args) \
+	.name = _name, \
+	.args = _args, \
+	.flags = G_DBUS_SIGNAL_FLAG_EXPERIMENTAL
+
+void g_dbus_set_flags(int flags);
+
+gboolean g_dbus_register_interface(DBusConnection *connection,
+					const char *path, const char *name,
+					const GDBusMethodTable *methods,
+					const GDBusSignalTable *signals,
+					const GDBusPropertyTable *properties,
+					void *user_data,
+					GDBusDestroyFunction destroy);
+gboolean g_dbus_unregister_interface(DBusConnection *connection,
+					const char *path, const char *name);
+
+gboolean g_dbus_register_security(const GDBusSecurityTable *security);
+gboolean g_dbus_unregister_security(const GDBusSecurityTable *security);
+
+void g_dbus_pending_success(DBusConnection *connection,
+					GDBusPendingReply pending);
+void g_dbus_pending_error(DBusConnection *connection,
+				GDBusPendingReply pending,
+				const char *name, const char *format, ...)
+					__attribute__((format(printf, 4, 5)));
+void g_dbus_pending_error_valist(DBusConnection *connection,
+				GDBusPendingReply pending, const char *name,
+					const char *format, va_list args);
+
+DBusMessage *g_dbus_create_error(DBusMessage *message, const char *name,
+						const char *format, ...)
+					__attribute__((format(printf, 3, 4)));
+DBusMessage *g_dbus_create_error_valist(DBusMessage *message, const char *name,
+					const char *format, va_list args);
+DBusMessage *g_dbus_create_reply(DBusMessage *message, int type, ...);
+DBusMessage *g_dbus_create_reply_valist(DBusMessage *message,
+						int type, va_list args);
+
+gboolean g_dbus_send_message(DBusConnection *connection, DBusMessage *message);
+gboolean g_dbus_send_error(DBusConnection *connection, DBusMessage *message,
+				const char *name, const char *format, ...)
+					 __attribute__((format(printf, 4, 5)));
+gboolean g_dbus_send_error_valist(DBusConnection *connection,
+					DBusMessage *message, const char *name,
+					const char *format, va_list args);
+gboolean g_dbus_send_reply(DBusConnection *connection,
+				DBusMessage *message, int type, ...);
+gboolean g_dbus_send_reply_valist(DBusConnection *connection,
+				DBusMessage *message, int type, va_list args);
+
+gboolean g_dbus_emit_signal(DBusConnection *connection,
+				const char *path, const char *interface,
+				const char *name, int type, ...);
+gboolean g_dbus_emit_signal_valist(DBusConnection *connection,
+				const char *path, const char *interface,
+				const char *name, int type, va_list args);
+
+guint g_dbus_add_service_watch(DBusConnection *connection, const char *name,
+				GDBusWatchFunction connect,
+				GDBusWatchFunction disconnect,
+				void *user_data, GDBusDestroyFunction destroy);
+guint g_dbus_add_disconnect_watch(DBusConnection *connection, const char *name,
+				GDBusWatchFunction function,
+				void *user_data, GDBusDestroyFunction destroy);
+guint g_dbus_add_signal_watch(DBusConnection *connection,
+				const char *sender, const char *path,
+				const char *interface, const char *member,
+				GDBusSignalFunction function, void *user_data,
+				GDBusDestroyFunction destroy);
+guint g_dbus_add_properties_watch(DBusConnection *connection,
+				const char *sender, const char *path,
+				const char *interface,
+				GDBusSignalFunction function, void *user_data,
+				GDBusDestroyFunction destroy);
+gboolean g_dbus_remove_watch(DBusConnection *connection, guint tag);
+void g_dbus_remove_all_watches(DBusConnection *connection);
+
+void g_dbus_pending_property_success(GDBusPendingPropertySet id);
+void g_dbus_pending_property_error_valist(GDBusPendingReply id,
+			const char *name, const char *format, va_list args);
+void g_dbus_pending_property_error(GDBusPendingReply id, const char *name,
+						const char *format, ...);
+void g_dbus_emit_property_changed(DBusConnection *connection,
+				const char *path, const char *interface,
+				const char *name);
+gboolean g_dbus_get_properties(DBusConnection *connection, const char *path,
+				const char *interface, DBusMessageIter *iter);
+
+gboolean g_dbus_attach_object_manager(DBusConnection *connection);
+gboolean g_dbus_detach_object_manager(DBusConnection *connection);
+
+typedef struct GDBusClient GDBusClient;
+typedef struct GDBusProxy GDBusProxy;
+
+GDBusProxy *g_dbus_proxy_new(GDBusClient *client, const char *path,
+							const char *interface);
+
+GDBusProxy *g_dbus_proxy_ref(GDBusProxy *proxy);
+void g_dbus_proxy_unref(GDBusProxy *proxy);
+
+const char *g_dbus_proxy_get_path(GDBusProxy *proxy);
+const char *g_dbus_proxy_get_interface(GDBusProxy *proxy);
+
+gboolean g_dbus_proxy_get_property(GDBusProxy *proxy, const char *name,
+							DBusMessageIter *iter);
+
+gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name);
+
+typedef void (* GDBusResultFunction) (const DBusError *error, void *user_data);
+
+gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
+				const char *name, int type, const void *value,
+				GDBusResultFunction function, void *user_data,
+				GDBusDestroyFunction destroy);
+
+typedef void (* GDBusSetupFunction) (DBusMessageIter *iter, void *user_data);
+typedef void (* GDBusReturnFunction) (DBusMessage *message, void *user_data);
+
+gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method,
+				GDBusSetupFunction setup,
+				GDBusReturnFunction function, void *user_data,
+				GDBusDestroyFunction destroy);
+
+typedef void (* GDBusProxyFunction) (GDBusProxy *proxy, void *user_data);
+typedef void (* GDBusPropertyFunction) (GDBusProxy *proxy, const char *name,
+					DBusMessageIter *iter, void *user_data);
+
+gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy,
+			GDBusPropertyFunction function, void *user_data);
+
+GDBusClient *g_dbus_client_new(DBusConnection *connection,
+					const char *service, const char *path);
+
+GDBusClient *g_dbus_client_ref(GDBusClient *client);
+void g_dbus_client_unref(GDBusClient *client);
+
+gboolean g_dbus_client_set_connect_watch(GDBusClient *client,
+				GDBusWatchFunction function, void *user_data);
+gboolean g_dbus_client_set_disconnect_watch(GDBusClient *client,
+				GDBusWatchFunction function, void *user_data);
+gboolean g_dbus_client_set_signal_watch(GDBusClient *client,
+				GDBusMessageFunction function, void *user_data);
+
+gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
+					GDBusProxyFunction proxy_added,
+					GDBusProxyFunction proxy_removed,
+					GDBusPropertyFunction property_changed,
+					void *user_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GDBUS_H */
diff --git a/gdbus/mainloop.c b/gdbus/mainloop.c
new file mode 100644
index 0000000..099b67f
--- /dev/null
+++ b/gdbus/mainloop.c
@@ -0,0 +1,380 @@
+/*
+ *
+ *  D-Bus helper library
+ *
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <dbus/dbus.h>
+
+#include "gdbus.h"
+
+#define DISPATCH_TIMEOUT  0
+
+#define info(fmt...)
+#define error(fmt...)
+#define debug(fmt...)
+
+struct timeout_handler {
+	guint id;
+	DBusTimeout *timeout;
+};
+
+struct watch_info {
+	guint id;
+	DBusWatch *watch;
+	DBusConnection *conn;
+};
+
+struct disconnect_data {
+	GDBusWatchFunction function;
+	void *user_data;
+};
+
+static gboolean disconnected_signal(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	struct disconnect_data *dc_data = data;
+
+	error("Got disconnected from the system message bus");
+
+	dc_data->function(conn, dc_data->user_data);
+
+	dbus_connection_unref(conn);
+
+	return TRUE;
+}
+
+static gboolean message_dispatch(void *data)
+{
+	DBusConnection *conn = data;
+
+	dbus_connection_ref(conn);
+
+	/* Dispatch messages */
+	while (dbus_connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS);
+
+	dbus_connection_unref(conn);
+
+	return FALSE;
+}
+
+static inline void queue_dispatch(DBusConnection *conn,
+						DBusDispatchStatus status)
+{
+	if (status == DBUS_DISPATCH_DATA_REMAINS)
+		g_timeout_add(DISPATCH_TIMEOUT, message_dispatch, conn);
+}
+
+static gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+	struct watch_info *info = data;
+	unsigned int flags = 0;
+	DBusDispatchStatus status;
+	DBusConnection *conn;
+
+	conn = dbus_connection_ref(info->conn);
+
+	if (cond & G_IO_IN)  flags |= DBUS_WATCH_READABLE;
+	if (cond & G_IO_OUT) flags |= DBUS_WATCH_WRITABLE;
+	if (cond & G_IO_HUP) flags |= DBUS_WATCH_HANGUP;
+	if (cond & G_IO_ERR) flags |= DBUS_WATCH_ERROR;
+
+	dbus_watch_handle(info->watch, flags);
+
+	status = dbus_connection_get_dispatch_status(conn);
+	queue_dispatch(conn, status);
+
+	dbus_connection_unref(conn);
+
+	return TRUE;
+}
+
+static void watch_info_free(void *data)
+{
+	struct watch_info *info = data;
+
+	if (info->id > 0) {
+		g_source_remove(info->id);
+		info->id = 0;
+	}
+
+	dbus_connection_unref(info->conn);
+
+	g_free(info);
+}
+
+static dbus_bool_t add_watch(DBusWatch *watch, void *data)
+{
+	DBusConnection *conn = data;
+	GIOCondition cond = G_IO_HUP | G_IO_ERR;
+	GIOChannel *chan;
+	struct watch_info *info;
+	unsigned int flags;
+	int fd;
+
+	if (!dbus_watch_get_enabled(watch))
+		return TRUE;
+
+	info = g_new0(struct watch_info, 1);
+
+	fd = dbus_watch_get_unix_fd(watch);
+	chan = g_io_channel_unix_new(fd);
+
+	info->watch = watch;
+	info->conn = dbus_connection_ref(conn);
+
+	dbus_watch_set_data(watch, info, watch_info_free);
+
+	flags = dbus_watch_get_flags(watch);
+
+	if (flags & DBUS_WATCH_READABLE) cond |= G_IO_IN;
+	if (flags & DBUS_WATCH_WRITABLE) cond |= G_IO_OUT;
+
+	info->id = g_io_add_watch(chan, cond, watch_func, info);
+
+	g_io_channel_unref(chan);
+
+	return TRUE;
+}
+
+static void remove_watch(DBusWatch *watch, void *data)
+{
+	if (dbus_watch_get_enabled(watch))
+		return;
+
+	/* will trigger watch_info_free() */
+	dbus_watch_set_data(watch, NULL, NULL);
+}
+
+static void watch_toggled(DBusWatch *watch, void *data)
+{
+	/* Because we just exit on OOM, enable/disable is
+	 * no different from add/remove */
+	if (dbus_watch_get_enabled(watch))
+		add_watch(watch, data);
+	else
+		remove_watch(watch, data);
+}
+
+static gboolean timeout_handler_dispatch(gpointer data)
+{
+	struct timeout_handler *handler = data;
+
+	handler->id = 0;
+
+	/* if not enabled should not be polled by the main loop */
+	if (!dbus_timeout_get_enabled(handler->timeout))
+		return FALSE;
+
+	dbus_timeout_handle(handler->timeout);
+
+	return FALSE;
+}
+
+static void timeout_handler_free(void *data)
+{
+	struct timeout_handler *handler = data;
+
+	if (handler->id > 0) {
+		g_source_remove(handler->id);
+		handler->id = 0;
+	}
+
+	g_free(handler);
+}
+
+static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
+{
+	int interval = dbus_timeout_get_interval(timeout);
+	struct timeout_handler *handler;
+
+	if (!dbus_timeout_get_enabled(timeout))
+		return TRUE;
+
+	handler = g_new0(struct timeout_handler, 1);
+
+	handler->timeout = timeout;
+
+	dbus_timeout_set_data(timeout, handler, timeout_handler_free);
+
+	handler->id = g_timeout_add(interval, timeout_handler_dispatch,
+								handler);
+
+	return TRUE;
+}
+
+static void remove_timeout(DBusTimeout *timeout, void *data)
+{
+	/* will trigger timeout_handler_free() */
+	dbus_timeout_set_data(timeout, NULL, NULL);
+}
+
+static void timeout_toggled(DBusTimeout *timeout, void *data)
+{
+	if (dbus_timeout_get_enabled(timeout))
+		add_timeout(timeout, data);
+	else
+		remove_timeout(timeout, data);
+}
+
+static void dispatch_status(DBusConnection *conn,
+					DBusDispatchStatus status, void *data)
+{
+	if (!dbus_connection_get_is_connected(conn))
+		return;
+
+	queue_dispatch(conn, status);
+}
+
+static inline void setup_dbus_with_main_loop(DBusConnection *conn)
+{
+	dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
+						watch_toggled, conn, NULL);
+
+	dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout,
+						timeout_toggled, NULL, NULL);
+
+	dbus_connection_set_dispatch_status_function(conn, dispatch_status,
+								NULL, NULL);
+}
+
+static gboolean setup_bus(DBusConnection *conn, const char *name,
+						DBusError *error)
+{
+	gboolean result;
+	DBusDispatchStatus status;
+
+	if (name != NULL) {
+		result = g_dbus_request_name(conn, name, error);
+
+		if (error != NULL) {
+			if (dbus_error_is_set(error) == TRUE)
+				return FALSE;
+		}
+
+		if (result == FALSE)
+			return FALSE;
+	}
+
+	setup_dbus_with_main_loop(conn);
+
+	status = dbus_connection_get_dispatch_status(conn);
+	queue_dispatch(conn, status);
+
+	return TRUE;
+}
+
+DBusConnection *g_dbus_setup_bus(DBusBusType type, const char *name,
+							DBusError *error)
+{
+	DBusConnection *conn;
+
+	conn = dbus_bus_get(type, error);
+
+	if (error != NULL) {
+		if (dbus_error_is_set(error) == TRUE)
+			return NULL;
+	}
+
+	if (conn == NULL)
+		return NULL;
+
+	if (setup_bus(conn, name, error) == FALSE) {
+		dbus_connection_unref(conn);
+		return NULL;
+	}
+
+	return conn;
+}
+
+DBusConnection *g_dbus_setup_private(DBusBusType type, const char *name,
+							DBusError *error)
+{
+	DBusConnection *conn;
+
+	conn = dbus_bus_get_private(type, error);
+
+	if (error != NULL) {
+		if (dbus_error_is_set(error) == TRUE)
+			return NULL;
+	}
+
+	if (conn == NULL)
+		return NULL;
+
+	if (setup_bus(conn, name, error) == FALSE) {
+		dbus_connection_unref(conn);
+		return NULL;
+	}
+
+	return conn;
+}
+
+gboolean g_dbus_request_name(DBusConnection *connection, const char *name,
+							DBusError *error)
+{
+	int result;
+
+	result = dbus_bus_request_name(connection, name,
+					DBUS_NAME_FLAG_DO_NOT_QUEUE, error);
+
+	if (error != NULL) {
+		if (dbus_error_is_set(error) == TRUE)
+			return FALSE;
+	}
+
+	if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+		if (error != NULL)
+			dbus_set_error(error, name, "Name already in use");
+
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
+				GDBusWatchFunction function,
+				void *user_data, DBusFreeFunction destroy)
+{
+	struct disconnect_data *dc_data;
+
+	dc_data = g_new0(struct disconnect_data, 1);
+
+	dc_data->function = function;
+	dc_data->user_data = user_data;
+
+	dbus_connection_set_exit_on_disconnect(connection, FALSE);
+
+	if (g_dbus_add_signal_watch(connection, NULL, NULL,
+				DBUS_INTERFACE_LOCAL, "Disconnected",
+				disconnected_signal, dc_data, g_free) == 0) {
+		error("Failed to add watch for D-Bus Disconnected signal");
+		g_free(dc_data);
+		return FALSE;
+	}
+
+	return TRUE;
+}
diff --git a/gdbus/object.c b/gdbus/object.c
new file mode 100644
index 0000000..3327cf4
--- /dev/null
+++ b/gdbus/object.c
@@ -0,0 +1,1776 @@
+/*
+ *
+ *  D-Bus helper library
+ *
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+
+#include "gdbus.h"
+
+#define info(fmt...)
+#define error(fmt...)
+#define debug(fmt...)
+
+#define DBUS_INTERFACE_OBJECT_MANAGER "org.freedesktop.DBus.ObjectManager"
+
+#ifndef DBUS_ERROR_UNKNOWN_PROPERTY
+#define DBUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty"
+#endif
+
+#ifndef DBUS_ERROR_PROPERTY_READ_ONLY
+#define DBUS_ERROR_PROPERTY_READ_ONLY "org.freedesktop.DBus.Error.PropertyReadOnly"
+#endif
+
+struct generic_data {
+	unsigned int refcount;
+	DBusConnection *conn;
+	char *path;
+	GSList *interfaces;
+	GSList *objects;
+	GSList *added;
+	GSList *removed;
+	guint process_id;
+	gboolean pending_prop;
+	char *introspect;
+	struct generic_data *parent;
+};
+
+struct interface_data {
+	char *name;
+	const GDBusMethodTable *methods;
+	const GDBusSignalTable *signals;
+	const GDBusPropertyTable *properties;
+	GSList *pending_prop;
+	void *user_data;
+	GDBusDestroyFunction destroy;
+};
+
+struct security_data {
+	GDBusPendingReply pending;
+	DBusMessage *message;
+	const GDBusMethodTable *method;
+	void *iface_user_data;
+};
+
+struct property_data {
+	DBusConnection *conn;
+	GDBusPendingPropertySet id;
+	DBusMessage *message;
+};
+
+static int global_flags = 0;
+static struct generic_data *root;
+
+static gboolean process_changes(gpointer user_data);
+static void process_properties_from_interface(struct generic_data *data,
+						struct interface_data *iface);
+static void process_property_changes(struct generic_data *data);
+
+static void print_arguments(GString *gstr, const GDBusArgInfo *args,
+						const char *direction)
+{
+	for (; args && args->name; args++) {
+		g_string_append_printf(gstr,
+					"<arg name=\"%s\" type=\"%s\"",
+					args->name, args->signature);
+
+		if (direction)
+			g_string_append_printf(gstr,
+					" direction=\"%s\"/>\n", direction);
+		else
+			g_string_append_printf(gstr, "/>\n");
+
+	}
+}
+
+#define G_DBUS_ANNOTATE(name_, value_)				\
+	"<annotation name=\"org.freedesktop.DBus." name_ "\" "	\
+	"value=\"" value_ "\"/>"
+
+#define G_DBUS_ANNOTATE_DEPRECATED \
+	G_DBUS_ANNOTATE("Deprecated", "true")
+
+#define G_DBUS_ANNOTATE_NOREPLY \
+	G_DBUS_ANNOTATE("Method.NoReply", "true")
+
+static gboolean check_experimental(int flags, int flag)
+{
+	if (!(flags & flag))
+		return FALSE;
+
+	return !(global_flags & G_DBUS_FLAG_ENABLE_EXPERIMENTAL);
+}
+
+static void generate_interface_xml(GString *gstr, struct interface_data *iface)
+{
+	const GDBusMethodTable *method;
+	const GDBusSignalTable *signal;
+	const GDBusPropertyTable *property;
+
+	for (method = iface->methods; method && method->name; method++) {
+		if (check_experimental(method->flags,
+					G_DBUS_METHOD_FLAG_EXPERIMENTAL))
+			continue;
+
+		g_string_append_printf(gstr, "<method name=\"%s\">",
+								method->name);
+		print_arguments(gstr, method->in_args, "in");
+		print_arguments(gstr, method->out_args, "out");
+
+		if (method->flags & G_DBUS_METHOD_FLAG_DEPRECATED)
+			g_string_append_printf(gstr,
+						G_DBUS_ANNOTATE_DEPRECATED);
+
+		if (method->flags & G_DBUS_METHOD_FLAG_NOREPLY)
+			g_string_append_printf(gstr, G_DBUS_ANNOTATE_NOREPLY);
+
+		g_string_append_printf(gstr, "</method>");
+	}
+
+	for (signal = iface->signals; signal && signal->name; signal++) {
+		if (check_experimental(signal->flags,
+					G_DBUS_SIGNAL_FLAG_EXPERIMENTAL))
+			continue;
+
+		g_string_append_printf(gstr, "<signal name=\"%s\">",
+								signal->name);
+		print_arguments(gstr, signal->args, NULL);
+
+		if (signal->flags & G_DBUS_SIGNAL_FLAG_DEPRECATED)
+			g_string_append_printf(gstr,
+						G_DBUS_ANNOTATE_DEPRECATED);
+
+		g_string_append_printf(gstr, "</signal>\n");
+	}
+
+	for (property = iface->properties; property && property->name;
+								property++) {
+		if (check_experimental(property->flags,
+					G_DBUS_PROPERTY_FLAG_EXPERIMENTAL))
+			continue;
+
+		g_string_append_printf(gstr, "<property name=\"%s\""
+					" type=\"%s\" access=\"%s%s\">",
+					property->name,	property->type,
+					property->get ? "read" : "",
+					property->set ? "write" : "");
+
+		if (property->flags & G_DBUS_PROPERTY_FLAG_DEPRECATED)
+			g_string_append_printf(gstr,
+						G_DBUS_ANNOTATE_DEPRECATED);
+
+		g_string_append_printf(gstr, "</property>");
+	}
+}
+
+static void generate_introspection_xml(DBusConnection *conn,
+				struct generic_data *data, const char *path)
+{
+	GSList *list;
+	GString *gstr;
+	char **children;
+	int i;
+
+	g_free(data->introspect);
+
+	gstr = g_string_new(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
+
+	g_string_append_printf(gstr, "<node>");
+
+	for (list = data->interfaces; list; list = list->next) {
+		struct interface_data *iface = list->data;
+
+		g_string_append_printf(gstr, "<interface name=\"%s\">",
+								iface->name);
+
+		generate_interface_xml(gstr, iface);
+
+		g_string_append_printf(gstr, "</interface>");
+	}
+
+	if (!dbus_connection_list_registered(conn, path, &children))
+		goto done;
+
+	for (i = 0; children[i]; i++)
+		g_string_append_printf(gstr, "<node name=\"%s\"/>",
+								children[i]);
+
+	dbus_free_string_array(children);
+
+done:
+	g_string_append_printf(gstr, "</node>");
+
+	data->introspect = g_string_free(gstr, FALSE);
+}
+
+static DBusMessage *introspect(DBusConnection *connection,
+				DBusMessage *message, void *user_data)
+{
+	struct generic_data *data = user_data;
+	DBusMessage *reply;
+
+	if (data->introspect == NULL)
+		generate_introspection_xml(connection, data,
+						dbus_message_get_path(message));
+
+	reply = dbus_message_new_method_return(message);
+	if (reply == NULL)
+		return NULL;
+
+	dbus_message_append_args(reply, DBUS_TYPE_STRING, &data->introspect,
+					DBUS_TYPE_INVALID);
+
+	return reply;
+}
+
+static DBusHandlerResult process_message(DBusConnection *connection,
+			DBusMessage *message, const GDBusMethodTable *method,
+							void *iface_user_data)
+{
+	DBusMessage *reply;
+
+	reply = method->function(connection, message, iface_user_data);
+
+	if (method->flags & G_DBUS_METHOD_FLAG_NOREPLY) {
+		if (reply != NULL)
+			dbus_message_unref(reply);
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	if (method->flags & G_DBUS_METHOD_FLAG_ASYNC) {
+		if (reply == NULL)
+			return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	if (reply == NULL)
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+	dbus_connection_send(connection, reply, NULL);
+	dbus_message_unref(reply);
+
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static GDBusPendingReply next_pending = 1;
+static GSList *pending_security = NULL;
+
+static const GDBusSecurityTable *security_table = NULL;
+
+void g_dbus_pending_success(DBusConnection *connection,
+					GDBusPendingReply pending)
+{
+	GSList *list;
+
+	for (list = pending_security; list; list = list->next) {
+		struct security_data *secdata = list->data;
+
+		if (secdata->pending != pending)
+			continue;
+
+		pending_security = g_slist_remove(pending_security, secdata);
+
+		process_message(connection, secdata->message,
+				secdata->method, secdata->iface_user_data);
+
+		dbus_message_unref(secdata->message);
+		g_free(secdata);
+		return;
+	}
+}
+
+void g_dbus_pending_error_valist(DBusConnection *connection,
+				GDBusPendingReply pending, const char *name,
+					const char *format, va_list args)
+{
+	GSList *list;
+
+	for (list = pending_security; list; list = list->next) {
+		struct security_data *secdata = list->data;
+		DBusMessage *reply;
+
+		if (secdata->pending != pending)
+			continue;
+
+		pending_security = g_slist_remove(pending_security, secdata);
+
+		reply = g_dbus_create_error_valist(secdata->message,
+							name, format, args);
+		if (reply != NULL) {
+			dbus_connection_send(connection, reply, NULL);
+			dbus_message_unref(reply);
+		}
+
+		dbus_message_unref(secdata->message);
+		g_free(secdata);
+		return;
+	}
+}
+
+void g_dbus_pending_error(DBusConnection *connection,
+				GDBusPendingReply pending,
+				const char *name, const char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+
+	g_dbus_pending_error_valist(connection, pending, name, format, args);
+
+	va_end(args);
+}
+
+int polkit_check_authorization(DBusConnection *conn,
+				const char *action, gboolean interaction,
+				void (*function) (dbus_bool_t authorized,
+							void *user_data),
+						void *user_data, int timeout);
+
+struct builtin_security_data {
+	DBusConnection *conn;
+	GDBusPendingReply pending;
+};
+
+static void builtin_security_result(dbus_bool_t authorized, void *user_data)
+{
+	struct builtin_security_data *data = user_data;
+
+	if (authorized == TRUE)
+		g_dbus_pending_success(data->conn, data->pending);
+	else
+		g_dbus_pending_error(data->conn, data->pending,
+						DBUS_ERROR_AUTH_FAILED, NULL);
+
+	g_free(data);
+}
+
+static void builtin_security_function(DBusConnection *conn,
+						const char *action,
+						gboolean interaction,
+						GDBusPendingReply pending)
+{
+	struct builtin_security_data *data;
+
+	data = g_new0(struct builtin_security_data, 1);
+	data->conn = conn;
+	data->pending = pending;
+
+	if (polkit_check_authorization(conn, action, interaction,
+				builtin_security_result, data, 30000) < 0)
+		g_dbus_pending_error(conn, pending, NULL, NULL);
+}
+
+static gboolean check_privilege(DBusConnection *conn, DBusMessage *msg,
+			const GDBusMethodTable *method, void *iface_user_data)
+{
+	const GDBusSecurityTable *security;
+
+	for (security = security_table; security && security->privilege;
+								security++) {
+		struct security_data *secdata;
+		gboolean interaction;
+
+		if (security->privilege != method->privilege)
+			continue;
+
+		secdata = g_new(struct security_data, 1);
+		secdata->pending = next_pending++;
+		secdata->message = dbus_message_ref(msg);
+		secdata->method = method;
+		secdata->iface_user_data = iface_user_data;
+
+		pending_security = g_slist_prepend(pending_security, secdata);
+
+		if (security->flags & G_DBUS_SECURITY_FLAG_ALLOW_INTERACTION)
+			interaction = TRUE;
+		else
+			interaction = FALSE;
+
+		if (!(security->flags & G_DBUS_SECURITY_FLAG_BUILTIN) &&
+							security->function)
+			security->function(conn, security->action,
+						interaction, secdata->pending);
+		else
+			builtin_security_function(conn, security->action,
+						interaction, secdata->pending);
+
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static GDBusPendingPropertySet next_pending_property = 1;
+static GSList *pending_property_set;
+
+static struct property_data *remove_pending_property_data(
+						GDBusPendingPropertySet id)
+{
+	struct property_data *propdata;
+	GSList *l;
+
+	for (l = pending_property_set; l != NULL; l = l->next) {
+		propdata = l->data;
+		if (propdata->id != id)
+			continue;
+
+		break;
+	}
+
+	if (l == NULL)
+		return NULL;
+
+	pending_property_set = g_slist_delete_link(pending_property_set, l);
+
+	return propdata;
+}
+
+void g_dbus_pending_property_success(GDBusPendingPropertySet id)
+{
+	struct property_data *propdata;
+
+	propdata = remove_pending_property_data(id);
+	if (propdata == NULL)
+		return;
+
+	g_dbus_send_reply(propdata->conn, propdata->message,
+							DBUS_TYPE_INVALID);
+	dbus_message_unref(propdata->message);
+	g_free(propdata);
+}
+
+void g_dbus_pending_property_error_valist(GDBusPendingReply id,
+					const char *name, const char *format,
+					va_list args)
+{
+	struct property_data *propdata;
+	DBusMessage *reply;
+
+	propdata = remove_pending_property_data(id);
+	if (propdata == NULL)
+		return;
+
+	reply = g_dbus_create_error_valist(propdata->message, name, format,
+									args);
+	if (reply != NULL) {
+		dbus_connection_send(propdata->conn, reply, NULL);
+		dbus_message_unref(reply);
+	}
+
+	dbus_message_unref(propdata->message);
+	g_free(propdata);
+}
+
+void g_dbus_pending_property_error(GDBusPendingReply id, const char *name,
+						const char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+
+	g_dbus_pending_property_error_valist(id, name, format, args);
+
+	va_end(args);
+}
+
+static void reset_parent(gpointer data, gpointer user_data)
+{
+	struct generic_data *child = data;
+	struct generic_data *parent = user_data;
+
+	child->parent = parent;
+}
+
+static void append_property(struct interface_data *iface,
+			const GDBusPropertyTable *p, DBusMessageIter *dict)
+{
+	DBusMessageIter entry, value;
+
+	dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
+								&entry);
+	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &p->name);
+	dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, p->type,
+								&value);
+
+	p->get(p, &value, iface->user_data);
+
+	dbus_message_iter_close_container(&entry, &value);
+	dbus_message_iter_close_container(dict, &entry);
+}
+
+static void append_properties(struct interface_data *data,
+							DBusMessageIter *iter)
+{
+	DBusMessageIter dict;
+	const GDBusPropertyTable *p;
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+				DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+				DBUS_TYPE_STRING_AS_STRING
+				DBUS_TYPE_VARIANT_AS_STRING
+				DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+	for (p = data->properties; p && p->name; p++) {
+		if (check_experimental(p->flags,
+					G_DBUS_PROPERTY_FLAG_EXPERIMENTAL))
+			continue;
+
+		if (p->get == NULL)
+			continue;
+
+		if (p->exists != NULL && !p->exists(p, data->user_data))
+			continue;
+
+		append_property(data, p, &dict);
+	}
+
+	dbus_message_iter_close_container(iter, &dict);
+}
+
+static void append_interface(gpointer data, gpointer user_data)
+{
+	struct interface_data *iface = data;
+	DBusMessageIter *array = user_data;
+	DBusMessageIter entry;
+
+	dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL,
+								&entry);
+	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &iface->name);
+	append_properties(data, &entry);
+	dbus_message_iter_close_container(array, &entry);
+}
+
+static void emit_interfaces_added(struct generic_data *data)
+{
+	DBusMessage *signal;
+	DBusMessageIter iter, array;
+
+	if (root == NULL || data == root)
+		return;
+
+	signal = dbus_message_new_signal(root->path,
+					DBUS_INTERFACE_OBJECT_MANAGER,
+					"InterfacesAdded");
+	if (signal == NULL)
+		return;
+
+	dbus_message_iter_init_append(signal, &iter);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+								&data->path);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+				DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+				DBUS_TYPE_STRING_AS_STRING
+				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
+				DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
+
+	g_slist_foreach(data->added, append_interface, &array);
+	g_slist_free(data->added);
+	data->added = NULL;
+
+	dbus_message_iter_close_container(&iter, &array);
+
+	g_dbus_send_message(data->conn, signal);
+}
+
+static struct interface_data *find_interface(GSList *interfaces,
+						const char *name)
+{
+	GSList *list;
+
+	if (name == NULL)
+		return NULL;
+
+	for (list = interfaces; list; list = list->next) {
+		struct interface_data *iface = list->data;
+		if (!strcmp(name, iface->name))
+			return iface;
+	}
+
+	return NULL;
+}
+
+static gboolean g_dbus_args_have_signature(const GDBusArgInfo *args,
+							DBusMessage *message)
+{
+	const char *sig = dbus_message_get_signature(message);
+	const char *p = NULL;
+
+	for (; args && args->signature && *sig; args++) {
+		p = args->signature;
+
+		for (; *sig && *p; sig++, p++) {
+			if (*p != *sig)
+				return FALSE;
+		}
+	}
+
+	if (*sig || (p && *p) || (args && args->signature))
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean remove_interface(struct generic_data *data, const char *name)
+{
+	struct interface_data *iface;
+
+	iface = find_interface(data->interfaces, name);
+	if (iface == NULL)
+		return FALSE;
+
+	process_properties_from_interface(data, iface);
+
+	data->interfaces = g_slist_remove(data->interfaces, iface);
+
+	if (iface->destroy) {
+		iface->destroy(iface->user_data);
+		iface->user_data = NULL;
+	}
+
+	/*
+	 * Interface being removed was just added, on the same mainloop
+	 * iteration? Don't send any signal
+	 */
+	if (g_slist_find(data->added, iface)) {
+		data->added = g_slist_remove(data->added, iface);
+		g_free(iface->name);
+		g_free(iface);
+		return TRUE;
+	}
+
+	if (data->parent == NULL) {
+		g_free(iface->name);
+		g_free(iface);
+		return TRUE;
+	}
+
+	data->removed = g_slist_prepend(data->removed, iface->name);
+	g_free(iface);
+
+	if (data->process_id > 0)
+		return TRUE;
+
+	data->process_id = g_idle_add(process_changes, data);
+
+	return TRUE;
+}
+
+static struct generic_data *invalidate_parent_data(DBusConnection *conn,
+						const char *child_path)
+{
+	struct generic_data *data = NULL, *child = NULL, *parent = NULL;
+	char *parent_path, *slash;
+
+	parent_path = g_strdup(child_path);
+	slash = strrchr(parent_path, '/');
+	if (slash == NULL)
+		goto done;
+
+	if (slash == parent_path && parent_path[1] != '\0')
+		parent_path[1] = '\0';
+	else
+		*slash = '\0';
+
+	if (!strlen(parent_path))
+		goto done;
+
+	if (dbus_connection_get_object_path_data(conn, parent_path,
+							(void *) &data) == FALSE) {
+		goto done;
+	}
+
+	parent = invalidate_parent_data(conn, parent_path);
+
+	if (data == NULL) {
+		data = parent;
+		if (data == NULL)
+			goto done;
+	}
+
+	g_free(data->introspect);
+	data->introspect = NULL;
+
+	if (!dbus_connection_get_object_path_data(conn, child_path,
+							(void *) &child))
+		goto done;
+
+	if (child == NULL || g_slist_find(data->objects, child) != NULL)
+		goto done;
+
+	data->objects = g_slist_prepend(data->objects, child);
+	child->parent = data;
+
+done:
+	g_free(parent_path);
+	return data;
+}
+
+static inline const GDBusPropertyTable *find_property(const GDBusPropertyTable *properties,
+							const char *name)
+{
+	const GDBusPropertyTable *p;
+
+	for (p = properties; p && p->name; p++) {
+		if (strcmp(name, p->name) != 0)
+			continue;
+
+		if (check_experimental(p->flags,
+					G_DBUS_PROPERTY_FLAG_EXPERIMENTAL))
+			break;
+
+		return p;
+	}
+
+	return NULL;
+}
+
+static DBusMessage *properties_get(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	struct generic_data *data = user_data;
+	struct interface_data *iface;
+	const GDBusPropertyTable *property;
+	const char *interface, *name;
+	DBusMessageIter iter, value;
+	DBusMessage *reply;
+
+	if (!dbus_message_get_args(message, NULL,
+					DBUS_TYPE_STRING, &interface,
+					DBUS_TYPE_STRING, &name,
+					DBUS_TYPE_INVALID))
+		return NULL;
+
+	iface = find_interface(data->interfaces, interface);
+	if (iface == NULL)
+		return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+				"No such interface '%s'", interface);
+
+	property = find_property(iface->properties, name);
+	if (property == NULL)
+		return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+				"No such property '%s'", name);
+
+	if (property->exists != NULL &&
+			!property->exists(property, iface->user_data))
+		return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+					"No such property '%s'", name);
+
+	if (property->get == NULL)
+		return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+				"Property '%s' is not readable", name);
+
+	reply = dbus_message_new_method_return(message);
+	if (reply == NULL)
+		return NULL;
+
+	dbus_message_iter_init_append(reply, &iter);
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+						property->type, &value);
+
+	if (!property->get(property, &value, iface->user_data)) {
+		dbus_message_unref(reply);
+		return NULL;
+	}
+
+	dbus_message_iter_close_container(&iter, &value);
+
+	return reply;
+}
+
+static DBusMessage *properties_get_all(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	struct generic_data *data = user_data;
+	struct interface_data *iface;
+	const char *interface;
+	DBusMessageIter iter;
+	DBusMessage *reply;
+
+	if (!dbus_message_get_args(message, NULL,
+					DBUS_TYPE_STRING, &interface,
+					DBUS_TYPE_INVALID))
+		return NULL;
+
+	iface = find_interface(data->interfaces, interface);
+	if (iface == NULL)
+		return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+					"No such interface '%s'", interface);
+
+	reply = dbus_message_new_method_return(message);
+	if (reply == NULL)
+		return NULL;
+
+	dbus_message_iter_init_append(reply, &iter);
+
+	append_properties(iface, &iter);
+
+	return reply;
+}
+
+static DBusMessage *properties_set(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	struct generic_data *data = user_data;
+	DBusMessageIter iter, sub;
+	struct interface_data *iface;
+	const GDBusPropertyTable *property;
+	const char *name, *interface;
+	struct property_data *propdata;
+	gboolean valid_signature;
+	char *signature;
+
+	if (!dbus_message_iter_init(message, &iter))
+		return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+							"No arguments given");
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+		return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+					"Invalid argument type: '%c'",
+					dbus_message_iter_get_arg_type(&iter));
+
+	dbus_message_iter_get_basic(&iter, &interface);
+	dbus_message_iter_next(&iter);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+		return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+					"Invalid argument type: '%c'",
+					dbus_message_iter_get_arg_type(&iter));
+
+	dbus_message_iter_get_basic(&iter, &name);
+	dbus_message_iter_next(&iter);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+		return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+					"Invalid argument type: '%c'",
+					dbus_message_iter_get_arg_type(&iter));
+
+	dbus_message_iter_recurse(&iter, &sub);
+
+	iface = find_interface(data->interfaces, interface);
+	if (iface == NULL)
+		return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+					"No such interface '%s'", interface);
+
+	property = find_property(iface->properties, name);
+	if (property == NULL)
+		return g_dbus_create_error(message,
+						DBUS_ERROR_UNKNOWN_PROPERTY,
+						"No such property '%s'", name);
+
+	if (property->set == NULL)
+		return g_dbus_create_error(message,
+					DBUS_ERROR_PROPERTY_READ_ONLY,
+					"Property '%s' is not writable", name);
+
+	if (property->exists != NULL &&
+			!property->exists(property, iface->user_data))
+		return g_dbus_create_error(message,
+						DBUS_ERROR_UNKNOWN_PROPERTY,
+						"No such property '%s'", name);
+
+	signature = dbus_message_iter_get_signature(&sub);
+	valid_signature = strcmp(signature, property->type) ? FALSE : TRUE;
+	dbus_free(signature);
+	if (!valid_signature)
+		return g_dbus_create_error(message,
+					DBUS_ERROR_INVALID_SIGNATURE,
+					"Invalid signature for '%s'", name);
+
+	propdata = g_new(struct property_data, 1);
+	propdata->id = next_pending_property++;
+	propdata->message = dbus_message_ref(message);
+	propdata->conn = connection;
+	pending_property_set = g_slist_prepend(pending_property_set, propdata);
+
+	property->set(property, &sub, propdata->id, iface->user_data);
+
+	return NULL;
+}
+
+static const GDBusMethodTable properties_methods[] = {
+	{ GDBUS_METHOD("Get",
+			GDBUS_ARGS({ "interface", "s" }, { "name", "s" }),
+			GDBUS_ARGS({ "value", "v" }),
+			properties_get) },
+	{ GDBUS_ASYNC_METHOD("Set",
+			GDBUS_ARGS({ "interface", "s" }, { "name", "s" },
+							{ "value", "v" }),
+			NULL,
+			properties_set) },
+	{ GDBUS_METHOD("GetAll",
+			GDBUS_ARGS({ "interface", "s" }),
+			GDBUS_ARGS({ "properties", "a{sv}" }),
+			properties_get_all) },
+	{ }
+};
+
+static const GDBusSignalTable properties_signals[] = {
+	{ GDBUS_SIGNAL("PropertiesChanged",
+			GDBUS_ARGS({ "interface", "s" },
+					{ "changed_properties", "a{sv}" },
+					{ "invalidated_properties", "as"})) },
+	{ }
+};
+
+static void append_name(gpointer data, gpointer user_data)
+{
+	char *name = data;
+	DBusMessageIter *iter = user_data;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &name);
+}
+
+static void emit_interfaces_removed(struct generic_data *data)
+{
+	DBusMessage *signal;
+	DBusMessageIter iter, array;
+
+	if (root == NULL || data == root)
+		return;
+
+	signal = dbus_message_new_signal(root->path,
+					DBUS_INTERFACE_OBJECT_MANAGER,
+					"InterfacesRemoved");
+	if (signal == NULL)
+		return;
+
+	dbus_message_iter_init_append(signal, &iter);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+								&data->path);
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+					DBUS_TYPE_STRING_AS_STRING, &array);
+
+	g_slist_foreach(data->removed, append_name, &array);
+	g_slist_free_full(data->removed, g_free);
+	data->removed = NULL;
+
+	dbus_message_iter_close_container(&iter, &array);
+
+	g_dbus_send_message(data->conn, signal);
+}
+
+static gboolean process_changes(gpointer user_data)
+{
+	struct generic_data *data = user_data;
+
+	data->process_id = 0;
+
+	if (data->added != NULL)
+		emit_interfaces_added(data);
+
+	/* Flush pending properties */
+	if (data->pending_prop == TRUE)
+		process_property_changes(data);
+
+	if (data->removed != NULL)
+		emit_interfaces_removed(data);
+
+	return FALSE;
+}
+
+static void generic_unregister(DBusConnection *connection, void *user_data)
+{
+	struct generic_data *data = user_data;
+	struct generic_data *parent = data->parent;
+
+	if (parent != NULL)
+		parent->objects = g_slist_remove(parent->objects, data);
+
+	if (data->process_id > 0) {
+		g_source_remove(data->process_id);
+		process_changes(data);
+	}
+
+	g_slist_foreach(data->objects, reset_parent, data->parent);
+	g_slist_free(data->objects);
+
+	dbus_connection_unref(data->conn);
+	g_free(data->introspect);
+	g_free(data->path);
+	g_free(data);
+}
+
+static DBusHandlerResult generic_message(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	struct generic_data *data = user_data;
+	struct interface_data *iface;
+	const GDBusMethodTable *method;
+	const char *interface;
+
+	interface = dbus_message_get_interface(message);
+
+	iface = find_interface(data->interfaces, interface);
+	if (iface == NULL)
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+	for (method = iface->methods; method &&
+			method->name && method->function; method++) {
+
+		if (dbus_message_is_method_call(message, iface->name,
+							method->name) == FALSE)
+			continue;
+
+		if (check_experimental(method->flags,
+					G_DBUS_METHOD_FLAG_EXPERIMENTAL))
+			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+		if (g_dbus_args_have_signature(method->in_args,
+							message) == FALSE)
+			continue;
+
+		if (check_privilege(connection, message, method,
+						iface->user_data) == TRUE)
+			return DBUS_HANDLER_RESULT_HANDLED;
+
+		return process_message(connection, message, method,
+							iface->user_data);
+	}
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusObjectPathVTable generic_table = {
+	.unregister_function	= generic_unregister,
+	.message_function	= generic_message,
+};
+
+static const GDBusMethodTable introspect_methods[] = {
+	{ GDBUS_METHOD("Introspect", NULL,
+			GDBUS_ARGS({ "xml", "s" }), introspect) },
+	{ }
+};
+
+static void append_interfaces(struct generic_data *data, DBusMessageIter *iter)
+{
+	DBusMessageIter array;
+	GSList *l;
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+				DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+				DBUS_TYPE_STRING_AS_STRING
+				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
+				DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
+
+	for (l = data->interfaces; l != NULL; l = l->next) {
+		if (g_slist_find(data->added, l->data))
+			continue;
+
+		append_interface(l->data, &array);
+	}
+
+	dbus_message_iter_close_container(iter, &array);
+}
+
+static void append_object(gpointer data, gpointer user_data)
+{
+	struct generic_data *child = data;
+	DBusMessageIter *array = user_data;
+	DBusMessageIter entry;
+
+	dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL,
+								&entry);
+	dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
+								&child->path);
+	append_interfaces(child, &entry);
+	dbus_message_iter_close_container(array, &entry);
+
+	g_slist_foreach(child->objects, append_object, user_data);
+}
+
+static DBusMessage *get_objects(DBusConnection *connection,
+				DBusMessage *message, void *user_data)
+{
+	struct generic_data *data = user_data;
+	DBusMessage *reply;
+	DBusMessageIter iter;
+	DBusMessageIter array;
+
+	reply = dbus_message_new_method_return(message);
+	if (reply == NULL)
+		return NULL;
+
+	dbus_message_iter_init_append(reply, &iter);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+					DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+					DBUS_TYPE_OBJECT_PATH_AS_STRING
+					DBUS_TYPE_ARRAY_AS_STRING
+					DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+					DBUS_TYPE_STRING_AS_STRING
+					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
+					DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+					DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+					&array);
+
+	g_slist_foreach(data->objects, append_object, &array);
+
+	dbus_message_iter_close_container(&iter, &array);
+
+	return reply;
+}
+
+static const GDBusMethodTable manager_methods[] = {
+	{ GDBUS_METHOD("GetManagedObjects", NULL,
+		GDBUS_ARGS({ "objects", "a{oa{sa{sv}}}" }), get_objects) },
+	{ }
+};
+
+static const GDBusSignalTable manager_signals[] = {
+	{ GDBUS_SIGNAL("InterfacesAdded",
+		GDBUS_ARGS({ "object", "o" },
+				{ "interfaces", "a{sa{sv}}" })) },
+	{ GDBUS_SIGNAL("InterfacesRemoved",
+		GDBUS_ARGS({ "object", "o" }, { "interfaces", "as" })) },
+	{ }
+};
+
+static gboolean add_interface(struct generic_data *data,
+				const char *name,
+				const GDBusMethodTable *methods,
+				const GDBusSignalTable *signals,
+				const GDBusPropertyTable *properties,
+				void *user_data,
+				GDBusDestroyFunction destroy)
+{
+	struct interface_data *iface;
+	const GDBusMethodTable *method;
+	const GDBusSignalTable *signal;
+	const GDBusPropertyTable *property;
+
+	for (method = methods; method && method->name; method++) {
+		if (!check_experimental(method->flags,
+					G_DBUS_METHOD_FLAG_EXPERIMENTAL))
+			goto done;
+	}
+
+	for (signal = signals; signal && signal->name; signal++) {
+		if (!check_experimental(signal->flags,
+					G_DBUS_SIGNAL_FLAG_EXPERIMENTAL))
+			goto done;
+	}
+
+	for (property = properties; property && property->name; property++) {
+		if (!check_experimental(property->flags,
+					G_DBUS_PROPERTY_FLAG_EXPERIMENTAL))
+			goto done;
+	}
+
+	/* Nothing to register */
+	return FALSE;
+
+done:
+	iface = g_new0(struct interface_data, 1);
+	iface->name = g_strdup(name);
+	iface->methods = methods;
+	iface->signals = signals;
+	iface->properties = properties;
+	iface->user_data = user_data;
+	iface->destroy = destroy;
+
+	data->interfaces = g_slist_append(data->interfaces, iface);
+	if (data->parent == NULL)
+		return TRUE;
+
+	data->added = g_slist_append(data->added, iface);
+	if (data->process_id > 0)
+		return TRUE;
+
+	data->process_id = g_idle_add(process_changes, data);
+
+	return TRUE;
+}
+
+static struct generic_data *object_path_ref(DBusConnection *connection,
+							const char *path)
+{
+	struct generic_data *data;
+
+	if (dbus_connection_get_object_path_data(connection, path,
+						(void *) &data) == TRUE) {
+		if (data != NULL) {
+			data->refcount++;
+			return data;
+		}
+	}
+
+	data = g_new0(struct generic_data, 1);
+	data->conn = dbus_connection_ref(connection);
+	data->path = g_strdup(path);
+	data->refcount = 1;
+
+	data->introspect = g_strdup(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "<node></node>");
+
+	if (!dbus_connection_register_object_path(connection, path,
+						&generic_table, data)) {
+		g_free(data->introspect);
+		g_free(data);
+		return NULL;
+	}
+
+	invalidate_parent_data(connection, path);
+
+	add_interface(data, DBUS_INTERFACE_INTROSPECTABLE, introspect_methods,
+						NULL, NULL, data, NULL);
+
+	return data;
+}
+
+static void object_path_unref(DBusConnection *connection, const char *path)
+{
+	struct generic_data *data = NULL;
+
+	if (dbus_connection_get_object_path_data(connection, path,
+						(void *) &data) == FALSE)
+		return;
+
+	if (data == NULL)
+		return;
+
+	data->refcount--;
+
+	if (data->refcount > 0)
+		return;
+
+	remove_interface(data, DBUS_INTERFACE_INTROSPECTABLE);
+	remove_interface(data, DBUS_INTERFACE_PROPERTIES);
+
+	invalidate_parent_data(data->conn, data->path);
+
+	dbus_connection_unregister_object_path(data->conn, data->path);
+}
+
+static gboolean check_signal(DBusConnection *conn, const char *path,
+				const char *interface, const char *name,
+				const GDBusArgInfo **args)
+{
+	struct generic_data *data = NULL;
+	struct interface_data *iface;
+	const GDBusSignalTable *signal;
+
+	*args = NULL;
+	if (!dbus_connection_get_object_path_data(conn, path,
+					(void *) &data) || data == NULL) {
+		error("dbus_connection_emit_signal: path %s isn't registered",
+				path);
+		return FALSE;
+	}
+
+	iface = find_interface(data->interfaces, interface);
+	if (iface == NULL) {
+		error("dbus_connection_emit_signal: %s does not implement %s",
+				path, interface);
+		return FALSE;
+	}
+
+	for (signal = iface->signals; signal && signal->name; signal++) {
+		if (strcmp(signal->name, name) != 0)
+			continue;
+
+		if (signal->flags & G_DBUS_SIGNAL_FLAG_EXPERIMENTAL) {
+			const char *env = g_getenv("GDBUS_EXPERIMENTAL");
+			if (g_strcmp0(env, "1") != 0)
+				break;
+		}
+
+		*args = signal->args;
+		return TRUE;
+	}
+
+	error("No signal named %s on interface %s", name, interface);
+	return FALSE;
+}
+
+static dbus_bool_t emit_signal_valist(DBusConnection *conn,
+						const char *path,
+						const char *interface,
+						const char *name,
+						int first,
+						va_list var_args)
+{
+	DBusMessage *signal;
+	dbus_bool_t ret;
+	const GDBusArgInfo *args;
+
+	if (!check_signal(conn, path, interface, name, &args))
+		return FALSE;
+
+	signal = dbus_message_new_signal(path, interface, name);
+	if (signal == NULL) {
+		error("Unable to allocate new %s.%s signal", interface,  name);
+		return FALSE;
+	}
+
+	ret = dbus_message_append_args_valist(signal, first, var_args);
+	if (!ret)
+		goto fail;
+
+	if (g_dbus_args_have_signature(args, signal) == FALSE) {
+		error("%s.%s: got unexpected signature '%s'", interface, name,
+					dbus_message_get_signature(signal));
+		ret = FALSE;
+		goto fail;
+	}
+
+	ret = dbus_connection_send(conn, signal, NULL);
+
+fail:
+	dbus_message_unref(signal);
+
+	return ret;
+}
+
+gboolean g_dbus_register_interface(DBusConnection *connection,
+					const char *path, const char *name,
+					const GDBusMethodTable *methods,
+					const GDBusSignalTable *signals,
+					const GDBusPropertyTable *properties,
+					void *user_data,
+					GDBusDestroyFunction destroy)
+{
+	struct generic_data *data;
+
+	data = object_path_ref(connection, path);
+	if (data == NULL)
+		return FALSE;
+
+	if (find_interface(data->interfaces, name)) {
+		object_path_unref(connection, path);
+		return FALSE;
+	}
+
+	if (!add_interface(data, name, methods, signals, properties, user_data,
+								destroy)) {
+		object_path_unref(connection, path);
+		return FALSE;
+	}
+
+	if (properties != NULL && !find_interface(data->interfaces,
+						DBUS_INTERFACE_PROPERTIES))
+		add_interface(data, DBUS_INTERFACE_PROPERTIES,
+				properties_methods, properties_signals, NULL,
+				data, NULL);
+
+	g_free(data->introspect);
+	data->introspect = NULL;
+
+	return TRUE;
+}
+
+gboolean g_dbus_unregister_interface(DBusConnection *connection,
+					const char *path, const char *name)
+{
+	struct generic_data *data = NULL;
+
+	if (path == NULL)
+		return FALSE;
+
+	if (dbus_connection_get_object_path_data(connection, path,
+						(void *) &data) == FALSE)
+		return FALSE;
+
+	if (data == NULL)
+		return FALSE;
+
+	if (remove_interface(data, name) == FALSE)
+		return FALSE;
+
+	g_free(data->introspect);
+	data->introspect = NULL;
+
+	object_path_unref(connection, data->path);
+
+	return TRUE;
+}
+
+gboolean g_dbus_register_security(const GDBusSecurityTable *security)
+{
+	if (security_table != NULL)
+		return FALSE;
+
+	security_table = security;
+
+	return TRUE;
+}
+
+gboolean g_dbus_unregister_security(const GDBusSecurityTable *security)
+{
+	security_table = NULL;
+
+	return TRUE;
+}
+
+DBusMessage *g_dbus_create_error_valist(DBusMessage *message, const char *name,
+					const char *format, va_list args)
+{
+	char str[1024];
+
+	vsnprintf(str, sizeof(str), format, args);
+
+	return dbus_message_new_error(message, name, str);
+}
+
+DBusMessage *g_dbus_create_error(DBusMessage *message, const char *name,
+						const char *format, ...)
+{
+	va_list args;
+	DBusMessage *reply;
+
+	va_start(args, format);
+
+	reply = g_dbus_create_error_valist(message, name, format, args);
+
+	va_end(args);
+
+	return reply;
+}
+
+DBusMessage *g_dbus_create_reply_valist(DBusMessage *message,
+						int type, va_list args)
+{
+	DBusMessage *reply;
+
+	reply = dbus_message_new_method_return(message);
+	if (reply == NULL)
+		return NULL;
+
+	if (dbus_message_append_args_valist(reply, type, args) == FALSE) {
+		dbus_message_unref(reply);
+		return NULL;
+	}
+
+	return reply;
+}
+
+DBusMessage *g_dbus_create_reply(DBusMessage *message, int type, ...)
+{
+	va_list args;
+	DBusMessage *reply;
+
+	va_start(args, type);
+
+	reply = g_dbus_create_reply_valist(message, type, args);
+
+	va_end(args);
+
+	return reply;
+}
+
+gboolean g_dbus_send_message(DBusConnection *connection, DBusMessage *message)
+{
+	dbus_bool_t result;
+
+	if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL)
+		dbus_message_set_no_reply(message, TRUE);
+	else if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL) {
+		const char *path = dbus_message_get_path(message);
+		const char *interface = dbus_message_get_interface(message);
+		const char *name = dbus_message_get_member(message);
+		const GDBusArgInfo *args;
+
+		if (!check_signal(connection, path, interface, name, &args))
+			return FALSE;
+	}
+
+	result = dbus_connection_send(connection, message, NULL);
+
+	dbus_message_unref(message);
+
+	return result;
+}
+
+gboolean g_dbus_send_error_valist(DBusConnection *connection,
+					DBusMessage *message, const char *name,
+					const char *format, va_list args)
+{
+	DBusMessage *error;
+	char str[1024];
+
+	vsnprintf(str, sizeof(str), format, args);
+
+	error = dbus_message_new_error(message, name, str);
+	if (error == NULL)
+		return FALSE;
+
+	return g_dbus_send_message(connection, error);
+}
+
+gboolean g_dbus_send_error(DBusConnection *connection, DBusMessage *message,
+				const char *name, const char *format, ...)
+{
+	va_list args;
+	gboolean result;
+
+	va_start(args, format);
+
+	result = g_dbus_send_error_valist(connection, message, name,
+							format, args);
+
+	va_end(args);
+
+	return result;
+}
+
+gboolean g_dbus_send_reply_valist(DBusConnection *connection,
+				DBusMessage *message, int type, va_list args)
+{
+	DBusMessage *reply;
+
+	reply = dbus_message_new_method_return(message);
+	if (reply == NULL)
+		return FALSE;
+
+	if (dbus_message_append_args_valist(reply, type, args) == FALSE) {
+		dbus_message_unref(reply);
+		return FALSE;
+	}
+
+	return g_dbus_send_message(connection, reply);
+}
+
+gboolean g_dbus_send_reply(DBusConnection *connection,
+				DBusMessage *message, int type, ...)
+{
+	va_list args;
+	gboolean result;
+
+	va_start(args, type);
+
+	result = g_dbus_send_reply_valist(connection, message, type, args);
+
+	va_end(args);
+
+	return result;
+}
+
+gboolean g_dbus_emit_signal(DBusConnection *connection,
+				const char *path, const char *interface,
+				const char *name, int type, ...)
+{
+	va_list args;
+	gboolean result;
+
+	va_start(args, type);
+
+	result = emit_signal_valist(connection, path, interface,
+							name, type, args);
+
+	va_end(args);
+
+	return result;
+}
+
+gboolean g_dbus_emit_signal_valist(DBusConnection *connection,
+				const char *path, const char *interface,
+				const char *name, int type, va_list args)
+{
+	return emit_signal_valist(connection, path, interface,
+							name, type, args);
+}
+
+static void process_properties_from_interface(struct generic_data *data,
+						struct interface_data *iface)
+{
+	GSList *l;
+	DBusMessage *signal;
+	DBusMessageIter iter, dict, array;
+	GSList *invalidated;
+
+	if (iface->pending_prop == NULL)
+		return;
+
+	signal = dbus_message_new_signal(data->path,
+			DBUS_INTERFACE_PROPERTIES, "PropertiesChanged");
+	if (signal == NULL) {
+		error("Unable to allocate new " DBUS_INTERFACE_PROPERTIES
+						".PropertiesChanged signal");
+		return;
+	}
+
+	iface->pending_prop = g_slist_reverse(iface->pending_prop);
+
+	dbus_message_iter_init_append(signal, &iter);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,	&iface->name);
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+	invalidated = NULL;
+
+	for (l = iface->pending_prop; l != NULL; l = l->next) {
+		GDBusPropertyTable *p = l->data;
+
+		if (p->get == NULL)
+			continue;
+
+		if (p->exists != NULL && !p->exists(p, iface->user_data)) {
+			invalidated = g_slist_prepend(invalidated, p);
+			continue;
+		}
+
+		append_property(iface, p, &dict);
+	}
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+				DBUS_TYPE_STRING_AS_STRING, &array);
+	for (l = invalidated; l != NULL; l = g_slist_next(l)) {
+		GDBusPropertyTable *p = l->data;
+
+		dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
+								&p->name);
+	}
+	g_slist_free(invalidated);
+	dbus_message_iter_close_container(&iter, &array);
+
+	g_dbus_send_message(data->conn, signal);
+
+	g_slist_free(iface->pending_prop);
+	iface->pending_prop = NULL;
+}
+
+static void process_property_changes(struct generic_data *data)
+{
+	GSList *l;
+
+	for (l = data->interfaces; l != NULL; l = l->next) {
+		struct interface_data *iface = l->data;
+
+		process_properties_from_interface(data, iface);
+	}
+
+	data->pending_prop = FALSE;
+}
+
+void g_dbus_emit_property_changed(DBusConnection *connection,
+				const char *path, const char *interface,
+				const char *name)
+{
+	const GDBusPropertyTable *property;
+	struct generic_data *data;
+	struct interface_data *iface;
+
+	if (path == NULL)
+		return;
+
+	if (!dbus_connection_get_object_path_data(connection, path,
+					(void **) &data) || data == NULL)
+		return;
+
+	iface = find_interface(data->interfaces, interface);
+	if (iface == NULL)
+		return;
+
+	property = find_property(iface->properties, name);
+	if (property == NULL) {
+		error("Could not find property %s in %p", name,
+							iface->properties);
+		return;
+	}
+
+	if (g_slist_find(iface->pending_prop, (void *) property) != NULL)
+		return;
+
+	data->pending_prop = TRUE;
+	iface->pending_prop = g_slist_prepend(iface->pending_prop,
+						(void *) property);
+
+	if (!data->process_id) {
+		data->process_id = g_idle_add(process_changes, data);
+		return;
+	}
+}
+
+gboolean g_dbus_get_properties(DBusConnection *connection, const char *path,
+				const char *interface, DBusMessageIter *iter)
+{
+	struct generic_data *data;
+	struct interface_data *iface;
+
+	if (path == NULL)
+		return FALSE;
+
+	if (!dbus_connection_get_object_path_data(connection, path,
+					(void **) &data) || data == NULL)
+		return FALSE;
+
+	iface = find_interface(data->interfaces, interface);
+	if (iface == NULL)
+		return FALSE;
+
+	append_properties(iface, iter);
+
+	return TRUE;
+}
+
+gboolean g_dbus_attach_object_manager(DBusConnection *connection)
+{
+	struct generic_data *data;
+
+	data = object_path_ref(connection, "/");
+	if (data == NULL)
+		return FALSE;
+
+	add_interface(data, DBUS_INTERFACE_OBJECT_MANAGER,
+					manager_methods, manager_signals,
+					NULL, data, NULL);
+	root = data;
+
+	return TRUE;
+}
+
+gboolean g_dbus_detach_object_manager(DBusConnection *connection)
+{
+	if (!g_dbus_unregister_interface(connection, "/",
+					DBUS_INTERFACE_OBJECT_MANAGER))
+		return FALSE;
+
+	root = NULL;
+
+	return TRUE;
+}
+
+void g_dbus_set_flags(int flags)
+{
+	global_flags = flags;
+}
diff --git a/gdbus/polkit.c b/gdbus/polkit.c
new file mode 100644
index 0000000..9e95fa3
--- /dev/null
+++ b/gdbus/polkit.c
@@ -0,0 +1,202 @@
+/*
+ *
+ *  D-Bus helper library
+ *
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <dbus/dbus.h>
+
+#include <glib.h>
+
+int polkit_check_authorization(DBusConnection *conn,
+				const char *action, gboolean interaction,
+				void (*function) (dbus_bool_t authorized,
+							void *user_data),
+						void *user_data, int timeout);
+
+static void add_dict_with_string_value(DBusMessageIter *iter,
+					const char *key, const char *str)
+{
+	DBusMessageIter dict, entry, value;
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+	dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
+								NULL, &entry);
+
+	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+	dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+					DBUS_TYPE_STRING_AS_STRING, &value);
+	dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str);
+	dbus_message_iter_close_container(&entry, &value);
+
+	dbus_message_iter_close_container(&dict, &entry);
+	dbus_message_iter_close_container(iter, &dict);
+}
+
+static void add_empty_string_dict(DBusMessageIter *iter)
+{
+	DBusMessageIter dict;
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING
+			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+	dbus_message_iter_close_container(iter, &dict);
+}
+
+static void add_arguments(DBusConnection *conn, DBusMessageIter *iter,
+				const char *action, dbus_uint32_t flags)
+{
+	const char *busname = dbus_bus_get_unique_name(conn);
+	const char *kind = "system-bus-name";
+	const char *cancel = "";
+	DBusMessageIter subject;
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
+							NULL, &subject);
+	dbus_message_iter_append_basic(&subject, DBUS_TYPE_STRING, &kind);
+	add_dict_with_string_value(&subject, "name", busname);
+	dbus_message_iter_close_container(iter, &subject);
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &action);
+	add_empty_string_dict(iter);
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &flags);
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &cancel);
+}
+
+static dbus_bool_t parse_result(DBusMessageIter *iter)
+{
+	DBusMessageIter result;
+	dbus_bool_t authorized, challenge;
+
+	dbus_message_iter_recurse(iter, &result);
+
+	dbus_message_iter_get_basic(&result, &authorized);
+	dbus_message_iter_get_basic(&result, &challenge);
+
+	return authorized;
+}
+
+struct authorization_data {
+	void (*function) (dbus_bool_t authorized, void *user_data);
+	void *user_data;
+};
+
+static void authorization_reply(DBusPendingCall *call, void *user_data)
+{
+	struct authorization_data *data = user_data;
+	DBusMessage *reply;
+	DBusMessageIter iter;
+	dbus_bool_t authorized = FALSE;
+
+	reply = dbus_pending_call_steal_reply(call);
+
+	if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
+		goto done;
+
+	if (dbus_message_has_signature(reply, "(bba{ss})") == FALSE)
+		goto done;
+
+	dbus_message_iter_init(reply, &iter);
+
+	authorized = parse_result(&iter);
+
+done:
+	if (data->function != NULL)
+		data->function(authorized, data->user_data);
+
+	dbus_message_unref(reply);
+
+	dbus_pending_call_unref(call);
+}
+
+#define AUTHORITY_DBUS	"org.freedesktop.PolicyKit1"
+#define AUTHORITY_INTF	"org.freedesktop.PolicyKit1.Authority"
+#define AUTHORITY_PATH	"/org/freedesktop/PolicyKit1/Authority"
+
+int polkit_check_authorization(DBusConnection *conn,
+				const char *action, gboolean interaction,
+				void (*function) (dbus_bool_t authorized,
+							void *user_data),
+						void *user_data, int timeout)
+{
+	struct authorization_data *data;
+	DBusMessage *msg;
+	DBusMessageIter iter;
+	DBusPendingCall *call;
+	dbus_uint32_t flags = 0x00000000;
+
+	if (conn == NULL)
+		return -EINVAL;
+
+	data = dbus_malloc0(sizeof(*data));
+	if (data == NULL)
+		return -ENOMEM;
+
+	msg = dbus_message_new_method_call(AUTHORITY_DBUS, AUTHORITY_PATH,
+				AUTHORITY_INTF, "CheckAuthorization");
+	if (msg == NULL) {
+		dbus_free(data);
+		return -ENOMEM;
+	}
+
+	if (interaction == TRUE)
+		flags |= 0x00000001;
+
+	if (action == NULL)
+		action = "org.freedesktop.policykit.exec";
+
+	dbus_message_iter_init_append(msg, &iter);
+	add_arguments(conn, &iter, action, flags);
+
+	if (dbus_connection_send_with_reply(conn, msg,
+						&call, timeout) == FALSE) {
+		dbus_message_unref(msg);
+		dbus_free(data);
+		return -EIO;
+	}
+
+	if (call == NULL) {
+		dbus_message_unref(msg);
+		dbus_free(data);
+		return -EIO;
+	}
+
+	data->function = function;
+	data->user_data = user_data;
+
+	dbus_pending_call_set_notify(call, authorization_reply,
+							data, dbus_free);
+
+	dbus_message_unref(msg);
+
+	return 0;
+}
diff --git a/gdbus/watch.c b/gdbus/watch.c
new file mode 100644
index 0000000..9e4f994
--- /dev/null
+++ b/gdbus/watch.c
@@ -0,0 +1,815 @@
+/*
+ *
+ *  D-Bus helper library
+ *
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+
+#include "gdbus.h"
+
+#define info(fmt...)
+#define error(fmt...)
+#define debug(fmt...)
+
+static DBusHandlerResult message_filter(DBusConnection *connection,
+					DBusMessage *message, void *user_data);
+
+static guint listener_id = 0;
+static GSList *listeners = NULL;
+
+struct service_data {
+	DBusConnection *conn;
+	DBusPendingCall *call;
+	char *name;
+	const char *owner;
+	guint id;
+	struct filter_callback *callback;
+};
+
+struct filter_callback {
+	GDBusWatchFunction conn_func;
+	GDBusWatchFunction disc_func;
+	GDBusSignalFunction signal_func;
+	GDBusDestroyFunction destroy_func;
+	struct service_data *data;
+	void *user_data;
+	guint id;
+};
+
+struct filter_data {
+	DBusConnection *connection;
+	DBusHandleMessageFunction handle_func;
+	char *name;
+	char *owner;
+	char *path;
+	char *interface;
+	char *member;
+	char *argument;
+	GSList *callbacks;
+	GSList *processed;
+	guint name_watch;
+	gboolean lock;
+	gboolean registered;
+};
+
+static struct filter_data *filter_data_find_match(DBusConnection *connection,
+							const char *name,
+							const char *owner,
+							const char *path,
+							const char *interface,
+							const char *member,
+							const char *argument)
+{
+	GSList *current;
+
+	for (current = listeners;
+			current != NULL; current = current->next) {
+		struct filter_data *data = current->data;
+
+		if (connection != data->connection)
+			continue;
+
+		if (g_strcmp0(name, data->name) != 0)
+			continue;
+
+		if (g_strcmp0(owner, data->owner) != 0)
+			continue;
+
+		if (g_strcmp0(path, data->path) != 0)
+			continue;
+
+		if (g_strcmp0(interface, data->interface) != 0)
+			continue;
+
+		if (g_strcmp0(member, data->member) != 0)
+			continue;
+
+		if (g_strcmp0(argument, data->argument) != 0)
+			continue;
+
+		return data;
+	}
+
+	return NULL;
+}
+
+static struct filter_data *filter_data_find(DBusConnection *connection)
+{
+	GSList *current;
+
+	for (current = listeners;
+			current != NULL; current = current->next) {
+		struct filter_data *data = current->data;
+
+		if (connection != data->connection)
+			continue;
+
+		return data;
+	}
+
+	return NULL;
+}
+
+static void format_rule(struct filter_data *data, char *rule, size_t size)
+{
+	const char *sender;
+	int offset;
+
+	offset = snprintf(rule, size, "type='signal'");
+	sender = data->name ? : data->owner;
+
+	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);
+}
+
+static gboolean add_match(struct filter_data *data,
+				DBusHandleMessageFunction filter)
+{
+	DBusError err;
+	char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
+
+	format_rule(data, rule, sizeof(rule));
+	dbus_error_init(&err);
+
+	dbus_bus_add_match(data->connection, rule, &err);
+	if (dbus_error_is_set(&err)) {
+		error("Adding match rule \"%s\" failed: %s", rule,
+				err.message);
+		dbus_error_free(&err);
+		return FALSE;
+	}
+
+	data->handle_func = filter;
+	data->registered = TRUE;
+
+	return TRUE;
+}
+
+static gboolean remove_match(struct filter_data *data)
+{
+	DBusError err;
+	char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
+
+	format_rule(data, rule, sizeof(rule));
+
+	dbus_error_init(&err);
+
+	dbus_bus_remove_match(data->connection, rule, &err);
+	if (dbus_error_is_set(&err)) {
+		error("Removing owner match rule for %s failed: %s",
+				rule, err.message);
+		dbus_error_free(&err);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static struct filter_data *filter_data_get(DBusConnection *connection,
+					DBusHandleMessageFunction filter,
+					const char *sender,
+					const char *path,
+					const char *interface,
+					const char *member,
+					const char *argument)
+{
+	struct filter_data *data;
+	const char *name = NULL, *owner = NULL;
+
+	if (filter_data_find(connection) == NULL) {
+		if (!dbus_connection_add_filter(connection,
+					message_filter, NULL, NULL)) {
+			error("dbus_connection_add_filter() failed");
+			return NULL;
+		}
+	}
+
+	if (sender == NULL)
+		goto proceed;
+
+	if (sender[0] == ':')
+		owner = sender;
+	else
+		name = sender;
+
+proceed:
+	data = filter_data_find_match(connection, name, owner, path,
+						interface, member, argument);
+	if (data)
+		return data;
+
+	data = g_new0(struct filter_data, 1);
+
+	data->connection = dbus_connection_ref(connection);
+	data->name = g_strdup(name);
+	data->owner = g_strdup(owner);
+	data->path = g_strdup(path);
+	data->interface = g_strdup(interface);
+	data->member = g_strdup(member);
+	data->argument = g_strdup(argument);
+
+	if (!add_match(data, filter)) {
+		g_free(data);
+		return NULL;
+	}
+
+	listeners = g_slist_append(listeners, data);
+
+	return data;
+}
+
+static struct filter_callback *filter_data_find_callback(
+						struct filter_data *data,
+						guint id)
+{
+	GSList *l;
+
+	for (l = data->callbacks; l; l = l->next) {
+		struct filter_callback *cb = l->data;
+		if (cb->id == id)
+			return cb;
+	}
+	for (l = data->processed; l; l = l->next) {
+		struct filter_callback *cb = l->data;
+		if (cb->id == id)
+			return cb;
+	}
+
+	return NULL;
+}
+
+static void filter_data_free(struct filter_data *data)
+{
+	GSList *l;
+
+	for (l = data->callbacks; l != NULL; l = l->next)
+		g_free(l->data);
+
+	g_slist_free(data->callbacks);
+	g_dbus_remove_watch(data->connection, data->name_watch);
+	g_free(data->name);
+	g_free(data->owner);
+	g_free(data->path);
+	g_free(data->interface);
+	g_free(data->member);
+	g_free(data->argument);
+	dbus_connection_unref(data->connection);
+	g_free(data);
+}
+
+static void filter_data_call_and_free(struct filter_data *data)
+{
+	GSList *l;
+
+	for (l = data->callbacks; l != NULL; l = l->next) {
+		struct filter_callback *cb = l->data;
+		if (cb->disc_func)
+			cb->disc_func(data->connection, cb->user_data);
+		if (cb->destroy_func)
+			cb->destroy_func(cb->user_data);
+		g_free(cb);
+	}
+
+	filter_data_free(data);
+}
+
+static struct filter_callback *filter_data_add_callback(
+						struct filter_data *data,
+						GDBusWatchFunction connect,
+						GDBusWatchFunction disconnect,
+						GDBusSignalFunction signal,
+						GDBusDestroyFunction destroy,
+						void *user_data)
+{
+	struct filter_callback *cb = NULL;
+
+	cb = g_new0(struct filter_callback, 1);
+
+	cb->conn_func = connect;
+	cb->disc_func = disconnect;
+	cb->signal_func = signal;
+	cb->destroy_func = destroy;
+	cb->user_data = user_data;
+	cb->id = ++listener_id;
+
+	if (data->lock)
+		data->processed = g_slist_append(data->processed, cb);
+	else
+		data->callbacks = g_slist_append(data->callbacks, cb);
+
+	return cb;
+}
+
+static void service_data_free(struct service_data *data)
+{
+	struct filter_callback *callback = data->callback;
+
+	dbus_connection_unref(data->conn);
+
+	if (data->call)
+		dbus_pending_call_unref(data->call);
+
+	if (data->id)
+		g_source_remove(data->id);
+
+	g_free(data->name);
+	g_free(data);
+
+	callback->data = NULL;
+}
+
+static gboolean filter_data_remove_callback(struct filter_data *data,
+						struct filter_callback *cb)
+{
+	DBusConnection *connection;
+
+	data->callbacks = g_slist_remove(data->callbacks, cb);
+	data->processed = g_slist_remove(data->processed, cb);
+
+	/* Cancel pending operations */
+	if (cb->data) {
+		if (cb->data->call)
+			dbus_pending_call_cancel(cb->data->call);
+		service_data_free(cb->data);
+	}
+
+	if (cb->destroy_func)
+		cb->destroy_func(cb->user_data);
+
+	g_free(cb);
+
+	/* Don't remove the filter if other callbacks exist or data is lock
+	 * processing callbacks */
+	if (data->callbacks || data->lock)
+		return TRUE;
+
+	if (data->registered && !remove_match(data))
+		return FALSE;
+
+	connection = dbus_connection_ref(data->connection);
+	listeners = g_slist_remove(listeners, data);
+
+	/* Remove filter if there are no listeners left for the connection */
+	if (filter_data_find(connection) == NULL)
+		dbus_connection_remove_filter(connection, message_filter,
+						NULL);
+
+	filter_data_free(data);
+	dbus_connection_unref(connection);
+
+	return TRUE;
+}
+
+static DBusHandlerResult signal_filter(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	struct filter_data *data = user_data;
+	struct filter_callback *cb;
+
+	while (data->callbacks) {
+		cb = data->callbacks->data;
+
+		if (cb->signal_func && !cb->signal_func(connection, message,
+							cb->user_data)) {
+			filter_data_remove_callback(data, cb);
+			continue;
+		}
+
+		/* Check if the watch was removed/freed by the callback
+		 * function */
+		if (!g_slist_find(data->callbacks, cb))
+			continue;
+
+		data->callbacks = g_slist_remove(data->callbacks, cb);
+		data->processed = g_slist_append(data->processed, cb);
+	}
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void update_name_cache(const char *name, const char *owner)
+{
+	GSList *l;
+
+	for (l = listeners; l != NULL; l = l->next) {
+		struct filter_data *data = l->data;
+
+		if (g_strcmp0(data->name, name) != 0)
+			continue;
+
+		g_free(data->owner);
+		data->owner = g_strdup(owner);
+	}
+}
+
+static const char *check_name_cache(const char *name)
+{
+	GSList *l;
+
+	for (l = listeners; l != NULL; l = l->next) {
+		struct filter_data *data = l->data;
+
+		if (g_strcmp0(data->name, name) != 0)
+			continue;
+
+		return data->owner;
+	}
+
+	return NULL;
+}
+
+static DBusHandlerResult service_filter(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	struct filter_data *data = user_data;
+	struct filter_callback *cb;
+	char *name, *old, *new;
+
+	if (!dbus_message_get_args(message, NULL,
+				DBUS_TYPE_STRING, &name,
+				DBUS_TYPE_STRING, &old,
+				DBUS_TYPE_STRING, &new,
+				DBUS_TYPE_INVALID)) {
+		error("Invalid arguments for NameOwnerChanged signal");
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+	}
+
+	update_name_cache(name, new);
+
+	while (data->callbacks) {
+		cb = data->callbacks->data;
+
+		if (*new == '\0') {
+			if (cb->disc_func)
+				cb->disc_func(connection, cb->user_data);
+		} else {
+			if (cb->conn_func)
+				cb->conn_func(connection, cb->user_data);
+		}
+
+		/* Check if the watch was removed/freed by the callback
+		 * function */
+		if (!g_slist_find(data->callbacks, cb))
+			continue;
+
+		/* Only auto remove if it is a bus name watch */
+		if (data->argument[0] == ':' &&
+				(cb->conn_func == NULL || cb->disc_func == NULL)) {
+			filter_data_remove_callback(data, cb);
+			continue;
+		}
+
+		data->callbacks = g_slist_remove(data->callbacks, cb);
+		data->processed = g_slist_append(data->processed, cb);
+	}
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+
+static DBusHandlerResult message_filter(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	struct filter_data *data;
+	const char *sender, *path, *iface, *member, *arg = NULL;
+	GSList *current, *delete_listener = NULL;
+
+	/* Only filter signals */
+	if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+	sender = dbus_message_get_sender(message);
+	path = dbus_message_get_path(message);
+	iface = dbus_message_get_interface(message);
+	member = dbus_message_get_member(message);
+	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
+
+	/* Sender is always the owner */
+
+	for (current = listeners; current != NULL; current = current->next) {
+		data = current->data;
+
+		if (connection != data->connection)
+			continue;
+
+		if (data->owner && g_str_equal(sender, data->owner) == FALSE)
+			continue;
+
+		if (data->path && g_str_equal(path, data->path) == FALSE)
+			continue;
+
+		if (data->interface && g_str_equal(iface,
+						data->interface) == FALSE)
+			continue;
+
+		if (data->member && g_str_equal(member, data->member) == FALSE)
+			continue;
+
+		if (data->argument && g_str_equal(arg,
+						data->argument) == FALSE)
+			continue;
+
+		if (data->handle_func) {
+			data->lock = TRUE;
+
+			data->handle_func(connection, message, data);
+
+			data->callbacks = data->processed;
+			data->processed = NULL;
+			data->lock = FALSE;
+		}
+
+		if (!data->callbacks)
+			delete_listener = g_slist_prepend(delete_listener,
+								current);
+	}
+
+	for (current = delete_listener; current != NULL;
+					current = delete_listener->next) {
+		GSList *l = current->data;
+
+		data = l->data;
+
+		/* Has any other callback added callbacks back to this data? */
+		if (data->callbacks != NULL)
+			continue;
+
+		remove_match(data);
+		listeners = g_slist_delete_link(listeners, l);
+
+		filter_data_free(data);
+	}
+
+	g_slist_free(delete_listener);
+
+	/* Remove filter if there are no listeners left for the connection */
+	if (filter_data_find(connection) == NULL)
+		dbus_connection_remove_filter(connection, message_filter,
+						NULL);
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static gboolean update_service(void *user_data)
+{
+	struct service_data *data = user_data;
+	struct filter_callback *cb = data->callback;
+
+	update_name_cache(data->name, data->owner);
+	if (cb->conn_func)
+		cb->conn_func(data->conn, cb->user_data);
+
+	service_data_free(data);
+
+	return FALSE;
+}
+
+static void service_reply(DBusPendingCall *call, void *user_data)
+{
+	struct service_data *data = user_data;
+	DBusMessage *reply;
+	DBusError err;
+
+	reply = dbus_pending_call_steal_reply(call);
+	if (reply == NULL)
+		return;
+
+	dbus_error_init(&err);
+
+	if (dbus_set_error_from_message(&err, reply))
+		goto fail;
+
+	if (dbus_message_get_args(reply, &err,
+					DBUS_TYPE_STRING, &data->owner,
+						DBUS_TYPE_INVALID) == FALSE)
+		goto fail;
+
+	update_service(data);
+
+	goto done;
+
+fail:
+	error("%s", err.message);
+	dbus_error_free(&err);
+	service_data_free(data);
+done:
+	dbus_message_unref(reply);
+}
+
+static void check_service(DBusConnection *connection,
+					const char *name,
+					struct filter_callback *callback)
+{
+	DBusMessage *message;
+	struct service_data *data;
+
+	data = g_try_malloc0(sizeof(*data));
+	if (data == NULL) {
+		error("Can't allocate data structure");
+		return;
+	}
+
+	data->conn = dbus_connection_ref(connection);
+	data->name = g_strdup(name);
+	data->callback = callback;
+	callback->data = data;
+
+	data->owner = check_name_cache(name);
+	if (data->owner != NULL) {
+		data->id = g_idle_add(update_service, data);
+		return;
+	}
+
+	message = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
+			DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetNameOwner");
+	if (message == NULL) {
+		error("Can't allocate new message");
+		g_free(data);
+		return;
+	}
+
+	dbus_message_append_args(message, DBUS_TYPE_STRING, &name,
+							DBUS_TYPE_INVALID);
+
+	if (dbus_connection_send_with_reply(connection, message,
+							&data->call, -1) == FALSE) {
+		error("Failed to execute method call");
+		g_free(data);
+		goto done;
+	}
+
+	if (data->call == NULL) {
+		error("D-Bus connection not available");
+		g_free(data);
+		goto done;
+	}
+
+	dbus_pending_call_set_notify(data->call, service_reply, data, NULL);
+
+done:
+	dbus_message_unref(message);
+}
+
+guint g_dbus_add_service_watch(DBusConnection *connection, const char *name,
+				GDBusWatchFunction connect,
+				GDBusWatchFunction disconnect,
+				void *user_data, GDBusDestroyFunction destroy)
+{
+	struct filter_data *data;
+	struct filter_callback *cb;
+
+	if (name == NULL)
+		return 0;
+
+	data = filter_data_get(connection, service_filter, NULL, NULL,
+				DBUS_INTERFACE_DBUS, "NameOwnerChanged",
+				name);
+	if (data == NULL)
+		return 0;
+
+	cb = filter_data_add_callback(data, connect, disconnect, NULL, destroy,
+					user_data);
+	if (cb == NULL)
+		return 0;
+
+	if (connect)
+		check_service(connection, name, cb);
+
+	return cb->id;
+}
+
+guint g_dbus_add_disconnect_watch(DBusConnection *connection, const char *name,
+				GDBusWatchFunction func,
+				void *user_data, GDBusDestroyFunction destroy)
+{
+	return g_dbus_add_service_watch(connection, name, NULL, func,
+							user_data, destroy);
+}
+
+guint g_dbus_add_signal_watch(DBusConnection *connection,
+				const char *sender, const char *path,
+				const char *interface, const char *member,
+				GDBusSignalFunction function, void *user_data,
+				GDBusDestroyFunction destroy)
+{
+	struct filter_data *data;
+	struct filter_callback *cb;
+
+	data = filter_data_get(connection, signal_filter, sender, path,
+				interface, member, NULL);
+	if (data == NULL)
+		return 0;
+
+	cb = filter_data_add_callback(data, NULL, NULL, function, destroy,
+					user_data);
+	if (cb == NULL)
+		return 0;
+
+	if (data->name != NULL && data->name_watch == 0)
+		data->name_watch = g_dbus_add_service_watch(connection,
+							data->name, NULL,
+							NULL, NULL, NULL);
+
+	return cb->id;
+}
+
+guint g_dbus_add_properties_watch(DBusConnection *connection,
+				const char *sender, const char *path,
+				const char *interface,
+				GDBusSignalFunction function, void *user_data,
+				GDBusDestroyFunction destroy)
+{
+	struct filter_data *data;
+	struct filter_callback *cb;
+
+	data = filter_data_get(connection, signal_filter, sender, path,
+				DBUS_INTERFACE_PROPERTIES, "PropertiesChanged",
+				interface);
+	if (data == NULL)
+		return 0;
+
+	cb = filter_data_add_callback(data, NULL, NULL, function, destroy,
+					user_data);
+	if (cb == NULL)
+		return 0;
+
+	if (data->name != NULL && data->name_watch == 0)
+		data->name_watch = g_dbus_add_service_watch(connection,
+							data->name, NULL,
+							NULL, NULL, NULL);
+
+	return cb->id;
+}
+
+gboolean g_dbus_remove_watch(DBusConnection *connection, guint id)
+{
+	struct filter_data *data;
+	struct filter_callback *cb;
+	GSList *ldata;
+
+	if (id == 0)
+		return FALSE;
+
+	for (ldata = listeners; ldata; ldata = ldata->next) {
+		data = ldata->data;
+
+		cb = filter_data_find_callback(data, id);
+		if (cb) {
+			filter_data_remove_callback(data, cb);
+			return TRUE;
+		}
+	}
+
+	return FALSE;
+}
+
+void g_dbus_remove_all_watches(DBusConnection *connection)
+{
+	struct filter_data *data;
+
+	while ((data = filter_data_find(connection))) {
+		listeners = g_slist_remove(listeners, data);
+		filter_data_call_and_free(data);
+	}
+
+	dbus_connection_remove_filter(connection, message_filter, NULL);
+}
diff --git a/gdhcp/client.c b/gdhcp/client.c
new file mode 100644
index 0000000..f423f52
--- /dev/null
+++ b/gdhcp/client.c
@@ -0,0 +1,2934 @@
+/*
+ *
+ *  DHCP client library with GLib integration
+ *
+ *  Copyright (C) 2009-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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+
+#include <netpacket/packet.h>
+#include <netinet/if_ether.h>
+#include <net/ethernet.h>
+
+#include <linux/if.h>
+#include <linux/filter.h>
+
+#include <glib.h>
+
+#include "gdhcp.h"
+#include "common.h"
+#include "ipv4ll.h"
+#include "timer.h"
+
+/* Set to 0 to temporarily rollback to old timer model for DHCP */
+#define FEATURE_USE_RT_TIMERS 0
+
+#define DISCOVER_TIMEOUT 3
+#define DISCOVER_RETRIES 10
+
+#define REQUEST_TIMEOUT 3
+#define REQUEST_RETRIES 5
+#define LEASE_TIME_ONE_WEEK_SECONDS (60 * 60 * 24 * 7)
+
+typedef enum _listen_mode {
+	L_NONE,
+	L2,
+	L3,
+	L_ARP,
+} ListenMode;
+
+typedef enum _dhcp_client_state {
+	INIT_SELECTING,
+	REQUESTING,
+	BOUND,
+	RENEWING,
+	REBINDING,
+	RELEASED,
+	IPV4LL_PROBE,
+	IPV4LL_ANNOUNCE,
+	IPV4LL_MONITOR,
+	IPV4LL_DEFEND,
+	INFORMATION_REQ,
+	SOLICITATION,
+	REQUEST,
+	RENEW,
+	REBIND,
+	RELEASE,
+} ClientState;
+
+struct _GDHCPClient {
+	int ref_count;
+	GDHCPType type;
+	ClientState state;
+	int ifindex;
+	char *interface;
+	uint8_t mac_address[6];
+	uint32_t xid;
+	uint32_t server_ip;
+	uint32_t requested_ip;
+	char *assigned_ip;
+	time_t start;
+	uint32_t lease_seconds;
+	ListenMode listen_mode;
+	int listener_sockfd;
+	uint8_t retry_times;
+	uint8_t ack_retry_times;
+	uint8_t conflicts;
+	guint timeout;
+	guint listener_watch;
+	GIOChannel *listener_channel;
+	GList *require_list;
+	GList *request_list;
+	GHashTable *code_value_hash;
+	GHashTable *send_value_hash;
+	GDHCPClientEventFunc lease_available_cb;
+	gpointer lease_available_data;
+	GDHCPClientEventFunc ipv4ll_available_cb;
+	gpointer ipv4ll_available_data;
+	GDHCPClientEventFunc no_lease_cb;
+	gpointer no_lease_data;
+	GDHCPClientEventFunc lease_lost_cb;
+	gpointer lease_lost_data;
+	GDHCPClientEventFunc ipv4ll_lost_cb;
+	gpointer ipv4ll_lost_data;
+	GDHCPClientEventFunc address_conflict_cb;
+	gpointer address_conflict_data;
+	GDHCPDebugFunc debug_func;
+	gpointer debug_data;
+	GDHCPClientEventFunc information_req_cb;
+	gpointer information_req_data;
+	GDHCPClientEventFunc solicitation_cb;
+	gpointer solicitation_data;
+	GDHCPClientEventFunc advertise_cb;
+	gpointer advertise_data;
+	GDHCPClientEventFunc request_cb;
+	gpointer request_data;
+	GDHCPClientEventFunc renew_cb;
+	gpointer renew_data;
+	GDHCPClientEventFunc rebind_cb;
+	gpointer rebind_data;
+	GDHCPClientEventFunc release_cb;
+	gpointer release_data;
+	GDHCPClientEventFunc wake_event_cb;
+	gpointer wake_event_data;
+	char *last_address;
+	unsigned char *duid;
+	int duid_len;
+	unsigned char *server_duid;
+	int server_duid_len;
+	uint16_t status_code;
+	uint32_t iaid;
+	uint32_t T1, T2;
+	uint32_t next_event;
+	int can_sleep;
+	struct in6_addr ia_na;
+	struct in6_addr ia_ta;
+	time_t last_renew;
+	time_t last_rebind;
+	time_t expire;
+};
+
+static inline void debug(GDHCPClient *client, const char *format, ...)
+{
+	char str[256];
+	va_list ap;
+
+	if (client->debug_func == NULL)
+		return;
+
+	va_start(ap, format);
+
+	if (vsnprintf(str, sizeof(str), format, ap) > 0)
+		client->debug_func(str, client->debug_data);
+
+	va_end(ap);
+}
+
+static void timer_source_remove(GDHCPClient *dhcp_client)
+{
+#if FEATURE_USE_RT_TIMERS
+	g_rttimeout_source_remove(dhcp_client->timeout);
+#else
+	g_source_remove(dhcp_client->timeout);
+#endif
+}
+
+
+static guint timeout_add_full (gint priority, guint32 interval,
+			   GSourceFunc function, gpointer data,
+			   GDestroyNotify notify)
+{
+#if FEATURE_USE_RT_TIMERS
+	return g_rttimeout_add_full(G_CLOCK_REALTIME, priority, interval,
+					function, data, notify);
+#else
+	return g_timeout_add_full(priority, interval,
+					function, data, notify);
+#endif
+}
+
+static guint timeout_add_seconds_full (gint priority, guint32 interval,
+				   GSourceFunc function, gpointer data,
+				   GDestroyNotify notify)
+{
+#if FEATURE_USE_RT_TIMERS
+	return g_rttimeout_add_seconds_full(G_CLOCK_REALTIME,
+				priority, interval, function,
+				data, notify);
+#else
+	return g_timeout_add_seconds_full(priority, interval,
+				function, data, notify);
+#endif
+}
+
+static void remove_timer(GDHCPClient *dhcp_client)
+{
+	if (dhcp_client->timeout > 0) {
+        timer_source_remove(dhcp_client);
+		dhcp_client->timeout = 0;
+	}
+}
+
+/* Initialize the packet with the proper defaults */
+static void init_packet(GDHCPClient *dhcp_client, gpointer pkt, char type)
+{
+	if (dhcp_client->type == G_DHCP_IPV6)
+		dhcpv6_init_header(pkt, type);
+	else {
+		struct dhcp_packet *packet = pkt;
+
+		dhcp_init_header(packet, type);
+		memcpy(packet->chaddr, dhcp_client->mac_address, 6);
+	}
+}
+
+static void add_request_options(GDHCPClient *dhcp_client,
+				struct dhcp_packet *packet)
+{
+	int len = 0;
+	GList *list;
+	uint8_t code;
+	int end = dhcp_end_option(packet->options);
+
+	for (list = dhcp_client->request_list; list; list = list->next) {
+		code = (uint8_t) GPOINTER_TO_INT(list->data);
+
+		packet->options[end + OPT_DATA + len] = code;
+		len++;
+	}
+
+	if (len) {
+		packet->options[end + OPT_CODE] = DHCP_PARAM_REQ;
+		packet->options[end + OPT_LEN] = len;
+		packet->options[end + OPT_DATA + len] = DHCP_END;
+	}
+}
+
+struct hash_params {
+	unsigned char *buf;
+	int max_buf;
+	unsigned char **ptr_buf;
+};
+
+static void add_dhcpv6_binary_option(gpointer key, gpointer value,
+					gpointer user_data)
+{
+	uint8_t *option = value;
+	uint16_t len;
+	struct hash_params *params = user_data;
+
+	/* option[0][1] contains option code */
+	len = option[2] << 8 | option[3];
+
+	if ((*params->ptr_buf + len + 2 + 2) > (params->buf + params->max_buf))
+		return;
+
+	memcpy(*params->ptr_buf, option, len + 2 + 2);
+	(*params->ptr_buf) += len + 2 + 2;
+}
+
+static void add_dhcpv6_send_options(GDHCPClient *dhcp_client,
+				unsigned char *buf, int max_buf,
+				unsigned char **ptr_buf)
+{
+	struct hash_params params = {
+		.buf = buf,
+		.max_buf = max_buf,
+		.ptr_buf = ptr_buf
+	};
+
+	if (dhcp_client->type == G_DHCP_IPV4)
+		return;
+
+	g_hash_table_foreach(dhcp_client->send_value_hash,
+				add_dhcpv6_binary_option, &params);
+
+	*ptr_buf = *params.ptr_buf;
+}
+
+static void copy_option(uint8_t *buf, uint16_t code, uint16_t len,
+			uint8_t *msg)
+{
+	buf[0] = code >> 8;
+	buf[1] = code & 0xff;
+	buf[2] = len >> 8;
+	buf[3] = len & 0xff;
+	if (len > 0 && msg != NULL)
+		memcpy(&buf[4], msg, len);
+}
+
+static void set_wake(GDHCPClient *dhcp_client, uint32_t timeout)
+{
+    debug(dhcp_client, "Stay awake for %d", timeout);
+
+	dhcp_client->next_event = timeout + time(NULL);
+    dhcp_client->can_sleep = FALSE;
+    if (dhcp_client->wake_event_cb)
+        dhcp_client->wake_event_cb(dhcp_client,
+                dhcp_client->wake_event_data);
+}
+
+static void release_wake(GDHCPClient *dhcp_client, uint32_t timeout)
+{
+    debug(dhcp_client, "may sleep for %d", timeout);
+	dhcp_client->next_event = timeout + time(NULL);
+    dhcp_client->can_sleep = TRUE;
+    if (dhcp_client->wake_event_cb)
+        dhcp_client->wake_event_cb(dhcp_client,
+                dhcp_client->wake_event_data);
+}
+
+int g_dhcp_get_next_event(GDHCPClient *dhcp_client, time_t *next_event)
+{
+    *next_event = dhcp_client->next_event;
+
+    return dhcp_client->can_sleep;
+}
+
+static void add_dhcpv6_request_options(GDHCPClient *dhcp_client,
+				struct dhcpv6_packet *packet,
+				unsigned char *buf, int max_buf,
+				unsigned char **ptr_buf)
+{
+	GList *list;
+	uint16_t code;
+	int len;
+
+	if (dhcp_client->type == G_DHCP_IPV4)
+		return;
+
+	for (list = dhcp_client->request_list; list; list = list->next) {
+		code = (uint16_t) GPOINTER_TO_INT(list->data);
+
+		switch (code) {
+		case G_DHCPV6_CLIENTID:
+			if (dhcp_client->duid == NULL)
+				return;
+
+			len = 2 + 2 + dhcp_client->duid_len;
+			if ((*ptr_buf + len) > (buf + max_buf)) {
+				debug(dhcp_client, "Too long dhcpv6 message "
+					"when writing client id option");
+				return;
+			}
+
+			copy_option(*ptr_buf, G_DHCPV6_CLIENTID,
+				dhcp_client->duid_len, dhcp_client->duid);
+			(*ptr_buf) += len;
+			break;
+
+		case G_DHCPV6_SERVERID:
+			if (dhcp_client->server_duid == NULL)
+				return;
+
+			len = 2 + 2 + dhcp_client->server_duid_len;
+			if ((*ptr_buf + len) > (buf + max_buf)) {
+				debug(dhcp_client, "Too long dhcpv6 message "
+					"when writing server id option");
+				return;
+			}
+
+			copy_option(*ptr_buf, G_DHCPV6_SERVERID,
+				dhcp_client->server_duid_len,
+				dhcp_client->server_duid);
+			(*ptr_buf) += len;
+			break;
+
+		case G_DHCPV6_RAPID_COMMIT:
+			len = 2 + 2;
+			if ((*ptr_buf + len) > (buf + max_buf)) {
+				debug(dhcp_client, "Too long dhcpv6 message "
+					"when writing rapid commit option");
+				return;
+			}
+
+			copy_option(*ptr_buf, G_DHCPV6_RAPID_COMMIT, 0, 0);
+			(*ptr_buf) += len;
+			break;
+
+		case G_DHCPV6_ORO:
+			break;
+
+		case G_DHCPV6_DNS_SERVERS:
+			break;
+
+		case G_DHCPV6_SNTP_SERVERS:
+			break;
+
+		default:
+			break;
+		}
+	}
+}
+
+static void add_binary_option(gpointer key, gpointer value, gpointer user_data)
+{
+	uint8_t *option = value;
+	struct dhcp_packet *packet = user_data;
+
+	dhcp_add_binary_option(packet, option);
+}
+
+static void add_send_options(GDHCPClient *dhcp_client,
+				struct dhcp_packet *packet)
+{
+	g_hash_table_foreach(dhcp_client->send_value_hash,
+				add_binary_option, packet);
+}
+
+static const char *get_message_type(uint8_t type)
+{
+	switch (type) {
+	case DHCPDISCOVER:
+		return "DISCOVER";
+	case DHCPOFFER:
+		return "OFFER";
+	case DHCPREQUEST:
+		return "REQUEST";
+	case DHCPDECLINE:
+		return "DECLINE";
+	case DHCPACK:
+		return "ACK";
+	case DHCPNAK:
+		return "NAK";
+	case DHCPRELEASE:
+		return "RELEASE";
+	case DHCPINFORM:
+		return "INFORM";
+	default:
+		return "";
+	}
+}
+/*
+ * Return an RFC 951- and 2131-complaint BOOTP 'secs' value that
+ * represents the number of seconds elapsed from the start of
+ * attempting DHCP to satisfy some DHCP servers that allow for an
+ * "authoritative" reply before responding.
+ */
+static uint16_t dhcp_attempt_secs(GDHCPClient *dhcp_client)
+{
+	return htons(MIN(time(NULL) - dhcp_client->start, UINT16_MAX));
+}
+
+static int send_discover(GDHCPClient *dhcp_client, uint32_t requested)
+{
+	const uint8_t type = DHCPDISCOVER;
+	struct dhcp_packet packet;
+	struct in_addr dest;
+	char destbuf[INET_ADDRSTRLEN];
+
+	init_packet(dhcp_client, &packet, type);
+
+	packet.xid = dhcp_client->xid;
+	packet.secs = dhcp_attempt_secs(dhcp_client);
+
+	if (requested)
+		dhcp_add_option_uint32(&packet, DHCP_REQUESTED_IP, requested);
+
+	/* Explicitly saying that we want RFC-compliant packets helps
+	 * some buggy DHCP servers to NOT send bigger packets */
+	dhcp_add_option_uint16(&packet, DHCP_MAX_SIZE, 576);
+
+	add_request_options(dhcp_client, &packet);
+
+	add_send_options(dhcp_client, &packet);
+
+	dest.s_addr = INADDR_BROADCAST;
+
+	debug(dhcp_client, "%s on %s to %s port %d interval %d",
+		get_message_type(type),
+		dhcp_client->interface,
+		inet_ntop(AF_INET, &dest, destbuf, sizeof(destbuf)),
+		SERVER_PORT,
+		DISCOVER_TIMEOUT);
+
+	return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT,
+					dest.s_addr, SERVER_PORT,
+					MAC_BCAST_ADDR, dhcp_client->ifindex);
+}
+
+static int send_select(GDHCPClient *dhcp_client)
+{
+	const uint8_t type = DHCPREQUEST;
+	struct dhcp_packet packet;
+	struct in_addr request, dest;
+	char requestbuf[INET_ADDRSTRLEN], destbuf[INET_ADDRSTRLEN];
+
+	init_packet(dhcp_client, &packet, type);
+
+	packet.xid = dhcp_client->xid;
+	packet.secs = dhcp_attempt_secs(dhcp_client);
+
+	dhcp_add_option_uint32(&packet, DHCP_REQUESTED_IP,
+						dhcp_client->requested_ip);
+	dhcp_add_option_uint32(&packet, DHCP_SERVER_ID,
+						dhcp_client->server_ip);
+
+	add_request_options(dhcp_client, &packet);
+
+	add_send_options(dhcp_client, &packet);
+
+	request.s_addr = dhcp_client->requested_ip;
+	dest.s_addr = INADDR_BROADCAST;
+
+	debug(dhcp_client, "%s of %s on %s to %s port %d interval %d",
+		get_message_type(type),
+		inet_ntop(AF_INET, &request, requestbuf, sizeof(requestbuf)),
+		dhcp_client->interface,
+		inet_ntop(AF_INET, &dest, destbuf, sizeof(destbuf)),
+		SERVER_PORT,
+		REQUEST_TIMEOUT);
+
+	return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT,
+					dest.s_addr, SERVER_PORT,
+					MAC_BCAST_ADDR, dhcp_client->ifindex);
+}
+
+static int send_renew(GDHCPClient *dhcp_client)
+{
+	const uint8_t type = DHCPREQUEST;
+	struct dhcp_packet packet;
+	struct in_addr request, dest;
+	char requestbuf[INET_ADDRSTRLEN], destbuf[INET_ADDRSTRLEN];
+
+	init_packet(dhcp_client , &packet, type);
+	packet.xid = dhcp_client->xid;
+	packet.ciaddr = htonl(dhcp_client->requested_ip);
+
+	add_request_options(dhcp_client, &packet);
+
+	add_send_options(dhcp_client, &packet);
+
+	request.s_addr = dhcp_client->requested_ip;
+	dest.s_addr = dhcp_client->server_ip;
+
+	debug(dhcp_client, "%s of %s on %s to %s port %d interval %d",
+		get_message_type(type),
+		inet_ntop(AF_INET, &request, requestbuf, sizeof(requestbuf)),
+		dhcp_client->interface,
+		inet_ntop(AF_INET, &dest, destbuf, sizeof(destbuf)),
+		SERVER_PORT,
+		REQUEST_TIMEOUT);
+
+	return dhcp_send_kernel_packet(&packet,
+		request.s_addr, CLIENT_PORT,
+		dest.s_addr, SERVER_PORT);
+}
+
+static int send_rebound(GDHCPClient *dhcp_client)
+{
+	const uint8_t type = DHCPREQUEST;
+	struct dhcp_packet packet;
+	struct in_addr request, dest;
+	char requestbuf[INET_ADDRSTRLEN], destbuf[INET_ADDRSTRLEN];
+
+	init_packet(dhcp_client , &packet, type);
+	packet.xid = dhcp_client->xid;
+	packet.ciaddr = htonl(dhcp_client->requested_ip);
+
+	add_request_options(dhcp_client, &packet);
+
+	add_send_options(dhcp_client, &packet);
+
+	request.s_addr = dhcp_client->requested_ip;
+	dest.s_addr = INADDR_BROADCAST;
+
+	debug(dhcp_client, "%s of %s on %s to %s port %d interval %d",
+		get_message_type(type),
+		inet_ntop(AF_INET, &request, requestbuf, sizeof(requestbuf)),
+		dhcp_client->interface,
+		inet_ntop(AF_INET, &dest, destbuf, sizeof(destbuf)),
+		SERVER_PORT,
+		REQUEST_TIMEOUT);
+
+	return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT,
+					INADDR_BROADCAST, SERVER_PORT,
+					MAC_BCAST_ADDR, dhcp_client->ifindex);
+}
+
+static int send_release(GDHCPClient *dhcp_client,
+			uint32_t server, uint32_t ciaddr)
+{
+	const uint8_t type = DHCPRELEASE;
+	struct dhcp_packet packet;
+	struct in_addr release, dest;
+	char releasebuf[INET_ADDRSTRLEN], destbuf[INET_ADDRSTRLEN];
+
+	init_packet(dhcp_client, &packet, type);
+	packet.xid = rand();
+	packet.ciaddr = htonl(ciaddr);
+
+	dhcp_add_option_uint32(&packet, DHCP_SERVER_ID, server);
+
+	release.s_addr = ciaddr;
+	dest.s_addr = server;
+
+	debug(dhcp_client, "%s of %s on %s to %s port %d",
+		get_message_type(type),
+		inet_ntop(AF_INET, &release, releasebuf, sizeof(releasebuf)),
+		dhcp_client->interface,
+		inet_ntop(AF_INET, &dest, destbuf, sizeof(destbuf)),
+		SERVER_PORT);
+
+	return dhcp_send_kernel_packet(&packet, release.s_addr, CLIENT_PORT,
+						dest.s_addr, SERVER_PORT);
+}
+
+static gboolean ipv4ll_probe_timeout(gpointer dhcp_data);
+static int switch_listening_mode(GDHCPClient *dhcp_client,
+					ListenMode listen_mode);
+
+static gboolean send_probe_packet(gpointer dhcp_data)
+{
+	GDHCPClient *dhcp_client;
+	guint timeout;
+
+	dhcp_client = dhcp_data;
+	/* if requested_ip is not valid, pick a new address*/
+	if (dhcp_client->requested_ip == 0) {
+		debug(dhcp_client, "pick a new random address");
+		dhcp_client->requested_ip = ipv4ll_random_ip(0);
+	}
+
+	debug(dhcp_client, "sending IPV4LL probe request");
+
+	if (dhcp_client->retry_times == 1) {
+		dhcp_client->state = IPV4LL_PROBE;
+		switch_listening_mode(dhcp_client, L_ARP);
+	}
+	ipv4ll_send_arp_packet(dhcp_client->mac_address, 0,
+			dhcp_client->requested_ip, dhcp_client->ifindex);
+
+	if (dhcp_client->retry_times < PROBE_NUM) {
+		/*add a random timeout in range of PROBE_MIN to PROBE_MAX*/
+		timeout = ipv4ll_random_delay_ms(PROBE_MAX-PROBE_MIN);
+		timeout += PROBE_MIN*1000;
+	} else
+		timeout = (ANNOUNCE_WAIT * 1000);
+
+	dhcp_client->timeout =
+                timeout_add_full(G_PRIORITY_HIGH,
+				timeout,
+				ipv4ll_probe_timeout,
+				dhcp_client,
+				NULL);
+	return FALSE;
+}
+
+static gboolean ipv4ll_announce_timeout(gpointer dhcp_data);
+static gboolean ipv4ll_defend_timeout(gpointer dhcp_data);
+
+static gboolean send_announce_packet(gpointer dhcp_data)
+{
+	GDHCPClient *dhcp_client;
+
+	dhcp_client = dhcp_data;
+
+	debug(dhcp_client, "sending IPV4LL announce request");
+
+	ipv4ll_send_arp_packet(dhcp_client->mac_address,
+				dhcp_client->requested_ip,
+				dhcp_client->requested_ip,
+				dhcp_client->ifindex);
+
+	remove_timer(dhcp_client);
+
+	if (dhcp_client->state == IPV4LL_DEFEND) {
+		dhcp_client->timeout =
+			timeout_add_seconds_full(G_PRIORITY_HIGH,
+						DEFEND_INTERVAL,
+						ipv4ll_defend_timeout,
+						dhcp_client,
+						NULL);
+		set_wake(dhcp_client, DEFEND_INTERVAL);
+		return TRUE;
+	} else
+		dhcp_client->timeout =
+			timeout_add_seconds_full(G_PRIORITY_HIGH,
+						ANNOUNCE_INTERVAL,
+						ipv4ll_announce_timeout,
+						dhcp_client,
+						NULL);
+		set_wake(dhcp_client, ANNOUNCE_INTERVAL);
+	return TRUE;
+}
+
+static void get_interface_mac_address(int index, uint8_t *mac_address)
+{
+	struct ifreq ifr;
+	int sk, err;
+
+	sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+	if (sk < 0) {
+		perror("Open socket error");
+		return;
+	}
+
+	memset(&ifr, 0, sizeof(ifr));
+	ifr.ifr_ifindex = index;
+
+	err = ioctl(sk, SIOCGIFNAME, &ifr);
+	if (err < 0) {
+		perror("Get interface name error");
+		goto done;
+	}
+
+	err = ioctl(sk, SIOCGIFHWADDR, &ifr);
+	if (err < 0) {
+		perror("Get mac address error");
+		goto done;
+	}
+
+	memcpy(mac_address, ifr.ifr_hwaddr.sa_data, 6);
+
+done:
+	close(sk);
+}
+
+int g_dhcpv6_create_duid(GDHCPDuidType duid_type, int index, int type,
+			unsigned char **duid, int *duid_len)
+{
+	time_t duid_time;
+
+	switch (duid_type) {
+	case G_DHCPV6_DUID_LLT:
+		*duid_len = 2 + 2 + 4 + ETH_ALEN;
+		*duid = g_try_malloc(*duid_len);
+		if (*duid == NULL)
+			return -ENOMEM;
+
+		(*duid)[0] = 0;
+		(*duid)[1] = 1;
+		get_interface_mac_address(index, &(*duid)[2 + 2 + 4]);
+		(*duid)[2] = 0;
+		(*duid)[3] = type;
+		duid_time = time(NULL) - DUID_TIME_EPOCH;
+		(*duid)[4] = duid_time >> 24;
+		(*duid)[5] = duid_time >> 16;
+		(*duid)[6] = duid_time >> 8;
+		(*duid)[7] = duid_time & 0xff;
+		break;
+	case G_DHCPV6_DUID_EN:
+		return -EINVAL;
+	case G_DHCPV6_DUID_LL:
+		*duid_len = 2 + 2 + ETH_ALEN;
+		*duid = g_try_malloc(*duid_len);
+		if (*duid == NULL)
+			return -ENOMEM;
+
+		(*duid)[0] = 0;
+		(*duid)[1] = 3;
+		get_interface_mac_address(index, &(*duid)[2 + 2]);
+		(*duid)[2] = 0;
+		(*duid)[3] = type;
+		break;
+	}
+
+	return 0;
+}
+
+int g_dhcpv6_client_set_duid(GDHCPClient *dhcp_client, unsigned char *duid,
+			int duid_len)
+{
+	if (dhcp_client == NULL || dhcp_client->type == G_DHCP_IPV4)
+		return -EINVAL;
+
+	g_free(dhcp_client->duid);
+
+	dhcp_client->duid = duid;
+	dhcp_client->duid_len = duid_len;
+
+	return 0;
+}
+
+uint32_t g_dhcpv6_client_get_iaid(GDHCPClient *dhcp_client)
+{
+	if (dhcp_client == NULL || dhcp_client->type == G_DHCP_IPV4)
+		return 0;
+
+	return dhcp_client->iaid;
+}
+
+void g_dhcpv6_client_create_iaid(GDHCPClient *dhcp_client, int index,
+				unsigned char *iaid)
+{
+	uint8_t buf[6];
+
+	get_interface_mac_address(index, buf);
+
+	memcpy(iaid, &buf[2], 4);
+	dhcp_client->iaid = iaid[0] << 24 |
+			iaid[1] << 16 | iaid[2] << 8 | iaid[3];
+}
+
+int g_dhcpv6_client_get_timeouts(GDHCPClient *dhcp_client,
+				uint32_t *T1, uint32_t *T2,
+				time_t *last_renew, time_t *last_rebind,
+				time_t *expire)
+{
+	if (dhcp_client == NULL || dhcp_client->type == G_DHCP_IPV4)
+		return -EINVAL;
+
+	if (T1 != NULL)
+		*T1 = dhcp_client->T1;
+
+	if (T2 != NULL)
+		*T2 = dhcp_client->T2;
+
+	if (last_renew != NULL)
+		*last_renew = dhcp_client->last_renew;
+
+	if (last_rebind != NULL)
+		*last_rebind = dhcp_client->last_rebind;
+
+	if (expire != NULL)
+		*expire = dhcp_client->expire;
+
+	return 0;
+}
+
+static uint8_t *create_iaaddr(GDHCPClient *dhcp_client, uint8_t *buf,
+				uint16_t len)
+{
+	buf[0] = 0;
+	buf[1] = G_DHCPV6_IAADDR;
+	buf[2] = 0;
+	buf[3] = len;
+	memcpy(&buf[4], &dhcp_client->ia_na, 16);
+	memset(&buf[20], 0, 4); /* preferred */
+	memset(&buf[24], 0, 4); /* valid */
+	return buf;
+}
+
+static void put_iaid(GDHCPClient *dhcp_client, int index, uint8_t *buf)
+{
+	uint32_t iaid;
+
+	iaid = g_dhcpv6_client_get_iaid(dhcp_client);
+	if (iaid == 0) {
+		g_dhcpv6_client_create_iaid(dhcp_client, index, buf);
+		return;
+	}
+
+	buf[0] = iaid >> 24;
+	buf[1] = iaid >> 16;
+	buf[2] = iaid >> 8;
+	buf[3] = iaid;
+}
+
+int g_dhcpv6_client_set_ia(GDHCPClient *dhcp_client, int index,
+			int code, uint32_t *T1, uint32_t *T2,
+			gboolean add_iaaddr)
+{
+	if (code == G_DHCPV6_IA_TA) {
+		uint8_t ia_options[4];
+
+		put_iaid(dhcp_client, index, ia_options);
+
+		g_dhcp_client_set_request(dhcp_client, G_DHCPV6_IA_TA);
+		g_dhcpv6_client_set_send(dhcp_client, G_DHCPV6_IA_TA,
+					ia_options, sizeof(ia_options));
+
+	} else if (code == G_DHCPV6_IA_NA) {
+
+		g_dhcp_client_set_request(dhcp_client, G_DHCPV6_IA_NA);
+
+		if (add_iaaddr == TRUE) {
+#define IAADDR_LEN (16+4+4)
+			uint8_t ia_options[4+4+4+2+2+IAADDR_LEN];
+
+			put_iaid(dhcp_client, index, ia_options);
+
+			if (T1 != NULL) {
+				ia_options[4] = *T1 >> 24;
+				ia_options[5] = *T1 >> 16;
+				ia_options[6] = *T1 >> 8;
+				ia_options[7] = *T1;
+			} else
+				memset(&ia_options[4], 0x00, 4);
+
+			if (T2 != NULL) {
+				ia_options[8] = *T2 >> 24;
+				ia_options[9] = *T2 >> 16;
+				ia_options[10] = *T2 >> 8;
+				ia_options[11] = *T2;
+			} else
+				memset(&ia_options[8], 0x00, 4);
+
+			create_iaaddr(dhcp_client, &ia_options[12],
+					IAADDR_LEN);
+
+			g_dhcpv6_client_set_send(dhcp_client, G_DHCPV6_IA_NA,
+					ia_options, sizeof(ia_options));
+		} else {
+			uint8_t ia_options[4+4+4];
+
+			put_iaid(dhcp_client, index, ia_options);
+
+			memset(&ia_options[4], 0x00, 4); /* T1 (4 bytes) */
+			memset(&ia_options[8], 0x00, 4); /* T2 (4 bytes) */
+
+			g_dhcpv6_client_set_send(dhcp_client, G_DHCPV6_IA_NA,
+					ia_options, sizeof(ia_options));
+		}
+
+	} else
+		return -EINVAL;
+
+	return 0;
+}
+
+int g_dhcpv6_client_set_oro(GDHCPClient *dhcp_client, int args, ...)
+{
+	va_list va;
+	int i, j, len = sizeof(uint16_t) * args;
+	uint8_t *values;
+
+	values = g_try_malloc(len);
+	if (values == NULL)
+		return -ENOMEM;
+
+	va_start(va, args);
+	for (i = 0, j = 0; i < args; i++) {
+		uint16_t value = va_arg(va, int);
+		values[j++] = value >> 8;
+		values[j++] = value & 0xff;
+	}
+	va_end(va);
+
+	g_dhcpv6_client_set_send(dhcp_client, G_DHCPV6_ORO, values, len);
+
+	g_free(values);
+
+	return 0;
+}
+
+static int send_dhcpv6_msg(GDHCPClient *dhcp_client, int type, char *msg)
+{
+	struct dhcpv6_packet *packet;
+	uint8_t buf[MAX_DHCPV6_PKT_SIZE];
+	unsigned char *ptr;
+	int ret, max_buf;
+
+	memset(buf, 0, sizeof(buf));
+	packet = (struct dhcpv6_packet *)&buf[0];
+	ptr = buf + sizeof(struct dhcpv6_packet);
+
+	debug(dhcp_client, "sending DHCPv6 %s message", msg);
+
+	init_packet(dhcp_client, packet, type);
+
+	dhcp_client->xid = packet->transaction_id[0] << 16 |
+			packet->transaction_id[1] << 8 |
+			packet->transaction_id[2];
+
+	max_buf = MAX_DHCPV6_PKT_SIZE - sizeof(struct dhcpv6_packet);
+
+	add_dhcpv6_request_options(dhcp_client, packet, buf, max_buf, &ptr);
+
+	add_dhcpv6_send_options(dhcp_client, buf, max_buf, &ptr);
+
+	ret = dhcpv6_send_packet(dhcp_client->ifindex, packet, ptr - buf);
+
+	debug(dhcp_client, "sent %d pkt %p len %d", ret, packet, ptr - buf);
+	return ret;
+}
+
+static int send_solicitation(GDHCPClient *dhcp_client)
+{
+	return send_dhcpv6_msg(dhcp_client, DHCPV6_SOLICIT, "solicit");
+}
+
+static int send_dhcpv6_request(GDHCPClient *dhcp_client)
+{
+	return send_dhcpv6_msg(dhcp_client, DHCPV6_REQUEST, "request");
+}
+
+static int send_dhcpv6_renew(GDHCPClient *dhcp_client)
+{
+	return send_dhcpv6_msg(dhcp_client, DHCPV6_RENEW, "renew");
+}
+
+static int send_dhcpv6_rebind(GDHCPClient *dhcp_client)
+{
+	return send_dhcpv6_msg(dhcp_client, DHCPV6_REBIND, "rebind");
+}
+
+static int send_dhcpv6_release(GDHCPClient *dhcp_client)
+{
+	return send_dhcpv6_msg(dhcp_client, DHCPV6_RELEASE, "release");
+}
+
+static int send_information_req(GDHCPClient *dhcp_client)
+{
+	return send_dhcpv6_msg(dhcp_client, DHCPV6_INFORMATION_REQ,
+				"information-req");
+}
+
+static void remove_value(gpointer data, gpointer user_data)
+{
+	char *value = data;
+	g_free(value);
+}
+
+static void remove_option_value(gpointer data)
+{
+	GList *option_value = data;
+
+	g_list_foreach(option_value, remove_value, NULL);
+}
+
+GDHCPClient *g_dhcp_client_new(GDHCPType type,
+			int ifindex, GDHCPClientError *error)
+{
+	GDHCPClient *dhcp_client;
+
+	if (ifindex < 0) {
+		*error = G_DHCP_CLIENT_ERROR_INVALID_INDEX;
+		return NULL;
+	}
+
+	dhcp_client = g_try_new0(GDHCPClient, 1);
+	if (dhcp_client == NULL) {
+		*error = G_DHCP_CLIENT_ERROR_NOMEM;
+		return NULL;
+	}
+
+	dhcp_client->interface = get_interface_name(ifindex);
+	if (dhcp_client->interface == NULL) {
+		*error = G_DHCP_CLIENT_ERROR_INTERFACE_UNAVAILABLE;
+		goto error;
+	}
+
+	if (interface_is_up(ifindex) == FALSE) {
+		*error = G_DHCP_CLIENT_ERROR_INTERFACE_DOWN;
+		goto error;
+	}
+
+	get_interface_mac_address(ifindex, dhcp_client->mac_address);
+
+	dhcp_client->listener_sockfd = -1;
+	dhcp_client->listener_channel = NULL;
+	dhcp_client->listen_mode = L_NONE;
+	dhcp_client->ref_count = 1;
+	dhcp_client->type = type;
+	dhcp_client->ifindex = ifindex;
+	dhcp_client->lease_available_cb = NULL;
+	dhcp_client->ipv4ll_available_cb = NULL;
+	dhcp_client->no_lease_cb = NULL;
+	dhcp_client->lease_lost_cb = NULL;
+	dhcp_client->ipv4ll_lost_cb = NULL;
+	dhcp_client->address_conflict_cb = NULL;
+	dhcp_client->wake_event_cb = NULL;
+	dhcp_client->listener_watch = 0;
+	dhcp_client->retry_times = 0;
+	dhcp_client->ack_retry_times = 0;
+	dhcp_client->code_value_hash = g_hash_table_new_full(g_direct_hash,
+				g_direct_equal, NULL, remove_option_value);
+	dhcp_client->send_value_hash = g_hash_table_new_full(g_direct_hash,
+				g_direct_equal, NULL, g_free);
+	dhcp_client->request_list = NULL;
+	dhcp_client->require_list = NULL;
+	dhcp_client->duid = NULL;
+	dhcp_client->duid_len = 0;
+	dhcp_client->last_renew = dhcp_client->last_rebind = time(NULL);
+	dhcp_client->expire = 0;
+
+	*error = G_DHCP_CLIENT_ERROR_NONE;
+
+	return dhcp_client;
+
+error:
+	g_free(dhcp_client->interface);
+	g_free(dhcp_client);
+	return NULL;
+}
+
+#define SERVER_AND_CLIENT_PORTS  ((67 << 16) + 68)
+
+static int dhcp_l2_socket(int ifindex)
+{
+	int fd;
+	struct sockaddr_ll sock;
+
+	/*
+	 * Comment:
+	 *
+	 *	I've selected not to see LL header, so BPF doesn't see it, too.
+	 *	The filter may also pass non-IP and non-ARP packets, but we do
+	 *	a more complete check when receiving the message in userspace.
+	 *
+	 * and filter shamelessly stolen from:
+	 *
+	 *	http://www.flamewarmaster.de/software/dhcpclient/
+	 *
+	 * There are a few other interesting ideas on that page (look under
+	 * "Motivation").  Use of netlink events is most interesting.  Think
+	 * of various network servers listening for events and reconfiguring.
+	 * That would obsolete sending HUP signals and/or make use of restarts.
+	 *
+	 * Copyright: 2006, 2007 Stefan Rompf <sux@loplof.de>.
+	 * License: GPL v2.
+	 *
+	 * TODO: make conditional?
+	 */
+	static const struct sock_filter filter_instr[] = {
+		/* check for udp */
+		BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
+		/* L5, L1, is UDP? */
+		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 2, 0),
+		/* ugly check for arp on ethernet-like and IPv4 */
+		BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2), /* L1: */
+		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x08000604, 3, 4),/* L3, L4 */
+		/* skip IP header */
+		BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), /* L5: */
+		/* check udp source and destination ports */
+		BPF_STMT(BPF_LD|BPF_W|BPF_IND, 0),
+		/* L3, L4 */
+		BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SERVER_AND_CLIENT_PORTS, 0, 1),
+		/* returns */
+		BPF_STMT(BPF_RET|BPF_K, 0x0fffffff), /* L3: pass */
+		BPF_STMT(BPF_RET|BPF_K, 0), /* L4: reject */
+	};
+
+	static const struct sock_fprog filter_prog = {
+		.len = sizeof(filter_instr) / sizeof(filter_instr[0]),
+		/* casting const away: */
+		.filter = (struct sock_filter *) filter_instr,
+	};
+
+	fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(ETH_P_IP));
+	if (fd < 0)
+		return fd;
+
+	if (SERVER_PORT == 67 && CLIENT_PORT == 68)
+		/* Use only if standard ports are in use */
+		setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
+							sizeof(filter_prog));
+
+	memset(&sock, 0, sizeof(sock));
+	sock.sll_family = AF_PACKET;
+	sock.sll_protocol = htons(ETH_P_IP);
+	sock.sll_ifindex = ifindex;
+
+	if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) != 0) {
+		close(fd);
+		return -errno;
+	}
+
+	return fd;
+}
+
+static gboolean sanity_check(struct ip_udp_dhcp_packet *packet, int bytes)
+{
+	if (packet->ip.protocol != IPPROTO_UDP)
+		return FALSE;
+
+	if (packet->ip.version != IPVERSION)
+		return FALSE;
+
+	if (packet->ip.ihl != sizeof(packet->ip) >> 2)
+		return FALSE;
+
+	if (packet->udp.dest != htons(CLIENT_PORT))
+		return FALSE;
+
+	if (ntohs(packet->udp.len) != (uint16_t)(bytes - sizeof(packet->ip)))
+		return FALSE;
+
+	return TRUE;
+}
+
+static int dhcp_recv_l2_packet(struct dhcp_packet *dhcp_pkt, int fd)
+{
+	int bytes;
+	struct ip_udp_dhcp_packet packet;
+	uint16_t check;
+
+	memset(&packet, 0, sizeof(packet));
+
+	bytes = read(fd, &packet, sizeof(packet));
+	if (bytes < 0)
+		return -1;
+
+	if (bytes < (int) (sizeof(packet.ip) + sizeof(packet.udp)))
+		return -1;
+
+	if (bytes < ntohs(packet.ip.tot_len))
+		/* packet is bigger than sizeof(packet), we did partial read */
+		return -1;
+
+	/* ignore any extra garbage bytes */
+	bytes = ntohs(packet.ip.tot_len);
+
+	if (sanity_check(&packet, bytes) == FALSE)
+		return -1;
+
+	check = packet.ip.check;
+	packet.ip.check = 0;
+	if (check != dhcp_checksum(&packet.ip, sizeof(packet.ip)))
+		return -1;
+
+	/* verify UDP checksum. IP header has to be modified for this */
+	memset(&packet.ip, 0, offsetof(struct iphdr, protocol));
+	/* ip.xx fields which are not memset: protocol, check, saddr, daddr */
+	packet.ip.tot_len = packet.udp.len; /* yes, this is needed */
+	check = packet.udp.check;
+	packet.udp.check = 0;
+	if (check && check != dhcp_checksum(&packet, bytes))
+		return -1;
+
+	memcpy(dhcp_pkt, &packet.data, bytes - (sizeof(packet.ip) +
+							sizeof(packet.udp)));
+
+	if (dhcp_pkt->cookie != htonl(DHCP_MAGIC))
+		return -1;
+
+	return bytes - (sizeof(packet.ip) + sizeof(packet.udp));
+}
+
+static void ipv4ll_start(GDHCPClient *dhcp_client)
+{
+	guint timeout;
+	int seed;
+
+	remove_timer(dhcp_client);
+
+	switch_listening_mode(dhcp_client, L_NONE);
+	dhcp_client->type = G_DHCP_IPV4LL;
+	dhcp_client->retry_times = 0;
+	dhcp_client->requested_ip = 0;
+
+	/*try to start with a based mac address ip*/
+	seed = (dhcp_client->mac_address[4] << 8 | dhcp_client->mac_address[4]);
+	dhcp_client->requested_ip = ipv4ll_random_ip(seed);
+
+	/*first wait a random delay to avoid storm of arp request on boot*/
+	timeout = ipv4ll_random_delay_ms(PROBE_WAIT);
+
+	dhcp_client->retry_times++;
+	dhcp_client->timeout = timeout_add_full(G_PRIORITY_HIGH,
+						timeout,
+						send_probe_packet,
+						dhcp_client,
+						NULL);
+}
+
+static void ipv4ll_stop(GDHCPClient *dhcp_client)
+{
+
+	switch_listening_mode(dhcp_client, L_NONE);
+
+	remove_timer(dhcp_client);
+
+	if (dhcp_client->listener_watch > 0) {
+		g_source_remove(dhcp_client->listener_watch);
+		dhcp_client->listener_watch = 0;
+	}
+
+	dhcp_client->state = IPV4LL_PROBE;
+	dhcp_client->retry_times = 0;
+	dhcp_client->requested_ip = 0;
+
+	g_free(dhcp_client->assigned_ip);
+	dhcp_client->assigned_ip = NULL;
+}
+
+static int ipv4ll_recv_arp_packet(GDHCPClient *dhcp_client)
+{
+	int bytes;
+	struct ether_arp arp;
+	uint32_t ip_requested;
+	int source_conflict;
+	int target_conflict;
+
+	memset(&arp, 0, sizeof(arp));
+	bytes = read(dhcp_client->listener_sockfd, &arp, sizeof(arp));
+	if (bytes < 0)
+		return bytes;
+
+	if (arp.arp_op != htons(ARPOP_REPLY) &&
+			arp.arp_op != htons(ARPOP_REQUEST))
+		return -EINVAL;
+
+	ip_requested = htonl(dhcp_client->requested_ip);
+	source_conflict = !memcmp(arp.arp_spa, &ip_requested,
+						sizeof(ip_requested));
+
+	target_conflict = !memcmp(arp.arp_tpa, &ip_requested,
+				sizeof(ip_requested));
+
+	if (!source_conflict && !target_conflict)
+		return 0;
+
+	dhcp_client->conflicts++;
+
+	debug(dhcp_client, "IPV4LL conflict detected");
+
+	if (dhcp_client->state == IPV4LL_MONITOR) {
+		if (!source_conflict)
+			return 0;
+		dhcp_client->state = IPV4LL_DEFEND;
+		debug(dhcp_client, "DEFEND mode conflicts : %d",
+			dhcp_client->conflicts);
+		/*Try to defend with a single announce*/
+		send_announce_packet(dhcp_client);
+		return 0;
+	}
+
+	if (dhcp_client->state == IPV4LL_DEFEND) {
+		if (!source_conflict)
+			return 0;
+		else if (dhcp_client->ipv4ll_lost_cb != NULL)
+			dhcp_client->ipv4ll_lost_cb(dhcp_client,
+						dhcp_client->ipv4ll_lost_data);
+	}
+
+	ipv4ll_stop(dhcp_client);
+
+	if (dhcp_client->conflicts < MAX_CONFLICTS) {
+		/*restart whole state machine*/
+		dhcp_client->retry_times++;
+		dhcp_client->timeout =
+			timeout_add_full(G_PRIORITY_HIGH,
+					ipv4ll_random_delay_ms(PROBE_WAIT),
+					send_probe_packet,
+					dhcp_client,
+					NULL);
+	}
+	/* Here we got a lot of conflicts, RFC3927 states that we have
+	 * to wait RATE_LIMIT_INTERVAL before retrying,
+	 * but we just report failure.
+	 */
+	else if (dhcp_client->no_lease_cb != NULL)
+			dhcp_client->no_lease_cb(dhcp_client,
+						dhcp_client->no_lease_data);
+
+	return 0;
+}
+
+static gboolean check_package_owner(GDHCPClient *dhcp_client, gpointer pkt)
+{
+	if (dhcp_client->type