--- /dev/null
+*.o
+*.a
+*.lo
+*.la
+.deps
+.libs
+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
+shave
+shave-libtool
+
+connman.pc
+include/connman
+include/version.h
+src/connmand
+src/connman.exp
+src/connman.ver
+src/connman.conf
+src/connman.service
+src/*-connman.rules
+plugins/connman.policy
+plugins/builtin.h
+scripts/connman
+scripts/udhcpc-script
+scripts/dhclient-script
+client/cm
+tools/wifi-scan
+doc/*.bak
+doc/*.stamp
+doc/connman.*
+doc/connman-*.txt
+doc/*.sgml
+doc/version.xml
+doc/xml
+doc/html
--- /dev/null
+Marcel Holtmann <marcel@holtmann.org>
+Inaky Perez-Gonzalez <inaky@linux.intel.com>
--- /dev/null
+ 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.
--- /dev/null
+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.
--- /dev/null
+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
+
+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.
+
+ During start of daemon
+ {Manager} [/] Devices = dbus.Array([dbus.ObjectPath('/dev_00_90_CC ...
+ {Device} [/dev_00_90_CC_xx_xx_xx] Powered = 1
+ {Device} [/dev_00_90_CC_xx_xx_xx] Networks = dbus.Array( ...
+
+ During shutdown of daemon
+ {Device} [/dev_00_90_CC_xx_xx_xx] Networks = dbus.Array( ...
+ {Device} [/dev_00_90_CC_xx_xx_xx] Powered = 0
+ {Manager} [/] Devices = dbus.Array([], ...
+
+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
+
--- /dev/null
+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.
+
--- /dev/null
+
+SUBDIRS = gdbus gatchat include plugins src client tools scripts test doc
+
+pkgconfigdir = $(libdir)/pkgconfig
+
+pkgconfig_DATA = connman.pc
+
+DISTCHECK_CONFIGURE_FLAGS = --disable-gtk-doc \
+ --disable-datafiles \
+ --enable-loopback \
+ --enable-ethernet \
+ --enable-wifi \
+ --enable-bluetooth \
+ --enable-udhcp \
+ --enable-dhclient \
+ --enable-resolvconf \
+ --enable-dnsproxy \
+ --enable-novatel \
+ --enable-huawei \
+ --enable-hso \
+ --enable-client \
+ --enable-tools
+
+DISTCLEANFILES = $(pkgconfig_DATA)
+
+MAINTAINERCLEANFILES = Makefile.in \
+ aclocal.m4 configure config.h.in config.sub config.guess \
+ ltmain.sh depcomp compile missing install-sh mkinstalldirs \
+ shave shave-libtool
+
+# get rid of debian build dirs
+maintainer-clean-local:
+ -rm -rf debian/build debian/tmp \
+ debian/connman \
+ debian/connman-dbg \
+ debian/connman-doc \
+ debian/connman-dev \
+ debian/connman-test \
+ debian/*.debhelper debian/files debian/*.substvars \
+ build-stamp configure-stamp stamp-h.in
--- /dev/null
+Connection Manager
+******************
+
+Copyright (C) 2007-2009 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, routing and DNS configuration
+
+Various plugins can be enabled for networking support:
+ - Ethernet plugin
+ - WiFi plugin with WEP40/WEP128 and WPA/WPA2 (personal only) support
+ - Bluetooth plugin
+
+Also plugins with additional features are available:
+ - DHCP plugins (uDHCP and dhclient)
+ - Resolver plugins (resolvconf and DNS proxy)
+ - Loopback setup
+ - PolicyKit support
+
+
+Compilation and installation
+============================
+
+In order to compile Connection Manager you need following software packages:
+ - GCC compiler
+ - GLib library
+ - D-Bus library
+ - udev library (optional)
+ - PolicyKit (optional)
+ - PPP support (optional)
+
+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:
+
+ --enable-ethernet
+
+ Enable support for Ethernet network cards
+
+ --enable-wifi
+
+ Enable support for WiFi devices (requires wpa_supplicant)
+
+
+ --enable-bluetooth
+
+ Enable support for Bluetooth devices (requires BlueZ)
+
+ --enable-ppp
+
+ Enable PPP support for dialup connections (requires pppd)
+
+ The location of the pppd binary is auto-detected, but it
+ can be overwritten via --with-pppd=<path-to-binary>.
+
+ --enable-udhcp
+
+ Enable DHCP client support for BusyBox based systems
+
+ The location of the udhcpc binary is auto-detected, but it
+ can be overwritten via --with-udhcpc=<path-to-binary>.
+
+ --enable-dhclient
+
+ Enable DHCP client support for ISC dhclient based systems
+
+ The location of the dhclient binary is auto-detected, but it
+ can be overwritten via --with-dhclient=<path-to-binary>.
+
+ At least one DHCP client option should be selected. It is
+ possible to select both and then uDHCP will be tried first
+ before falling back to dhclient.
+
+ --enable-dnsproxy
+
+ Enable DNS proxy support for /etc/resolv.conf abstraction
+
+ The best solution for multiple connections and proper DNS
+ handling is a DNS proxy server. This binds a DNS proxy
+ server to port 53 on the loopback interface (127.0.0.1).
+
+ The /etc/resolv.conf file needs a "nameserver 127.0.0.1"
+ entry, but can now set the immutable bit or be on a read-only
+ filesystem. No further modification to that file will be made.
+
+ It is important that this is not used together with other
+ DNS proxy solution like dnsmasq.
+
+ --enable-resolvconf
+
+ Enable resolvconf support for Debian/Ubuntu based systems
+
+ The resolvconf package from Debian can be used to handle
+ configuration of the /etc/resolv.conf file.
+
+ It is safe to select this option even when resolvconf is not
+ installed. A missing resolvconf will be detected and in that
+ case it falls back to modifying /etc/resolv.conf directly.
+
+ The location of the resolvconf binary is auto-detected, but it
+ can be overwritten via --with-resolvconf=<path-to-binary>.
+
+ --enable-loopback
+
+ Enable 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 select this option even if networking scripts
+ are in place. It detects an already configured loopback
+ device and leaves it as it is.
+
+ --enable-udev
+
+ Enable device detection support via udev
+
+ Network devices are by default detected via the builtin RTNL
+ functionality. This allows to detect TTY based modem devices
+ via udev.
+
+ --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.
+
--- /dev/null
+
+ o Support for WPA/WPA2 Enterprise WiFi authentication
+
+ With wpa_supplicant the support for WPA/WPA2 Enterprise is already
+ present, but it needs properly hooked up. This involves a correct
+ security architecture since it uses personalized credentials.
+
+ o Support for WPS based WiFi authentication
+
+ Newer versions of wpa_supplicant contain support for WPS. For full
+ integration of WPS support, the agent concept needs to be extended.
+
+ o Support for multiple profiles
+
+ Currently only one active profile (the default profile) is supported.
+
+ o Support for static IPv4 configuration
+
+ This is in theory possible, but no D-Bus API has been defined on how
+ to configure it.
+
+ o Support for interface statistics
+
+ Information about carrier speed etc. should be exported.
+
+ o Support for handling RFKILL events
+
+ The RFKILL events are received via the udev infrastructure, but not
+ acted upon. Current problem is to assign the event to the correct
+ physical device. In case of platform RFKILL switches this is a real
+ problem and not solved yet.
+
--- /dev/null
+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"
+ fi
+])
+
+AC_DEFUN([SHAVE_ARG_ENABLE],
+[
+ AC_ARG_ENABLE([shave],
+ AS_HELP_STRING(
+ [--enable-shave],
+ [use shave to make the build pretty [[default=no]]]),,
+ [enable_shave=no]
+ )
+ AC_CONFIG_FILES(shave shave-libtool)
+])
+
+AC_DEFUN([SHAVE_INIT],
+[
+ if test x"$enable_shave" = xyes; then
+ dnl where can we find the shave scripts?
+ m4_if([$1],,
+ [shavedir="$ac_pwd"],
+ [shavedir="$ac_pwd/$1"])
+ AC_SUBST(shavedir)
+
+ dnl make is now quiet
+ AC_SUBST([MAKEFLAGS], [-s])
+ AC_SUBST([AM_MAKEFLAGS], ['`test -z $V && echo -s`'])
+
+ dnl we need sed
+ AC_CHECK_PROG(SED,sed,sed,false)
+
+ dnl substitute libtool
+ SHAVE_SAVED_LIBTOOL=$LIBTOOL
+ LIBTOOL="${SHELL} ${shavedir}/shave-libtool '${SHAVE_SAVED_LIBTOOL}'"
+ AC_SUBST(LIBTOOL)
+
+ dnl substitute cc/cxx
+ SHAVE_SAVED_CC=$CC
+ SHAVE_SAVED_CXX=$CXX
+ SHAVE_SAVED_FC=$FC
+ SHAVE_SAVED_F77=$F77
+ CC="${SHELL} ${shavedir}/shave cc ${SHAVE_SAVED_CC}"
+ CXX="${SHELL} ${shavedir}/shave cxx ${SHAVE_SAVED_CXX}"
+ FC="${SHELL} ${shavedir}/shave fc ${SHAVE_SAVED_FC}"
+ F77="${SHELL} ${shavedir}/shave f77 ${SHAVE_SAVED_F77}"
+ AC_SUBST(CC)
+ AC_SUBST(CXX)
+ AC_SUBST(FC)
+ AC_SUBST(F77)
+
+ V=@
+ else
+ V=1
+ fi
+ Q='$(V:1=)'
+ AC_SUBST(V)
+ AC_SUBST(Q)
+])
+
+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"])
+])
--- /dev/null
+#!/bin/sh
+
+aclocal && \
+ autoheader && \
+ libtoolize --automake --copy --force && \
+ automake --add-missing --copy && \
+ autoconf
--- /dev/null
+#!/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-loopback=builtin \
+ --enable-ethernet=builtin \
+ --enable-wifi=builtin \
+ --enable-bluetooth=builtin \
+ --enable-ofono=builtin \
+ --enable-modemmgr=builtin \
+ --enable-udhcp=builtin \
+ --enable-dhclient=builtin \
+ --enable-resolvconf=builtin \
+ --enable-dnsproxy=builtin \
+ --enable-novatel \
+ --enable-huawei \
+ --enable-hso=builtin \
+ --enable-ppp \
+ --enable-udev \
+ --enable-iwmx \
+ --enable-iospm \
+ --enable-polkit=builtin \
+ --enable-client \
+ --enable-tools $*
--- /dev/null
+
+if CLIENT
+noinst_PROGRAMS = cm
+
+cm_SOURCES = main.c
+
+cm_LDADD = @DBUS_LIBS@
+endif
+
+AM_CFLAGS = @DBUS_CFLAGS@
+
+MAINTAINERCLEANFILES = Makefile.in
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <dbus/dbus.h>
+
+#define CONNMAN_SERVICE "org.moblin.connman"
+
+#define CONNMAN_MANAGER_INTERFACE CONNMAN_SERVICE ".Manager"
+#define CONNMAN_MANAGER_PATH "/"
+
+static DBusMessage *get_properties(DBusConnection *connection)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+
+ message = dbus_message_new_method_call(CONNMAN_SERVICE,
+ CONNMAN_MANAGER_PATH,
+ CONNMAN_MANAGER_INTERFACE,
+ "GetProperties");
+ if (message == NULL)
+ return NULL;
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(connection,
+ message, -1, &error);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ fprintf(stderr, "%s\n", error.message);
+ dbus_error_free(&error);
+ } else
+ fprintf(stderr, "Failed to get properties\n");
+ dbus_message_unref(message);
+ return NULL;
+ }
+
+ dbus_message_unref(message);
+
+ return reply;
+}
+
+static const char *extract_state(DBusMessage *message)
+{
+ DBusMessageIter array, dict;
+
+ dbus_message_iter_init(message, &array);
+ dbus_message_iter_recurse(&array, &dict);
+
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+ const char *key;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+
+ dbus_message_iter_recurse(&entry, &value);
+
+ //type = dbus_message_iter_get_arg_type(&value);
+ //dbus_message_iter_get_basic(&value, &val);
+
+ if (strcmp(key, "State") == 0) {
+ const char *val;
+ dbus_message_iter_get_basic(&value, &val);
+ return val;
+ }
+
+ dbus_message_iter_next(&dict);
+ }
+
+ return NULL;
+}
+
+static void print_objects(DBusMessageIter *array)
+{
+ DBusMessageIter value;
+
+ if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
+ return;
+
+ dbus_message_iter_recurse(array, &value);
+
+ while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_OBJECT_PATH) {
+ const char *path;
+
+ dbus_message_iter_get_basic(&value, &path);
+
+ printf("%s\n", path);
+
+ dbus_message_iter_next(&value);
+ }
+}
+
+static void extract_devices(DBusMessage *message)
+{
+ DBusMessageIter array, dict;
+
+ dbus_message_iter_init(message, &array);
+ dbus_message_iter_recurse(&array, &dict);
+
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+ const char *key;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+
+ dbus_message_iter_recurse(&entry, &value);
+
+ //type = dbus_message_iter_get_arg_type(&value);
+ //dbus_message_iter_get_basic(&value, &val);
+
+ if (strcmp(key, "Devices") == 0) {
+ print_objects(&value);
+ return;
+ }
+
+ dbus_message_iter_next(&dict);
+ }
+}
+
+static int cmd_status(DBusConnection *connection)
+{
+ DBusMessage *message;
+ const char *state;
+
+ message = get_properties(connection);
+
+ state = extract_state(message);
+
+ dbus_message_unref(message);
+
+ if (state == NULL)
+ return -EINVAL;
+
+ printf("System is %s\n", state);
+
+ return 0;
+}
+
+static int cmd_devices(DBusConnection *connection)
+{
+ DBusMessage *message;
+
+ message = get_properties(connection);
+
+ extract_devices(message);
+
+ dbus_message_unref(message);
+
+ return 0;
+}
+
+static void usage(const char *program)
+{
+ printf("ConnMan utility ver %s\n\n", VERSION);
+
+ printf("Usage:\n"
+ "\t%s <command>\n\n", program);
+
+ printf("Commands:\n"
+ "\thelp\n"
+ "\tdev\n"
+ "\n");
+}
+
+int main(int argc, char *argv[])
+{
+ DBusConnection *conn;
+
+ if (argc > 1 && strcmp(argv[1], "help") == 0) {
+ usage(argv[0]);
+ exit(0);
+ }
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (!conn) {
+ fprintf(stderr, "Can't get on system bus\n");
+ exit(1);
+ }
+
+ if (argc > 1) {
+ if (strcmp(argv[1], "dev") == 0)
+ cmd_devices(conn);
+ } else
+ cmd_status(conn);
+
+ dbus_connection_unref(conn);
+
+ return 0;
+}
--- /dev/null
+AC_PREREQ(2.60)
+AC_INIT()
+
+AM_INIT_AUTOMAKE(connman, 0.19)
+AM_CONFIG_HEADER(config.h)
+
+AM_MAINTAINER_MODE
+
+AC_PREFIX_DEFAULT(/usr/local)
+
+COMPILER_FLAGS
+
+AC_LANG_C
+
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_CC_PIE
+AC_PROG_INSTALL
+
+m4_define([_LT_AC_TAGCONFIG], [])
+m4_ifdef([AC_LIBTOOL_TAGS], [AC_LIBTOOL_TAGS([])])
+
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
+
+GTK_DOC_CHECK
+
+SHAVE_ARG_ENABLE
+
+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 -O0"
+ 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(loopback,
+ AC_HELP_STRING([--enable-loopback], [enable loopback support]),
+ [enable_loopback=${enableval}], [enable_loopback="no"])
+AM_CONDITIONAL(LOOPBACK, test "${enable_loopback}" != "no")
+AM_CONDITIONAL(LOOPBACK_BUILTIN, test "${enable_loopback}" = "builtin")
+
+AC_ARG_ENABLE(ethernet,
+ AC_HELP_STRING([--enable-ethernet], [enable Ethernet support]),
+ [enable_ethernet=${enableval}], [enable_ethernet="no"])
+AM_CONDITIONAL(ETHERNET, test "${enable_ethernet}" != "no")
+AM_CONDITIONAL(ETHERNET_BUILTIN, test "${enable_ethernet}" = "builtin")
+
+AC_ARG_ENABLE(wifi,
+ AC_HELP_STRING([--enable-wifi], [enable WiFi support]),
+ [enable_wifi=${enableval}], [enable_wifi="no"])
+if (test "${enable_wifi}" != "no"); then
+ AC_PATH_PROG(WPASUPPLICANT, [wpa_supplicant], [],
+ $PATH:/sbin:/usr/sbin)
+fi
+AM_CONDITIONAL(WIFI, test "${enable_wifi}" != "no")
+AM_CONDITIONAL(WIFI_BUILTIN, test "${enable_wifi}" = "builtin")
+
+AC_ARG_ENABLE(bluetooth,
+ AC_HELP_STRING([--enable-bluetooth], [enable Bluetooth support]),
+ [enable_bluetooth=${enableval}], [enable_bluetooth="no"])
+AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no")
+AM_CONDITIONAL(BLUETOOTH_BUILTIN, test "${enable_bluetooth}" = "builtin")
+
+AC_ARG_ENABLE(ofono,
+ AC_HELP_STRING([--enable-ofono], [enable oFono support]),
+ [enable_ofono=${enableval}], [enable_ofono="no"])
+AM_CONDITIONAL(OFONO, test "${enable_ofono}" != "no")
+AM_CONDITIONAL(OFONO_BUILTIN, test "${enable_ofono}" = "builtin")
+
+AC_ARG_ENABLE(modemmgr,
+ AC_HELP_STRING([--enable-modemmgr], [enable Modem Manager support]),
+ [enable_modemmgr=${enableval}], [enable_modemmgr="no"])
+AM_CONDITIONAL(MODEMMGR, test "${enable_modemmgr}" != "no")
+AM_CONDITIONAL(MODEMMGR_BUILTIN, test "${enable_modemmgr}" = "builtin")
+
+AC_ARG_WITH(udhcpc, AC_HELP_STRING([--with-udhcpc=PROGRAM],
+ [specify location of udhcpc binary]), [path_udhcpc=${withval}])
+
+AC_ARG_ENABLE(udhcp,
+ AC_HELP_STRING([--enable-udhcp], [enable uDHCP support]),
+ [enable_udhcp=${enableval}], [enable_udhcp="no"])
+if (test "${enable_udhcp}" != "no"); then
+ if (test -z "${path_udhcpc}"); then
+ AC_PATH_PROG(UDHCPC, [udhcpc], [], $PATH:/sbin:/usr/sbin)
+ else
+ UDHCPC="${path_udhcpc}"
+ AC_SUBST(UDHCPC)
+ fi
+fi
+AM_CONDITIONAL(UDHCP, test "${enable_udhcp}" != "no")
+AM_CONDITIONAL(UDHCP_BUILTIN, test "${enable_udhcp}" = "builtin")
+
+AC_ARG_WITH(dhclient, AC_HELP_STRING([--with-dhclient=PROGRAM],
+ [specify location of dhclient binary]), [path_dhclient=${withval}])
+
+AC_ARG_ENABLE(dhclient,
+ AC_HELP_STRING([--enable-dhclient], [enable dhclient support]),
+ [enable_dhclient=${enableval}], [enable_dhclient="no"])
+if (test "${enable_dhclient}" != "no"); then
+ if (test -z "${path_dhclient}"); then
+ AC_PATH_PROG(DHCLIENT, [dhclient], [], $PATH:/sbin:/usr/sbin)
+ else
+ DHCLIENT="${path_dhclient}"
+ AC_SUBST(DHCLIENT)
+ fi
+fi
+AM_CONDITIONAL(DHCLIENT, test "${enable_dhclient}" != "no")
+AM_CONDITIONAL(DHCLIENT_BUILTIN, test "${enable_dhclient}" = "builtin")
+
+AC_ARG_WITH(resolvconf, AC_HELP_STRING([--with-resolvconf=PROGRAM],
+ [specify location of resolvconf binary]), [path_resolvconf=${withval}])
+
+AC_ARG_ENABLE(resolvconf,
+ AC_HELP_STRING([--enable-resolvconf], [enable resolvconf support]),
+ [enable_resolvconf=${enableval}], [enable_resolvconf="no"])
+if (test "${enable_resolvconf}" != "no"); then
+ if (test -z "${path_resolvconf}"); then
+ AC_PATH_PROG(RESOLVCONF, [resolvconf], [], $PATH:/sbin:/usr/sbin)
+ else
+ RESOLVCONF="${path_resolvconf}"
+ AC_SUBST(RESOLVCONF)
+ fi
+fi
+AM_CONDITIONAL(RESOLVCONF, test "${enable_resolvconf}" != "no")
+AM_CONDITIONAL(RESOLVCONF_BUILTIN, test "${enable_resolvconf}" = "builtin")
+
+AC_ARG_ENABLE(dnsproxy,
+ AC_HELP_STRING([--enable-dnsproxy], [enable DNS proxy support]),
+ [enable_dnsproxy=${enableval}], [enable_dnsproxy="no"])
+AM_CONDITIONAL(DNSPROXY, test "${enable_dnsproxy}" != "no")
+AM_CONDITIONAL(DNSPROXY_BUILTIN, test "${enable_dnsproxy}" = "builtin")
+
+AC_ARG_ENABLE(novatel, AC_HELP_STRING([--enable-novatel],
+ [enable Novatel support]), [enable_novatel=${enableval}])
+AM_CONDITIONAL(NOVATEL, test "${enable_novatel}" = "yes")
+
+AC_ARG_ENABLE(huawei, AC_HELP_STRING([--enable-huawei],
+ [enable HUAWEI support]), [enable_huawei=${enableval}])
+AM_CONDITIONAL(HUAWEI, test "${enable_huawei}" = "yes")
+
+AC_ARG_ENABLE(hso,
+ AC_HELP_STRING([--enable-hso], [enable HSO support]),
+ [enable_hso=${enableval}], [enable_hso="no"])
+AM_CONDITIONAL(HSO, test "${enable_hso}" != "no")
+AM_CONDITIONAL(HSO_BUILTIN, test "${enable_hso}" = "builtin")
+
+AC_ARG_WITH(pppd, AC_HELP_STRING([--with-pppd=PROGRAM],
+ [specify location of pppd binary]), [path_pppd=${withval}])
+
+AC_ARG_ENABLE(ppp, AC_HELP_STRING([--enable-ppp],
+ [enable PPP support]), [enable_ppp=${enableval}])
+if (test "${enable_ppp}" = "yes" || test "${enable_novatel}" = "yes" ||
+ test "${enable_huawei}" = "yes"); then
+ if (test -z "${path_pppd}"); then
+ AC_PATH_PROG(PPPD, [pppd], [], $PATH:/sbin:/usr/sbin)
+ else
+ PPPD="${path_pppd}"
+ AC_SUBST(PPPD)
+ fi
+ AC_CHECK_HEADERS(pppd/pppd.h, enable_ppp=yes,
+ AC_MSG_ERROR(PPP development files are required))
+fi
+AM_CONDITIONAL(PPPD, test "${enable_ppp}" = "yes")
+
+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))
+
+AC_CHECK_LIB(dl, dlopen, dummy=yes,
+ AC_MSG_ERROR(dynamic linking loader is required))
+
+AC_ARG_ENABLE(udev, AC_HELP_STRING([--enable-udev],
+ [enable udev support]), [enable_udev=${enableval}])
+if (test "${enable_udev}" = "yes"); then
+ AC_DEFINE(HAVE_UDEV, 1, [Define if udev support is available])
+ PKG_CHECK_MODULES(UDEV, libudev >= 129, dummy=yes,
+ AC_MSG_ERROR(udev >= 129 is required))
+ AC_CHECK_LIB(udev, udev_enumerate_add_match_property, dummy=yes,
+ AC_DEFINE(NEED_UDEV_ENUMERATE_ADD_MATCH_PROPERTY, 1,
+ [Define to 1 if you need the
+ udev_enumerate_add_match_property() function.]))
+ AC_CHECK_LIB(udev, udev_device_get_parent_with_subsystem_devtype, dummy=yes,
+ AC_DEFINE(NEED_UDEV_DEVICE_GET_PARENT_WITH_SUBSYSTEM_DEVTYPE, 1,
+ [Define to 1 if you need the
+ udev_device_get_parent_with_subsystem_devtype()
+ function.]))
+ UDEV_DATADIR="`$PKG_CONFIG --variable=rulesdir libudev`"
+ if (test -z "${UDEV_DATADIR}"); then
+ UDEV_DATADIR="${sysconfdir}/udev/rules.d"
+ fi
+ AC_SUBST(UDEV_DATADIR)
+fi
+AC_SUBST(UDEV_CFLAGS)
+AC_SUBST(UDEV_LIBS)
+AM_CONDITIONAL(UDEV, test "${enable_udev}" = "yes")
+
+AC_ARG_WITH(iwmxsdk, AC_HELP_STRING([--with-iwmxsdk=PATH],
+ [path to Intel WiMAX SDK]),
+ [pkgconfig_iwmxsdk=${withval}/lib/pkgconfig])
+
+AC_ARG_ENABLE(iwmx, AC_HELP_STRING([--enable-iwmx],
+ [enable Intel WiMAX support]), [enable_iwmx=${enableval}])
+if (test "${enable_iwmx}" = "yes"); then
+ enable_threads="yes"
+ export PKG_CONFIG_PATH="${pkgconfig_iwmxsdk}"
+ PKG_CHECK_MODULES(IWMXSDK, libiWmxSdk-0, dummy=yes,
+ AC_MSG_ERROR(Intel WiMAX SDK is required))
+ PKG_CONFIG_PATH=""
+ AC_SUBST(IWMXSDK_CFLAGS)
+ AC_SUBST(IWMXSDK_LIBS)
+fi
+AM_CONDITIONAL(IWMX, test "${enable_iwmx}" = "yes")
+
+AC_ARG_ENABLE(iospm, AC_HELP_STRING([--enable-iospm],
+ [enable Intel OSPM support]), [enable_iospm=${enableval}])
+AM_CONDITIONAL(IOSPM, test "${enable_iospm}" = "yes")
+
+PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
+ AC_MSG_ERROR(GLib >= 2.16 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.0, dummy=yes,
+ AC_MSG_ERROR(D-Bus >= 1.0 is required))
+AC_CHECK_LIB(dbus-1, dbus_watch_get_unix_fd, dummy=yes,
+ AC_DEFINE(NEED_DBUS_WATCH_GET_UNIX_FD, 1,
+ [Define to 1 if you need the dbus_watch_get_unix_fd() function.]))
+AC_SUBST(DBUS_CFLAGS)
+AC_SUBST(DBUS_LIBS)
+DBUS_DATADIR="`$PKG_CONFIG --variable=sysconfdir dbus-1`"
+if (test -z "{DBUS_DATADIR}"); then
+ DBUS_DATADIR="${sysconfdir}/dbus-1/system.d"
+else
+ DBUS_DATADIR="$DBUS_DATADIR/dbus-1/system.d"
+fi
+AC_SUBST(DBUS_DATADIR)
+
+AC_SUBST([GDBUS_CFLAGS], ['$(DBUS_CFLAGS) -I$(top_srcdir)/gdbus'])
+AC_SUBST([GDBUS_LIBS], ['$(top_builddir)/gdbus/libgdbus.la $(DBUS_LIBS)'])
+
+AC_SUBST([GATCHAT_CFLAGS], ['-I$(top_srcdir)/gatchat'])
+AC_SUBST([GATCHAT_LIBS], ['$(top_builddir)/gatchat/libgatchat.la'])
+
+AC_ARG_ENABLE(polkit,
+ AC_HELP_STRING([--enable-polkit], [enable PolicyKit support]),
+ [enable_polkit=${enableval}], [enable_polkit="no"])
+if (test "${enable_polkit}" != "no"); then
+ PKG_CHECK_MODULES(POLKIT, polkit-dbus >= 0.7, dummy=yes,
+ AC_MSG_ERROR(PolicyKit >= 0.7 is required))
+ AC_SUBST(POLKIT_CFLAGS)
+ AC_SUBST(POLKIT_LIBS)
+ POLKIT_DATADIR="`$PKG_CONFIG --variable=policydir polkit`"
+ if (test -z "${POLKIT_DATADIR}"); then
+ POLKIT_DATADIR="${datadir}/PolicyKit/policy"
+ fi
+ AC_SUBST(POLKIT_DATADIR)
+fi
+AM_CONDITIONAL(POLKIT, test "${enable_polkit}" != "no")
+AM_CONDITIONAL(POLKIT_BUILTIN, test "${enable_polkit}" = "builtin")
+
+AC_ARG_ENABLE(client, AC_HELP_STRING([--enable-client],
+ [enable command line client]), [enable_client=${enableval}])
+AM_CONDITIONAL(CLIENT, test "${enable_client}" = "yes")
+
+AC_ARG_ENABLE(tools, AC_HELP_STRING([--enable-tools],
+ [enable testing tools]), [enable_tools=${enableval}])
+if (test "${enable_tools}" = "yes"); then
+ PKG_CHECK_MODULES(NETLINK, libnl-1, dummy=yes,
+ AC_MSG_ERROR(Netlink library is required))
+ AC_SUBST(NETLINK_CFLAGS)
+ AC_SUBST(NETLINK_LIBS)
+fi
+AM_CONDITIONAL(TOOLS, test "${enable_tools}" = "yes")
+
+AC_ARG_ENABLE(fake, AC_HELP_STRING([--enable-fake],
+ [enable fake device support]), [enable_fake=${enableval}])
+AM_CONDITIONAL(FAKE, test "${enable_fake}" = "yes")
+
+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")
+
+SHAVE_INIT
+
+AC_OUTPUT(Makefile gdbus/Makefile gatchat/Makefile
+ include/Makefile include/version.h
+ src/Makefile src/connman.service
+ scripts/connman scripts/Makefile
+ plugins/Makefile client/Makefile
+ tools/Makefile test/Makefile
+ doc/Makefile doc/version.xml connman.pc)
--- /dev/null
+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}
--- /dev/null
+connman (0.19) unstable; urgency=low
+
+ * Initial maemo support.
+
+ -- Jukka Rissanen <jukka.rissanen@nokia.com> Wed, 24 Jun 2009 20:55:50 +0300
--- /dev/null
+usr/include/connman
+usr/lib/pkgconfig
--- /dev/null
+usr/share/gtk-doc/html/connman
--- /dev/null
+usr/bin/*-*
+
--- /dev/null
+# Set connman options here
+DAEMON_OPTS="-i wlan*"
--- /dev/null
+#!/bin/sh
+
+DAEMON=/usr/sbin/connmand
+PIDFILE=/var/run/connmand.pid
+DESC="Connection Manager"
+NAME=connman
+
+. /lib/lsb/init-functions
+
+if [ -f /etc/default/connman ] ; then
+ . /etc/default/connman
+fi
+
+set -e
+
+unset USE_UPSTART
+INITCTL=/sbin/initctl
+test -x /sbin/initctl && USE_UPSTART=1
+
+do_start() {
+ if [ -z "$USE_UPSTART" ]; then
+ start-stop-daemon --start --oknodo \
+ --pidfile $PIDFILE --exec $DAEMON -- $DAEMON_OPTS
+ else
+ $INITCTL start $NAME
+ fi
+}
+
+do_stop() {
+ if [ -z "$USE_UPSTART" ]; then
+ start-stop-daemon --stop --oknodo --quiet \
+ --pidfile $PIDFILE --exec $DAEMON
+ else
+ $INITCTL stop $NAME
+ fi
+}
+
+case "$1" in
+ start)
+ log_daemon_msg "Starting $DESC"
+ do_start
+ log_end_msg $?
+ ;;
+ stop)
+ log_daemon_msg "Stopping $DESC"
+ do_stop
+ log_end_msg $?
+ ;;
+ restart|force-reload)
+ log_daemon_msg "Restarting $DESC"
+ do_stop
+ sleep 1
+ do_start
+ log_end_msg $?
+ ;;
+ *)
+ log_success_msg "Usage: $0 {start|stop|restart|force-reload}" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
--- /dev/null
+etc/dbus-1/system.d/connman.conf
+usr/sbin/connmand
+usr/lib/connman/plugins/*.so
+usr/lib/connman/scripts
+usr/share/dbus-1
+var/lib/connman
+var/run/connman
--- /dev/null
+description "starting connman"
+author "Jukka Rissanen"
+
+console none
+
+# We do not start automatically yet
+#start on started xsession
+stop on ACT_DEAD
+stop on stopping dbus
+
+pre-start script
+ /usr/sbin/waitdbus system
+ initctl stop icd2
+ initctl stop wlancond
+ initctl stop dnsmasq
+end script
+
+post-stop script
+ # stop dnsmasq, wlancond and icd2 because
+ # they are in use in this system at the moment
+ initctl start dnsmasq
+ initctl start wlancond
+ initctl start icd2
+ killall wpa_supplicant
+end script
+
+exec /usr/sbin/connmand -n -i wlan*
+
+respawn
--- /dev/null
+Source: connman
+Priority: optional
+Maintainer: Jukka Rissanen <jukka.rissanen@nokia.com>
+Build-Depends: debhelper (>> 3.0.0), autotools-dev, libglib2.0-dev, libdbus-glib-1-dev,
+ upstart-dev (>= 0.3.8-18)
+Standards-Version: 3.7.2
+Section: net
+
+Package: connman
+Section: net
+Provides: osso-ic
+Replaces: osso-ic
+Architecture: any
+Depends: dbus, dbus-1-utils, ${shlibs:Depends}
+Description: Connection manager
+ This package contains the connection manager daemon
+
+Package: connman-dbg
+Section: net
+Architecture: any
+Depends: connman (= ${Source-Version})
+Description: Debug symbols for connman
+ Debug symbols for connman
+
+Package: connman-doc
+Section: net
+Architecture: any
+Description: Documentation for connman
+ This package contains the documentation for the connman
+
+Package: connman-dev
+Section: net
+Architecture: any
+Depends: libglib2.0-dev
+Description: Development files for connman
+ This package contains header and other development files for the connman
+
+Package: connman-test
+Section: net
+Architecture: any
+Depends: python, connman
+Description: Test scripts for connman
+ This package contains test files for the connman
--- /dev/null
+#!/usr/bin/make -f
+# Sample debian/rules that uses debhelper.
+# GNU copyright 1997 to 1999 by Joey Hess.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+# These are used for cross-compiling and for saving the configure script
+# from having to guess our platform (since we know it already)
+DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+
+# FOR AUTOCONF 2.52 AND NEWER ONLY
+ifeq ($(DEB_BUILD_GNU_TYPE), $(DEB_HOST_GNU_TYPE))
+ confflags += --build $(DEB_HOST_GNU_TYPE)
+else
+ confflags += --build $(DEB_BUILD_GNU_TYPE) --host $(DEB_HOST_GNU_TYPE)
+endif
+
+# nostrip option
+ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
+ INSTALL_PROGRAM += -s
+endif
+
+# use thumb mode if it's enabled
+ifneq (,$(findstring thumb,$(DEB_BUILD_OPTIONS)))
+ CFLAGS += -mthumb
+endif
+
+ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
+ confflags += --enable-debug
+endif
+
+ifneq (,$(findstring docs,$(DEB_BUILD_OPTIONS)))
+ confflags += --enable-gtk-doc
+endif
+
+ifneq (,$(findstring dmalloc,$(DEB_BUILD_OPTIONS)))
+ CONFIG_DMALLOC=--enable-dmalloc
+ CFLAGS += -DDMALLOC_ENABLE
+endif
+
+# default flags
+CFLAGS += -g -O2
+
+configure: configure.ac debian/changelog
+ ./bootstrap
+
+config.status: configure
+ dh_testdir
+ifneq (,$(findstring docs,$(DEB_BUILD_OPTIONS)))
+ if [ ! -f doc/gtk-doc.make ]; then gtkdocize --copy --docdir doc; fi
+endif
+ # Add here commands to configure the package.
+ CFLAGS="$(CFLAGS)" ./configure $(confflags) \
+ --prefix=/usr \
+ --mandir=\$${prefix}/share/man \
+ --localstatedir=/var \
+ --sysconfdir=/etc \
+ --disable-fake \
+ --enable-loopback \
+ --enable-wifi \
+ --enable-bluetooth \
+ --enable-udhcp \
+ --with-udhcpc=/sbin/udhcpc \
+ --enable-dhclient \
+ --enable-resolvconf \
+ --enable-dnsproxy \
+ $(CONFIG_DMALLOC) $*
+# --enable-client
+# --enable-ethernet
+# --enable-ppp
+# --enable-udev
+
+build: build-stamp
+
+build-stamp: config.status
+ dh_testdir
+ # Add here commands to compile the package.
+ $(MAKE)
+ touch build-stamp
+
+clean:
+ dh_testdir
+ dh_testroot
+ rm -f build-stamp
+ # Add here commands to clean up after the build process.
+ -if [ -f Makefile ] ; then $(MAKE) distclean ; fi
+ -test -r /usr/share/misc/config.sub && \
+ cp -f /usr/share/misc/config.sub config.sub
+ -test -r /usr/share/misc/config.guess && \
+ cp -f /usr/share/misc/config.guess config.guess
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+ # Add here commands to install the package into debian/tmp
+ $(MAKE) install DESTDIR=$(CURDIR)/debian/tmp
+ # Create document dir although it is only used if docs are built
+ -mkdir -p debian/tmp/usr/share/gtk-doc/html/connman
+ # Services file is copied separately
+ # the system-services dir is in use in Maemo Fremantle release
+ -mkdir -p debian/tmp/usr/share/dbus-1/system-services
+ -cp src/connman.service debian/tmp/usr/share/dbus-1/system-services/org.moblin.connman.service
+
+ # the services dir is in use in Maemo Diablo release
+ #-mkdir -p debian/tmp/usr/share/dbus-1/services
+ #-cp src/connman.service debian/tmp/usr/share/dbus-1/services/
+
+ # test scripts to usr/bin
+ -mkdir -p debian/tmp/usr/bin
+ -cp -a test/*-* debian/tmp/usr/bin/
+
+ # connman temp dirs
+ -mkdir -p debian/tmp/var/lib/connman
+ -mkdir -p debian/tmp/var/run/connman
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+ dh_testdir
+ dh_testroot
+ dh_installdocs
+ dh_installchangelogs
+ dh_install --sourcedir=debian/tmp --list-missing -v
+ dh_installinit -- start 59 2 3 4 . stop 15 0 1 5 6 .
+ dh_installupstart
+ dh_link
+ dh_strip --dbg-package=connman
+ dh_compress
+ dh_fixperms
+ dh_makeshlibs
+ dh_installdeb
+ dh_shlibdeps
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+binary: binary-indep binary-arch
+
+.PHONY: build clean binary-indep binary-arch binary install
--- /dev/null
+
+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
+
+EXTRA_DIST += overview-api.txt behavior-api.txt manager-api.txt \
+ device-api.txt network-api.txt service-api.txt \
+ connection-api.txt profile-api.txt agent-api.txt plugin-api.txt
--- /dev/null
+Agent hierarchy
+===============
+
+Service unique name
+Interface org.moblin.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.
--- /dev/null
+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.
+
--- /dev/null
+Connection hierarchy
+====================
+
+Service org.moblin.connman
+Interface org.moblin.connman.Connection
+Object path [variable prefix]/{connection0,connection1,...}
+
+Methods dict GetProperties()
+
+ Returns properties for the connection object. See
+ the properties section for available properties.
+
+ Possible Errors: [service].Error.InvalidArguments
+
+Signals PropertyChanged(string name, variant value)
+
+ This signal indicates a changed value of the given
+ property.
+
+Properties string Type [readonly]
+
+ The connection type (for example wifi etc.)
+
+ string Interface [readonly]
+
+ The connection interface (for example "eth0" etc.)
+
+ This value is for pure informational purposes. It
+ is not guaranteed that it is always present.
+
+ uint8 Strength [readonly]
+
+ Indicates the signal strength of the connection.
+
+ This property is optional and not always present.
+
+ boolean Default [readonly]
+
+ Indicates if it is a default connection. It is
+ possible to have multiple default connections.
+
+ object Device [readonly]
+
+ The object path of the device this connection has
+ been established with.
+
+ object Network [readonly]
+
+ The object path of the network this connection
+ belongs to.
+
+ This property is optional and not always present.
+
+ string IPv4.Method [readonly]
+
+ Indicates the way how the IPv4 settings were
+ configured. Possible values here are "dhcp"
+ and "static".
+
+ string IPv4.Address [readonly]
+
+ Shows the current configured IPv4 address.
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+Device hierarchy
+================
+
+Service org.moblin.connman
+Interface org.moblin.connman.Device
+Object path [variable prefix]/{device0,device1,...}
+
+Methods dict GetProperties()
+
+ Returns properties for the device object. 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.DoesNotExist
+
+ void JoinNetwork(dict network)
+
+ Join network specified by the given properties. The
+ properties for WiFi networks can be WiFi.SSID,
+ WiFi.Security and WiFi.Passphrase.
+
+ Possible Errors: [service].Error.InvalidArguments
+
+ object CreateNetwork(dict network)
+
+ Creates a network object from the specified
+ properties. Valid properties are WiFi.SSID,
+ WiFi.Security and WiFi.Passphrase. Check the
+ network interface description for details.
+
+ Possible Errors: [service].Error.InvalidArguments
+
+ void RemoveNetwork(object network)
+
+ Removes a previously created network object.
+
+ Possible Errors: [service].Error.InvalidArguments
+ [service].Error.DoesNotExist
+
+ void ProposeScan()
+
+ Proposes to trigger a scan transaction.
+
+ Possible Errors: [service].Error.InvalidArguments
+
+Signals PropertyChanged(string name, variant value)
+
+ This signal indicates a changed value of the given
+ property.
+
+Properties string Address [readonly]
+
+ The address of the device.
+
+ string Name [readonly]
+
+ The device name (for example "Wireless" etc.)
+
+ This name can be used for directly displaying it in
+ the application. It has pure informational purpose.
+
+ string Type [readonly]
+
+ The device type (for example "ethernet", "wifi" etc.)
+
+ string Interface [readonly]
+
+ The device interface (for example "eth0" etc.)
+
+ This value is for pure informational purposes. It
+ is not guaranteed that it is always present.
+
+ string Policy [readwrite]
+
+ Setting of the device power and connection policy.
+ Possible values are "ignore", "off", "auto"
+ and "manual".
+
+ The policy defines on how the device is initialized
+ when brought up and how it connects. The actual
+ device power state can be changed independently to
+ this value.
+
+ If a device is switched off and the policy is changed
+ to "auto" or "manual", the device will be switched
+ on. For a current active device changing the policy
+ to "off" results in powering down the device.
+
+ The "ignore" policy can be set for devices that are
+ detected, but managed by a different entity on the
+ system. For example for complex network setups.
+
+ Devices that can connect to various networks, the
+ difference between "auto" or "manual" defines if
+ known networks are connected automatically or not.
+ For simple devices like Ethernet cards, setting
+ the "manual" policy might fail.
+
+ uint8 Priority [readwrite]
+
+ The device priority. Higher values indicate the
+ preference for this device.
+
+ boolean Powered [readwrite]
+
+ Switch a device on or off. This will also modify
+ the list of networks in range. All known networks
+ will be still available via the Networks property.
+
+ Changing this value doesn't change the value of the
+ Policy property.
+
+ The value of this property can be changed by other
+ parts of the system (including the kernel). An
+ example would be modifications via the "ifconfig"
+ command line utility.
+
+ uint16 ScanInterval [readwrite]
+
+ The scan interval describes the time in seconds
+ between automated scan attempts. Setting this
+ value to 0 will disable the background scanning.
+
+ The default value is 300 and so every 5 minutes
+ a scan procedure will be triggered.
+
+ This property is not available with all types
+ of devices. Some might not support background
+ scanning at all.
+
+ boolean Scanning [readonly]
+
+ Indicates if a device is scanning. Not all device
+ types might support this. Also some hardware might
+ execute background scanning without notifying the
+ driver about it. Use this property only for visual
+ indication.
+
+ array{object} Networks [readonly]
+
+ List of networks objects paths. Every object path
+ represents a network in range or a known network.
--- /dev/null
+# -*- 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
--- /dev/null
+Manager hierarchy
+=================
+
+Service org.moblin.connman
+Interface org.moblin.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.DoesNotExist
+
+ object AddProfile(string name)
+
+ Add a new profile with the specified name.
+
+ It is possible to create two profiles with the same
+ name. The identification is done via the object path
+ and not the name of the profile.
+
+ Possible Errors: [service].Error.InvalidArguments
+
+ void RemoveProfile(object path)
+
+ Remove profile with specified object path.
+
+ It is not possible to remove the current active
+ profile. To remove the active profile a different
+ one must be selected via ActiveProfile property
+ first.
+
+ At minimum one profile must be available all the time.
+
+ 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
+
+Signals PropertyChanged(string name, variant value)
+
+ This signal indicates a changed value of the given
+ property.
+
+ StateChanged(string state)
+
+ This signal is similar to the PropertyChanged signal
+ for the State property.
+
+ It exists for application state only care about the
+ current state and so can avoid to be woken up when
+ other details changes.
+
+Properties string State [readonly]
+
+ The global connection state of a system. Possible
+ values are "online" if at least one connection exists
+ and "offline" if no device is connected.
+
+ In certain situations the state might change to
+ the value "connected". This can only be seen if
+ previously no connection was present.
+
+ string Policy [readwrite]
+
+ The global connection policy of a system. This
+ allows to configure how connections are established
+ and also when they are taken down again.
+
+ Possible values are "single", "multiple" and "ask".
+
+ For the single policy, the priority setting of the
+ device defines which becomes the default connection
+ when multiple are available.
+
+ 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.
+
+ object ActiveProfile [readwrite]
+
+ Object path of the current active profile.
+
+ array{object} Profiles [readonly]
+
+ List of profile object paths.
+
+ array{object} Devices [readonly]
+
+ List of device object paths.
+
+ array{object} Services [readonly]
+
+ List of service object paths. The list is sorted
+ internally to have the service with the default
+ route always first and then the favorite services
+ followed by scan results.
+
+ This list represents the available services for the
+ current selected profile. If the profile gets changed
+ then this list will be updated.
+
+ The same list is available via the profile object
+ itself. It is just provided here for convenience of
+ applications only dealing with the current active
+ profile.
+
+ array{object} Connections [readonly]
+
+ List of active connection object paths.
--- /dev/null
+Network hierarchy
+=================
+
+Service org.moblin.connman
+Interface org.moblin.connman.Network
+Object path [variable prefix]/{network0,network1,...}
+
+Methods dict GetProperties()
+
+ Returns properties for the network object. 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.DoesNotExist
+
+Signals PropertyChanged(string name, variant value)
+
+ This signal indicates a changed value of the given
+ property.
+
+Properties string Address [readonly]
+
+ The address of the network.
+
+ string Name [readonly]
+
+ The pretty/long version of the network name. For
+ example in case of WiFi this should be the UTF-8
+ valid version of the SSID.
+
+ This property might not be available for every
+ network. For example hidden WiFi networks will
+ not include it.
+
+ boolean Connected [readonly]
+
+ Indicates that this network is currently connected.
+
+ uint8 Strength [readonly]
+
+ Indicates the signal strength of the network. This
+ is a normalized value between 0 and 100.
+
+ object Device [readonly]
+
+ The object path of the device this networks
+ belongs to.
+
+ array{byte} WiFi.SSID [readonly]
+
+ If the network type is WiFi, then this property is
+ present and contains the binary SSID value.
+
+ string WiFi.Mode [readonly, readwrite]
+
+ If the network type is WiFi, then this property is
+ present and contains the mode of the network. The
+ possible values are "managed" or "adhoc".
+
+ For scanned networks this value is read only, but in
+ case the network was manually created it is also
+ changeable.
+
+ string WiFi.Security [readonly, readwrite]
+
+ If the network type is WiFi, then this property is
+ present and contains the security method or key
+ management setting.
+
+ For scanned networks this value is read only, but in
+ case the network was manually created it is also
+ changeable.
+
+ Possible values are "none", "wep", "wpa" and "rsn".
+
+ string WiFi.Passphrase [readwrite]
+
+ If the network type is WiFi and a passhrase is
+ requires, then this property is present and contains
+ the passphrase in clear text.
+
+ For systems using PolicyKit, the access to this value
+ will be protected by the security policy.
--- /dev/null
+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, a WiMAX service provider
+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) |
+ +---------------------------------------+
+ | Clear WiMAX (strength 70) |
+ +---------------------------------------+
+ | Other AP (strength 70, rsn) |
+ +---------------------------------------+
+ | Friends AP (strength 70, wep) |
+ +---------------------------------------+
+ | Other WiMAX (strength 50) |
+ +---------------------------------------+
+
+If non 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/WiMAX (signal strength first, then prefer WiMAX over WiFi,
+ 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.
+
+The WiFi and WiMAX networks are treated equally since both provide signal
+strength information and networks closer in the proximity should be shown
+before others since it is more likely they are selected first. The signal
+strength value is normalized to 0-100 (effectively a percentage) and allows
+an easy sorting.
+
+If the signal strength is identical than the WiMAX network should be shown
+first since it is a licensed spectrum and more reliable. Also the number
+of WiMAX networks will be smaller than the number of WiFi since that operates
+in an unlicensed spectrum.
+
+WiFi networks with the same signal strength are then sorted by its 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 or WiMAX network. 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, WiMAX 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
+other 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 service 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 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. This includes Ethernet devices with no cable plugged into
+them. This is of course suboptimal since the user doesn't need to be bothered
+with a device that he/she can actually physically see.
+
+So in this case the user interface can choose to just not show Ethernet
+devices with a favorite=no setting. This is an advanced tweak that is up
+to the user interface. However it is highly recommended to not show Ethernet
+device until Connection Manager marks them as favorite.
+
+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 WiMAX networks the provide name like Clear or X-OHM will be used. This
+name either comes directly from the networks itself or from a provisioning
+database of the WiMAX service.
+
+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.
+
+With Ethernet services a special "carrier" state is available. It indicates
+that the cable has been plugged in. This state is only used when the device
+is from type Ethernet.
+
+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.
+
+Some service might require special authentication procedure like a web based
+confirmation. The "login" should be used for this in the future. Currently
+this is not implemented.
+
+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 |<-------------------------------+
+ +---------------+ |
+ | | |
+ | +----------------------+ |
+ | | |
+ | V |
+ | +-------------+ |
+ +----------------------| carrier |<----+
+ | +-------------+ |
+ | |
+ | +-------------+ |
+ +----------------------| failure | |
+ | service.Connect() +-------------+ |
+ V A |
+ +---------------+ | |
+ | association |-----------------+ |
+ +---------------+ error | |
+ | | |
+ | success | |
+ V | |
+ +---------------+ | |
+ | configuration |-----------------+ |
+ +---------------+ error |
+ | |
+ | success |
+ V |
+ +---------------+ |
+ | ready |<----------------+ |
+ +---------------+ | |
+ | | |
+ | 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.
+
+
+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("org.moblin.connman", "/"),
+ "org.moblin.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, WiMAX providers 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. For WiMAX the provider name will
+be used for grouping different base stations and access providers. 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("org.moblin.connman", path),
+ "org.moblin.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 service 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 transaction 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 send via the PropertyChanged signal on the
+service interface. This allows asynchronous monitoring with having to poll
+Connection Manager for changes.
--- /dev/null
+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 definied 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)
--- /dev/null
+Profile hierarchy
+=================
+
+Service org.moblin.connman
+Interface org.moblin.connman.Profile
+Object path [variable prefix]/{profile0,profile1,...}
+
+Methods dict GetProperties()
+
+ Returns properties for the profile object. See
+ the properties section for available properties.
+
+ Possible Errors: [service].Error.InvalidArguments
+
+Signals PropertyChanged(string name, variant value)
+
+ This signal indicates a changed value of the given
+ property.
+
+Properties string Name [readonly]
+
+ Name of this profile.
+
+ array{object} Services [readonly]
+
+ List of service objects.
--- /dev/null
+Network Working Group P. Mockapetris
+Request for Comments: 1035 ISI
+ November 1987
+Obsoletes: RFCs 882, 883, 973
+
+ DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION
+
+
+1. STATUS OF THIS MEMO
+
+This RFC describes the details of the domain system and protocol, and
+assumes that the reader is familiar with the concepts discussed in a
+companion RFC, "Domain Names - Concepts and Facilities" [RFC-1034].
+
+The domain system is a mixture of functions and data types which are an
+official protocol and functions and data types which are still
+experimental. Since the domain system is intentionally extensible, new
+data types and experimental behavior should always be expected in parts
+of the system beyond the official protocol. The official protocol parts
+include standard queries, responses and the Internet class RR data
+formats (e.g., host addresses). Since the previous RFC set, several
+definitions have changed, so some previous definitions are obsolete.
+
+Experimental or obsolete features are clearly marked in these RFCs, and
+such information should be used with caution.
+
+The reader is especially cautioned not to depend on the values which
+appear in examples to be current or complete, since their purpose is
+primarily pedagogical. Distribution of this memo is unlimited.
+
+ Table of Contents
+
+ 1. STATUS OF THIS MEMO 1
+ 2. INTRODUCTION 3
+ 2.1. Overview 3
+ 2.2. Common configurations 4
+ 2.3. Conventions 7
+ 2.3.1. Preferred name syntax 7
+ 2.3.2. Data Transmission Order 8
+ 2.3.3. Character Case 9
+ 2.3.4. Size limits 10
+ 3. DOMAIN NAME SPACE AND RR DEFINITIONS 10
+ 3.1. Name space definitions 10
+ 3.2. RR definitions 11
+ 3.2.1. Format 11
+ 3.2.2. TYPE values 12
+ 3.2.3. QTYPE values 12
+ 3.2.4. CLASS values 13
+
+
+
+Mockapetris [Page 1]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 3.2.5. QCLASS values 13
+ 3.3. Standard RRs 13
+ 3.3.1. CNAME RDATA format 14
+ 3.3.2. HINFO RDATA format 14
+ 3.3.3. MB RDATA format (EXPERIMENTAL) 14
+ 3.3.4. MD RDATA format (Obsolete) 15
+ 3.3.5. MF RDATA format (Obsolete) 15
+ 3.3.6. MG RDATA format (EXPERIMENTAL) 16
+ 3.3.7. MINFO RDATA format (EXPERIMENTAL) 16
+ 3.3.8. MR RDATA format (EXPERIMENTAL) 17
+ 3.3.9. MX RDATA format 17
+ 3.3.10. NULL RDATA format (EXPERIMENTAL) 17
+ 3.3.11. NS RDATA format 18
+ 3.3.12. PTR RDATA format 18
+ 3.3.13. SOA RDATA format 19
+ 3.3.14. TXT RDATA format 20
+ 3.4. ARPA Internet specific RRs 20
+ 3.4.1. A RDATA format 20
+ 3.4.2. WKS RDATA format 21
+ 3.5. IN-ADDR.ARPA domain 22
+ 3.6. Defining new types, classes, and special namespaces 24
+ 4. MESSAGES 25
+ 4.1. Format 25
+ 4.1.1. Header section format 26
+ 4.1.2. Question section format 28
+ 4.1.3. Resource record format 29
+ 4.1.4. Message compression 30
+ 4.2. Transport 32
+ 4.2.1. UDP usage 32
+ 4.2.2. TCP usage 32
+ 5. MASTER FILES 33
+ 5.1. Format 33
+ 5.2. Use of master files to define zones 35
+ 5.3. Master file example 36
+ 6. NAME SERVER IMPLEMENTATION 37
+ 6.1. Architecture 37
+ 6.1.1. Control 37
+ 6.1.2. Database 37
+ 6.1.3. Time 39
+ 6.2. Standard query processing 39
+ 6.3. Zone refresh and reload processing 39
+ 6.4. Inverse queries (Optional) 40
+ 6.4.1. The contents of inverse queries and responses 40
+ 6.4.2. Inverse query and response example 41
+ 6.4.3. Inverse query processing 42
+
+
+
+
+
+
+Mockapetris [Page 2]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 6.5. Completion queries and responses 42
+ 7. RESOLVER IMPLEMENTATION 43
+ 7.1. Transforming a user request into a query 43
+ 7.2. Sending the queries 44
+ 7.3. Processing responses 46
+ 7.4. Using the cache 47
+ 8. MAIL SUPPORT 47
+ 8.1. Mail exchange binding 48
+ 8.2. Mailbox binding (Experimental) 48
+ 9. REFERENCES and BIBLIOGRAPHY 50
+ Index 54
+
+2. INTRODUCTION
+
+2.1. Overview
+
+The goal of domain names is to provide a mechanism for naming resources
+in such a way that the names are usable in different hosts, networks,
+protocol families, internets, and administrative organizations.
+
+From the user's point of view, domain names are useful as arguments to a
+local agent, called a resolver, which retrieves information associated
+with the domain name. Thus a user might ask for the host address or
+mail information associated with a particular domain name. To enable
+the user to request a particular type of information, an appropriate
+query type is passed to the resolver with the domain name. To the user,
+the domain tree is a single information space; the resolver is
+responsible for hiding the distribution of data among name servers from
+the user.
+
+From the resolver's point of view, the database that makes up the domain
+space is distributed among various name servers. Different parts of the
+domain space are stored in different name servers, although a particular
+data item will be stored redundantly in two or more name servers. The
+resolver starts with knowledge of at least one name server. When the
+resolver processes a user query it asks a known name server for the
+information; in return, the resolver either receives the desired
+information or a referral to another name server. Using these
+referrals, resolvers learn the identities and contents of other name
+servers. Resolvers are responsible for dealing with the distribution of
+the domain space and dealing with the effects of name server failure by
+consulting redundant databases in other servers.
+
+Name servers manage two kinds of data. The first kind of data held in
+sets called zones; each zone is the complete database for a particular
+"pruned" subtree of the domain space. This data is called
+authoritative. A name server periodically checks to make sure that its
+zones are up to date, and if not, obtains a new copy of updated zones
+
+
+
+Mockapetris [Page 3]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+from master files stored locally or in another name server. The second
+kind of data is cached data which was acquired by a local resolver.
+This data may be incomplete, but improves the performance of the
+retrieval process when non-local data is repeatedly accessed. Cached
+data is eventually discarded by a timeout mechanism.
+
+This functional structure isolates the problems of user interface,
+failure recovery, and distribution in the resolvers and isolates the
+database update and refresh problems in the name servers.
+
+2.2. Common configurations
+
+A host can participate in the domain name system in a number of ways,
+depending on whether the host runs programs that retrieve information
+from the domain system, name servers that answer queries from other
+hosts, or various combinations of both functions. The simplest, and
+perhaps most typical, configuration is shown below:
+
+ Local Host | Foreign
+ |
+ +---------+ +----------+ | +--------+
+ | | user queries | |queries | | |
+ | User |-------------->| |---------|->|Foreign |
+ | Program | | Resolver | | | Name |
+ | |<--------------| |<--------|--| Server |
+ | | user responses| |responses| | |
+ +---------+ +----------+ | +--------+
+ | A |
+ cache additions | | references |
+ V | |
+ +----------+ |
+ | cache | |
+ +----------+ |
+
+User programs interact with the domain name space through resolvers; the
+format of user queries and user responses is specific to the host and
+its operating system. User queries will typically be operating system
+calls, and the resolver and its cache will be part of the host operating
+system. Less capable hosts may choose to implement the resolver as a
+subroutine to be linked in with every program that needs its services.
+Resolvers answer user queries with information they acquire via queries
+to foreign name servers and the local cache.
+
+Note that the resolver may have to make several queries to several
+different foreign name servers to answer a particular user query, and
+hence the resolution of a user query may involve several network
+accesses and an arbitrary amount of time. The queries to foreign name
+servers and the corresponding responses have a standard format described
+
+
+
+Mockapetris [Page 4]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+in this memo, and may be datagrams.
+
+Depending on its capabilities, a name server could be a stand alone
+program on a dedicated machine or a process or processes on a large
+timeshared host. A simple configuration might be:
+
+ Local Host | Foreign
+ |
+ +---------+ |
+ / /| |
+ +---------+ | +----------+ | +--------+
+ | | | | |responses| | |
+ | | | | Name |---------|->|Foreign |
+ | Master |-------------->| Server | | |Resolver|
+ | files | | | |<--------|--| |
+ | |/ | | queries | +--------+
+ +---------+ +----------+ |
+
+Here a primary name server acquires information about one or more zones
+by reading master files from its local file system, and answers queries
+about those zones that arrive from foreign resolvers.
+
+The DNS requires that all zones be redundantly supported by more than
+one name server. Designated secondary servers can acquire zones and
+check for updates from the primary server using the zone transfer
+protocol of the DNS. This configuration is shown below:
+
+ Local Host | Foreign
+ |
+ +---------+ |
+ / /| |
+ +---------+ | +----------+ | +--------+
+ | | | | |responses| | |
+ | | | | Name |---------|->|Foreign |
+ | Master |-------------->| Server | | |Resolver|
+ | files | | | |<--------|--| |
+ | |/ | | queries | +--------+
+ +---------+ +----------+ |
+ A |maintenance | +--------+
+ | +------------|->| |
+ | queries | |Foreign |
+ | | | Name |
+ +------------------|--| Server |
+ maintenance responses | +--------+
+
+In this configuration, the name server periodically establishes a
+virtual circuit to a foreign name server to acquire a copy of a zone or
+to check that an existing copy has not changed. The messages sent for
+
+
+
+Mockapetris [Page 5]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+these maintenance activities follow the same form as queries and
+responses, but the message sequences are somewhat different.
+
+The information flow in a host that supports all aspects of the domain
+name system is shown below:
+
+ Local Host | Foreign
+ |
+ +---------+ +----------+ | +--------+
+ | | user queries | |queries | | |
+ | User |-------------->| |---------|->|Foreign |
+ | Program | | Resolver | | | Name |
+ | |<--------------| |<--------|--| Server |
+ | | user responses| |responses| | |
+ +---------+ +----------+ | +--------+
+ | A |
+ cache additions | | references |
+ V | |
+ +----------+ |
+ | Shared | |
+ | database | |
+ +----------+ |
+ A | |
+ +---------+ refreshes | | references |
+ / /| | V |
+ +---------+ | +----------+ | +--------+
+ | | | | |responses| | |
+ | | | | Name |---------|->|Foreign |
+ | Master |-------------->| Server | | |Resolver|
+ | files | | | |<--------|--| |
+ | |/ | | queries | +--------+
+ +---------+ +----------+ |
+ A |maintenance | +--------+
+ | +------------|->| |
+ | queries | |Foreign |
+ | | | Name |
+ +------------------|--| Server |
+ maintenance responses | +--------+
+
+The shared database holds domain space data for the local name server
+and resolver. The contents of the shared database will typically be a
+mixture of authoritative data maintained by the periodic refresh
+operations of the name server and cached data from previous resolver
+requests. The structure of the domain data and the necessity for
+synchronization between name servers and resolvers imply the general
+characteristics of this database, but the actual format is up to the
+local implementor.
+
+
+
+
+Mockapetris [Page 6]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+Information flow can also be tailored so that a group of hosts act
+together to optimize activities. Sometimes this is done to offload less
+capable hosts so that they do not have to implement a full resolver.
+This can be appropriate for PCs or hosts which want to minimize the
+amount of new network code which is required. This scheme can also
+allow a group of hosts can share a small number of caches rather than
+maintaining a large number of separate caches, on the premise that the
+centralized caches will have a higher hit ratio. In either case,
+resolvers are replaced with stub resolvers which act as front ends to
+resolvers located in a recursive server in one or more name servers
+known to perform that service:
+
+ Local Hosts | Foreign
+ |
+ +---------+ |
+ | | responses |
+ | Stub |<--------------------+ |
+ | Resolver| | |
+ | |----------------+ | |
+ +---------+ recursive | | |
+ queries | | |
+ V | |
+ +---------+ recursive +----------+ | +--------+
+ | | queries | |queries | | |
+ | Stub |-------------->| Recursive|---------|->|Foreign |
+ | Resolver| | Server | | | Name |
+ | |<--------------| |<--------|--| Server |
+ +---------+ responses | |responses| | |
+ +----------+ | +--------+
+ | Central | |
+ | cache | |
+ +----------+ |
+
+In any case, note that domain components are always replicated for
+reliability whenever possible.
+
+2.3. Conventions
+
+The domain system has several conventions dealing with low-level, but
+fundamental, issues. While the implementor is free to violate these
+conventions WITHIN HIS OWN SYSTEM, he must observe these conventions in
+ALL behavior observed from other hosts.
+
+2.3.1. Preferred name syntax
+
+The DNS specifications attempt to be as general as possible in the rules
+for constructing domain names. The idea is that the name of any
+existing object can be expressed as a domain name with minimal changes.
+
+
+
+Mockapetris [Page 7]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+However, when assigning a domain name for an object, the prudent user
+will select a name which satisfies both the rules of the domain system
+and any existing rules for the object, whether these rules are published
+or implied by existing programs.
+
+For example, when naming a mail domain, the user should satisfy both the
+rules of this memo and those in RFC-822. When creating a new host name,
+the old rules for HOSTS.TXT should be followed. This avoids problems
+when old software is converted to use domain names.
+
+The following syntax will result in fewer problems with many
+
+applications that use domain names (e.g., mail, TELNET).
+
+<domain> ::= <subdomain> | " "
+
+<subdomain> ::= <label> | <subdomain> "." <label>
+
+<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
+
+<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
+
+<let-dig-hyp> ::= <let-dig> | "-"
+
+<let-dig> ::= <letter> | <digit>
+
+<letter> ::= any one of the 52 alphabetic characters A through Z in
+upper case and a through z in lower case
+
+<digit> ::= any one of the ten digits 0 through 9
+
+Note that while upper and lower case letters are allowed in domain
+names, no significance is attached to the case. That is, two names with
+the same spelling but different case are to be treated as if identical.
+
+The labels must follow the rules for ARPANET host names. They must
+start with a letter, end with a letter or digit, and have as interior
+characters only letters, digits, and hyphen. There are also some
+restrictions on the length. Labels must be 63 characters or less.
+
+For example, the following strings identify hosts in the Internet:
+
+A.ISI.EDU XX.LCS.MIT.EDU SRI-NIC.ARPA
+
+2.3.2. Data Transmission Order
+
+The order of transmission of the header and data described in this
+document is resolved to the octet level. Whenever a diagram shows a
+
+
+
+Mockapetris [Page 8]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+group of octets, the order of transmission of those octets is the normal
+order in which they are read in English. For example, in the following
+diagram, the octets are transmitted in the order they are numbered.
+
+ 0 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 1 | 2 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 3 | 4 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 5 | 6 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Whenever an octet represents a numeric quantity, the left most bit in
+the diagram is the high order or most significant bit. That is, the bit
+labeled 0 is the most significant bit. For example, the following
+diagram represents the value 170 (decimal).
+
+ 0 1 2 3 4 5 6 7
+ +-+-+-+-+-+-+-+-+
+ |1 0 1 0 1 0 1 0|
+ +-+-+-+-+-+-+-+-+
+
+Similarly, whenever a multi-octet field represents a numeric quantity
+the left most bit of the whole field is the most significant bit. When
+a multi-octet quantity is transmitted the most significant octet is
+transmitted first.
+
+2.3.3. Character Case
+
+For all parts of the DNS that are part of the official protocol, all
+comparisons between character strings (e.g., labels, domain names, etc.)
+are done in a case-insensitive manner. At present, this rule is in
+force throughout the domain system without exception. However, future
+additions beyond current usage may need to use the full binary octet
+capabilities in names, so attempts to store domain names in 7-bit ASCII
+or use of special bytes to terminate labels, etc., should be avoided.
+
+When data enters the domain system, its original case should be
+preserved whenever possible. In certain circumstances this cannot be
+done. For example, if two RRs are stored in a database, one at x.y and
+one at X.Y, they are actually stored at the same place in the database,
+and hence only one casing would be preserved. The basic rule is that
+case can be discarded only when data is used to define structure in a
+database, and two names are identical when compared in a case
+insensitive manner.
+
+
+
+
+Mockapetris [Page 9]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+Loss of case sensitive data must be minimized. Thus while data for x.y
+and X.Y may both be stored under a single location x.y or X.Y, data for
+a.x and B.X would never be stored under A.x, A.X, b.x, or b.X. In
+general, this preserves the case of the first label of a domain name,
+but forces standardization of interior node labels.
+
+Systems administrators who enter data into the domain database should
+take care to represent the data they supply to the domain system in a
+case-consistent manner if their system is case-sensitive. The data
+distribution system in the domain system will ensure that consistent
+representations are preserved.
+
+2.3.4. Size limits
+
+Various objects and parameters in the DNS have size limits. They are
+listed below. Some could be easily changed, others are more
+fundamental.
+
+labels 63 octets or less
+
+names 255 octets or less
+
+TTL positive values of a signed 32 bit number.
+
+UDP messages 512 octets or less
+
+3. DOMAIN NAME SPACE AND RR DEFINITIONS
+
+3.1. Name space definitions
+
+Domain names in messages are expressed in terms of a sequence of labels.
+Each label is represented as a one octet length field followed by that
+number of octets. Since every domain name ends with the null label of
+the root, a domain name is terminated by a length byte of zero. The
+high order two bits of every length octet must be zero, and the
+remaining six bits of the length field limit the label to 63 octets or
+less.
+
+To simplify implementations, the total length of a domain name (i.e.,
+label octets and label length octets) is restricted to 255 octets or
+less.
+
+Although labels can contain any 8 bit values in octets that make up a
+label, it is strongly recommended that labels follow the preferred
+syntax described elsewhere in this memo, which is compatible with
+existing host naming conventions. Name servers and resolvers must
+compare labels in a case-insensitive manner (i.e., A=a), assuming ASCII
+with zero parity. Non-alphabetic codes must match exactly.
+
+
+
+Mockapetris [Page 10]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.2. RR definitions
+
+3.2.1. Format
+
+All RRs have the same top level format shown below:
+
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / /
+ / NAME /
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | CLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TTL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RDLENGTH |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+ / RDATA /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+
+where:
+
+NAME an owner name, i.e., the name of the node to which this
+ resource record pertains.
+
+TYPE two octets containing one of the RR TYPE codes.
+
+CLASS two octets containing one of the RR CLASS codes.
+
+TTL a 32 bit signed integer that specifies the time interval
+ that the resource record may be cached before the source
+ of the information should again be consulted. Zero
+ values are interpreted to mean that the RR can only be
+ used for the transaction in progress, and should not be
+ cached. For example, SOA records are always distributed
+ with a zero TTL to prohibit caching. Zero values can
+ also be used for extremely volatile data.
+
+RDLENGTH an unsigned 16 bit integer that specifies the length in
+ octets of the RDATA field.
+
+
+
+Mockapetris [Page 11]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+RDATA a variable length string of octets that describes the
+ resource. The format of this information varies
+ according to the TYPE and CLASS of the resource record.
+
+3.2.2. TYPE values
+
+TYPE fields are used in resource records. Note that these types are a
+subset of QTYPEs.
+
+TYPE value and meaning
+
+A 1 a host address
+
+NS 2 an authoritative name server
+
+MD 3 a mail destination (Obsolete - use MX)
+
+MF 4 a mail forwarder (Obsolete - use MX)
+
+CNAME 5 the canonical name for an alias
+
+SOA 6 marks the start of a zone of authority
+
+MB 7 a mailbox domain name (EXPERIMENTAL)
+
+MG 8 a mail group member (EXPERIMENTAL)
+
+MR 9 a mail rename domain name (EXPERIMENTAL)
+
+NULL 10 a null RR (EXPERIMENTAL)
+
+WKS 11 a well known service description
+
+PTR 12 a domain name pointer
+
+HINFO 13 host information
+
+MINFO 14 mailbox or mail list information
+
+MX 15 mail exchange
+
+TXT 16 text strings
+
+3.2.3. QTYPE values
+
+QTYPE fields appear in the question part of a query. QTYPES are a
+superset of TYPEs, hence all TYPEs are valid QTYPEs. In addition, the
+following QTYPEs are defined:
+
+
+
+Mockapetris [Page 12]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+AXFR 252 A request for a transfer of an entire zone
+
+MAILB 253 A request for mailbox-related records (MB, MG or MR)
+
+MAILA 254 A request for mail agent RRs (Obsolete - see MX)
+
+* 255 A request for all records
+
+3.2.4. CLASS values
+
+CLASS fields appear in resource records. The following CLASS mnemonics
+and values are defined:
+
+IN 1 the Internet
+
+CS 2 the CSNET class (Obsolete - used only for examples in
+ some obsolete RFCs)
+
+CH 3 the CHAOS class
+
+HS 4 Hesiod [Dyer 87]
+
+3.2.5. QCLASS values
+
+QCLASS fields appear in the question section of a query. QCLASS values
+are a superset of CLASS values; every CLASS is a valid QCLASS. In
+addition to CLASS values, the following QCLASSes are defined:
+
+* 255 any class
+
+3.3. Standard RRs
+
+The following RR definitions are expected to occur, at least
+potentially, in all classes. In particular, NS, SOA, CNAME, and PTR
+will be used in all classes, and have the same format in all classes.
+Because their RDATA format is known, all domain names in the RDATA
+section of these RRs may be compressed.
+
+<domain-name> is a domain name represented as a series of labels, and
+terminated by a label with zero length. <character-string> is a single
+length octet followed by that number of characters. <character-string>
+is treated as binary information, and can be up to 256 characters in
+length (including the length octet).
+
+
+
+
+
+
+
+
+Mockapetris [Page 13]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.1. CNAME RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / CNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+CNAME A <domain-name> which specifies the canonical or primary
+ name for the owner. The owner name is an alias.
+
+CNAME RRs cause no additional section processing, but name servers may
+choose to restart the query at the canonical name in certain cases. See
+the description of name server logic in [RFC-1034] for details.
+
+3.3.2. HINFO RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / CPU /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / OS /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+CPU A <character-string> which specifies the CPU type.
+
+OS A <character-string> which specifies the operating
+ system type.
+
+Standard values for CPU and OS can be found in [RFC-1010].
+
+HINFO records are used to acquire general information about a host. The
+main use is for protocols such as FTP that can use special procedures
+when talking between machines or operating systems of the same type.
+
+3.3.3. MB RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MADNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME A <domain-name> which specifies a host which has the
+ specified mailbox.
+
+
+
+Mockapetris [Page 14]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+MB records cause additional section processing which looks up an A type
+RRs corresponding to MADNAME.
+
+3.3.4. MD RDATA format (Obsolete)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MADNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME A <domain-name> which specifies a host which has a mail
+ agent for the domain which should be able to deliver
+ mail for the domain.
+
+MD records cause additional section processing which looks up an A type
+record corresponding to MADNAME.
+
+MD is obsolete. See the definition of MX and [RFC-974] for details of
+the new scheme. The recommended policy for dealing with MD RRs found in
+a master file is to reject them, or to convert them to MX RRs with a
+preference of 0.
+
+3.3.5. MF RDATA format (Obsolete)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MADNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME A <domain-name> which specifies a host which has a mail
+ agent for the domain which will accept mail for
+ forwarding to the domain.
+
+MF records cause additional section processing which looks up an A type
+record corresponding to MADNAME.
+
+MF is obsolete. See the definition of MX and [RFC-974] for details ofw
+the new scheme. The recommended policy for dealing with MD RRs found in
+a master file is to reject them, or to convert them to MX RRs with a
+preference of 10.
+
+
+
+
+
+
+
+Mockapetris [Page 15]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.6. MG RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MGMNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MGMNAME A <domain-name> which specifies a mailbox which is a
+ member of the mail group specified by the domain name.
+
+MG records cause no additional section processing.
+
+3.3.7. MINFO RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / RMAILBX /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / EMAILBX /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+RMAILBX A <domain-name> which specifies a mailbox which is
+ responsible for the mailing list or mailbox. If this
+ domain name names the root, the owner of the MINFO RR is
+ responsible for itself. Note that many existing mailing
+ lists use a mailbox X-request for the RMAILBX field of
+ mailing list X, e.g., Msgroup-request for Msgroup. This
+ field provides a more general mechanism.
+
+
+EMAILBX A <domain-name> which specifies a mailbox which is to
+ receive error messages related to the mailing list or
+ mailbox specified by the owner of the MINFO RR (similar
+ to the ERRORS-TO: field which has been proposed). If
+ this domain name names the root, errors should be
+ returned to the sender of the message.
+
+MINFO records cause no additional section processing. Although these
+records can be associated with a simple mailbox, they are usually used
+with a mailing list.
+
+
+
+
+
+
+
+
+Mockapetris [Page 16]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.8. MR RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / NEWNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NEWNAME A <domain-name> which specifies a mailbox which is the
+ proper rename of the specified mailbox.
+
+MR records cause no additional section processing. The main use for MR
+is as a forwarding entry for a user who has moved to a different
+mailbox.
+
+3.3.9. MX RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | PREFERENCE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / EXCHANGE /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+PREFERENCE A 16 bit integer which specifies the preference given to
+ this RR among others at the same owner. Lower values
+ are preferred.
+
+EXCHANGE A <domain-name> which specifies a host willing to act as
+ a mail exchange for the owner name.
+
+MX records cause type A additional section processing for the host
+specified by EXCHANGE. The use of MX RRs is explained in detail in
+[RFC-974].
+
+3.3.10. NULL RDATA format (EXPERIMENTAL)
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / <anything> /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+Anything at all may be in the RDATA field so long as it is 65535 octets
+or less.
+
+
+
+
+Mockapetris [Page 17]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+NULL records cause no additional section processing. NULL RRs are not
+allowed in master files. NULLs are used as placeholders in some
+experimental extensions of the DNS.
+
+3.3.11. NS RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / NSDNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NSDNAME A <domain-name> which specifies a host which should be
+ authoritative for the specified class and domain.
+
+NS records cause both the usual additional section processing to locate
+a type A record, and, when used in a referral, a special search of the
+zone in which they reside for glue information.
+
+The NS RR states that the named host should be expected to have a zone
+starting at owner name of the specified class. Note that the class may
+not indicate the protocol family which should be used to communicate
+with the host, although it is typically a strong hint. For example,
+hosts which are name servers for either Internet (IN) or Hesiod (HS)
+class information are normally queried using IN class protocols.
+
+3.3.12. PTR RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / PTRDNAME /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+PTRDNAME A <domain-name> which points to some location in the
+ domain name space.
+
+PTR records cause no additional section processing. These RRs are used
+in special domains to point to some other location in the domain space.
+These records are simple data, and don't imply any special processing
+similar to that performed by CNAME, which identifies aliases. See the
+description of the IN-ADDR.ARPA domain for an example.
+
+
+
+
+
+
+
+
+Mockapetris [Page 18]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.3.13. SOA RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / RNAME /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | SERIAL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | REFRESH |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RETRY |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | EXPIRE |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | MINIMUM |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MNAME The <domain-name> of the name server that was the
+ original or primary source of data for this zone.
+
+RNAME A <domain-name> which specifies the mailbox of the
+ person responsible for this zone.
+
+SERIAL The unsigned 32 bit version number of the original copy
+ of the zone. Zone transfers preserve this value. This
+ value wraps and should be compared using sequence space
+ arithmetic.
+
+REFRESH A 32 bit time interval before the zone should be
+ refreshed.
+
+RETRY A 32 bit time interval that should elapse before a
+ failed refresh should be retried.
+
+EXPIRE A 32 bit time value that specifies the upper limit on
+ the time interval that can elapse before the zone is no
+ longer authoritative.
+
+
+
+
+
+Mockapetris [Page 19]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+MINIMUM The unsigned 32 bit minimum TTL field that should be
+ exported with any RR from this zone.
+
+SOA records cause no additional section processing.
+
+All times are in units of seconds.
+
+Most of these fields are pertinent only for name server maintenance
+operations. However, MINIMUM is used in all query operations that
+retrieve RRs from a zone. Whenever a RR is sent in a response to a
+query, the TTL field is set to the maximum of the TTL field from the RR
+and the MINIMUM field in the appropriate SOA. Thus MINIMUM is a lower
+bound on the TTL field for all RRs in a zone. Note that this use of
+MINIMUM should occur when the RRs are copied into the response and not
+when the zone is loaded from a master file or via a zone transfer. The
+reason for this provison is to allow future dynamic update facilities to
+change the SOA RR with known semantics.
+
+
+3.3.14. TXT RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / TXT-DATA /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+TXT-DATA One or more <character-string>s.
+
+TXT RRs are used to hold descriptive text. The semantics of the text
+depends on the domain where it is found.
+
+3.4. Internet specific RRs
+
+3.4.1. A RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ADDRESS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ADDRESS A 32 bit Internet address.
+
+Hosts that have multiple Internet addresses will have multiple A
+records.
+
+
+
+
+
+Mockapetris [Page 20]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+A records cause no additional section processing. The RDATA section of
+an A line in a master file is an Internet address expressed as four
+decimal numbers separated by dots without any imbedded spaces (e.g.,
+"10.2.0.52" or "192.0.5.6").
+
+3.4.2. WKS RDATA format
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ADDRESS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | PROTOCOL | |
+ +--+--+--+--+--+--+--+--+ |
+ | |
+ / <BIT MAP> /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ADDRESS An 32 bit Internet address
+
+PROTOCOL An 8 bit IP protocol number
+
+<BIT MAP> A variable length bit map. The bit map must be a
+ multiple of 8 bits long.
+
+The WKS record is used to describe the well known services supported by
+a particular protocol on a particular internet address. The PROTOCOL
+field specifies an IP protocol number, and the bit map has one bit per
+port of the specified protocol. The first bit corresponds to port 0,
+the second to port 1, etc. If the bit map does not include a bit for a
+protocol of interest, that bit is assumed zero. The appropriate values
+and mnemonics for ports and protocols are specified in [RFC-1010].
+
+For example, if PROTOCOL=TCP (6), the 26th bit corresponds to TCP port
+25 (SMTP). If this bit is set, a SMTP server should be listening on TCP
+port 25; if zero, SMTP service is not supported on the specified
+address.
+
+The purpose of WKS RRs is to provide availability information for
+servers for TCP and UDP. If a server supports both TCP and UDP, or has
+multiple Internet addresses, then multiple WKS RRs are used.
+
+WKS RRs cause no additional section processing.
+
+In master files, both ports and protocols are expressed using mnemonics
+or decimal numbers.
+
+
+
+
+Mockapetris [Page 21]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.5. IN-ADDR.ARPA domain
+
+The Internet uses a special domain to support gateway location and
+Internet address to host mapping. Other classes may employ a similar
+strategy in other domains. The intent of this domain is to provide a
+guaranteed method to perform host address to host name mapping, and to
+facilitate queries to locate all gateways on a particular network in the
+Internet.
+
+Note that both of these services are similar to functions that could be
+performed by inverse queries; the difference is that this part of the
+domain name space is structured according to address, and hence can
+guarantee that the appropriate data can be located without an exhaustive
+search of the domain space.
+
+The domain begins at IN-ADDR.ARPA and has a substructure which follows
+the Internet addressing structure.
+
+Domain names in the IN-ADDR.ARPA domain are defined to have up to four
+labels in addition to the IN-ADDR.ARPA suffix. Each label represents
+one octet of an Internet address, and is expressed as a character string
+for a decimal value in the range 0-255 (with leading zeros omitted
+except in the case of a zero octet which is represented by a single
+zero).
+
+Host addresses are represented by domain names that have all four labels
+specified. Thus data for Internet address 10.2.0.52 is located at
+domain name 52.0.2.10.IN-ADDR.ARPA. The reversal, though awkward to
+read, allows zones to be delegated which are exactly one network of
+address space. For example, 10.IN-ADDR.ARPA can be a zone containing
+data for the ARPANET, while 26.IN-ADDR.ARPA can be a separate zone for
+MILNET. Address nodes are used to hold pointers to primary host names
+in the normal domain space.
+
+Network numbers correspond to some non-terminal nodes at various depths
+in the IN-ADDR.ARPA domain, since Internet network numbers are either 1,
+2, or 3 octets. Network nodes are used to hold pointers to the primary
+host names of gateways attached to that network. Since a gateway is, by
+definition, on more than one network, it will typically have two or more
+network nodes which point at it. Gateways will also have host level
+pointers at their fully qualified addresses.
+
+Both the gateway pointers at network nodes and the normal host pointers
+at full address nodes use the PTR RR to point back to the primary domain
+names of the corresponding hosts.
+
+For example, the IN-ADDR.ARPA domain will contain information about the
+ISI gateway between net 10 and 26, an MIT gateway from net 10 to MIT's
+
+
+
+Mockapetris [Page 22]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+net 18, and hosts A.ISI.EDU and MULTICS.MIT.EDU. Assuming that ISI
+gateway has addresses 10.2.0.22 and 26.0.0.103, and a name MILNET-
+GW.ISI.EDU, and the MIT gateway has addresses 10.0.0.77 and 18.10.0.4
+and a name GW.LCS.MIT.EDU, the domain database would contain:
+
+ 10.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 10.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 18.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 26.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 22.0.2.10.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 103.0.0.26.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 77.0.0.10.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 4.0.10.18.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+ 103.0.3.26.IN-ADDR.ARPA. PTR A.ISI.EDU.
+ 6.0.0.10.IN-ADDR.ARPA. PTR MULTICS.MIT.EDU.
+
+Thus a program which wanted to locate gateways on net 10 would originate
+a query of the form QTYPE=PTR, QCLASS=IN, QNAME=10.IN-ADDR.ARPA. It
+would receive two RRs in response:
+
+ 10.IN-ADDR.ARPA. PTR MILNET-GW.ISI.EDU.
+ 10.IN-ADDR.ARPA. PTR GW.LCS.MIT.EDU.
+
+The program could then originate QTYPE=A, QCLASS=IN queries for MILNET-
+GW.ISI.EDU. and GW.LCS.MIT.EDU. to discover the Internet addresses of
+these gateways.
+
+A resolver which wanted to find the host name corresponding to Internet
+host address 10.0.0.6 would pursue a query of the form QTYPE=PTR,
+QCLASS=IN, QNAME=6.0.0.10.IN-ADDR.ARPA, and would receive:
+
+ 6.0.0.10.IN-ADDR.ARPA. PTR MULTICS.MIT.EDU.
+
+Several cautions apply to the use of these services:
+ - Since the IN-ADDR.ARPA special domain and the normal domain
+ for a particular host or gateway will be in different zones,
+ the possibility exists that that the data may be inconsistent.
+
+ - Gateways will often have two names in separate domains, only
+ one of which can be primary.
+
+ - Systems that use the domain database to initialize their
+ routing tables must start with enough gateway information to
+ guarantee that they can access the appropriate name server.
+
+ - The gateway data only reflects the existence of a gateway in a
+ manner equivalent to the current HOSTS.TXT file. It doesn't
+ replace the dynamic availability information from GGP or EGP.
+
+
+
+Mockapetris [Page 23]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+3.6. Defining new types, classes, and special namespaces
+
+The previously defined types and classes are the ones in use as of the
+date of this memo. New definitions should be expected. This section
+makes some recommendations to designers considering additions to the
+existing facilities. The mailing list NAMEDROPPERS@SRI-NIC.ARPA is the
+forum where general discussion of design issues takes place.
+
+In general, a new type is appropriate when new information is to be
+added to the database about an existing object, or we need new data
+formats for some totally new object. Designers should attempt to define
+types and their RDATA formats that are generally applicable to all
+classes, and which avoid duplication of information. New classes are
+appropriate when the DNS is to be used for a new protocol, etc which
+requires new class-specific data formats, or when a copy of the existing
+name space is desired, but a separate management domain is necessary.
+
+New types and classes need mnemonics for master files; the format of the
+master files requires that the mnemonics for type and class be disjoint.
+
+TYPE and CLASS values must be a proper subset of QTYPEs and QCLASSes
+respectively.
+
+The present system uses multiple RRs to represent multiple values of a
+type rather than storing multiple values in the RDATA section of a
+single RR. This is less efficient for most applications, but does keep
+RRs shorter. The multiple RRs assumption is incorporated in some
+experimental work on dynamic update methods.
+
+The present system attempts to minimize the duplication of data in the
+database in order to insure consistency. Thus, in order to find the
+address of the host for a mail exchange, you map the mail domain name to
+a host name, then the host name to addresses, rather than a direct
+mapping to host address. This approach is preferred because it avoids
+the opportunity for inconsistency.
+
+In defining a new type of data, multiple RR types should not be used to
+create an ordering between entries or express different formats for
+equivalent bindings, instead this information should be carried in the
+body of the RR and a single type used. This policy avoids problems with
+caching multiple types and defining QTYPEs to match multiple types.
+
+For example, the original form of mail exchange binding used two RR
+types one to represent a "closer" exchange (MD) and one to represent a
+"less close" exchange (MF). The difficulty is that the presence of one
+RR type in a cache doesn't convey any information about the other
+because the query which acquired the cached information might have used
+a QTYPE of MF, MD, or MAILA (which matched both). The redesigned
+
+
+
+Mockapetris [Page 24]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+service used a single type (MX) with a "preference" value in the RDATA
+section which can order different RRs. However, if any MX RRs are found
+in the cache, then all should be there.
+
+4. MESSAGES
+
+4.1. Format
+
+All communications inside of the domain protocol are carried in a single
+format called a message. The top level format of message is divided
+into 5 sections (some of which are empty in certain cases) shown below:
+
+ +---------------------+
+ | Header |
+ +---------------------+
+ | Question | the question for the name server
+ +---------------------+
+ | Answer | RRs answering the question
+ +---------------------+
+ | Authority | RRs pointing toward an authority
+ +---------------------+
+ | Additional | RRs holding additional information
+ +---------------------+
+
+The header section is always present. The header includes fields that
+specify which of the remaining sections are present, and also specify
+whether the message is a query or a response, a standard query or some
+other opcode, etc.
+
+The names of the sections after the header are derived from their use in
+standard queries. The question section contains fields that describe a
+question to a name server. These fields are a query type (QTYPE), a
+query class (QCLASS), and a query domain name (QNAME). The last three
+sections have the same format: a possibly empty list of concatenated
+resource records (RRs). The answer section contains RRs that answer the
+question; the authority section contains RRs that point toward an
+authoritative name server; the additional records section contains RRs
+which relate to the query, but are not strictly answers for the
+question.
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 25]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+4.1.1. Header section format
+
+The header contains the following fields:
+
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ID |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QDCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ANCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | NSCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ARCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ID A 16 bit identifier assigned by the program that
+ generates any kind of query. This identifier is copied
+ the corresponding reply and can be used by the requester
+ to match up replies to outstanding queries.
+
+QR A one bit field that specifies whether this message is a
+ query (0), or a response (1).
+
+OPCODE A four bit field that specifies kind of query in this
+ message. This value is set by the originator of a query
+ and copied into the response. The values are:
+
+ 0 a standard query (QUERY)
+
+ 1 an inverse query (IQUERY)
+
+ 2 a server status request (STATUS)
+
+ 3-15 reserved for future use
+
+AA Authoritative Answer - this bit is valid in responses,
+ and specifies that the responding name server is an
+ authority for the domain name in question section.
+
+ Note that the contents of the answer section may have
+ multiple owner names because of aliases. The AA bit
+
+
+
+Mockapetris [Page 26]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ corresponds to the name which matches the query name, or
+ the first owner name in the answer section.
+
+TC TrunCation - specifies that this message was truncated
+ due to length greater than that permitted on the
+ transmission channel.
+
+RD Recursion Desired - this bit may be set in a query and
+ is copied into the response. If RD is set, it directs
+ the name server to pursue the query recursively.
+ Recursive query support is optional.
+
+RA Recursion Available - this be is set or cleared in a
+ response, and denotes whether recursive query support is
+ available in the name server.
+
+Z Reserved for future use. Must be zero in all queries
+ and responses.
+
+RCODE Response code - this 4 bit field is set as part of
+ responses. The values have the following
+ interpretation:
+
+ 0 No error condition
+
+ 1 Format error - The name server was
+ unable to interpret the query.
+
+ 2 Server failure - The name server was
+ unable to process this query due to a
+ problem with the name server.
+
+ 3 Name Error - Meaningful only for
+ responses from an authoritative name
+ server, this code signifies that the
+ domain name referenced in the query does
+ not exist.
+
+ 4 Not Implemented - The name server does
+ not support the requested kind of query.
+
+ 5 Refused - The name server refuses to
+ perform the specified operation for
+ policy reasons. For example, a name
+ server may not wish to provide the
+ information to the particular requester,
+ or a name server may not wish to perform
+ a particular operation (e.g., zone
+
+
+
+Mockapetris [Page 27]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ transfer) for particular data.
+
+ 6-15 Reserved for future use.
+
+QDCOUNT an unsigned 16 bit integer specifying the number of
+ entries in the question section.
+
+ANCOUNT an unsigned 16 bit integer specifying the number of
+ resource records in the answer section.
+
+NSCOUNT an unsigned 16 bit integer specifying the number of name
+ server resource records in the authority records
+ section.
+
+ARCOUNT an unsigned 16 bit integer specifying the number of
+ resource records in the additional records section.
+
+4.1.2. Question section format
+
+The question section is used to carry the "question" in most queries,
+i.e., the parameters that define what is being asked. The section
+contains QDCOUNT (usually 1) entries, each of the following format:
+
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / QNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QTYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QCLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+QNAME a domain name represented as a sequence of labels, where
+ each label consists of a length octet followed by that
+ number of octets. The domain name terminates with the
+ zero length octet for the null label of the root. Note
+ that this field may be an odd number of octets; no
+ padding is used.
+
+QTYPE a two octet code which specifies the type of the query.
+ The values for this field include all codes valid for a
+ TYPE field, together with some more general codes which
+ can match more than one type of RR.
+
+
+
+Mockapetris [Page 28]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+QCLASS a two octet code that specifies the class of the query.
+ For example, the QCLASS field is IN for the Internet.
+
+4.1.3. Resource record format
+
+The answer, authority, and additional sections all share the same
+format: a variable number of resource records, where the number of
+records is specified in the corresponding count field in the header.
+Each resource record has the following format:
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / /
+ / NAME /
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | CLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TTL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RDLENGTH |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+ / RDATA /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NAME a domain name to which this resource record pertains.
+
+TYPE two octets containing one of the RR type codes. This
+ field specifies the meaning of the data in the RDATA
+ field.
+
+CLASS two octets which specify the class of the data in the
+ RDATA field.
+
+TTL a 32 bit unsigned integer that specifies the time
+ interval (in seconds) that the resource record may be
+ cached before it should be discarded. Zero values are
+ interpreted to mean that the RR can only be used for the
+ transaction in progress, and should not be cached.
+
+
+
+
+
+Mockapetris [Page 29]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+RDLENGTH an unsigned 16 bit integer that specifies the length in
+ octets of the RDATA field.
+
+RDATA a variable length string of octets that describes the
+ resource. The format of this information varies
+ according to the TYPE and CLASS of the resource record.
+ For example, the if the TYPE is A and the CLASS is IN,
+ the RDATA field is a 4 octet ARPA Internet address.
+
+4.1.4. Message compression
+
+In order to reduce the size of messages, the domain system utilizes a
+compression scheme which eliminates the repetition of domain names in a
+message. In this scheme, an entire domain name or a list of labels at
+the end of a domain name is replaced with a pointer to a prior occurance
+of the same name.
+
+The pointer takes the form of a two octet sequence:
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | 1 1| OFFSET |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+The first two bits are ones. This allows a pointer to be distinguished
+from a label, since the label must begin with two zero bits because
+labels are restricted to 63 octets or less. (The 10 and 01 combinations
+are reserved for future use.) The OFFSET field specifies an offset from
+the start of the message (i.e., the first octet of the ID field in the
+domain header). A zero offset specifies the first byte of the ID field,
+etc.
+
+The compression scheme allows a domain name in a message to be
+represented as either:
+
+ - a sequence of labels ending in a zero octet
+
+ - a pointer
+
+ - a sequence of labels ending with a pointer
+
+Pointers can only be used for occurances of a domain name where the
+format is not class specific. If this were not the case, a name server
+or resolver would be required to know the format of all RRs it handled.
+As yet, there are no such cases, but they may occur in future RDATA
+formats.
+
+If a domain name is contained in a part of the message subject to a
+length field (such as the RDATA section of an RR), and compression is
+
+
+
+Mockapetris [Page 30]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+used, the length of the compressed name is used in the length
+calculation, rather than the length of the expanded name.
+
+Programs are free to avoid using pointers in messages they generate,
+although this will reduce datagram capacity, and may cause truncation.
+However all programs are required to understand arriving messages that
+contain pointers.
+
+For example, a datagram might need to use the domain names F.ISI.ARPA,
+FOO.F.ISI.ARPA, ARPA, and the root. Ignoring the other fields of the
+message, these domain names might be represented as:
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 20 | 1 | F |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 22 | 3 | I |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 24 | S | I |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 26 | 4 | A |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 28 | R | P |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 30 | A | 0 |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 40 | 3 | F |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 42 | O | O |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 44 | 1 1| 20 |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 64 | 1 1| 26 |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ 92 | 0 | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+The domain name for F.ISI.ARPA is shown at offset 20. The domain name
+FOO.F.ISI.ARPA is shown at offset 40; this definition uses a pointer to
+concatenate a label for FOO to the previously defined F.ISI.ARPA. The
+domain name ARPA is defined at offset 64 using a pointer to the ARPA
+component of the name F.ISI.ARPA at 20; note that this pointer relies on
+ARPA being the last label in the string at 20. The root domain name is
+
+
+
+Mockapetris [Page 31]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+defined by a single octet of zeros at 92; the root domain name has no
+labels.
+
+4.2. Transport
+
+The DNS assumes that messages will be transmitted as datagrams or in a
+byte stream carried by a virtual circuit. While virtual circuits can be
+used for any DNS activity, datagrams are preferred for queries due to
+their lower overhead and better performance. Zone refresh activities
+must use virtual circuits because of the need for reliable transfer.
+
+The Internet supports name server access using TCP [RFC-793] on server
+port 53 (decimal) as well as datagram access using UDP [RFC-768] on UDP
+port 53 (decimal).
+
+4.2.1. UDP usage
+
+Messages sent using UDP user server port 53 (decimal).
+
+Messages carried by UDP are restricted to 512 bytes (not counting the IP
+or UDP headers). Longer messages are truncated and the TC bit is set in
+the header.
+
+UDP is not acceptable for zone transfers, but is the recommended method
+for standard queries in the Internet. Queries sent using UDP may be
+lost, and hence a retransmission strategy is required. Queries or their
+responses may be reordered by the network, or by processing in name
+servers, so resolvers should not depend on them being returned in order.
+
+The optimal UDP retransmission policy will vary with performance of the
+Internet and the needs of the client, but the following are recommended:
+
+ - The client should try other servers and server addresses
+ before repeating a query to a specific address of a server.
+
+ - The retransmission interval should be based on prior
+ statistics if possible. Too aggressive retransmission can
+ easily slow responses for the community at large. Depending
+ on how well connected the client is to its expected servers,
+ the minimum retransmission interval should be 2-5 seconds.
+
+More suggestions on server selection and retransmission policy can be
+found in the resolver section of this memo.
+
+4.2.2. TCP usage
+
+Messages sent over TCP connections use server port 53 (decimal). The
+message is prefixed with a two byte length field which gives the message
+
+
+
+Mockapetris [Page 32]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+length, excluding the two byte length field. This length field allows
+the low-level processing to assemble a complete message before beginning
+to parse it.
+
+Several connection management policies are recommended:
+
+ - The server should not block other activities waiting for TCP
+ data.
+
+ - The server should support multiple connections.
+
+ - The server should assume that the client will initiate
+ connection closing, and should delay closing its end of the
+ connection until all outstanding client requests have been
+ satisfied.
+
+ - If the server needs to close a dormant connection to reclaim
+ resources, it should wait until the connection has been idle
+ for a period on the order of two minutes. In particular, the
+ server should allow the SOA and AXFR request sequence (which
+ begins a refresh operation) to be made on a single connection.
+ Since the server would be unable to answer queries anyway, a
+ unilateral close or reset may be used instead of a graceful
+ close.
+
+5. MASTER FILES
+
+Master files are text files that contain RRs in text form. Since the
+contents of a zone can be expressed in the form of a list of RRs a
+master file is most often used to define a zone, though it can be used
+to list a cache's contents. Hence, this section first discusses the
+format of RRs in a master file, and then the special considerations when
+a master file is used to create a zone in some name server.
+
+5.1. Format
+
+The format of these files is a sequence of entries. Entries are
+predominantly line-oriented, though parentheses can be used to continue
+a list of items across a line boundary, and text literals can contain
+CRLF within the text. Any combination of tabs and spaces act as a
+delimiter between the separate items that make up an entry. The end of
+any line in the master file can end with a comment. The comment starts
+with a ";" (semicolon).
+
+The following entries are defined:
+
+ <blank>[<comment>]
+
+
+
+
+Mockapetris [Page 33]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ $ORIGIN <domain-name> [<comment>]
+
+ $INCLUDE <file-name> [<domain-name>] [<comment>]
+
+ <domain-name><rr> [<comment>]
+
+ <blank><rr> [<comment>]
+
+Blank lines, with or without comments, are allowed anywhere in the file.
+
+Two control entries are defined: $ORIGIN and $INCLUDE. $ORIGIN is
+followed by a domain name, and resets the current origin for relative
+domain names to the stated name. $INCLUDE inserts the named file into
+the current file, and may optionally specify a domain name that sets the
+relative domain name origin for the included file. $INCLUDE may also
+have a comment. Note that a $INCLUDE entry never changes the relative
+origin of the parent file, regardless of changes to the relative origin
+made within the included file.
+
+The last two forms represent RRs. If an entry for an RR begins with a
+blank, then the RR is assumed to be owned by the last stated owner. If
+an RR entry begins with a <domain-name>, then the owner name is reset.
+
+<rr> contents take one of the following forms:
+
+ [<TTL>] [<class>] <type> <RDATA>
+
+ [<class>] [<TTL>] <type> <RDATA>
+
+The RR begins with optional TTL and class fields, followed by a type and
+RDATA field appropriate to the type and class. Class and type use the
+standard mnemonics, TTL is a decimal integer. Omitted class and TTL
+values are default to the last explicitly stated values. Since type and
+class mnemonics are disjoint, the parse is unique. (Note that this
+order is different from the order used in examples and the order used in
+the actual RRs; the given order allows easier parsing and defaulting.)
+
+<domain-name>s make up a large share of the data in the master file.
+The labels in the domain name are expressed as character strings and
+separated by dots. Quoting conventions allow arbitrary characters to be
+stored in domain names. Domain names that end in a dot are called
+absolute, and are taken as complete. Domain names which do not end in a
+dot are called relative; the actual domain name is the concatenation of
+the relative part with an origin specified in a $ORIGIN, $INCLUDE, or as
+an argument to the master file loading routine. A relative name is an
+error when no origin is available.
+
+
+
+
+
+Mockapetris [Page 34]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+<character-string> is expressed in one or two ways: as a contiguous set
+of characters without interior spaces, or as a string beginning with a "
+and ending with a ". Inside a " delimited string any character can
+occur, except for a " itself, which must be quoted using \ (back slash).
+
+Because these files are text files several special encodings are
+necessary to allow arbitrary data to be loaded. In particular:
+
+ of the root.
+
+@ A free standing @ is used to denote the current origin.
+
+\X where X is any character other than a digit (0-9), is
+ used to quote that character so that its special meaning
+ does not apply. For example, "\." can be used to place
+ a dot character in a label.
+
+\DDD where each D is a digit is the octet corresponding to
+ the decimal number described by DDD. The resulting
+ octet is assumed to be text and is not checked for
+ special meaning.
+
+( ) Parentheses are used to group data that crosses a line
+ boundary. In effect, line terminations are not
+ recognized within parentheses.
+
+; Semicolon is used to start a comment; the remainder of
+ the line is ignored.
+
+5.2. Use of master files to define zones
+
+When a master file is used to load a zone, the operation should be
+suppressed if any errors are encountered in the master file. The
+rationale for this is that a single error can have widespread
+consequences. For example, suppose that the RRs defining a delegation
+have syntax errors; then the server will return authoritative name
+errors for all names in the subzone (except in the case where the
+subzone is also present on the server).
+
+Several other validity checks that should be performed in addition to
+insuring that the file is syntactically correct:
+
+ 1. All RRs in the file should have the same class.
+
+ 2. Exactly one SOA RR should be present at the top of the zone.
+
+ 3. If delegations are present and glue information is required,
+ it should be present.
+
+
+
+Mockapetris [Page 35]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 4. Information present outside of the authoritative nodes in the
+ zone should be glue information, rather than the result of an
+ origin or similar error.
+
+5.3. Master file example
+
+The following is an example file which might be used to define the
+ISI.EDU zone.and is loaded with an origin of ISI.EDU:
+
+@ IN SOA VENERA Action\.domains (
+ 20 ; SERIAL
+ 7200 ; REFRESH
+ 600 ; RETRY
+ 3600000; EXPIRE
+ 60) ; MINIMUM
+
+ NS A.ISI.EDU.
+ NS VENERA
+ NS VAXA
+ MX 10 VENERA
+ MX 20 VAXA
+
+A A 26.3.0.103
+
+VENERA A 10.1.0.52
+ A 128.9.0.32
+
+VAXA A 10.2.0.27
+ A 128.9.0.33
+
+
+$INCLUDE <SUBSYS>ISI-MAILBOXES.TXT
+
+Where the file <SUBSYS>ISI-MAILBOXES.TXT is:
+
+ MOE MB A.ISI.EDU.
+ LARRY MB A.ISI.EDU.
+ CURLEY MB A.ISI.EDU.
+ STOOGES MG MOE
+ MG LARRY
+ MG CURLEY
+
+Note the use of the \ character in the SOA RR to specify the responsible
+person mailbox "Action.domains@E.ISI.EDU".
+
+
+
+
+
+
+
+Mockapetris [Page 36]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+6. NAME SERVER IMPLEMENTATION
+
+6.1. Architecture
+
+The optimal structure for the name server will depend on the host
+operating system and whether the name server is integrated with resolver
+operations, either by supporting recursive service, or by sharing its
+database with a resolver. This section discusses implementation
+considerations for a name server which shares a database with a
+resolver, but most of these concerns are present in any name server.
+
+6.1.1. Control
+
+A name server must employ multiple concurrent activities, whether they
+are implemented as separate tasks in the host's OS or multiplexing
+inside a single name server program. It is simply not acceptable for a
+name server to block the service of UDP requests while it waits for TCP
+data for refreshing or query activities. Similarly, a name server
+should not attempt to provide recursive service without processing such
+requests in parallel, though it may choose to serialize requests from a
+single client, or to regard identical requests from the same client as
+duplicates. A name server should not substantially delay requests while
+it reloads a zone from master files or while it incorporates a newly
+refreshed zone into its database.
+
+6.1.2. Database
+
+While name server implementations are free to use any internal data
+structures they choose, the suggested structure consists of three major
+parts:
+
+ - A "catalog" data structure which lists the zones available to
+ this server, and a "pointer" to the zone data structure. The
+ main purpose of this structure is to find the nearest ancestor
+ zone, if any, for arriving standard queries.
+
+ - Separate data structures for each of the zones held by the
+ name server.
+
+ - A data structure for cached data. (or perhaps separate caches
+ for different classes)
+
+All of these data structures can be implemented an identical tree
+structure format, with different data chained off the nodes in different
+parts: in the catalog the data is pointers to zones, while in the zone
+and cache data structures, the data will be RRs. In designing the tree
+framework the designer should recognize that query processing will need
+to traverse the tree using case-insensitive label comparisons; and that
+
+
+
+Mockapetris [Page 37]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+in real data, a few nodes have a very high branching factor (100-1000 or
+more), but the vast majority have a very low branching factor (0-1).
+
+One way to solve the case problem is to store the labels for each node
+in two pieces: a standardized-case representation of the label where all
+ASCII characters are in a single case, together with a bit mask that
+denotes which characters are actually of a different case. The
+branching factor diversity can be handled using a simple linked list for
+a node until the branching factor exceeds some threshold, and
+transitioning to a hash structure after the threshold is exceeded. In
+any case, hash structures used to store tree sections must insure that
+hash functions and procedures preserve the casing conventions of the
+DNS.
+
+The use of separate structures for the different parts of the database
+is motivated by several factors:
+
+ - The catalog structure can be an almost static structure that
+ need change only when the system administrator changes the
+ zones supported by the server. This structure can also be
+ used to store parameters used to control refreshing
+ activities.
+
+ - The individual data structures for zones allow a zone to be
+ replaced simply by changing a pointer in the catalog. Zone
+ refresh operations can build a new structure and, when
+ complete, splice it into the database via a simple pointer
+ replacement. It is very important that when a zone is
+ refreshed, queries should not use old and new data
+ simultaneously.
+
+ - With the proper search procedures, authoritative data in zones
+ will always "hide", and hence take precedence over, cached
+ data.
+
+ - Errors in zone definitions that cause overlapping zones, etc.,
+ may cause erroneous responses to queries, but problem
+ determination is simplified, and the contents of one "bad"
+ zone can't corrupt another.
+
+ - Since the cache is most frequently updated, it is most
+ vulnerable to corruption during system restarts. It can also
+ become full of expired RR data. In either case, it can easily
+ be discarded without disturbing zone data.
+
+A major aspect of database design is selecting a structure which allows
+the name server to deal with crashes of the name server's host. State
+information which a name server should save across system crashes
+
+
+
+Mockapetris [Page 38]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+includes the catalog structure (including the state of refreshing for
+each zone) and the zone data itself.
+
+6.1.3. Time
+
+Both the TTL data for RRs and the timing data for refreshing activities
+depends on 32 bit timers in units of seconds. Inside the database,
+refresh timers and TTLs for cached data conceptually "count down", while
+data in the zone stays with constant TTLs.
+
+A recommended implementation strategy is to store time in two ways: as
+a relative increment and as an absolute time. One way to do this is to
+use positive 32 bit numbers for one type and negative numbers for the
+other. The RRs in zones use relative times; the refresh timers and
+cache data use absolute times. Absolute numbers are taken with respect
+to some known origin and converted to relative values when placed in the
+response to a query. When an absolute TTL is negative after conversion
+to relative, then the data is expired and should be ignored.
+
+6.2. Standard query processing
+
+The major algorithm for standard query processing is presented in
+[RFC-1034].
+
+When processing queries with QCLASS=*, or some other QCLASS which
+matches multiple classes, the response should never be authoritative
+unless the server can guarantee that the response covers all classes.
+
+When composing a response, RRs which are to be inserted in the
+additional section, but duplicate RRs in the answer or authority
+sections, may be omitted from the additional section.
+
+When a response is so long that truncation is required, the truncation
+should start at the end of the response and work forward in the
+datagram. Thus if there is any data for the authority section, the
+answer section is guaranteed to be unique.
+
+The MINIMUM value in the SOA should be used to set a floor on the TTL of
+data distributed from a zone. This floor function should be done when
+the data is copied into a response. This will allow future dynamic
+update protocols to change the SOA MINIMUM field without ambiguous
+semantics.
+
+6.3. Zone refresh and reload processing
+
+In spite of a server's best efforts, it may be unable to load zone data
+from a master file due to syntax errors, etc., or be unable to refresh a
+zone within the its expiration parameter. In this case, the name server
+
+
+
+Mockapetris [Page 39]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+should answer queries as if it were not supposed to possess the zone.
+
+If a master is sending a zone out via AXFR, and a new version is created
+during the transfer, the master should continue to send the old version
+if possible. In any case, it should never send part of one version and
+part of another. If completion is not possible, the master should reset
+the connection on which the zone transfer is taking place.
+
+6.4. Inverse queries (Optional)
+
+Inverse queries are an optional part of the DNS. Name servers are not
+required to support any form of inverse queries. If a name server
+receives an inverse query that it does not support, it returns an error
+response with the "Not Implemented" error set in the header. While
+inverse query support is optional, all name servers must be at least
+able to return the error response.
+
+6.4.1. The contents of inverse queries and responses Inverse
+queries reverse the mappings performed by standard query operations;
+while a standard query maps a domain name to a resource, an inverse
+query maps a resource to a domain name. For example, a standard query
+might bind a domain name to a host address; the corresponding inverse
+query binds the host address to a domain name.
+
+Inverse queries take the form of a single RR in the answer section of
+the message, with an empty question section. The owner name of the
+query RR and its TTL are not significant. The response carries
+questions in the question section which identify all names possessing
+the query RR WHICH THE NAME SERVER KNOWS. Since no name server knows
+about all of the domain name space, the response can never be assumed to
+be complete. Thus inverse queries are primarily useful for database
+management and debugging activities. Inverse queries are NOT an
+acceptable method of mapping host addresses to host names; use the IN-
+ADDR.ARPA domain instead.
+
+Where possible, name servers should provide case-insensitive comparisons
+for inverse queries. Thus an inverse query asking for an MX RR of
+"Venera.isi.edu" should get the same response as a query for
+"VENERA.ISI.EDU"; an inverse query for HINFO RR "IBM-PC UNIX" should
+produce the same result as an inverse query for "IBM-pc unix". However,
+this cannot be guaranteed because name servers may possess RRs that
+contain character strings but the name server does not know that the
+data is character.
+
+When a name server processes an inverse query, it either returns:
+
+ 1. zero, one, or multiple domain names for the specified
+ resource as QNAMEs in the question section
+
+
+
+Mockapetris [Page 40]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 2. an error code indicating that the name server doesn't support
+ inverse mapping of the specified resource type.
+
+When the response to an inverse query contains one or more QNAMEs, the
+owner name and TTL of the RR in the answer section which defines the
+inverse query is modified to exactly match an RR found at the first
+QNAME.
+
+RRs returned in the inverse queries cannot be cached using the same
+mechanism as is used for the replies to standard queries. One reason
+for this is that a name might have multiple RRs of the same type, and
+only one would appear. For example, an inverse query for a single
+address of a multiply homed host might create the impression that only
+one address existed.
+
+6.4.2. Inverse query and response example The overall structure
+of an inverse query for retrieving the domain name that corresponds to
+Internet address 10.1.0.52 is shown below:
+
+ +-----------------------------------------+
+ Header | OPCODE=IQUERY, ID=997 |
+ +-----------------------------------------+
+ Question | <empty> |
+ +-----------------------------------------+
+ Answer | <anyname> A IN 10.1.0.52 |
+ +-----------------------------------------+
+ Authority | <empty> |
+ +-----------------------------------------+
+ Additional | <empty> |
+ +-----------------------------------------+
+
+This query asks for a question whose answer is the Internet style
+address 10.1.0.52. Since the owner name is not known, any domain name
+can be used as a placeholder (and is ignored). A single octet of zero,
+signifying the root, is usually used because it minimizes the length of
+the message. The TTL of the RR is not significant. The response to
+this query might be:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 41]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ +-----------------------------------------+
+ Header | OPCODE=RESPONSE, ID=997 |
+ +-----------------------------------------+
+ Question |QTYPE=A, QCLASS=IN, QNAME=VENERA.ISI.EDU |
+ +-----------------------------------------+
+ Answer | VENERA.ISI.EDU A IN 10.1.0.52 |
+ +-----------------------------------------+
+ Authority | <empty> |
+ +-----------------------------------------+
+ Additional | <empty> |
+ +-----------------------------------------+
+
+Note that the QTYPE in a response to an inverse query is the same as the
+TYPE field in the answer section of the inverse query. Responses to
+inverse queries may contain multiple questions when the inverse is not
+unique. If the question section in the response is not empty, then the
+RR in the answer section is modified to correspond to be an exact copy
+of an RR at the first QNAME.
+
+6.4.3. Inverse query processing
+
+Name servers that support inverse queries can support these operations
+through exhaustive searches of their databases, but this becomes
+impractical as the size of the database increases. An alternative
+approach is to invert the database according to the search key.
+
+For name servers that support multiple zones and a large amount of data,
+the recommended approach is separate inversions for each zone. When a
+particular zone is changed during a refresh, only its inversions need to
+be redone.
+
+Support for transfer of this type of inversion may be included in future
+versions of the domain system, but is not supported in this version.
+
+6.5. Completion queries and responses
+
+The optional completion services described in RFC-882 and RFC-883 have
+been deleted. Redesigned services may become available in the future.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 42]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+7. RESOLVER IMPLEMENTATION
+
+The top levels of the recommended resolver algorithm are discussed in
+[RFC-1034]. This section discusses implementation details assuming the
+database structure suggested in the name server implementation section
+of this memo.
+
+7.1. Transforming a user request into a query
+
+The first step a resolver takes is to transform the client's request,
+stated in a format suitable to the local OS, into a search specification
+for RRs at a specific name which match a specific QTYPE and QCLASS.
+Where possible, the QTYPE and QCLASS should correspond to a single type
+and a single class, because this makes the use of cached data much
+simpler. The reason for this is that the presence of data of one type
+in a cache doesn't confirm the existence or non-existence of data of
+other types, hence the only way to be sure is to consult an
+authoritative source. If QCLASS=* is used, then authoritative answers
+won't be available.
+
+Since a resolver must be able to multiplex multiple requests if it is to
+perform its function efficiently, each pending request is usually
+represented in some block of state information. This state block will
+typically contain:
+
+ - A timestamp indicating the time the request began.
+ The timestamp is used to decide whether RRs in the database
+ can be used or are out of date. This timestamp uses the
+ absolute time format previously discussed for RR storage in
+ zones and caches. Note that when an RRs TTL indicates a
+ relative time, the RR must be timely, since it is part of a
+ zone. When the RR has an absolute time, it is part of a
+ cache, and the TTL of the RR is compared against the timestamp
+ for the start of the request.
+
+ Note that using the timestamp is superior to using a current
+ time, since it allows RRs with TTLs of zero to be entered in
+ the cache in the usual manner, but still used by the current
+ request, even after intervals of many seconds due to system
+ load, query retransmission timeouts, etc.
+
+ - Some sort of parameters to limit the amount of work which will
+ be performed for this request.
+
+ The amount of work which a resolver will do in response to a
+ client request must be limited to guard against errors in the
+ database, such as circular CNAME references, and operational
+ problems, such as network partition which prevents the
+
+
+
+Mockapetris [Page 43]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ resolver from accessing the name servers it needs. While
+ local limits on the number of times a resolver will retransmit
+ a particular query to a particular name server address are
+ essential, the resolver should have a global per-request
+ counter to limit work on a single request. The counter should
+ be set to some initial value and decremented whenever the
+ resolver performs any action (retransmission timeout,
+ retransmission, etc.) If the counter passes zero, the request
+ is terminated with a temporary error.
+
+ Note that if the resolver structure allows one request to
+ start others in parallel, such as when the need to access a
+ name server for one request causes a parallel resolve for the
+ name server's addresses, the spawned request should be started
+ with a lower counter. This prevents circular references in
+ the database from starting a chain reaction of resolver
+ activity.
+
+ - The SLIST data structure discussed in [RFC-1034].
+
+ This structure keeps track of the state of a request if it
+ must wait for answers from foreign name servers.
+
+7.2. Sending the queries
+
+As described in [RFC-1034], the basic task of the resolver is to
+formulate a query which will answer the client's request and direct that
+query to name servers which can provide the information. The resolver
+will usually only have very strong hints about which servers to ask, in
+the form of NS RRs, and may have to revise the query, in response to
+CNAMEs, or revise the set of name servers the resolver is asking, in
+response to delegation responses which point the resolver to name
+servers closer to the desired information. In addition to the
+information requested by the client, the resolver may have to call upon
+its own services to determine the address of name servers it wishes to
+contact.
+
+In any case, the model used in this memo assumes that the resolver is
+multiplexing attention between multiple requests, some from the client,
+and some internally generated. Each request is represented by some
+state information, and the desired behavior is that the resolver
+transmit queries to name servers in a way that maximizes the probability
+that the request is answered, minimizes the time that the request takes,
+and avoids excessive transmissions. The key algorithm uses the state
+information of the request to select the next name server address to
+query, and also computes a timeout which will cause the next action
+should a response not arrive. The next action will usually be a
+transmission to some other server, but may be a temporary error to the
+
+
+
+Mockapetris [Page 44]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+client.
+
+The resolver always starts with a list of server names to query (SLIST).
+This list will be all NS RRs which correspond to the nearest ancestor
+zone that the resolver knows about. To avoid startup problems, the
+resolver should have a set of default servers which it will ask should
+it have no current NS RRs which are appropriate. The resolver then adds
+to SLIST all of the known addresses for the name servers, and may start
+parallel requests to acquire the addresses of the servers when the
+resolver has the name, but no addresses, for the name servers.
+
+To complete initialization of SLIST, the resolver attaches whatever
+history information it has to the each address in SLIST. This will
+usually consist of some sort of weighted averages for the response time
+of the address, and the batting average of the address (i.e., how often
+the address responded at all to the request). Note that this
+information should be kept on a per address basis, rather than on a per
+name server basis, because the response time and batting average of a
+particular server may vary considerably from address to address. Note
+also that this information is actually specific to a resolver address /
+server address pair, so a resolver with multiple addresses may wish to
+keep separate histories for each of its addresses. Part of this step
+must deal with addresses which have no such history; in this case an
+expected round trip time of 5-10 seconds should be the worst case, with
+lower estimates for the same local network, etc.
+
+Note that whenever a delegation is followed, the resolver algorithm
+reinitializes SLIST.
+
+The information establishes a partial ranking of the available name
+server addresses. Each time an address is chosen and the state should
+be altered to prevent its selection again until all other addresses have
+been tried. The timeout for each transmission should be 50-100% greater
+than the average predicted value to allow for variance in response.
+
+Some fine points:
+
+ - The resolver may encounter a situation where no addresses are
+ available for any of the name servers named in SLIST, and
+ where the servers in the list are precisely those which would
+ normally be used to look up their own addresses. This
+ situation typically occurs when the glue address RRs have a
+ smaller TTL than the NS RRs marking delegation, or when the
+ resolver caches the result of a NS search. The resolver
+ should detect this condition and restart the search at the
+ next ancestor zone, or alternatively at the root.
+
+
+
+
+
+Mockapetris [Page 45]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ - If a resolver gets a server error or other bizarre response
+ from a name server, it should remove it from SLIST, and may
+ wish to schedule an immediate transmission to the next
+ candidate server address.
+
+7.3. Processing responses
+
+The first step in processing arriving response datagrams is to parse the
+response. This procedure should include:
+
+ - Check the header for reasonableness. Discard datagrams which
+ are queries when responses are expected.
+
+ - Parse the sections of the message, and insure that all RRs are
+ correctly formatted.
+
+ - As an optional step, check the TTLs of arriving data looking
+ for RRs with excessively long TTLs. If a RR has an
+ excessively long TTL, say greater than 1 week, either discard
+ the whole response, or limit all TTLs in the response to 1
+ week.
+
+The next step is to match the response to a current resolver request.
+The recommended strategy is to do a preliminary matching using the ID
+field in the domain header, and then to verify that the question section
+corresponds to the information currently desired. This requires that
+the transmission algorithm devote several bits of the domain ID field to
+a request identifier of some sort. This step has several fine points:
+
+ - Some name servers send their responses from different
+ addresses than the one used to receive the query. That is, a
+ resolver cannot rely that a response will come from the same
+ address which it sent the corresponding query to. This name
+ server bug is typically encountered in UNIX systems.
+
+ - If the resolver retransmits a particular request to a name
+ server it should be able to use a response from any of the
+ transmissions. However, if it is using the response to sample
+ the round trip time to access the name server, it must be able
+ to determine which transmission matches the response (and keep
+ transmission times for each outgoing message), or only
+ calculate round trip times based on initial transmissions.
+
+ - A name server will occasionally not have a current copy of a
+ zone which it should have according to some NS RRs. The
+ resolver should simply remove the name server from the current
+ SLIST, and continue.
+
+
+
+
+Mockapetris [Page 46]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+7.4. Using the cache
+
+In general, we expect a resolver to cache all data which it receives in
+responses since it may be useful in answering future client requests.
+However, there are several types of data which should not be cached:
+
+ - When several RRs of the same type are available for a
+ particular owner name, the resolver should either cache them
+ all or none at all. When a response is truncated, and a
+ resolver doesn't know whether it has a complete set, it should
+ not cache a possibly partial set of RRs.
+
+ - Cached data should never be used in preference to
+ authoritative data, so if caching would cause this to happen
+ the data should not be cached.
+
+ - The results of an inverse query should not be cached.
+
+ - The results of standard queries where the QNAME contains "*"
+ labels if the data might be used to construct wildcards. The
+ reason is that the cache does not necessarily contain existing
+ RRs or zone boundary information which is necessary to
+ restrict the application of the wildcard RRs.
+
+ - RR data in responses of dubious reliability. When a resolver
+ receives unsolicited responses or RR data other than that
+ requested, it should discard it without caching it. The basic
+ implication is that all sanity checks on a packet should be
+ performed before any of it is cached.
+
+In a similar vein, when a resolver has a set of RRs for some name in a
+response, and wants to cache the RRs, it should check its cache for
+already existing RRs. Depending on the circumstances, either the data
+in the response or the cache is preferred, but the two should never be
+combined. If the data in the response is from authoritative data in the
+answer section, it is always preferred.
+
+8. MAIL SUPPORT
+
+The domain system defines a standard for mapping mailboxes into domain
+names, and two methods for using the mailbox information to derive mail
+routing information. The first method is called mail exchange binding
+and the other method is mailbox binding. The mailbox encoding standard
+and mail exchange binding are part of the DNS official protocol, and are
+the recommended method for mail routing in the Internet. Mailbox
+binding is an experimental feature which is still under development and
+subject to change.
+
+
+
+
+Mockapetris [Page 47]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+The mailbox encoding standard assumes a mailbox name of the form
+"<local-part>@<mail-domain>". While the syntax allowed in each of these
+sections varies substantially between the various mail internets, the
+preferred syntax for the ARPA Internet is given in [RFC-822].
+
+The DNS encodes the <local-part> as a single label, and encodes the
+<mail-domain> as a domain name. The single label from the <local-part>
+is prefaced to the domain name from <mail-domain> to form the domain
+name corresponding to the mailbox. Thus the mailbox HOSTMASTER@SRI-
+NIC.ARPA is mapped into the domain name HOSTMASTER.SRI-NIC.ARPA. If the
+<local-part> contains dots or other special characters, its
+representation in a master file will require the use of backslash
+quoting to ensure that the domain name is properly encoded. For
+example, the mailbox Action.domains@ISI.EDU would be represented as
+Action\.domains.ISI.EDU.
+
+8.1. Mail exchange binding
+
+Mail exchange binding uses the <mail-domain> part of a mailbox
+specification to determine where mail should be sent. The <local-part>
+is not even consulted. [RFC-974] specifies this method in detail, and
+should be consulted before attempting to use mail exchange support.
+
+One of the advantages of this method is that it decouples mail
+destination naming from the hosts used to support mail service, at the
+cost of another layer of indirection in the lookup function. However,
+the addition layer should eliminate the need for complicated "%", "!",
+etc encodings in <local-part>.
+
+The essence of the method is that the <mail-domain> is used as a domain
+name to locate type MX RRs which list hosts willing to accept mail for
+<mail-domain>, together with preference values which rank the hosts
+according to an order specified by the administrators for <mail-domain>.
+
+In this memo, the <mail-domain> ISI.EDU is used in examples, together
+with the hosts VENERA.ISI.EDU and VAXA.ISI.EDU as mail exchanges for
+ISI.EDU. If a mailer had a message for Mockapetris@ISI.EDU, it would
+route it by looking up MX RRs for ISI.EDU. The MX RRs at ISI.EDU name
+VENERA.ISI.EDU and VAXA.ISI.EDU, and type A queries can find the host
+addresses.
+
+8.2. Mailbox binding (Experimental)
+
+In mailbox binding, the mailer uses the entire mail destination
+specification to construct a domain name. The encoded domain name for
+the mailbox is used as the QNAME field in a QTYPE=MAILB query.
+
+Several outcomes are possible for this query:
+
+
+
+Mockapetris [Page 48]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ 1. The query can return a name error indicating that the mailbox
+ does not exist as a domain name.
+
+ In the long term, this would indicate that the specified
+ mailbox doesn't exist. However, until the use of mailbox
+ binding is universal, this error condition should be
+ interpreted to mean that the organization identified by the
+ global part does not support mailbox binding. The
+ appropriate procedure is to revert to exchange binding at
+ this point.
+
+ 2. The query can return a Mail Rename (MR) RR.
+
+ The MR RR carries new mailbox specification in its RDATA
+ field. The mailer should replace the old mailbox with the
+ new one and retry the operation.
+
+ 3. The query can return a MB RR.
+
+ The MB RR carries a domain name for a host in its RDATA
+ field. The mailer should deliver the message to that host
+ via whatever protocol is applicable, e.g., b,SMTP.
+
+ 4. The query can return one or more Mail Group (MG) RRs.
+
+ This condition means that the mailbox was actually a mailing
+ list or mail group, rather than a single mailbox. Each MG RR
+ has a RDATA field that identifies a mailbox that is a member
+ of the group. The mailer should deliver a copy of the
+ message to each member.
+
+ 5. The query can return a MB RR as well as one or more MG RRs.
+
+ This condition means the the mailbox was actually a mailing
+ list. The mailer can either deliver the message to the host
+ specified by the MB RR, which will in turn do the delivery to
+ all members, or the mailer can use the MG RRs to do the
+ expansion itself.
+
+In any of these cases, the response may include a Mail Information
+(MINFO) RR. This RR is usually associated with a mail group, but is
+legal with a MB. The MINFO RR identifies two mailboxes. One of these
+identifies a responsible person for the original mailbox name. This
+mailbox should be used for requests to be added to a mail group, etc.
+The second mailbox name in the MINFO RR identifies a mailbox that should
+receive error messages for mail failures. This is particularly
+appropriate for mailing lists when errors in member names should be
+reported to a person other than the one who sends a message to the list.
+
+
+
+Mockapetris [Page 49]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+New fields may be added to this RR in the future.
+
+
+9. REFERENCES and BIBLIOGRAPHY
+
+[Dyer 87] S. Dyer, F. Hsu, "Hesiod", Project Athena
+ Technical Plan - Name Service, April 1987, version 1.9.
+
+ Describes the fundamentals of the Hesiod name service.
+
+[IEN-116] J. Postel, "Internet Name Server", IEN-116,
+ USC/Information Sciences Institute, August 1979.
+
+ A name service obsoleted by the Domain Name System, but
+ still in use.
+
+[Quarterman 86] J. Quarterman, and J. Hoskins, "Notable Computer Networks",
+ Communications of the ACM, October 1986, volume 29, number
+ 10.
+
+[RFC-742] K. Harrenstien, "NAME/FINGER", RFC-742, Network
+ Information Center, SRI International, December 1977.
+
+[RFC-768] J. Postel, "User Datagram Protocol", RFC-768,
+ USC/Information Sciences Institute, August 1980.
+
+[RFC-793] J. Postel, "Transmission Control Protocol", RFC-793,
+ USC/Information Sciences Institute, September 1981.
+
+[RFC-799] D. Mills, "Internet Name Domains", RFC-799, COMSAT,
+ September 1981.
+
+ Suggests introduction of a hierarchy in place of a flat
+ name space for the Internet.
+
+[RFC-805] J. Postel, "Computer Mail Meeting Notes", RFC-805,
+ USC/Information Sciences Institute, February 1982.
+
+[RFC-810] E. Feinler, K. Harrenstien, Z. Su, and V. White, "DOD
+ Internet Host Table Specification", RFC-810, Network
+ Information Center, SRI International, March 1982.
+
+ Obsolete. See RFC-952.
+
+[RFC-811] K. Harrenstien, V. White, and E. Feinler, "Hostnames
+ Server", RFC-811, Network Information Center, SRI
+ International, March 1982.
+
+
+
+
+Mockapetris [Page 50]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ Obsolete. See RFC-953.
+
+[RFC-812] K. Harrenstien, and V. White, "NICNAME/WHOIS", RFC-812,
+ Network Information Center, SRI International, March
+ 1982.
+
+[RFC-819] Z. Su, and J. Postel, "The Domain Naming Convention for
+ Internet User Applications", RFC-819, Network
+ Information Center, SRI International, August 1982.
+
+ Early thoughts on the design of the domain system.
+ Current implementation is completely different.
+
+[RFC-821] J. Postel, "Simple Mail Transfer Protocol", RFC-821,
+ USC/Information Sciences Institute, August 1980.
+
+[RFC-830] Z. Su, "A Distributed System for Internet Name Service",
+ RFC-830, Network Information Center, SRI International,
+ October 1982.
+
+ Early thoughts on the design of the domain system.
+ Current implementation is completely different.
+
+[RFC-882] P. Mockapetris, "Domain names - Concepts and
+ Facilities," RFC-882, USC/Information Sciences
+ Institute, November 1983.
+
+ Superceeded by this memo.
+
+[RFC-883] P. Mockapetris, "Domain names - Implementation and
+ Specification," RFC-883, USC/Information Sciences
+ Institute, November 1983.
+
+ Superceeded by this memo.
+
+[RFC-920] J. Postel and J. Reynolds, "Domain Requirements",
+ RFC-920, USC/Information Sciences Institute,
+ October 1984.
+
+ Explains the naming scheme for top level domains.
+
+[RFC-952] K. Harrenstien, M. Stahl, E. Feinler, "DoD Internet Host
+ Table Specification", RFC-952, SRI, October 1985.
+
+ Specifies the format of HOSTS.TXT, the host/address
+ table replaced by the DNS.
+
+
+
+
+
+Mockapetris [Page 51]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+[RFC-953] K. Harrenstien, M. Stahl, E. Feinler, "HOSTNAME Server",
+ RFC-953, SRI, October 1985.
+
+ This RFC contains the official specification of the
+ hostname server protocol, which is obsoleted by the DNS.
+ This TCP based protocol accesses information stored in
+ the RFC-952 format, and is used to obtain copies of the
+ host table.
+
+[RFC-973] P. Mockapetris, "Domain System Changes and
+ Observations", RFC-973, USC/Information Sciences
+ Institute, January 1986.
+
+ Describes changes to RFC-882 and RFC-883 and reasons for
+ them.
+
+[RFC-974] C. Partridge, "Mail routing and the domain system",
+ RFC-974, CSNET CIC BBN Labs, January 1986.
+
+ Describes the transition from HOSTS.TXT based mail
+ addressing to the more powerful MX system used with the
+ domain system.
+
+[RFC-1001] NetBIOS Working Group, "Protocol standard for a NetBIOS
+ service on a TCP/UDP transport: Concepts and Methods",
+ RFC-1001, March 1987.
+
+ This RFC and RFC-1002 are a preliminary design for
+ NETBIOS on top of TCP/IP which proposes to base NetBIOS
+ name service on top of the DNS.
+
+[RFC-1002] NetBIOS Working Group, "Protocol standard for a NetBIOS
+ service on a TCP/UDP transport: Detailed
+ Specifications", RFC-1002, March 1987.
+
+[RFC-1010] J. Reynolds, and J. Postel, "Assigned Numbers", RFC-1010,
+ USC/Information Sciences Institute, May 1987.
+
+ Contains socket numbers and mnemonics for host names,
+ operating systems, etc.
+
+[RFC-1031] W. Lazear, "MILNET Name Domain Transition", RFC-1031,
+ November 1987.
+
+ Describes a plan for converting the MILNET to the DNS.
+
+[RFC-1032] M. Stahl, "Establishing a Domain - Guidelines for
+ Administrators", RFC-1032, November 1987.
+
+
+
+Mockapetris [Page 52]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ Describes the registration policies used by the NIC to
+ administer the top level domains and delegate subzones.
+
+[RFC-1033] M. Lottor, "Domain Administrators Operations Guide",
+ RFC-1033, November 1987.
+
+ A cookbook for domain administrators.
+
+[Solomon 82] M. Solomon, L. Landweber, and D. Neuhengen, "The CSNET
+ Name Server", Computer Networks, vol 6, nr 3, July 1982.
+
+ Describes a name service for CSNET which is independent
+ from the DNS and DNS use in the CSNET.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 53]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+Index
+
+ * 13
+
+ ; 33, 35
+
+ <character-string> 35
+ <domain-name> 34
+
+ @ 35
+
+ \ 35
+
+ A 12
+
+ Byte order 8
+
+ CH 13
+ Character case 9
+ CLASS 11
+ CNAME 12
+ Completion 42
+ CS 13
+
+ Hesiod 13
+ HINFO 12
+ HS 13
+
+ IN 13
+ IN-ADDR.ARPA domain 22
+ Inverse queries 40
+
+ Mailbox names 47
+ MB 12
+ MD 12
+ MF 12
+ MG 12
+ MINFO 12
+ MINIMUM 20
+ MR 12
+ MX 12
+
+ NS 12
+ NULL 12
+
+ Port numbers 32
+ Primary server 5
+ PTR 12, 18
+
+
+
+Mockapetris [Page 54]
+\f
+RFC 1035 Domain Implementation and Specification November 1987
+
+
+ QCLASS 13
+ QTYPE 12
+
+ RDATA 12
+ RDLENGTH 11
+
+ Secondary server 5
+ SOA 12
+ Stub resolvers 7
+
+ TCP 32
+ TXT 12
+ TYPE 11
+
+ UDP 32
+
+ WKS 12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris [Page 55]
+\f
--- /dev/null
+
+
+
+
+
+
+Network Working Group R. Droms
+Request for Comments: 2131 Bucknell University
+Obsoletes: 1541 March 1997
+Category: Standards Track
+
+ Dynamic Host Configuration Protocol
+
+Status of this memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Abstract
+
+ The Dynamic Host Configuration Protocol (DHCP) provides a framework
+ for passing configuration information to hosts on a TCPIP network.
+ DHCP is based on the Bootstrap Protocol (BOOTP) [7], adding the
+ capability of automatic allocation of reusable network addresses and
+ additional configuration options [19]. DHCP captures the behavior of
+ BOOTP relay agents [7, 21], and DHCP participants can interoperate
+ with BOOTP participants [9].
+
+Table of Contents
+
+ 1. Introduction. . . . . . . . . . . . . . . . . . . . . . . . . 2
+ 1.1 Changes to RFC1541. . . . . . . . . . . . . . . . . . . . . . 3
+ 1.2 Related Work. . . . . . . . . . . . . . . . . . . . . . . . . 4
+ 1.3 Problem definition and issues . . . . . . . . . . . . . . . . 4
+ 1.4 Requirements. . . . . . . . . . . . . . . . . . . . . . . . . 5
+ 1.5 Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 6
+ 1.6 Design goals. . . . . . . . . . . . . . . . . . . . . . . . . 6
+ 2. Protocol Summary. . . . . . . . . . . . . . . . . . . . . . . 8
+ 2.1 Configuration parameters repository . . . . . . . . . . . . . 11
+ 2.2 Dynamic allocation of network addresses . . . . . . . . . . . 12
+ 3. The Client-Server Protocol. . . . . . . . . . . . . . . . . . 13
+ 3.1 Client-server interaction - allocating a network address. . . 13
+ 3.2 Client-server interaction - reusing a previously allocated
+ network address . . . . . . . . . . . . . . . . . . . . . . . 17
+ 3.3 Interpretation and representation of time values. . . . . . . 20
+ 3.4 Obtaining parameters with externally configured network
+ address . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
+ 3.5 Client parameters in DHCP . . . . . . . . . . . . . . . . . . 21
+ 3.6 Use of DHCP in clients with multiple interfaces . . . . . . . 22
+ 3.7 When clients should use DHCP. . . . . . . . . . . . . . . . . 22
+ 4. Specification of the DHCP client-server protocol. . . . . . . 22
+
+
+
+Droms Standards Track [Page 1]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ 4.1 Constructing and sending DHCP messages. . . . . . . . . . . . 22
+ 4.2 DHCP server administrative controls . . . . . . . . . . . . . 25
+ 4.3 DHCP server behavior. . . . . . . . . . . . . . . . . . . . . 26
+ 4.4 DHCP client behavior. . . . . . . . . . . . . . . . . . . . . 34
+ 5. Acknowledgments. . . . . . . . . . . . . . . . . . . . . . . .42
+ 6. References . . . . . . . . . . . . . . . . . . . . . . . . . .42
+ 7. Security Considerations. . . . . . . . . . . . . . . . . . . .43
+ 8. Author's Address . . . . . . . . . . . . . . . . . . . . . . .44
+ A. Host Configuration Parameters . . . . . . . . . . . . . . . .45
+List of Figures
+ 1. Format of a DHCP message . . . . . . . . . . . . . . . . . . . 9
+ 2. Format of the 'flags' field. . . . . . . . . . . . . . . . . . 11
+ 3. Timeline diagram of messages exchanged between DHCP client and
+ servers when allocating a new network address. . . . . . . . . 15
+ 4. Timeline diagram of messages exchanged between DHCP client and
+ servers when reusing a previously allocated network address. . 18
+ 5. State-transition diagram for DHCP clients. . . . . . . . . . . 34
+List of Tables
+ 1. Description of fields in a DHCP message. . . . . . . . . . . . 10
+ 2. DHCP messages. . . . . . . . . . . . . . . . . . . . . . . . . 14
+ 3. Fields and options used by DHCP servers. . . . . . . . . . . . 28
+ 4. Client messages from various states. . . . . . . . . . . . . . 33
+ 5. Fields and options used by DHCP clients. . . . . . . . . . . . 37
+
+1. Introduction
+
+ The Dynamic Host Configuration Protocol (DHCP) provides configuration
+ parameters to Internet hosts. DHCP consists of two components: a
+ protocol for delivering host-specific configuration parameters from a
+ DHCP server to a host and a mechanism for allocation of network
+ addresses to hosts.
+
+ DHCP is built on a client-server model, where designated DHCP server
+ hosts allocate network addresses and deliver configuration parameters
+ to dynamically configured hosts. Throughout the remainder of this
+ document, the term "server" refers to a host providing initialization
+ parameters through DHCP, and the term "client" refers to a host
+ requesting initialization parameters from a DHCP server.
+
+ A host should not act as a DHCP server unless explicitly configured
+ to do so by a system administrator. The diversity of hardware and
+ protocol implementations in the Internet would preclude reliable
+ operation if random hosts were allowed to respond to DHCP requests.
+ For example, IP requires the setting of many parameters within the
+ protocol implementation software. Because IP can be used on many
+ dissimilar kinds of network hardware, values for those parameters
+ cannot be guessed or assumed to have correct defaults. Also,
+ distributed address allocation schemes depend on a polling/defense
+
+
+
+Droms Standards Track [Page 2]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ mechanism for discovery of addresses that are already in use. IP
+ hosts may not always be able to defend their network addresses, so
+ that such a distributed address allocation scheme cannot be
+ guaranteed to avoid allocation of duplicate network addresses.
+
+ DHCP supports three mechanisms for IP address allocation. In
+ "automatic allocation", DHCP assigns a permanent IP address to a
+ client. In "dynamic allocation", DHCP assigns an IP address to a
+ client for a limited period of time (or until the client explicitly
+ relinquishes the address). In "manual allocation", a client's IP
+ address is assigned by the network administrator, and DHCP is used
+ simply to convey the assigned address to the client. A particular
+ network will use one or more of these mechanisms, depending on the
+ policies of the network administrator.
+
+ Dynamic allocation is the only one of the three mechanisms that
+ allows automatic reuse of an address that is no longer needed by the
+ client to which it was assigned. Thus, dynamic allocation is
+ particularly useful for assigning an address to a client that will be
+ connected to the network only temporarily or for sharing a limited
+ pool of IP addresses among a group of clients that do not need
+ permanent IP addresses. Dynamic allocation may also be a good choice
+ for assigning an IP address to a new client being permanently
+ connected to a network where IP addresses are sufficiently scarce
+ that it is important to reclaim them when old clients are retired.
+ Manual allocation allows DHCP to be used to eliminate the error-prone
+ process of manually configuring hosts with IP addresses in
+ environments where (for whatever reasons) it is desirable to manage
+ IP address assignment outside of the DHCP mechanisms.
+
+ The format of DHCP messages is based on the format of BOOTP messages,
+ to capture the BOOTP relay agent behavior described as part of the
+ BOOTP specification [7, 21] and to allow interoperability of existing
+ BOOTP clients with DHCP servers. Using BOOTP relay agents eliminates
+ the necessity of having a DHCP server on each physical network
+ segment.
+
+1.1 Changes to RFC 1541
+
+ This document updates the DHCP protocol specification that appears in
+ RFC1541. A new DHCP message type, DHCPINFORM, has been added; see
+ section 3.4, 4.3 and 4.4 for details. The classing mechanism for
+ identifying DHCP clients to DHCP servers has been extended to include
+ "vendor" classes as defined in sections 4.2 and 4.3. The minimum
+ lease time restriction has been removed. Finally, many editorial
+ changes have been made to clarify the text as a result of experience
+ gained in DHCP interoperability tests.
+
+
+
+
+Droms Standards Track [Page 3]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+1.2 Related Work
+
+ There are several Internet protocols and related mechanisms that
+ address some parts of the dynamic host configuration problem. The
+ Reverse Address Resolution Protocol (RARP) [10] (through the
+ extensions defined in the Dynamic RARP (DRARP) [5]) explicitly
+ addresses the problem of network address discovery, and includes an
+ automatic IP address assignment mechanism. The Trivial File Transfer
+ Protocol (TFTP) [20] provides for transport of a boot image from a
+ boot server. The Internet Control Message Protocol (ICMP) [16]
+ provides for informing hosts of additional routers via "ICMP
+ redirect" messages. ICMP also can provide subnet mask information
+ through the "ICMP mask request" message and other information through
+ the (obsolete) "ICMP information request" message. Hosts can locate
+ routers through the ICMP router discovery mechanism [8].
+
+ BOOTP is a transport mechanism for a collection of configuration
+ information. BOOTP is also extensible, and official extensions [17]
+ have been defined for several configuration parameters. Morgan has
+ proposed extensions to BOOTP for dynamic IP address assignment [15].
+ The Network Information Protocol (NIP), used by the Athena project at
+ MIT, is a distributed mechanism for dynamic IP address assignment
+ [19]. The Resource Location Protocol RLP [1] provides for location
+ of higher level services. Sun Microsystems diskless workstations use
+ a boot procedure that employs RARP, TFTP and an RPC mechanism called
+ "bootparams" to deliver configuration information and operating
+ system code to diskless hosts. (Sun Microsystems, Sun Workstation
+ and SunOS are trademarks of Sun Microsystems, Inc.) Some Sun
+ networks also use DRARP and an auto-installation mechanism to
+ automate the configuration of new hosts in an existing network.
+
+ In other related work, the path minimum transmission unit (MTU)
+ discovery algorithm can determine the MTU of an arbitrary internet
+ path [14]. The Address Resolution Protocol (ARP) has been proposed
+ as a transport protocol for resource location and selection [6].
+ Finally, the Host Requirements RFCs [3, 4] mention specific
+ requirements for host reconfiguration and suggest a scenario for
+ initial configuration of diskless hosts.
+
+1.3 Problem definition and issues
+
+ DHCP is designed to supply DHCP clients with the configuration
+ parameters defined in the Host Requirements RFCs. After obtaining
+ parameters via DHCP, a DHCP client should be able to exchange packets
+ with any other host in the Internet. The TCP/IP stack parameters
+ supplied by DHCP are listed in Appendix A.
+
+
+
+
+
+Droms Standards Track [Page 4]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ Not all of these parameters are required for a newly initialized
+ client. A client and server may negotiate for the transmission of
+ only those parameters required by the client or specific to a
+ particular subnet.
+
+ DHCP allows but does not require the configuration of client
+ parameters not directly related to the IP protocol. DHCP also does
+ not address registration of newly configured clients with the Domain
+ Name System (DNS) [12, 13].
+
+ DHCP is not intended for use in configuring routers.
+
+1.4 Requirements
+
+ Throughout this document, the words that are used to define the
+ significance of particular requirements are capitalized. These words
+ are:
+
+ o "MUST"
+
+ This word or the adjective "REQUIRED" means that the
+ item is an absolute requirement of this specification.
+
+ o "MUST NOT"
+
+ This phrase means that the item is an absolute prohibition
+ of this specification.
+
+ o "SHOULD"
+
+ This word or the adjective "RECOMMENDED" means that there
+ may exist valid reasons in particular circumstances to ignore
+ this item, but the full implications should be understood and
+ the case carefully weighed before choosing a different course.
+
+ o "SHOULD NOT"
+
+ This phrase means that there may exist valid reasons in
+ particular circumstances when the listed behavior is acceptable
+ or even useful, but the full implications should be understood
+ and the case carefully weighed before implementing any behavior
+ described with this label.
+
+
+
+
+
+
+
+
+
+Droms Standards Track [Page 5]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ o "MAY"
+
+ This word or the adjective "OPTIONAL" means that this item is
+ truly optional. One vendor may choose to include the item
+ because a particular marketplace requires it or because it
+ enhances the product, for example; another vendor may omit the
+ same item.
+
+1.5 Terminology
+
+ This document uses the following terms:
+
+ o "DHCP client"
+
+ A DHCP client is an Internet host using DHCP to obtain
+ configuration parameters such as a network address.
+
+ o "DHCP server"
+
+ A DHCP server is an Internet host that returns configuration
+ parameters to DHCP clients.
+
+ o "BOOTP relay agent"
+
+ A BOOTP relay agent or relay agent is an Internet host or router
+ that passes DHCP messages between DHCP clients and DHCP servers.
+ DHCP is designed to use the same relay agent behavior as specified
+ in the BOOTP protocol specification.
+
+ o "binding"
+
+ A binding is a collection of configuration parameters, including
+ at least an IP address, associated with or "bound to" a DHCP
+ client. Bindings are managed by DHCP servers.
+
+1.6 Design goals
+
+ The following list gives general design goals for DHCP.
+
+ o DHCP should be a mechanism rather than a policy. DHCP must
+ allow local system administrators control over configuration
+ parameters where desired; e.g., local system administrators
+ should be able to enforce local policies concerning allocation
+ and access to local resources where desired.
+
+
+
+
+
+
+
+Droms Standards Track [Page 6]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ o Clients should require no manual configuration. Each client
+ should be able to discover appropriate local configuration
+ parameters without user intervention and incorporate those
+ parameters into its own configuration.
+
+ o Networks should require no manual configuration for individual
+ clients. Under normal circumstances, the network manager
+ should not have to enter any per-client configuration
+ parameters.
+
+ o DHCP should not require a server on each subnet. To allow for
+ scale and economy, DHCP must work across routers or through the
+ intervention of BOOTP relay agents.
+
+ o A DHCP client must be prepared to receive multiple responses
+ to a request for configuration parameters. Some installations
+ may include multiple, overlapping DHCP servers to enhance
+ reliability and increase performance.
+
+ o DHCP must coexist with statically configured, non-participating
+ hosts and with existing network protocol implementations.
+
+ o DHCP must interoperate with the BOOTP relay agent behavior as
+ described by RFC 951 and by RFC 1542 [21].
+
+ o DHCP must provide service to existing BOOTP clients.
+
+ The following list gives design goals specific to the transmission of
+ the network layer parameters. DHCP must:
+
+ o Guarantee that any specific network address will not be in
+ use by more than one DHCP client at a time,
+
+ o Retain DHCP client configuration across DHCP client reboot. A
+ DHCP client should, whenever possible, be assigned the same
+ configuration parameters (e.g., network address) in response
+ to each request,
+
+ o Retain DHCP client configuration across server reboots, and,
+ whenever possible, a DHCP client should be assigned the same
+ configuration parameters despite restarts of the DHCP mechanism,
+
+ o Allow automated assignment of configuration parameters to new
+ clients to avoid hand configuration for new clients,
+
+ o Support fixed or permanent allocation of configuration
+ parameters to specific clients.
+
+
+
+
+Droms Standards Track [Page 7]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+2. Protocol Summary
+
+ From the client's point of view, DHCP is an extension of the BOOTP
+ mechanism. This behavior allows existing BOOTP clients to
+ interoperate with DHCP servers without requiring any change to the
+ clients' initialization software. RFC 1542 [2] details the
+ interactions between BOOTP and DHCP clients and servers [9]. There
+ are some new, optional transactions that optimize the interaction
+ between DHCP clients and servers that are described in sections 3 and
+ 4.
+
+ Figure 1 gives the format of a DHCP message and table 1 describes
+ each of the fields in the DHCP message. The numbers in parentheses
+ indicate the size of each field in octets. The names for the fields
+ given in the figure will be used throughout this document to refer to
+ the fields in DHCP messages.
+
+ There are two primary differences between DHCP and BOOTP. First,
+ DHCP defines mechanisms through which clients can be assigned a
+ network address for a finite lease, allowing for serial reassignment
+ of network addresses to different clients. Second, DHCP provides the
+ mechanism for a client to acquire all of the IP configuration
+ parameters that it needs in order to operate.
+
+ DHCP introduces a small change in terminology intended to clarify the
+ meaning of one of the fields. What was the "vendor extensions" field
+ in BOOTP has been re-named the "options" field in DHCP. Similarly,
+ the tagged data items that were used inside the BOOTP "vendor
+ extensions" field, which were formerly referred to as "vendor
+ extensions," are now termed simply "options."
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Droms Standards Track [Page 8]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | op (1) | htype (1) | hlen (1) | hops (1) |
+ +---------------+---------------+---------------+---------------+
+ | xid (4) |
+ +-------------------------------+-------------------------------+
+ | secs (2) | flags (2) |
+ +-------------------------------+-------------------------------+
+ | ciaddr (4) |
+ +---------------------------------------------------------------+
+ | yiaddr (4) |
+ +---------------------------------------------------------------+
+ | siaddr (4) |
+ +---------------------------------------------------------------+
+ | giaddr (4) |
+ +---------------------------------------------------------------+
+ | |
+ | chaddr (16) |
+ | |
+ | |
+ +---------------------------------------------------------------+
+ | |
+ | sname (64) |
+ +---------------------------------------------------------------+
+ | |
+ | file (128) |
+ +---------------------------------------------------------------+
+ | |
+ | options (variable) |
+ +---------------------------------------------------------------+
+
+ Figure 1: Format of a DHCP message
+
+ DHCP defines a new 'client identifier' option that is used to pass an
+ explicit client identifier to a DHCP server. This change eliminates
+ the overloading of the 'chaddr' field in BOOTP messages, where
+ 'chaddr' is used both as a hardware address for transmission of BOOTP
+ reply messages and as a client identifier. The 'client identifier'
+ is an opaque key, not to be interpreted by the server; for example,
+ the 'client identifier' may contain a hardware address, identical to
+ the contents of the 'chaddr' field, or it may contain another type of
+ identifier, such as a DNS name. The 'client identifier' chosen by a
+ DHCP client MUST be unique to that client within the subnet to which
+ the client is attached. If the client uses a 'client identifier' in
+ one message, it MUST use that same identifier in all subsequent
+ messages, to ensure that all servers correctly identify the client.
+
+
+
+
+Droms Standards Track [Page 9]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ DHCP clarifies the interpretation of the 'siaddr' field as the
+ address of the server to use in the next step of the client's
+ bootstrap process. A DHCP server may return its own address in the
+ 'siaddr' field, if the server is prepared to supply the next
+ bootstrap service (e.g., delivery of an operating system executable
+ image). A DHCP server always returns its own address in the 'server
+ identifier' option.
+
+ FIELD OCTETS DESCRIPTION
+ ----- ------ -----------
+
+ op 1 Message op code / message type.
+ 1 = BOOTREQUEST, 2 = BOOTREPLY
+ htype 1 Hardware address type, see ARP section in "Assigned
+ Numbers" RFC; e.g., '1' = 10mb ethernet.
+ hlen 1 Hardware address length (e.g. '6' for 10mb
+ ethernet).
+ hops 1 Client sets to zero, optionally used by relay agents
+ when booting via a relay agent.
+ xid 4 Transaction ID, a random number chosen by the
+ client, used by the client and server to associate
+ messages and responses between a client and a
+ server.
+ secs 2 Filled in by client, seconds elapsed since client
+ began address acquisition or renewal process.
+ flags 2 Flags (see figure 2).
+ ciaddr 4 Client IP address; only filled in if client is in
+ BOUND, RENEW or REBINDING state and can respond
+ to ARP requests.
+ yiaddr 4 'your' (client) IP address.
+ siaddr 4 IP address of next server to use in bootstrap;
+ returned in DHCPOFFER, DHCPACK by server.
+ giaddr 4 Relay agent IP address, used in booting via a
+ relay agent.
+ chaddr 16 Client hardware address.
+ sname 64 Optional server host name, null terminated string.
+ file 128 Boot file name, null terminated string; "generic"
+ name or null in DHCPDISCOVER, fully qualified
+ directory-path name in DHCPOFFER.
+ options var Optional parameters field. See the options
+ documents for a list of defined options.
+
+ Table 1: Description of fields in a DHCP message
+
+ The 'options' field is now variable length. A DHCP client must be
+ prepared to receive DHCP messages with an 'options' field of at least
+ length 312 octets. This requirement implies that a DHCP client must
+ be prepared to receive a message of up to 576 octets, the minimum IP
+
+
+
+Droms Standards Track [Page 10]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ datagram size an IP host must be prepared to accept [3]. DHCP
+ clients may negotiate the use of larger DHCP messages through the
+ 'maximum DHCP message size' option. The options field may be further
+ extended into the 'file' and 'sname' fields.
+
+ In the case of a client using DHCP for initial configuration (before
+ the client's TCP/IP software has been completely configured), DHCP
+ requires creative use of the client's TCP/IP software and liberal
+ interpretation of RFC 1122. The TCP/IP software SHOULD accept and
+ forward to the IP layer any IP packets delivered to the client's
+ hardware address before the IP address is configured; DHCP servers
+ and BOOTP relay agents may not be able to deliver DHCP messages to
+ clients that cannot accept hardware unicast datagrams before the
+ TCP/IP software is configured.
+
+ To work around some clients that cannot accept IP unicast datagrams
+ before the TCP/IP software is configured as discussed in the previous
+ paragraph, DHCP uses the 'flags' field [21]. The leftmost bit is
+ defined as the BROADCAST (B) flag. The semantics of this flag are
+ discussed in section 4.1 of this document. The remaining bits of the
+ flags field are reserved for future use. They MUST be set to zero by
+ clients and ignored by servers and relay agents. Figure 2 gives the
+ format of the 'flags' field.
+
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |B| MBZ |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ B: BROADCAST flag
+
+ MBZ: MUST BE ZERO (reserved for future use)
+
+ Figure 2: Format of the 'flags' field
+
+2.1 Configuration parameters repository
+
+ The first service provided by DHCP is to provide persistent storage
+ of network parameters for network clients. The model of DHCP
+ persistent storage is that the DHCP service stores a key-value entry
+ for each client, where the key is some unique identifier (for
+ example, an IP subnet number and a unique identifier within the
+ subnet) and the value contains the configuration parameters for the
+ client.
+
+ For example, the key might be the pair (IP-subnet-number, hardware-
+ address) (note that the "hardware-address" should be typed by the
+
+
+
+Droms Standards Track [Page 11]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ type of hardware to accommodate possible duplication of hardware
+ addresses resulting from bit-ordering problems in a mixed-media,
+ bridged network) allowing for serial or concurrent reuse of a
+ hardware address on different subnets, and for hardware addresses
+ that may not be globally unique. Alternately, the key might be the
+ pair (IP-subnet-number, hostname), allowing the server to assign
+ parameters intelligently to a DHCP client that has been moved to a
+ different subnet or has changed hardware addresses (perhaps because
+ the network interface failed and was replaced). The protocol defines
+ that the key will be (IP-subnet-number, hardware-address) unless the
+ client explicitly supplies an identifier using the 'client
+ identifier' option. A client can query the DHCP service to
+ retrieve its configuration parameters. The client interface to the
+ configuration parameters repository consists of protocol messages to
+ request configuration parameters and responses from the server
+ carrying the configuration parameters.
+
+2.2 Dynamic allocation of network addresses
+
+ The second service provided by DHCP is the allocation of temporary or
+ permanent network (IP) addresses to clients. The basic mechanism for
+ the dynamic allocation of network addresses is simple: a client
+ requests the use of an address for some period of time. The
+ allocation mechanism (the collection of DHCP servers) guarantees not
+ to reallocate that address within the requested time and attempts to
+ return the same network address each time the client requests an
+ address. In this document, the period over which a network address
+ is allocated to a client is referred to as a "lease" [11]. The
+ client may extend its lease with subsequent requests. The client may
+ issue a message to release the address back to the server when the
+ client no longer needs the address. The client may ask for a
+ permanent assignment by asking for an infinite lease. Even when
+ assigning "permanent" addresses, a server may choose to give out
+ lengthy but non-infinite leases to allow detection of the fact that
+ the client has been retired.
+
+ In some environments it will be necessary to reassign network
+ addresses due to exhaustion of available addresses. In such
+ environments, the allocation mechanism will reuse addresses whose
+ lease has expired. The server should use whatever information is
+ available in the configuration information repository to choose an
+ address to reuse. For example, the server may choose the least
+ recently assigned address. As a consistency check, the allocating
+ server SHOULD probe the reused address before allocating the address,
+ e.g., with an ICMP echo request, and the client SHOULD probe the
+ newly received address, e.g., with ARP.
+
+
+
+
+
+Droms Standards Track [Page 12]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+3. The Client-Server Protocol
+
+ DHCP uses the BOOTP message format defined in RFC 951 and given in
+ table 1 and figure 1. The 'op' field of each DHCP message sent from
+ a client to a server contains BOOTREQUEST. BOOTREPLY is used in the
+ 'op' field of each DHCP message sent from a server to a client.
+
+ The first four octets of the 'options' field of the DHCP message
+ contain the (decimal) values 99, 130, 83 and 99, respectively (this
+ is the same magic cookie as is defined in RFC 1497 [17]). The
+ remainder of the 'options' field consists of a list of tagged
+ parameters that are called "options". All of the "vendor extensions"
+ listed in RFC 1497 are also DHCP options. RFC 1533 gives the
+ complete set of options defined for use with DHCP.
+
+ Several options have been defined so far. One particular option -
+ the "DHCP message type" option - must be included in every DHCP
+ message. This option defines the "type" of the DHCP message.
+ Additional options may be allowed, required, or not allowed,
+ depending on the DHCP message type.
+
+ Throughout this document, DHCP messages that include a 'DHCP message
+ type' option will be referred to by the type of the message; e.g., a
+ DHCP message with 'DHCP message type' option type 1 will be referred
+ to as a "DHCPDISCOVER" message.
+
+3.1 Client-server interaction - allocating a network address
+
+ The following summary of the protocol exchanges between clients and
+ servers refers to the DHCP messages described in table 2. The
+ timeline diagram in figure 3 shows the timing relationships in a
+ typical client-server interaction. If the client already knows its
+ address, some steps may be omitted; this abbreviated interaction is
+ described in section 3.2.
+
+ 1. The client broadcasts a DHCPDISCOVER message on its local physical
+ subnet. The DHCPDISCOVER message MAY include options that suggest
+ values for the network address and lease duration. BOOTP relay
+ agents may pass the message on to DHCP servers not on the same
+ physical subnet.
+
+ 2. Each server may respond with a DHCPOFFER message that includes an
+ available network address in the 'yiaddr' field (and other
+ configuration parameters in DHCP options). Servers need not
+ reserve the offered network address, although the protocol will
+ work more efficiently if the server avoids allocating the offered
+ network address to another client. When allocating a new address,
+ servers SHOULD check that the offered network address is not
+
+
+
+Droms Standards Track [Page 13]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ already in use; e.g., the server may probe the offered address
+ with an ICMP Echo Request. Servers SHOULD be implemented so that
+ network administrators MAY choose to disable probes of newly
+ allocated addresses. The server transmits the DHCPOFFER message
+ to the client, using the BOOTP relay agent if necessary.
+
+ Message Use
+ ------- ---
+
+ DHCPDISCOVER - Client broadcast to locate available servers.
+
+ DHCPOFFER - Server to client in response to DHCPDISCOVER with
+ offer of configuration parameters.
+
+ DHCPREQUEST - Client message to servers either (a) requesting
+ offered parameters from one server and implicitly
+ declining offers from all others, (b) confirming
+ correctness of previously allocated address after,
+ e.g., system reboot, or (c) extending the lease on a
+ particular network address.
+
+ DHCPACK - Server to client with configuration parameters,
+ including committed network address.
+
+ DHCPNAK - Server to client indicating client's notion of network
+ address is incorrect (e.g., client has moved to new
+ subnet) or client's lease as expired
+
+ DHCPDECLINE - Client to server indicating network address is already
+ in use.
+
+ DHCPRELEASE - Client to server relinquishing network address and
+ cancelling remaining lease.
+
+ DHCPINFORM - Client to server, asking only for local configuration
+ parameters; client already has externally configured
+ network address.
+
+ Table 2: DHCP messages
+
+
+
+
+
+
+
+
+
+
+
+
+Droms Standards Track [Page 14]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ Server Client Server
+ (not selected) (selected)
+
+ v v v
+ | | |
+ | Begins initialization |
+ | | |
+ | _____________/|\____________ |
+ |/DHCPDISCOVER | DHCPDISCOVER \|
+ | | |
+ Determines | Determines
+ configuration | configuration
+ | | |
+ |\ | ____________/ |
+ | \________ | /DHCPOFFER |
+ | DHCPOFFER\ |/ |
+ | \ | |
+ | Collects replies |
+ | \| |
+ | Selects configuration |
+ | | |
+ | _____________/|\____________ |
+ |/ DHCPREQUEST | DHCPREQUEST\ |
+ | | |
+ | | Commits configuration
+ | | |
+ | | _____________/|
+ | |/ DHCPACK |
+ | | |
+ | Initialization complete |
+ | | |
+ . . .
+ . . .
+ | | |
+ | Graceful shutdown |
+ | | |
+ | |\ ____________ |
+ | | DHCPRELEASE \|
+ | | |
+ | | Discards lease
+ | | |
+ v v v
+ Figure 3: Timeline diagram of messages exchanged between DHCP
+ client and servers when allocating a new network address
+
+
+
+
+
+
+
+Droms Standards Track [Page 15]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ 3. The client receives one or more DHCPOFFER messages from one or more
+ servers. The client may choose to wait for multiple responses.
+ The client chooses one server from which to request configuration
+ parameters, based on the configuration parameters offered in the
+ DHCPOFFER messages. The client broadcasts a DHCPREQUEST message
+ that MUST include the 'server identifier' option to indicate which
+ server it has selected, and that MAY include other options
+ specifying desired configuration values. The 'requested IP
+ address' option MUST be set to the value of 'yiaddr' in the
+ DHCPOFFER message from the server. This DHCPREQUEST message is
+ broadcast and relayed through DHCP/BOOTP relay agents. To help
+ ensure that any BOOTP relay agents forward the DHCPREQUEST message
+ to the same set of DHCP servers that received the original
+ DHCPDISCOVER message, the DHCPREQUEST message MUST use the same
+ value in the DHCP message header's 'secs' field and be sent to the
+ same IP broadcast address as the original DHCPDISCOVER message.
+ The client times out and retransmits the DHCPDISCOVER message if
+ the client receives no DHCPOFFER messages.
+
+ 4. The servers receive the DHCPREQUEST broadcast from the client.
+ Those servers not selected by the DHCPREQUEST message use the
+ message as notification that the client has declined that server's
+ offer. The server selected in the DHCPREQUEST message commits the
+ binding for the client to persistent storage and responds with a
+ DHCPACK message containing the configuration parameters for the
+ requesting client. The combination of 'client identifier' or
+ 'chaddr' and assigned network address constitute a unique
+ identifier for the client's lease and are used by both the client
+ and server to identify a lease referred to in any DHCP messages.
+ Any configuration parameters in the DHCPACK message SHOULD NOT
+ conflict with those in the earlier DHCPOFFER message to which the
+ client is responding. The server SHOULD NOT check the offered
+ network address at this point. The 'yiaddr' field in the DHCPACK
+ messages is filled in with the selected network address.
+
+ If the selected server is unable to satisfy the DHCPREQUEST message
+ (e.g., the requested network address has been allocated), the
+ server SHOULD respond with a DHCPNAK message.
+
+ A server MAY choose to mark addresses offered to clients in
+ DHCPOFFER messages as unavailable. The server SHOULD mark an
+ address offered to a client in a DHCPOFFER message as available if
+ the server receives no DHCPREQUEST message from that client.
+
+ 5. The client receives the DHCPACK message with configuration
+ parameters. The client SHOULD perform a final check on the
+ parameters (e.g., ARP for allocated network address), and notes the
+ duration of the lease specified in the DHCPACK message. At this
+
+
+
+Droms Standards Track [Page 16]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ point, the client is configured. If the client detects that the
+ address is already in use (e.g., through the use of ARP), the
+ client MUST send a DHCPDECLINE message to the server and restarts
+ the configuration process. The client SHOULD wait a minimum of ten
+ seconds before restarting the configuration process to avoid
+ excessive network traffic in case of looping.
+
+ If the client receives a DHCPNAK message, the client restarts the
+ configuration process.
+
+ The client times out and retransmits the DHCPREQUEST message if the
+ client receives neither a DHCPACK or a DHCPNAK message. The client
+ retransmits the DHCPREQUEST according to the retransmission
+ algorithm in section 4.1. The client should choose to retransmit
+ the DHCPREQUEST enough times to give adequate probability of
+ contacting the server without causing the client (and the user of
+ that client) to wait overly long before giving up; e.g., a client
+ retransmitting as described in section 4.1 might retransmit the
+ DHCPREQUEST message four times, for a total delay of 60 seconds,
+ before restarting the initialization procedure. If the client
+ receives neither a DHCPACK or a DHCPNAK message after employing the
+ retransmission algorithm, the client reverts to INIT state and
+ restarts the initialization process. The client SHOULD notify the
+ user that the initialization process has failed and is restarting.
+
+ 6. The client may choose to relinquish its lease on a network address
+ by sending a DHCPRELEASE message to the server. The client
+ identifies the lease to be released with its 'client identifier',
+ or 'chaddr' and network address in the DHCPRELEASE message. If the
+ client used a 'client identifier' when it obtained the lease, it
+ MUST use the same 'client identifier' in the DHCPRELEASE message.
+
+3.2 Client-server interaction - reusing a previously allocated network
+ address
+
+ If a client remembers and wishes to reuse a previously allocated
+ network address, a client may choose to omit some of the steps
+ described in the previous section. The timeline diagram in figure 4
+ shows the timing relationships in a typical client-server interaction
+ for a client reusing a previously allocated network address.
+
+
+
+
+
+
+
+
+
+
+
+Droms Standards Track [Page 17]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ 1. The client broadcasts a DHCPREQUEST message on its local subnet.
+ The message includes the client's network address in the
+ 'requested IP address' option. As the client has not received its
+ network address, it MUST NOT fill in the 'ciaddr' field. BOOTP
+ relay agents pass the message on to DHCP servers not on the same
+ subnet. If the client used a 'client identifier' to obtain its
+ address, the client MUST use the same 'client identifier' in the
+ DHCPREQUEST message.
+
+ 2. Servers with knowledge of the client's configuration parameters
+ respond with a DHCPACK message to the client. Servers SHOULD NOT
+ check that the client's network address is already in use; the
+ client may respond to ICMP Echo Request messages at this point.
+
+ Server Client Server
+
+ v v v
+ | | |
+ | Begins |
+ | initialization |
+ | | |
+ | /|\ |
+ | _________ __/ | \__________ |
+ | /DHCPREQU EST | DHCPREQUEST\ |
+ |/ | \|
+ | | |
+ Locates | Locates
+ configuration | configuration
+ | | |
+ |\ | /|
+ | \ | ___________/ |
+ | \ | / DHCPACK |
+ | \ _______ |/ |
+ | DHCPACK\ | |
+ | Initialization |
+ | complete |
+ | \| |
+ | | |
+ | (Subsequent |
+ | DHCPACKS |
+ | ignored) |
+ | | |
+ | | |
+ v v v
+
+ Figure 4: Timeline diagram of messages exchanged between DHCP
+ client and servers when reusing a previously allocated
+ network address
+
+
+
+Droms Standards Track [Page 18]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ If the client's request is invalid (e.g., the client has moved
+ to a new subnet), servers SHOULD respond with a DHCPNAK message to
+ the client. Servers SHOULD NOT respond if their information is not
+ guaranteed to be accurate. For example, a server that identifies a
+ request for an expired binding that is owned by another server SHOULD
+ NOT respond with a DHCPNAK unless the servers are using an explicit
+ mechanism to maintain coherency among the servers.
+
+ If 'giaddr' is 0x0 in the DHCPREQUEST message, the client is on
+ the same subnet as the server. The server MUST
+ broadcast the DHCPNAK message to the 0xffffffff broadcast address
+ because the client may not have a correct network address or subnet
+ mask, and the client may not be answering ARP requests.
+ Otherwise, the server MUST send the DHCPNAK message to the IP
+ address of the BOOTP relay agent, as recorded in 'giaddr'. The
+ relay agent will, in turn, forward the message directly to the
+ client's hardware address, so that the DHCPNAK can be delivered even
+ if the client has moved to a new network.
+
+ 3. The client receives the DHCPACK message with configuration
+ parameters. The client performs a final check on the parameters
+ (as in section 3.1), and notes the duration of the lease specified
+ in the DHCPACK message. The specific lease is implicitly identified
+ by the 'client identifier' or 'chaddr' and the network address. At
+ this point, the client is configured.
+
+ If the client detects that the IP address in the DHCPACK message
+ is already in use, the client MUST send a DHCPDECLINE message to the
+ server and restarts the configuration process by requesting a
+ new network address. This action corresponds to the client
+ moving to the INIT state in the DHCP state diagram, which is
+ described in section 4.4.
+
+ If the client receives a DHCPNAK message, it cannot reuse its
+ remembered network address. It must instead request a new
+ address by restarting the configuration process, this time
+ using the (non-abbreviated) procedure described in section
+ 3.1. This action also corresponds to the client moving to
+ the INIT state in the DHCP state diagram.
+
+ The client times out and retransmits the DHCPREQUEST message if
+ the client receives neither a DHCPACK nor a DHCPNAK message. The
+ client retransmits the DHCPREQUEST according to the retransmission
+ algorithm in section 4.1. The client should choose to retransmit
+ the DHCPREQUEST enough times to give adequate probability of
+ contacting the server without causing the client (and the user of
+ that client) to wait overly long before giving up; e.g., a client
+ retransmitting as described in section 4.1 might retransmit the
+
+
+
+Droms Standards Track [Page 19]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ DHCPREQUEST message four times, for a total delay of 60 seconds,
+ before restarting the initialization procedure. If the client
+ receives neither a DHCPACK or a DHCPNAK message after employing
+ the retransmission algorithm, the client MAY choose to use the
+ previously allocated network address and configuration parameters
+ for the remainder of the unexpired lease. This corresponds to
+ moving to BOUND state in the client state transition diagram shown
+ in figure 5.
+
+ 4. The client may choose to relinquish its lease on a network
+ address by sending a DHCPRELEASE message to the server. The
+ client identifies the lease to be released with its
+ 'client identifier', or 'chaddr' and network address in the
+ DHCPRELEASE message.
+
+ Note that in this case, where the client retains its network
+ address locally, the client will not normally relinquish its
+ lease during a graceful shutdown. Only in the case where the
+ client explicitly needs to relinquish its lease, e.g., the client
+ is about to be moved to a different subnet, will the client send
+ a DHCPRELEASE message.
+
+3.3 Interpretation and representation of time values
+
+ A client acquires a lease for a network address for a fixed period of
+ time (which may be infinite). Throughout the protocol, times are to
+ be represented in units of seconds. The time value of 0xffffffff is
+ reserved to represent "infinity".
+
+ As clients and servers may not have synchronized clocks, times are
+ represented in DHCP messages as relative times, to be interpreted
+ with respect to the client's local clock. Representing relative
+ times in units of seconds in an unsigned 32 bit word gives a range of
+ relative times from 0 to approximately 100 years, which is sufficient
+ for the relative times to be measured using DHCP.
+
+ The algorithm for lease duration interpretation given in the previous
+ paragraph assumes that client and server clocks are stable relative
+ to each other. If there is drift between the two clocks, the server
+ may consider the lease expired before the client does. To
+ compensate, the server may return a shorter lease duration to the
+ client than the server commits to its local database of client
+ information.
+
+3.4 Obtaining parameters with externally configured network address
+
+ If a client has obtained a network address through some other means
+ (e.g., manual configuration), it may use a DHCPINFORM request message
+
+
+
+Droms Standards Track [Page 20]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ to obtain other local configuration parameters. Servers receiving a
+ DHCPINFORM message construct a DHCPACK message with any local
+ configuration parameters appropriate for the client without:
+ allocating a new address, checking for an existing binding, filling
+ in 'yiaddr' or including lease time parameters. The servers SHOULD
+ unicast the DHCPACK reply to the address given in the 'ciaddr' field
+ of the DHCPINFORM message.
+
+ The server SHOULD check the network address in a DHCPINFORM message
+ for consistency, but MUST NOT check for an existing lease. The
+ server forms a DHCPACK message containing the configuration
+ parameters for the requesting client and sends the DHCPACK message
+ directly to the client.
+
+3.5 Client parameters in DHCP
+
+ Not all clients require initialization of all parameters listed in
+ Appendix A. Two techniques are used to reduce the number of
+ parameters transmitted from the server to the client. First, most of
+ the parameters have defaults defined in the Host Requirements RFCs;
+ if the client receives no parameters from the server that override
+ the defaults, a client uses those default values. Second, in its
+ initial DHCPDISCOVER or DHCPREQUEST message, a client may provide the
+ server with a list of specific parameters the client is interested
+ in. If the client includes a list of parameters in a DHCPDISCOVER
+ message, it MUST include that list in any subsequent DHCPREQUEST
+ messages.
+
+ The client SHOULD include the 'maximum DHCP message size' option to
+ let the server know how large the server may make its DHCP messages.
+ The parameters returned to a client may still exceed the space
+ allocated to options in a DHCP message. In this case, two additional
+ options flags (which must appear in the 'options' field of the
+ message) indicate that the 'file' and 'sname' fields are to be used
+ for options.
+
+ The client can inform the server which configuration parameters the
+ client is interested in by including the 'parameter request list'
+ option. The data portion of this option explicitly lists the options
+ requested by tag number.
+
+ In addition, the client may suggest values for the network address
+ and lease time in the DHCPDISCOVER message. The client may include
+ the 'requested IP address' option to suggest that a particular IP
+ address be assigned, and may include the 'IP address lease time'
+ option to suggest the lease time it would like. Other options
+ representing "hints" at configuration parameters are allowed in a
+ DHCPDISCOVER or DHCPREQUEST message. However, additional options may
+
+
+
+Droms Standards Track [Page 21]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ be ignored by servers, and multiple servers may, therefore, not
+ return identical values for some options. The 'requested IP address'
+ option is to be filled in only in a DHCPREQUEST message when the
+ client is verifying network parameters obtained previously. The
+ client fills in the 'ciaddr' field only when correctly configured
+ with an IP address in BOUND, RENEWING or REBINDING state.
+
+ If a server receives a DHCPREQUEST message with an invalid 'requested
+ IP address', the server SHOULD respond to the client with a DHCPNAK
+ message and may choose to report the problem to the system
+ administrator. The server may include an error message in the
+ 'message' option.
+
+3.6 Use of DHCP in clients with multiple interfaces
+
+ A client with multiple network interfaces must use DHCP through each
+ interface independently to obtain configuration information
+ parameters for those separate interfaces.
+
+3.7 When clients should use DHCP
+
+ A client SHOULD use DHCP to reacquire or verify its IP address and
+ network parameters whenever the local network parameters may have
+ changed; e.g., at system boot time or after a disconnection from the
+ local network, as the local network configuration may change without
+ the client's or user's knowledge.
+
+ If a client has knowledge of a previous network address and is unable
+ to contact a local DHCP server, the client may continue to use the
+ previous network address until the lease for that address expires.
+ If the lease expires before the client can contact a DHCP server, the
+ client must immediately discontinue use of the previous network
+ address and may inform local users of the problem.
+
+4. Specification of the DHCP client-server protocol
+
+ In this section, we assume that a DHCP server has a block of network
+ addresses from which it can satisfy requests for new addresses. Each
+ server also maintains a database of allocated addresses and leases in
+ local permanent storage.
+
+4.1 Constructing and sending DHCP messages
+
+ DHCP clients and servers both construct DHCP messages by filling in
+ fields in the fixed format section of the message and appending
+ tagged data items in the variable length option area. The options
+ area includes first a four-octet 'magic cookie' (which was described
+ in section 3), followed by the options. The last option must always
+
+
+
+Droms Standards Track [Page 22]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ be the 'end' option.
+
+ DHCP uses UDP as its transport protocol. DHCP messages from a client
+ to a server are sent to the 'DHCP server' port (67), and DHCP
+ messages from a server to a client are sent to the 'DHCP client' port
+ (68). A server with multiple network address (e.g., a multi-homed
+ host) MAY use any of its network addresses in outgoing DHCP messages.
+
+ The 'server identifier' field is used both to identify a DHCP server
+ in a DHCP message and as a destination address from clients to
+ servers. A server with multiple network addresses MUST be prepared
+ to to accept any of its network addresses as identifying that server
+ in a DHCP message. To accommodate potentially incomplete network
+ connectivity, a server MUST choose an address as a 'server
+ identifier' that, to the best of the server's knowledge, is reachable
+ from the client. For example, if the DHCP server and the DHCP client
+ are connected to the same subnet (i.e., the 'giaddr' field in the
+ message from the client is zero), the server SHOULD select the IP
+ address the server is using for communication on that subnet as the
+ 'server identifier'. If the server is using multiple IP addresses on
+ that subnet, any such address may be used. If the server has
+ received a message through a DHCP relay agent, the server SHOULD
+ choose an address from the interface on which the message was
+ recieved as the 'server identifier' (unless the server has other,
+ better information on which to make its choice). DHCP clients MUST
+ use the IP address provided in the 'server identifier' option for any
+ unicast requests to the DHCP server.
+
+ DHCP messages broadcast by a client prior to that client obtaining
+ its IP address must have the source address field in the IP header
+ set to 0.
+
+ If the 'giaddr' field in a DHCP message from a client is non-zero,
+ the server sends any return messages to the 'DHCP server' port on the
+ BOOTP relay agent whose address appears in 'giaddr'. If the 'giaddr'
+ field is zero and the 'ciaddr' field is nonzero, then the server
+ unicasts DHCPOFFER and DHCPACK messages to the address in 'ciaddr'.
+ If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is
+ set, then the server broadcasts DHCPOFFER and DHCPACK messages to
+ 0xffffffff. If the broadcast bit is not set and 'giaddr' is zero and
+ 'ciaddr' is zero, then the server unicasts DHCPOFFER and DHCPACK
+ messages to the client's hardware address and 'yiaddr' address. In
+ all cases, when 'giaddr' is zero, the server broadcasts any DHCPNAK
+ messages to 0xffffffff.
+
+ If the options in a DHCP message extend into the 'sname' and 'file'
+ fields, the 'option overload' option MUST appear in the 'options'
+ field, with value 1, 2 or 3, as specified in RFC 1533. If the
+
+
+
+Droms Standards Track [Page 23]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ 'option overload' option is present in the 'options' field, the
+ options in the 'options' field MUST be terminated by an 'end' option,
+ and MAY contain one or more 'pad' options to fill the options field.
+ The options in the 'sname' and 'file' fields (if in use as indicated
+ by the 'options overload' option) MUST begin with the first octet of
+ the field, MUST be terminated by an 'end' option, and MUST be
+ followed by 'pad' options to fill the remainder of the field. Any
+ individual option in the 'options', 'sname' and 'file' fields MUST be
+ entirely contained in that field. The options in the 'options' field
+ MUST be interpreted first, so that any 'option overload' options may
+ be interpreted. The 'file' field MUST be interpreted next (if the
+ 'option overload' option indicates that the 'file' field contains
+ DHCP options), followed by the 'sname' field.
+
+ The values to be passed in an 'option' tag may be too long to fit in
+ the 255 octets available to a single option (e.g., a list of routers
+ in a 'router' option [21]). Options may appear only once, unless
+ otherwise specified in the options document. The client concatenates
+ the values of multiple instances of the same option into a single
+ parameter list for configuration.
+
+ DHCP clients are responsible for all message retransmission. The
+ client MUST adopt a retransmission strategy that incorporates a
+ randomized exponential backoff algorithm to determine the delay
+ between retransmissions. The delay between retransmissions SHOULD be
+ chosen to allow sufficient time for replies from the server to be
+ delivered based on the characteristics of the internetwork between
+ the client and the server. For example, in a 10Mb/sec Ethernet
+ internetwork, the delay before the first retransmission SHOULD be 4
+ seconds randomized by the value of a uniform random number chosen
+ from the range -1 to +1. Clients with clocks that provide resolution
+ granularity of less than one second may choose a non-integer
+ randomization value. The delay before the next retransmission SHOULD
+ be 8 seconds randomized by the value of a uniform number chosen from
+ the range -1 to +1. The retransmission delay SHOULD be doubled with
+ subsequent retransmissions up to a maximum of 64 seconds. The client
+ MAY provide an indication of retransmission attempts to the user as
+ an indication of the progress of the configuration process.
+
+ The 'xid' field is used by the client to match incoming DHCP messages
+ with pending requests. A DHCP client MUST choose 'xid's in such a
+ way as to minimize the chance of using an 'xid' identical to one used
+ by another client. For example, a client may choose a different,
+ random initial 'xid' each time the client is rebooted, and
+ subsequently use sequential 'xid's until the next reboot. Selecting
+ a new 'xid' for each retransmission is an implementation decision. A
+ client may choose to reuse the same 'xid' or select a new 'xid' for
+ each retransmitted message.
+
+
+
+Droms Standards Track [Page 24]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ Normally, DHCP servers and BOOTP relay agents attempt to deliver
+ DHCPOFFER, DHCPACK and DHCPNAK messages directly to the client using
+ uicast delivery. The IP destination address (in the IP header) is
+ set to the DHCP 'yiaddr' address and the link-layer destination
+ address is set to the DHCP 'chaddr' address. Unfortunately, some
+ client implementations are unable to receive such unicast IP
+ datagrams until the implementation has been configured with a valid
+ IP address (leading to a deadlock in which the client's IP address
+ cannot be delivered until the client has been configured with an IP
+ address).
+
+ A client that cannot receive unicast IP datagrams until its protocol
+ software has been configured with an IP address SHOULD set the
+ BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
+ DHCPREQUEST messages that client sends. The BROADCAST bit will
+ provide a hint to the DHCP server and BOOTP relay agent to broadcast
+ any messages to the client on the client's subnet. A client that can
+ receive unicast IP datagrams before its protocol software has been
+ configured SHOULD clear the BROADCAST bit to 0. The BOOTP
+ clarifications document discusses the ramifications of the use of the
+ BROADCAST bit [21].
+
+ A server or relay agent sending or relaying a DHCP message directly
+ to a DHCP client (i.e., not to a relay agent specified in the
+ 'giaddr' field) SHOULD examine the BROADCAST bit in the 'flags'
+ field. If this bit is set to 1, the DHCP message SHOULD be sent as
+ an IP broadcast using an IP broadcast address (preferably 0xffffffff)
+ as the IP destination address and the link-layer broadcast address as
+ the link-layer destination address. If the BROADCAST bit is cleared
+ to 0, the message SHOULD be sent as an IP unicast to the IP address
+ specified in the 'yiaddr' field and the link-layer address specified
+ in the 'chaddr' field. If unicasting is not possible, the message
+ MAY be sent as an IP broadcast using an IP broadcast address
+ (preferably 0xffffffff) as the IP destination address and the link-
+ layer broadcast address as the link-layer destination address.
+
+4.2 DHCP server administrative controls
+
+ DHCP servers are not required to respond to every DHCPDISCOVER and
+ DHCPREQUEST message they receive. For example, a network
+ administrator, to retain stringent control over the clients attached
+ to the network, may choose to configure DHCP servers to respond only
+ to clients that have been previously registered through some external
+ mechanism. The DHCP specification describes only the interactions
+ between clients and servers when the clients and servers choose to
+ interact; it is beyond the scope of the DHCP specification to
+ describe all of the administrative controls that system
+ administrators might want to use. Specific DHCP server
+
+
+
+Droms Standards Track [Page 25]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ implementations may incorporate any controls or policies desired by a
+ network administrator.
+
+ In some environments, a DHCP server will have to consider the values
+ of the vendor class options included in DHCPDISCOVER or DHCPREQUEST
+ messages when determining the correct parameters for a particular
+ client.
+
+ A DHCP server needs to use some unique identifier to associate a
+ client with its lease. The client MAY choose to explicitly provide
+ the identifier through the 'client identifier' option. If the client
+ supplies a 'client identifier', the client MUST use the same 'client
+ identifier' in all subsequent messages, and the server MUST use that
+ identifier to identify the client. If the client does not provide a
+ 'client identifier' option, the server MUST use the contents of the
+ 'chaddr' field to identify the client. It is crucial for a DHCP
+ client to use an identifier unique within the subnet to which the
+ client is attached in the 'client identifier' option. Use of
+ 'chaddr' as the client's unique identifier may cause unexpected
+ results, as that identifier may be associated with a hardware
+ interface that could be moved to a new client. Some sites may choose
+ to use a manufacturer's serial number as the 'client identifier', to
+ avoid unexpected changes in a clients network address due to transfer
+ of hardware interfaces among computers. Sites may also choose to use
+ a DNS name as the 'client identifier', causing address leases to be
+ associated with the DNS name rather than a specific hardware box.
+
+ DHCP clients are free to use any strategy in selecting a DHCP server
+ among those from which the client receives a DHCPOFFER message. The
+ client implementation of DHCP SHOULD provide a mechanism for the user
+ to select directly the 'vendor class identifier' values.
+
+4.3 DHCP server behavior
+
+ A DHCP server processes incoming DHCP messages from a client based on
+ the current state of the binding for that client. A DHCP server can
+ receive the following messages from a client:
+
+ o DHCPDISCOVER
+
+ o DHCPREQUEST
+
+ o DHCPDECLINE
+
+ o DHCPRELEASE
+
+ o DHCPINFORM
+
+
+
+
+Droms Standards Track [Page 26]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ Table 3 gives the use of the fields and options in a DHCP message by
+ a server. The remainder of this section describes the action of the
+ DHCP server for each possible incoming message.
+
+4.3.1 DHCPDISCOVER message
+
+ When a server receives a DHCPDISCOVER message from a client, the
+ server chooses a network address for the requesting client. If no
+ address is available, the server may choose to report the problem to
+ the system administrator. If an address is available, the new address
+ SHOULD be chosen as follows:
+
+ o The client's current address as recorded in the client's current
+ binding, ELSE
+
+ o The client's previous address as recorded in the client's (now
+ expired or released) binding, if that address is in the server's
+ pool of available addresses and not already allocated, ELSE
+
+ o The address requested in the 'Requested IP Address' option, if that
+ address is valid and not already allocated, ELSE
+
+ o A new address allocated from the server's pool of available
+ addresses; the address is selected based on the subnet from which
+ the message was received (if 'giaddr' is 0) or on the address of
+ the relay agent that forwarded the message ('giaddr' when not 0).
+
+ As described in section 4.2, a server MAY, for administrative
+ reasons, assign an address other than the one requested, or may
+ refuse to allocate an address to a particular client even though free
+ addresses are available.
+
+ Note that, in some network architectures (e.g., internets with more
+ than one IP subnet assigned to a physical network segment), it may be
+ the case that the DHCP client should be assigned an address from a
+ different subnet than the address recorded in 'giaddr'. Thus, DHCP
+ does not require that the client be assigned as address from the
+ subnet in 'giaddr'. A server is free to choose some other subnet,
+ and it is beyond the scope of the DHCP specification to describe ways
+ in which the assigned IP address might be chosen.
+
+ While not required for correct operation of DHCP, the server SHOULD
+ NOT reuse the selected network address before the client responds to
+ the server's DHCPOFFER message. The server may choose to record the
+ address as offered to the client.
+
+ The server must also choose an expiration time for the lease, as
+ follows:
+
+
+
+Droms Standards Track [Page 27]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ o IF the client has not requested a specific lease in the
+ DHCPDISCOVER message and the client already has an assigned network
+ address, the server returns the lease expiration time previously
+ assigned to that address (note that the client must explicitly
+ request a specific lease to extend the expiration time on a
+ previously assigned address), ELSE
+
+ o IF the client has not requested a specific lease in the
+ DHCPDISCOVER message and the client does not have an assigned
+ network address, the server assigns a locally configured default
+ lease time, ELSE
+
+ o IF the client has requested a specific lease in the DHCPDISCOVER
+ message (regardless of whether the client has an assigned network
+ address), the server may choose either to return the requested
+ lease (if the lease is acceptable to local policy) or select
+ another lease.
+
+Field DHCPOFFER DHCPACK DHCPNAK
+----- --------- ------- -------
+'op' BOOTREPLY BOOTREPLY BOOTREPLY
+'htype' (From "Assigned Numbers" RFC)
+'hlen' (Hardware address length in octets)
+'hops' 0 0 0
+'xid' 'xid' from client 'xid' from client 'xid' from client
+ DHCPDISCOVER DHCPREQUEST DHCPREQUEST
+ message message message
+'secs' 0 0 0
+'ciaddr' 0 'ciaddr' from 0
+ DHCPREQUEST or 0
+'yiaddr' IP address offered IP address 0
+ to client assigned to client
+'siaddr' IP address of next IP address of next 0
+ bootstrap server bootstrap server
+'flags' 'flags' from 'flags' from 'flags' from
+ client DHCPDISCOVER client DHCPREQUEST client DHCPREQUEST
+ message message message
+'giaddr' 'giaddr' from 'giaddr' from 'giaddr' from
+ client DHCPDISCOVER client DHCPREQUEST client DHCPREQUEST
+ message message message
+'chaddr' 'chaddr' from 'chaddr' from 'chaddr' from
+ client DHCPDISCOVER client DHCPREQUEST client DHCPREQUEST
+ message message message
+'sname' Server host name Server host name (unused)
+ or options or options
+'file' Client boot file Client boot file (unused)
+ name or options name or options
+'options' options options
+
+
+
+Droms Standards Track [Page 28]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+Option DHCPOFFER DHCPACK DHCPNAK
+------ --------- ------- -------
+Requested IP address MUST NOT MUST NOT MUST NOT
+IP address lease time MUST MUST (DHCPREQUEST) MUST NOT
+ MUST NOT (DHCPINFORM)
+Use 'file'/'sname' fields MAY MAY MUST NOT
+DHCP message type DHCPOFFER DHCPACK DHCPNAK
+Parameter request list MUST NOT MUST NOT MUST NOT
+Message SHOULD SHOULD SHOULD
+Client identifier MUST NOT MUST NOT MAY
+Vendor class identifier MAY MAY MAY
+Server identifier MUST MUST MUST
+Maximum message size MUST NOT MUST NOT MUST NOT
+All others MAY MAY MUST NOT
+
+ Table 3: Fields and options used by DHCP servers
+
+ Once the network address and lease have been determined, the server
+ constructs a DHCPOFFER message with the offered configuration
+ parameters. It is important for all DHCP servers to return the same
+ parameters (with the possible exception of a newly allocated network
+ address) to ensure predictable client behavior regardless of which
+ server the client selects. The configuration parameters MUST be
+ selected by applying the following rules in the order given below.
+ The network administrator is responsible for configuring multiple
+ DHCP servers to ensure uniform responses from those servers. The
+ server MUST return to the client:
+
+ o The client's network address, as determined by the rules given
+ earlier in this section,
+
+ o The expiration time for the client's lease, as determined by the
+ rules given earlier in this section,
+
+ o Parameters requested by the client, according to the following
+ rules:
+
+ -- IF the server has been explicitly configured with a default
+ value for the parameter, the server MUST include that value
+ in an appropriate option in the 'option' field, ELSE
+
+ -- IF the server recognizes the parameter as a parameter
+ defined in the Host Requirements Document, the server MUST
+ include the default value for that parameter as given in the
+ Host Requirements Document in an appropriate option in the
+ 'option' field, ELSE
+
+ -- The server MUST NOT return a value for that parameter,
+
+
+
+Droms Standards Track [Page 29]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ The server MUST supply as many of the requested parameters as
+ possible and MUST omit any parameters it cannot provide. The
+ server MUST include each requested parameter only once unless
+ explicitly allowed in the DHCP Options and BOOTP Vendor
+ Extensions document.
+
+ o Any parameters from the existing binding that differ from the Host
+ Requirements Document defaults,
+
+ o Any parameters specific to this client (as identified by
+ the contents of 'chaddr' or 'client identifier' in the DHCPDISCOVER
+ or DHCPREQUEST message), e.g., as configured by the network
+ administrator,
+
+ o Any parameters specific to this client's class (as identified
+ by the contents of the 'vendor class identifier'
+ option in the DHCPDISCOVER or DHCPREQUEST message),
+ e.g., as configured by the network administrator; the parameters
+ MUST be identified by an exact match between the client's vendor
+ class identifiers and the client's classes identified in the
+ server,
+
+ o Parameters with non-default values on the client's subnet.
+
+ The server MAY choose to return the 'vendor class identifier' used to
+ determine the parameters in the DHCPOFFER message to assist the
+ client in selecting which DHCPOFFER to accept. The server inserts
+ the 'xid' field from the DHCPDISCOVER message into the 'xid' field of
+ the DHCPOFFER message and sends the DHCPOFFER message to the
+ requesting client.
+
+4.3.2 DHCPREQUEST message
+
+ A DHCPREQUEST message may come from a client responding to a
+ DHCPOFFER message from a server, from a client verifying a previously
+ allocated IP address or from a client extending the lease on a
+ network address. If the DHCPREQUEST message contains a 'server
+ identifier' option, the message is in response to a DHCPOFFER
+ message. Otherwise, the message is a request to verify or extend an
+ existing lease. If the client uses a 'client identifier' in a
+ DHCPREQUEST message, it MUST use that same 'client identifier' in all
+ subsequent messages. If the client included a list of requested
+ parameters in a DHCPDISCOVER message, it MUST include that list in
+ all subsequent messages.
+
+
+
+
+
+
+
+Droms Standards Track [Page 30]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ Any configuration parameters in the DHCPACK message SHOULD NOT
+ conflict with those in the earlier DHCPOFFER message to which the
+ client is responding. The client SHOULD use the parameters in the
+ DHCPACK message for configuration.
+
+ Clients send DHCPREQUEST messages as follows:
+
+ o DHCPREQUEST generated during SELECTING state:
+
+ Client inserts the address of the selected server in 'server
+ identifier', 'ciaddr' MUST be zero, 'requested IP address' MUST be
+ filled in with the yiaddr value from the chosen DHCPOFFER.
+
+ Note that the client may choose to collect several DHCPOFFER
+ messages and select the "best" offer. The client indicates its
+ selection by identifying the offering server in the DHCPREQUEST
+ message. If the client receives no acceptable offers, the client
+ may choose to try another DHCPDISCOVER message. Therefore, the
+ servers may not receive a specific DHCPREQUEST from which they can
+ decide whether or not the client has accepted the offer. Because
+ the servers have not committed any network address assignments on
+ the basis of a DHCPOFFER, servers are free to reuse offered
+ network addresses in response to subsequent requests. As an
+ implementation detail, servers SHOULD NOT reuse offered addresses
+ and may use an implementation-specific timeout mechanism to decide
+ when to reuse an offered address.
+
+ o DHCPREQUEST generated during INIT-REBOOT state:
+
+ 'server identifier' MUST NOT be filled in, 'requested IP address'
+ option MUST be filled in with client's notion of its previously
+ assigned address. 'ciaddr' MUST be zero. The client is seeking to
+ verify a previously allocated, cached configuration. Server SHOULD
+ send a DHCPNAK message to the client if the 'requested IP address'
+ is incorrect, or is on the wrong network.
+
+ Determining whether a client in the INIT-REBOOT state is on the
+ correct network is done by examining the contents of 'giaddr', the
+ 'requested IP address' option, and a database lookup. If the DHCP
+ server detects that the client is on the wrong net (i.e., the
+ result of applying the local subnet mask or remote subnet mask (if
+ 'giaddr' is not zero) to 'requested IP address' option value
+ doesn't match reality), then the server SHOULD send a DHCPNAK
+ message to the client.
+
+
+
+
+
+
+
+Droms Standards Track [Page 31]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ If the network is correct, then the DHCP server should check if
+ the client's notion of its IP address is correct. If not, then the
+ server SHOULD send a DHCPNAK message to the client. If the DHCP
+ server has no record of this client, then it MUST remain silent,
+ and MAY output a warning to the network administrator. This
+ behavior is necessary for peaceful coexistence of non-
+ communicating DHCP servers on the same wire.
+
+ If 'giaddr' is 0x0 in the DHCPREQUEST message, the client is on
+ the same subnet as the server. The server MUST broadcast the
+ DHCPNAK message to the 0xffffffff broadcast address because the
+ client may not have a correct network address or subnet mask, and
+ the client may not be answering ARP requests.
+
+ If 'giaddr' is set in the DHCPREQUEST message, the client is on a
+ different subnet. The server MUST set the broadcast bit in the
+ DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
+ client, because the client may not have a correct network address
+ or subnet mask, and the client may not be answering ARP requests.
+
+ o DHCPREQUEST generated during RENEWING state:
+
+ 'server identifier' MUST NOT be filled in, 'requested IP address'
+ option MUST NOT be filled in, 'ciaddr' MUST be filled in with
+ client's IP address. In this situation, the client is completely
+ configured, and is trying to extend its lease. This message will
+ be unicast, so no relay agents will be involved in its
+ transmission. Because 'giaddr' is therefore not filled in, the
+ DHCP server will trust the value in 'ciaddr', and use it when
+ replying to the client.
+
+ A client MAY choose to renew or extend its lease prior to T1. The
+ server may choose not to extend the lease (as a policy decision by
+ the network administrator), but should return a DHCPACK message
+ regardless.
+
+ o DHCPREQUEST generated during REBINDING state:
+
+ 'server identifier' MUST NOT be filled in, 'requested IP address'
+ option MUST NOT be filled in, 'ciaddr' MUST be filled in with
+ client's IP address. In this situation, the client is completely
+ configured, and is trying to extend its lease. This message MUST
+ be broadcast to the 0xffffffff IP broadcast address. The DHCP
+ server SHOULD check 'ciaddr' for correctness before replying to
+ the DHCPREQUEST.
+
+
+
+
+
+
+Droms Standards Track [Page 32]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ The DHCPREQUEST from a REBINDING client is intended to accommodate
+ sites that have multiple DHCP servers and a mechanism for
+ maintaining consistency among leases managed by multiple servers.
+ A DHCP server MAY extend a client's lease only if it has local
+ administrative authority to do so.
+
+4.3.3 DHCPDECLINE message
+
+ If the server receives a DHCPDECLINE message, the client has
+ discovered through some other means that the suggested network
+ address is already in use. The server MUST mark the network address
+ as not available and SHOULD notify the local system administrator of
+ a possible configuration problem.
+
+4.3.4 DHCPRELEASE message
+
+ Upon receipt of a DHCPRELEASE message, the server marks the network
+ address as not allocated. The server SHOULD retain a record of the
+ client's initialization parameters for possible reuse in response to
+ subsequent requests from the client.
+
+4.3.5 DHCPINFORM message
+
+ The server responds to a DHCPINFORM message by sending a DHCPACK
+ message directly to the address given in the 'ciaddr' field of the
+ DHCPINFORM message. The server MUST NOT send a lease expiration time
+ to the client and SHOULD NOT fill in 'yiaddr'. The server includes
+ other parameters in the DHCPACK message as defined in section 4.3.1.
+
+4.3.6 Client messages
+
+ Table 4 details the differences between messages from clients in
+ various states.
+
+ ---------------------------------------------------------------------
+ | |INIT-REBOOT |SELECTING |RENEWING |REBINDING |
+ ---------------------------------------------------------------------
+ |broad/unicast |broadcast |broadcast |unicast |broadcast |
+ |server-ip |MUST NOT |MUST |MUST NOT |MUST NOT |
+ |requested-ip |MUST |MUST |MUST NOT |MUST NOT |
+ |ciaddr |zero |zero |IP address |IP address|
+ ---------------------------------------------------------------------
+
+ Table 4: Client messages from different states
+
+
+
+
+
+
+
+Droms Standards Track [Page 33]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+4.4 DHCP client behavior
+
+ Figure 5 gives a state-transition diagram for a DHCP client. A
+ client can receive the following messages from a server:
+
+ o DHCPOFFER
+
+ o DHCPACK
+
+ o DHCPNAK
+
+ The DHCPINFORM message is not shown in figure 5. A client simply
+ sends the DHCPINFORM and waits for DHCPACK messages. Once the client
+ has selected its parameters, it has completed the configuration
+ process.
+
+ Table 5 gives the use of the fields and options in a DHCP message by
+ a client. The remainder of this section describes the action of the
+ DHCP client for each possible incoming message. The description in
+ the following section corresponds to the full configuration procedure
+ previously described in section 3.1, and the text in the subsequent
+ section corresponds to the abbreviated configuration procedure
+ described in section 3.2.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Droms Standards Track [Page 34]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ -------- -------
+| | +-------------------------->| |<-------------------+
+| INIT- | | +-------------------->| INIT | |
+| REBOOT |DHCPNAK/ +---------->| |<---+ |
+| |Restart| | ------- | |
+ -------- | DHCPNAK/ | | |
+ | Discard offer | -/Send DHCPDISCOVER |
+-/Send DHCPREQUEST | | |
+ | | | DHCPACK v | |
+ ----------- | (not accept.)/ ----------- | |
+| | | Send DHCPDECLINE | | |
+| REBOOTING | | | | SELECTING |<----+ |
+| | | / | | |DHCPOFFER/ |
+ ----------- | / ----------- | |Collect |
+ | | / | | | replies |
+DHCPACK/ | / +----------------+ +-------+ |
+Record lease, set| | v Select offer/ |
+timers T1, T2 ------------ send DHCPREQUEST | |
+ | +----->| | DHCPNAK, Lease expired/ |
+ | | | REQUESTING | Halt network |
+ DHCPOFFER/ | | | |
+ Discard ------------ | |
+ | | | | ----------- |
+ | +--------+ DHCPACK/ | | |
+ | Record lease, set -----| REBINDING | |
+ | timers T1, T2 / | | |
+ | | DHCPACK/ ----------- |
+ | v Record lease, set ^ |
+ +----------------> ------- /timers T1,T2 | |
+ +----->| |<---+ | |
+ | | BOUND |<---+ | |
+ DHCPOFFER, DHCPACK, | | | T2 expires/ DHCPNAK/
+ DHCPNAK/Discard ------- | Broadcast Halt network
+ | | | | DHCPREQUEST |
+ +-------+ | DHCPACK/ | |
+ T1 expires/ Record lease, set | |
+ Send DHCPREQUEST timers T1, T2 | |
+ to leasing server | | |
+ | ---------- | |
+ | | |------------+ |
+ +->| RENEWING | |
+ | |----------------------------+
+ ----------
+ Figure 5: State-transition diagram for DHCP clients
+
+
+
+
+
+
+
+Droms Standards Track [Page 35]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+4.4.1 Initialization and allocation of network address
+
+ The client begins in INIT state and forms a DHCPDISCOVER message.
+ The client SHOULD wait a random time between one and ten seconds to
+ desynchronize the use of DHCP at startup. The client sets 'ciaddr'
+ to 0x00000000. The client MAY request specific parameters by
+ including the 'parameter request list' option. The client MAY
+ suggest a network address and/or lease time by including the
+ 'requested IP address' and 'IP address lease time' options. The
+ client MUST include its hardware address in the 'chaddr' field, if
+ necessary for delivery of DHCP reply messages. The client MAY
+ include a different unique identifier in the 'client identifier'
+ option, as discussed in section 4.2. If the client included a list
+ of requested parameters in a DHCPDISCOVER message, it MUST include
+ that list in all subsequent messages.
+
+ The client generates and records a random transaction identifier and
+ inserts that identifier into the 'xid' field. The client records its
+ own local time for later use in computing the lease expiration. The
+ client then broadcasts the DHCPDISCOVER on the local hardware
+ broadcast address to the 0xffffffff IP broadcast address and 'DHCP
+ server' UDP port.
+
+ If the 'xid' of an arriving DHCPOFFER message does not match the
+ 'xid' of the most recent DHCPDISCOVER message, the DHCPOFFER message
+ must be silently discarded. Any arriving DHCPACK messages must be
+ silently discarded.
+
+ The client collects DHCPOFFER messages over a period of time, selects
+ one DHCPOFFER message from the (possibly many) incoming DHCPOFFER
+ messages (e.g., the first DHCPOFFER message or the DHCPOFFER message
+ from the previously used server) and extracts the server address from
+ the 'server identifier' option in the DHCPOFFER message. The time
+ over which the client collects messages and the mechanism used to
+ select one DHCPOFFER are implementation dependent.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Droms Standards Track [Page 36]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+Field DHCPDISCOVER DHCPREQUEST DHCPDECLINE,
+ DHCPINFORM DHCPRELEASE
+----- ------------ ----------- -----------
+'op' BOOTREQUEST BOOTREQUEST BOOTREQUEST
+'htype' (From "Assigned Numbers" RFC)
+'hlen' (Hardware address length in octets)
+'hops' 0 0 0
+'xid' selected by client 'xid' from server selected by
+ DHCPOFFER message client
+'secs' 0 or seconds since 0 or seconds since 0
+ DHCP process started DHCP process started
+'flags' Set 'BROADCAST' Set 'BROADCAST' 0
+ flag if client flag if client
+ requires broadcast requires broadcast
+ reply reply
+'ciaddr' 0 (DHCPDISCOVER) 0 or client's 0 (DHCPDECLINE)
+ client's network address client's network
+ network address (BOUND/RENEW/REBIND) address
+ (DHCPINFORM) (DHCPRELEASE)
+'yiaddr' 0 0 0
+'siaddr' 0 0 0
+'giaddr' 0 0 0
+'chaddr' client's hardware client's hardware client's hardware
+ address address address
+'sname' options, if options, if (unused)
+ indicated in indicated in
+ 'sname/file' 'sname/file'
+ option; otherwise option; otherwise
+ unused unused
+'file' options, if options, if (unused)
+ indicated in indicated in
+ 'sname/file' 'sname/file'
+ option; otherwise option; otherwise
+ unused unused
+'options' options options (unused)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Droms Standards Track [Page 37]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+Option DHCPDISCOVER DHCPREQUEST DHCPDECLINE,
+ DHCPINFORM DHCPRELEASE
+------ ------------ ----------- -----------
+Requested IP address MAY MUST (in MUST
+ (DISCOVER) SELECTING or (DHCPDECLINE),
+ MUST NOT INIT-REBOOT) MUST NOT
+ (INFORM) MUST NOT (in (DHCPRELEASE)
+ BOUND or
+ RENEWING)
+IP address lease time MAY MAY MUST NOT
+ (DISCOVER)
+ MUST NOT
+ (INFORM)
+Use 'file'/'sname' fields MAY MAY MAY
+DHCP message type DHCPDISCOVER/ DHCPREQUEST DHCPDECLINE/
+ DHCPINFORM DHCPRELEASE
+Client identifier MAY MAY MAY
+Vendor class identifier MAY MAY MUST NOT
+Server identifier MUST NOT MUST (after MUST
+ SELECTING)
+ MUST NOT (after
+ INIT-REBOOT,
+ BOUND, RENEWING
+ or REBINDING)
+Parameter request list MAY MAY MUST NOT
+Maximum message size MAY MAY MUST NOT
+Message SHOULD NOT SHOULD NOT SHOULD
+Site-specific MAY MAY MUST NOT
+All others MAY MAY MUST NOT
+
+ Table 5: Fields and options used by DHCP clients
+
+ If the parameters are acceptable, the client records the address of
+ the server that supplied the parameters from the 'server identifier'
+ field and sends that address in the 'server identifier' field of a
+ DHCPREQUEST broadcast message. Once the DHCPACK message from the
+ server arrives, the client is initialized and moves to BOUND state.
+ The DHCPREQUEST message contains the same 'xid' as the DHCPOFFER
+ message. The client records the lease expiration time as the sum of
+ the time at which the original request was sent and the duration of
+ the lease from the DHCPACK message. The client SHOULD perform a
+ check on the suggested address to ensure that the address is not
+ already in use. For example, if the client is on a network that
+ supports ARP, the client may issue an ARP request for the suggested
+ request. When broadcasting an ARP request for the suggested address,
+ the client must fill in its own hardware address as the sender's
+ hardware address, and 0 as the sender's IP address, to avoid
+ confusing ARP caches in other hosts on the same subnet. If the
+
+
+
+Droms Standards Track [Page 38]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ network address appears to be in use, the client MUST send a
+ DHCPDECLINE message to the server. The client SHOULD broadcast an ARP
+ reply to announce the client's new IP address and clear any outdated
+ ARP cache entries in hosts on the client's subnet.
+
+4.4.2 Initialization with known network address
+
+ The client begins in INIT-REBOOT state and sends a DHCPREQUEST
+ message. The client MUST insert its known network address as a
+ 'requested IP address' option in the DHCPREQUEST message. The client
+ may request specific configuration parameters by including the
+ 'parameter request list' option. The client generates and records a
+ random transaction identifier and inserts that identifier into the
+ 'xid' field. The client records its own local time for later use in
+ computing the lease expiration. The client MUST NOT include a
+ 'server identifier' in the DHCPREQUEST message. The client then
+ broadcasts the DHCPREQUEST on the local hardware broadcast address to
+ the 'DHCP server' UDP port.
+
+ Once a DHCPACK message with an 'xid' field matching that in the
+ client's DHCPREQUEST message arrives from any server, the client is
+ initialized and moves to BOUND state. The client records the lease
+ expiration time as the sum of the time at which the DHCPREQUEST
+ message was sent and the duration of the lease from the DHCPACK
+ message.
+
+4.4.3 Initialization with an externally assigned network address
+
+ The client sends a DHCPINFORM message. The client may request
+ specific configuration parameters by including the 'parameter request
+ list' option. The client generates and records a random transaction
+ identifier and inserts that identifier into the 'xid' field. The
+ client places its own network address in the 'ciaddr' field. The
+ client SHOULD NOT request lease time parameters.
+
+ The client then unicasts the DHCPINFORM to the DHCP server if it
+ knows the server's address, otherwise it broadcasts the message to
+ the limited (all 1s) broadcast address. DHCPINFORM messages MUST be
+ directed to the 'DHCP server' UDP port.
+
+ Once a DHCPACK message with an 'xid' field matching that in the
+ client's DHCPINFORM message arrives from any server, the client is
+ initialized.
+
+ If the client does not receive a DHCPACK within a reasonable period
+ of time (60 seconds or 4 tries if using timeout suggested in section
+ 4.1), then it SHOULD display a message informing the user of the
+ problem, and then SHOULD begin network processing using suitable
+
+
+
+Droms Standards Track [Page 39]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ defaults as per Appendix A.
+
+4.4.4 Use of broadcast and unicast
+
+ The DHCP client broadcasts DHCPDISCOVER, DHCPREQUEST and DHCPINFORM
+ messages, unless the client knows the address of a DHCP server. The
+ client unicasts DHCPRELEASE messages to the server. Because the
+ client is declining the use of the IP address supplied by the server,
+ the client broadcasts DHCPDECLINE messages.
+
+ When the DHCP client knows the address of a DHCP server, in either
+ INIT or REBOOTING state, the client may use that address in the
+ DHCPDISCOVER or DHCPREQUEST rather than the IP broadcast address.
+ The client may also use unicast to send DHCPINFORM messages to a
+ known DHCP server. If the client receives no response to DHCP
+ messages sent to the IP address of a known DHCP server, the DHCP
+ client reverts to using the IP broadcast address.
+
+4.4.5 Reacquisition and expiration
+
+ The client maintains two times, T1 and T2, that specify the times at
+ which the client tries to extend its lease on its network address.
+ T1 is the time at which the client enters the RENEWING state and
+ attempts to contact the server that originally issued the client's
+ network address. T2 is the time at which the client enters the
+ REBINDING state and attempts to contact any server. T1 MUST be
+ earlier than T2, which, in turn, MUST be earlier than the time at
+ which the client's lease will expire.
+
+ To avoid the need for synchronized clocks, T1 and T2 are expressed in
+ options as relative times [2].
+
+ At time T1 the client moves to RENEWING state and sends (via unicast)
+ a DHCPREQUEST message to the server to extend its lease. The client
+ sets the 'ciaddr' field in the DHCPREQUEST to its current network
+ address. The client records the local time at which the DHCPREQUEST
+ message is sent for computation of the lease expiration time. The
+ client MUST NOT include a 'server identifier' in the DHCPREQUEST
+ message.
+
+ Any DHCPACK messages that arrive with an 'xid' that does not match
+ the 'xid' of the client's DHCPREQUEST message are silently discarded.
+ When the client receives a DHCPACK from the server, the client
+ computes the lease expiration time as the sum of the time at which
+ the client sent the DHCPREQUEST message and the duration of the lease
+ in the DHCPACK message. The client has successfully reacquired its
+ network address, returns to BOUND state and may continue network
+ processing.
+
+
+
+Droms Standards Track [Page 40]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ If no DHCPACK arrives before time T2, the client moves to REBINDING
+ state and sends (via broadcast) a DHCPREQUEST message to extend its
+ lease. The client sets the 'ciaddr' field in the DHCPREQUEST to its
+ current network address. The client MUST NOT include a 'server
+ identifier' in the DHCPREQUEST message.
+
+ Times T1 and T2 are configurable by the server through options. T1
+ defaults to (0.5 * duration_of_lease). T2 defaults to (0.875 *
+ duration_of_lease). Times T1 and T2 SHOULD be chosen with some
+ random "fuzz" around a fixed value, to avoid synchronization of
+ client reacquisition.
+
+ A client MAY choose to renew or extend its lease prior to T1. The
+ server MAY choose to extend the client's lease according to policy
+ set by the network administrator. The server SHOULD return T1 and
+ T2, and their values SHOULD be adjusted from their original values to
+ take account of the time remaining on the lease.
+
+ In both RENEWING and REBINDING states, if the client receives no
+ response to its DHCPREQUEST message, the client SHOULD wait one-half
+ of the remaining time until T2 (in RENEWING state) and one-half of
+ the remaining lease time (in REBINDING state), down to a minimum of
+ 60 seconds, before retransmitting the DHCPREQUEST message.
+
+ If the lease expires before the client receives a DHCPACK, the client
+ moves to INIT state, MUST immediately stop any other network
+ processing and requests network initialization parameters as if the
+ client were uninitialized. If the client then receives a DHCPACK
+ allocating that client its previous network address, the client
+ SHOULD continue network processing. If the client is given a new
+ network address, it MUST NOT continue using the previous network
+ address and SHOULD notify the local users of the problem.
+
+4.4.6 DHCPRELEASE
+
+ If the client no longer requires use of its assigned network address
+ (e.g., the client is gracefully shut down), the client sends a
+ DHCPRELEASE message to the server. Note that the correct operation
+ of DHCP does not depend on the transmission of DHCPRELEASE messages.
+
+
+
+
+
+
+
+
+
+
+
+
+Droms Standards Track [Page 41]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+5. Acknowledgments
+
+ The author thanks the many (and too numerous to mention!) members of
+ the DHC WG for their tireless and ongoing efforts in the development
+ of DHCP and this document.
+
+ The efforts of J Allard, Mike Carney, Dave Lapp, Fred Lien and John
+ Mendonca in organizing DHCP interoperability testing sessions are
+ gratefully acknowledged.
+
+ The development of this document was supported in part by grants from
+ the Corporation for National Research Initiatives (CNRI), Bucknell
+ University and Sun Microsystems.
+
+6. References
+
+ [1] Acetta, M., "Resource Location Protocol", RFC 887, CMU, December
+ 1983.
+
+ [2] Alexander, S., and R. Droms, "DHCP Options and BOOTP Vendor
+ Extensions", RFC 1533, Lachman Technology, Inc., Bucknell
+ University, October 1993.
+
+ [3] Braden, R., Editor, "Requirements for Internet Hosts --
+ Communication Layers", STD 3, RFC 1122, USC/Information Sciences
+ Institute, October 1989.
+
+ [4] Braden, R., Editor, "Requirements for Internet Hosts --
+ Application and Support, STD 3, RFC 1123, USC/Information
+ Sciences Institute, October 1989.
+
+ [5] Brownell, D, "Dynamic Reverse Address Resolution Protocol
+ (DRARP)", Work in Progress.
+
+ [6] Comer, D., and R. Droms, "Uniform Access to Internet Directory
+ Services", Proc. of ACM SIGCOMM '90 (Special issue of Computer
+ Communications Review), 20(4):50--59, 1990.
+
+ [7] Croft, B., and J. Gilmore, "Bootstrap Protocol (BOOTP)", RFC 951,
+ Stanford and SUN Microsystems, September 1985.
+
+ [8] Deering, S., "ICMP Router Discovery Messages", RFC 1256, Xerox
+ PARC, September 1991.
+
+ [9] Droms, D., "Interoperation between DHCP and BOOTP", RFC 1534,
+ Bucknell University, October 1993.
+
+
+
+
+
+Droms Standards Track [Page 42]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ [10] Finlayson, R., Mann, T., Mogul, J., and M. Theimer, "A Reverse
+ Address Resolution Protocol", RFC 903, Stanford, June 1984.
+
+ [11] Gray C., and D. Cheriton, "Leases: An Efficient Fault-Tolerant
+ Mechanism for Distributed File Cache Consistency", In Proc. of
+ the Twelfth ACM Symposium on Operating Systems Design, 1989.
+
+ [12] Mockapetris, P., "Domain Names -- Concepts and Facilities", STD
+ 13, RFC 1034, USC/Information Sciences Institute, November 1987.
+
+ [13] Mockapetris, P., "Domain Names -- Implementation and
+ Specification", STD 13, RFC 1035, USC/Information Sciences
+ Institute, November 1987.
+
+ [14] Mogul J., and S. Deering, "Path MTU Discovery", RFC 1191,
+ November 1990.
+
+ [15] Morgan, R., "Dynamic IP Address Assignment for Ethernet Attached
+ Hosts", Work in Progress.
+
+ [16] Postel, J., "Internet Control Message Protocol", STD 5, RFC 792,
+ USC/Information Sciences Institute, September 1981.
+
+ [17] Reynolds, J., "BOOTP Vendor Information Extensions", RFC 1497,
+ USC/Information Sciences Institute, August 1993.
+
+ [18] Reynolds, J., and J. Postel, "Assigned Numbers", STD 2, RFC 1700,
+ USC/Information Sciences Institute, October 1994.
+
+ [19] Jeffrey Schiller and Mark Rosenstein. A Protocol for the Dynamic
+ Assignment of IP Addresses for use on an Ethernet. (Available
+ from the Athena Project, MIT), 1989.
+
+ [20] Sollins, K., "The TFTP Protocol (Revision 2)", RFC 783, NIC,
+ June 1981.
+
+ [21] Wimer, W., "Clarifications and Extensions for the Bootstrap
+ Protocol", RFC 1542, Carnegie Mellon University, October 1993.
+
+7. Security Considerations
+
+ DHCP is built directly on UDP and IP which are as yet inherently
+ insecure. Furthermore, DHCP is generally intended to make
+ maintenance of remote and/or diskless hosts easier. While perhaps
+ not impossible, configuring such hosts with passwords or keys may be
+ difficult and inconvenient. Therefore, DHCP in its current form is
+ quite insecure.
+
+
+
+
+Droms Standards Track [Page 43]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+ Unauthorized DHCP servers may be easily set up. Such servers can
+ then send false and potentially disruptive information to clients
+ such as incorrect or duplicate IP addresses, incorrect routing
+ information (including spoof routers, etc.), incorrect domain
+ nameserver addresses (such as spoof nameservers), and so on.
+ Clearly, once this seed information is in place, an attacker can
+ further compromise affected systems.
+
+ Malicious DHCP clients could masquerade as legitimate clients and
+ retrieve information intended for those legitimate clients. Where
+ dynamic allocation of resources is used, a malicious client could
+ claim all resources for itself, thereby denying resources to
+ legitimate clients.
+
+8. Author's Address
+
+ Ralph Droms
+ Computer Science Department
+ 323 Dana Engineering
+ Bucknell University
+ Lewisburg, PA 17837
+
+ Phone: (717) 524-1145
+ EMail: droms@bucknell.edu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Droms Standards Track [Page 44]
+\f
+RFC 2131 Dynamic Host Configuration Protocol March 1997
+
+
+A. Host Configuration Parameters
+
+ IP-layer_parameters,_per_host:_
+
+ Be a router on/off HRC 3.1
+ Non-local source routing on/off HRC 3.3.5
+ Policy filters for
+ non-local source routing (list) HRC 3.3.5
+ Maximum reassembly size integer HRC 3.3.2
+ Default TTL integer HRC 3.2.1.7
+ PMTU aging timeout integer MTU 6.6
+ MTU plateau table (list) MTU 7
+ IP-layer_parameters,_per_interface:_
+ IP address (address) HRC 3.3.1.6
+ Subnet mask (address mask) HRC 3.3.1.6
+ MTU integer HRC 3.3.3
+ All-subnets-MTU on/off HRC 3.3.3
+ Broadcast address flavor 0x00000000/0xffffffff HRC 3.3.6
+ Perform mask discovery on/off HRC 3.2.2.9
+ Be a mask supplier on/off HRC 3.2.2.9
+ Perform router discovery on/off RD 5.1
+ Router solicitation address (address) RD 5.1
+ Default routers, list of:
+ router address (address) HRC 3.3.1.6
+ preference level integer HRC 3.3.1.6
+ Static routes, list of:
+ destination (host/subnet/net) HRC 3.3.1.2
+ destination mask (address mask) HRC 3.3.1.2
+ type-of-service integer HRC 3.3.1.2
+ first-hop router (address) HRC 3.3.1.2
+ ignore redirects on/off HRC 3.3.1.2
+ PMTU integer MTU 6.6
+ perform PMTU discovery on/off MTU 6.6
+
+ Link-layer_parameters,_per_interface:_
+ Trailers on/off HRC 2.3.1
+ ARP cache timeout integer HRC 2.3.2.1
+ Ethernet encapsulation (RFC 894/RFC 1042) HRC 2.3.3
+
+ TCP_parameters,_per_host:_
+ TTL integer HRC 4.2.2.19
+ Keep-alive interval integer HRC 4.2.3.6
+ Keep-alive data size 0/1 HRC 4.2.3.6
+
+Key:
+
+ MTU = Path MTU Discovery (RFC 1191, Proposed Standard)
+ RD = Router Discovery (RFC 1256, Proposed Standard)
+
+
+
+Droms Standards Track [Page 45]
+\f
--- /dev/null
+
+
+
+
+
+
+Network Working Group S. Alexander
+Request for Comments: 2132 Silicon Graphics, Inc.
+Obsoletes: 1533 R. Droms
+Category: Standards Track Bucknell University
+ March 1997
+
+ DHCP Options and BOOTP Vendor Extensions
+
+Status of this memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Abstract
+
+ The Dynamic Host Configuration Protocol (DHCP) [1] provides a
+ framework for passing configuration information to hosts on a TCP/IP
+ network. Configuration parameters and other control information are
+ carried in tagged data items that are stored in the 'options' field
+ of the DHCP message. The data items themselves are also called
+ "options."
+
+ This document specifies the current set of DHCP options. Future
+ options will be specified in separate RFCs. The current list of
+ valid options is also available in ftp://ftp.isi.edu/in-
+ notes/iana/assignments [22].
+
+ All of the vendor information extensions defined in RFC 1497 [2] may
+ be used as DHCP options. The definitions given in RFC 1497 are
+ included in this document, which supersedes RFC 1497. All of the
+ DHCP options defined in this document, except for those specific to
+ DHCP as defined in section 9, may be used as BOOTP vendor information
+ extensions.
+
+Table of Contents
+
+ 1. Introduction .............................................. 2
+ 2. BOOTP Extension/DHCP Option Field Format .................. 4
+ 3. RFC 1497 Vendor Extensions ................................ 5
+ 4. IP Layer Parameters per Host .............................. 11
+ 5. IP Layer Parameters per Interface ........................ 13
+ 6. Link Layer Parameters per Interface ....................... 16
+ 7. TCP Parameters ............................................ 17
+ 8. Application and Service Parameters ........................ 18
+ 9. DHCP Extensions ........................................... 25
+
+
+
+Alexander & Droms Standards Track [Page 1]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ 10. Defining new extensions ................................... 31
+ 11. Acknowledgements .......................................... 31
+ 12. References ................................................ 32
+ 13. Security Considerations ................................... 33
+ 14. Authors' Addresses ........................................ 34
+
+1. Introduction
+
+ This document specifies options for use with both the Dynamic Host
+ Configuration Protocol and the Bootstrap Protocol.
+
+ The full description of DHCP packet formats may be found in the DHCP
+ specification document [1], and the full description of BOOTP packet
+ formats may be found in the BOOTP specification document [3]. This
+ document defines the format of information in the last field of DHCP
+ packets ('options') and of BOOTP packets ('vend'). The remainder of
+ this section defines a generalized use of this area for giving
+ information useful to a wide class of machines, operating systems and
+ configurations. Sites with a single DHCP or BOOTP server that is
+ shared among heterogeneous clients may choose to define other, site-
+ specific formats for the use of the 'options' field.
+
+ Section 2 of this memo describes the formats of DHCP options and
+ BOOTP vendor extensions. Section 3 describes options defined in
+ previous documents for use with BOOTP (all may also be used with
+ DHCP). Sections 4-8 define new options intended for use with both
+ DHCP and BOOTP. Section 9 defines options used only in DHCP.
+
+ References further describing most of the options defined in sections
+ 2-6 can be found in section 12. The use of the options defined in
+ section 9 is described in the DHCP specification [1].
+
+ Information on registering new options is contained in section 10.
+
+ This document updates the definition of DHCP/BOOTP options that
+ appears in RFC1533. The classing mechanism has been extended to
+ include vendor classes as described in section 8.4 and 9.13. The new
+ procedure for defining new DHCP/BOOTP options in described in section
+ 10. Several new options, including NIS+ domain and servers, Mobile
+ IP home agent, SMTP server, TFTP server and Bootfile server, have
+ been added. Text giving definitions used throughout the document has
+ been added in section 1.1. Text emphasizing the need for uniqueness
+ of client-identifiers has been added to section 9.14.
+
+
+
+
+
+
+
+
+Alexander & Droms Standards Track [Page 2]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+1.1 Requirements
+
+ Throughout this document, the words that are used to define the
+ significance of particular requirements are capitalized. These words
+ are:
+
+ o "MUST"
+
+ This word or the adjective "REQUIRED" means that the item is an
+ absolute requirement of this specification.
+
+ o "MUST NOT"
+
+ This phrase means that the item is an absolute prohibition of
+ this specification.
+
+ o "SHOULD"
+
+ This word or the adjective "RECOMMENDED" means that there may
+ exist valid reasons in particular circumstances to ignore this
+ item, but the full implications should be understood and the case
+ carefully weighed before choosing a different course.
+
+ o "SHOULD NOT"
+
+ This phrase means that there may exist valid reasons in
+ particular circumstances when the listed behavior is acceptable
+ or even useful, but the full implications should be understood
+ and the case carefully weighed before implementing any behavior
+ described with this label.
+
+ o "MAY"
+
+ This word or the adjective "OPTIONAL" means that this item is
+ truly optional. One vendor may choose to include the item
+ because a particular marketplace requires it or because it
+ enhances the product, for example; another vendor may omit the
+ same item.
+
+1.2 Terminology
+
+ This document uses the following terms:
+
+ o "DHCP client"
+
+ A DHCP client or "client" is an Internet host using DHCP to
+ obtain configuration parameters such as a network address.
+
+
+
+
+Alexander & Droms Standards Track [Page 3]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ o "DHCP server"
+
+ A DHCP server of "server"is an Internet host that returns
+ configuration parameters to DHCP clients.
+
+ o "binding"
+
+ A binding is a collection of configuration parameters, including
+ at least an IP address, associated with or "bound to" a DHCP
+ client. Bindings are managed by DHCP servers.
+
+2. BOOTP Extension/DHCP Option Field Format
+
+
+ DHCP options have the same format as the BOOTP 'vendor extensions'
+ defined in RFC 1497 [2]. Options may be fixed length or variable
+ length. All options begin with a tag octet, which uniquely
+ identifies the option. Fixed-length options without data consist of
+ only a tag octet. Only options 0 and 255 are fixed length. All
+ other options are variable-length with a length octet following the
+ tag octet. The value of the length octet does not include the two
+ octets specifying the tag and length. The length octet is followed
+ by "length" octets of data. Options containing NVT ASCII data SHOULD
+ NOT include a trailing NULL; however, the receiver of such options
+ MUST be prepared to delete trailing nulls if they exist. The
+ receiver MUST NOT require that a trailing null be included in the
+ data. In the case of some variable-length options the length field
+ is a constant but must still be specified.
+
+ Any options defined subsequent to this document MUST contain a length
+ octet even if the length is fixed or zero.
+
+ All multi-octet quantities are in network byte-order.
+
+ When used with BOOTP, the first four octets of the vendor information
+ field have been assigned to the "magic cookie" (as suggested in RFC
+ 951). This field identifies the mode in which the succeeding data is
+ to be interpreted. The value of the magic cookie is the 4 octet
+ dotted decimal 99.130.83.99 (or hexadecimal number 63.82.53.63) in
+ network byte order.
+
+ All of the "vendor extensions" defined in RFC 1497 are also DHCP
+ options.
+
+ Option codes 128 to 254 (decimal) are reserved for site-specific
+ options.
+
+
+
+
+
+Alexander & Droms Standards Track [Page 4]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ Except for the options in section 9, all options may be used with
+ either DHCP or BOOTP.
+
+ Many of these options have their default values specified in other
+ documents. In particular, RFC 1122 [4] specifies default values for
+ most IP and TCP configuration parameters.
+
+ Many options supply one or more 32-bit IP address. Use of IP
+ addresses rather than fully-qualified Domain Names (FQDNs) may make
+ future renumbering of IP hosts more difficult. Use of these
+ addresses is discouraged at sites that may require renumbering.
+
+3. RFC 1497 Vendor Extensions
+
+ This section lists the vendor extensions as defined in RFC 1497.
+ They are defined here for completeness.
+
+3.1. Pad Option
+
+ The pad option can be used to cause subsequent fields to align on
+ word boundaries.
+
+ The code for the pad option is 0, and its length is 1 octet.
+
+ Code
+ +-----+
+ | 0 |
+ +-----+
+
+3.2. End Option
+
+ The end option marks the end of valid information in the vendor
+ field. Subsequent octets should be filled with pad options.
+
+ The code for the end option is 255, and its length is 1 octet.
+
+ Code
+ +-----+
+ | 255 |
+ +-----+
+
+3.3. Subnet Mask
+
+ The subnet mask option specifies the client's subnet mask as per RFC
+ 950 [5].
+
+ If both the subnet mask and the router option are specified in a DHCP
+ reply, the subnet mask option MUST be first.
+
+
+
+Alexander & Droms Standards Track [Page 5]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ The code for the subnet mask option is 1, and its length is 4 octets.
+
+ Code Len Subnet Mask
+ +-----+-----+-----+-----+-----+-----+
+ | 1 | 4 | m1 | m2 | m3 | m4 |
+ +-----+-----+-----+-----+-----+-----+
+
+3.4. Time Offset
+
+ The time offset field specifies the offset of the client's subnet in
+ seconds from Coordinated Universal Time (UTC). The offset is
+ expressed as a two's complement 32-bit integer. A positive offset
+ indicates a location east of the zero meridian and a negative offset
+ indicates a location west of the zero meridian.
+
+ The code for the time offset option is 2, and its length is 4 octets.
+
+ Code Len Time Offset
+ +-----+-----+-----+-----+-----+-----+
+ | 2 | 4 | n1 | n2 | n3 | n4 |
+ +-----+-----+-----+-----+-----+-----+
+
+3.5. Router Option
+
+ The router option specifies a list of IP addresses for routers on the
+ client's subnet. Routers SHOULD be listed in order of preference.
+
+ The code for the router option is 3. The minimum length for the
+ router option is 4 octets, and the length MUST always be a multiple
+ of 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 3 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+3.6. Time Server Option
+
+ The time server option specifies a list of RFC 868 [6] time servers
+ available to the client. Servers SHOULD be listed in order of
+ preference.
+
+ The code for the time server option is 4. The minimum length for
+ this option is 4 octets, and the length MUST always be a multiple of
+ 4.
+
+
+
+
+
+
+Alexander & Droms Standards Track [Page 6]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 4 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+3.7. Name Server Option
+
+ The name server option specifies a list of IEN 116 [7] name servers
+ available to the client. Servers SHOULD be listed in order of
+ preference.
+
+ The code for the name server option is 5. The minimum length for
+ this option is 4 octets, and the length MUST always be a multiple of
+ 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 5 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+3.8. Domain Name Server Option
+
+ The domain name server option specifies a list of Domain Name System
+ (STD 13, RFC 1035 [8]) name servers available to the client. Servers
+ SHOULD be listed in order of preference.
+
+ The code for the domain name server option is 6. The minimum length
+ for this option is 4 octets, and the length MUST always be a multiple
+ of 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 6 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+3.9. Log Server Option
+
+ The log server option specifies a list of MIT-LCS UDP log servers
+ available to the client. Servers SHOULD be listed in order of
+ preference.
+
+ The code for the log server option is 7. The minimum length for this
+ option is 4 octets, and the length MUST always be a multiple of 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 7 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+
+
+Alexander & Droms Standards Track [Page 7]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+3.10. Cookie Server Option
+
+ The cookie server option specifies a list of RFC 865 [9] cookie
+ servers available to the client. Servers SHOULD be listed in order
+ of preference.
+
+ The code for the log server option is 8. The minimum length for this
+ option is 4 octets, and the length MUST always be a multiple of 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 8 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+3.11. LPR Server Option
+
+ The LPR server option specifies a list of RFC 1179 [10] line printer
+ servers available to the client. Servers SHOULD be listed in order
+ of preference.
+
+ The code for the LPR server option is 9. The minimum length for this
+ option is 4 octets, and the length MUST always be a multiple of 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 9 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+3.12. Impress Server Option
+
+ The Impress server option specifies a list of Imagen Impress servers
+ available to the client. Servers SHOULD be listed in order of
+ preference.
+
+ The code for the Impress server option is 10. The minimum length for
+ this option is 4 octets, and the length MUST always be a multiple of
+ 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 10 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+3.13. Resource Location Server Option
+
+ This option specifies a list of RFC 887 [11] Resource Location
+ servers available to the client. Servers SHOULD be listed in order
+ of preference.
+
+
+
+Alexander & Droms Standards Track [Page 8]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ The code for this option is 11. The minimum length for this option
+ is 4 octets, and the length MUST always be a multiple of 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 11 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+3.14. Host Name Option
+
+ This option specifies the name of the client. The name may or may
+ not be qualified with the local domain name (see section 3.17 for the
+ preferred way to retrieve the domain name). See RFC 1035 for
+ character set restrictions.
+
+ The code for this option is 12, and its minimum length is 1.
+
+ Code Len Host Name
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 12 | n | h1 | h2 | h3 | h4 | h5 | h6 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+3.15. Boot File Size Option
+
+ This option specifies the length in 512-octet blocks of the default
+ boot image for the client. The file length is specified as an
+ unsigned 16-bit integer.
+
+ The code for this option is 13, and its length is 2.
+
+ Code Len File Size
+ +-----+-----+-----+-----+
+ | 13 | 2 | l1 | l2 |
+ +-----+-----+-----+-----+
+
+3.16. Merit Dump File
+
+ This option specifies the path-name of a file to which the client's
+ core image should be dumped in the event the client crashes. The
+ path is formatted as a character string consisting of characters from
+ the NVT ASCII character set.
+
+ The code for this option is 14. Its minimum length is 1.
+
+ Code Len Dump File Pathname
+ +-----+-----+-----+-----+-----+-----+---
+ | 14 | n | n1 | n2 | n3 | n4 | ...
+ +-----+-----+-----+-----+-----+-----+---
+
+
+
+Alexander & Droms Standards Track [Page 9]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+3.17. Domain Name
+
+ This option specifies the domain name that client should use when
+ resolving hostnames via the Domain Name System.
+
+ The code for this option is 15. Its minimum length is 1.
+
+ Code Len Domain Name
+ +-----+-----+-----+-----+-----+-----+--
+ | 15 | n | d1 | d2 | d3 | d4 | ...
+ +-----+-----+-----+-----+-----+-----+--
+
+3.18. Swap Server
+
+ This specifies the IP address of the client's swap server.
+
+ The code for this option is 16 and its length is 4.
+
+ Code Len Swap Server Address
+ +-----+-----+-----+-----+-----+-----+
+ | 16 | n | a1 | a2 | a3 | a4 |
+ +-----+-----+-----+-----+-----+-----+
+
+3.19. Root Path
+
+ This option specifies the path-name that contains the client's root
+ disk. The path is formatted as a character string consisting of
+ characters from the NVT ASCII character set.
+
+ The code for this option is 17. Its minimum length is 1.
+
+ Code Len Root Disk Pathname
+ +-----+-----+-----+-----+-----+-----+---
+ | 17 | n | n1 | n2 | n3 | n4 | ...
+ +-----+-----+-----+-----+-----+-----+---
+
+3.20. Extensions Path
+
+ A string to specify a file, retrievable via TFTP, which contains
+ information which can be interpreted in the same way as the 64-octet
+ vendor-extension field within the BOOTP response, with the following
+ exceptions:
+
+ - the length of the file is unconstrained;
+ - all references to Tag 18 (i.e., instances of the
+ BOOTP Extensions Path field) within the file are
+ ignored.
+
+
+
+
+Alexander & Droms Standards Track [Page 10]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ The code for this option is 18. Its minimum length is 1.
+
+ Code Len Extensions Pathname
+ +-----+-----+-----+-----+-----+-----+---
+ | 18 | n | n1 | n2 | n3 | n4 | ...
+ +-----+-----+-----+-----+-----+-----+---
+
+4. IP Layer Parameters per Host
+
+ This section details the options that affect the operation of the IP
+ layer on a per-host basis.
+
+4.1. IP Forwarding Enable/Disable Option
+
+ This option specifies whether the client should configure its IP
+ layer for packet forwarding. A value of 0 means disable IP
+ forwarding, and a value of 1 means enable IP forwarding.
+
+ The code for this option is 19, and its length is 1.
+
+ Code Len Value
+ +-----+-----+-----+
+ | 19 | 1 | 0/1 |
+ +-----+-----+-----+
+
+4.2. Non-Local Source Routing Enable/Disable Option
+
+ This option specifies whether the client should configure its IP
+ layer to allow forwarding of datagrams with non-local source routes
+ (see Section 3.3.5 of [4] for a discussion of this topic). A value
+ of 0 means disallow forwarding of such datagrams, and a value of 1
+ means allow forwarding.
+
+ The code for this option is 20, and its length is 1.
+
+ Code Len Value
+ +-----+-----+-----+
+ | 20 | 1 | 0/1 |
+ +-----+-----+-----+
+
+4.3. Policy Filter Option
+
+ This option specifies policy filters for non-local source routing.
+ The filters consist of a list of IP addresses and masks which specify
+ destination/mask pairs with which to filter incoming source routes.
+
+ Any source routed datagram whose next-hop address does not match one
+ of the filters should be discarded by the client.
+
+
+
+Alexander & Droms Standards Track [Page 11]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ See [4] for further information.
+
+ The code for this option is 21. The minimum length of this option is
+ 8, and the length MUST be a multiple of 8.
+
+ Code Len Address 1 Mask 1
+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
+ | 21 | n | a1 | a2 | a3 | a4 | m1 | m2 | m3 | m4 |
+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
+ Address 2 Mask 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+---
+ | a1 | a2 | a3 | a4 | m1 | m2 | m3 | m4 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+---
+
+4.4. Maximum Datagram Reassembly Size
+
+ This option specifies the maximum size datagram that the client
+ should be prepared to reassemble. The size is specified as a 16-bit
+ unsigned integer. The minimum value legal value is 576.
+
+ The code for this option is 22, and its length is 2.
+
+ Code Len Size
+ +-----+-----+-----+-----+
+ | 22 | 2 | s1 | s2 |
+ +-----+-----+-----+-----+
+
+4.5. Default IP Time-to-live
+
+ This option specifies the default time-to-live that the client should
+ use on outgoing datagrams. The TTL is specified as an octet with a
+ value between 1 and 255.
+
+ The code for this option is 23, and its length is 1.
+
+ Code Len TTL
+ +-----+-----+-----+
+ | 23 | 1 | ttl |
+ +-----+-----+-----+
+
+4.6. Path MTU Aging Timeout Option
+
+ This option specifies the timeout (in seconds) to use when aging Path
+ MTU values discovered by the mechanism defined in RFC 1191 [12]. The
+ timeout is specified as a 32-bit unsigned integer.
+
+ The code for this option is 24, and its length is 4.
+
+
+
+
+Alexander & Droms Standards Track [Page 12]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ Code Len Timeout
+ +-----+-----+-----+-----+-----+-----+
+ | 24 | 4 | t1 | t2 | t3 | t4 |
+ +-----+-----+-----+-----+-----+-----+
+
+4.7. Path MTU Plateau Table Option
+
+ This option specifies a table of MTU sizes to use when performing
+ Path MTU Discovery as defined in RFC 1191. The table is formatted as
+ a list of 16-bit unsigned integers, ordered from smallest to largest.
+ The minimum MTU value cannot be smaller than 68.
+
+ The code for this option is 25. Its minimum length is 2, and the
+ length MUST be a multiple of 2.
+
+ Code Len Size 1 Size 2
+ +-----+-----+-----+-----+-----+-----+---
+ | 25 | n | s1 | s2 | s1 | s2 | ...
+ +-----+-----+-----+-----+-----+-----+---
+
+5. IP Layer Parameters per Interface
+
+ This section details the options that affect the operation of the IP
+ layer on a per-interface basis. It is expected that a client can
+ issue multiple requests, one per interface, in order to configure
+ interfaces with their specific parameters.
+
+5.1. Interface MTU Option
+
+ This option specifies the MTU to use on this interface. The MTU is
+ specified as a 16-bit unsigned integer. The minimum legal value for
+ the MTU is 68.
+
+ The code for this option is 26, and its length is 2.
+
+ Code Len MTU
+ +-----+-----+-----+-----+
+ | 26 | 2 | m1 | m2 |
+ +-----+-----+-----+-----+
+
+5.2. All Subnets are Local Option
+
+ This option specifies whether or not the client may assume that all
+ subnets of the IP network to which the client is connected use the
+ same MTU as the subnet of that network to which the client is
+ directly connected. A value of 1 indicates that all subnets share
+ the same MTU. A value of 0 means that the client should assume that
+ some subnets of the directly connected network may have smaller MTUs.
+
+
+
+Alexander & Droms Standards Track [Page 13]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ The code for this option is 27, and its length is 1.
+
+ Code Len Value
+ +-----+-----+-----+
+ | 27 | 1 | 0/1 |
+ +-----+-----+-----+
+
+5.3. Broadcast Address Option
+
+ This option specifies the broadcast address in use on the client's
+ subnet. Legal values for broadcast addresses are specified in
+ section 3.2.1.3 of [4].
+
+ The code for this option is 28, and its length is 4.
+
+ Code Len Broadcast Address
+ +-----+-----+-----+-----+-----+-----+
+ | 28 | 4 | b1 | b2 | b3 | b4 |
+ +-----+-----+-----+-----+-----+-----+
+
+5.4. Perform Mask Discovery Option
+
+ This option specifies whether or not the client should perform subnet
+ mask discovery using ICMP. A value of 0 indicates that the client
+ should not perform mask discovery. A value of 1 means that the
+ client should perform mask discovery.
+
+ The code for this option is 29, and its length is 1.
+
+ Code Len Value
+ +-----+-----+-----+
+ | 29 | 1 | 0/1 |
+ +-----+-----+-----+
+
+5.5. Mask Supplier Option
+
+ This option specifies whether or not the client should respond to
+ subnet mask requests using ICMP. A value of 0 indicates that the
+ client should not respond. A value of 1 means that the client should
+ respond.
+
+ The code for this option is 30, and its length is 1.
+
+ Code Len Value
+ +-----+-----+-----+
+ | 30 | 1 | 0/1 |
+ +-----+-----+-----+
+
+
+
+
+Alexander & Droms Standards Track [Page 14]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+5.6. Perform Router Discovery Option
+
+ This option specifies whether or not the client should solicit
+ routers using the Router Discovery mechanism defined in RFC 1256
+ [13]. A value of 0 indicates that the client should not perform
+ router discovery. A value of 1 means that the client should perform
+ router discovery.
+
+ The code for this option is 31, and its length is 1.
+
+ Code Len Value
+ +-----+-----+-----+
+ | 31 | 1 | 0/1 |
+ +-----+-----+-----+
+
+5.7. Router Solicitation Address Option
+
+ This option specifies the address to which the client should transmit
+ router solicitation requests.
+
+ The code for this option is 32, and its length is 4.
+
+ Code Len Address
+ +-----+-----+-----+-----+-----+-----+
+ | 32 | 4 | a1 | a2 | a3 | a4 |
+ +-----+-----+-----+-----+-----+-----+
+
+5.8. Static Route Option
+
+ This option specifies a list of static routes that the client should
+ install in its routing cache. If multiple routes to the same
+ destination are specified, they are listed in descending order of
+ priority.
+
+ The routes consist of a list of IP address pairs. The first address
+ is the destination address, and the second address is the router for
+ the destination.
+
+ The default route (0.0.0.0) is an illegal destination for a static
+ route. See section 3.5 for information about the router option.
+
+ The code for this option is 33. The minimum length of this option is
+ 8, and the length MUST be a multiple of 8.
+
+
+
+
+
+
+
+
+Alexander & Droms Standards Track [Page 15]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ Code Len Destination 1 Router 1
+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
+ | 33 | n | d1 | d2 | d3 | d4 | r1 | r2 | r3 | r4 |
+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
+ Destination 2 Router 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+---
+ | d1 | d2 | d3 | d4 | r1 | r2 | r3 | r4 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+---
+
+6. Link Layer Parameters per Interface
+
+ This section lists the options that affect the operation of the data
+ link layer on a per-interface basis.
+
+6.1. Trailer Encapsulation Option
+
+ This option specifies whether or not the client should negotiate the
+ use of trailers (RFC 893 [14]) when using the ARP protocol. A value
+ of 0 indicates that the client should not attempt to use trailers. A
+ value of 1 means that the client should attempt to use trailers.
+
+ The code for this option is 34, and its length is 1.
+
+ Code Len Value
+ +-----+-----+-----+
+ | 34 | 1 | 0/1 |
+ +-----+-----+-----+
+
+6.2. ARP Cache Timeout Option
+
+ This option specifies the timeout in seconds for ARP cache entries.
+ The time is specified as a 32-bit unsigned integer.
+
+ The code for this option is 35, and its length is 4.
+
+ Code Len Time
+ +-----+-----+-----+-----+-----+-----+
+ | 35 | 4 | t1 | t2 | t3 | t4 |
+ +-----+-----+-----+-----+-----+-----+
+
+6.3. Ethernet Encapsulation Option
+
+ This option specifies whether or not the client should use Ethernet
+ Version 2 (RFC 894 [15]) or IEEE 802.3 (RFC 1042 [16]) encapsulation
+ if the interface is an Ethernet. A value of 0 indicates that the
+ client should use RFC 894 encapsulation. A value of 1 means that the
+ client should use RFC 1042 encapsulation.
+
+
+
+
+Alexander & Droms Standards Track [Page 16]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ The code for this option is 36, and its length is 1.
+
+ Code Len Value
+ +-----+-----+-----+
+ | 36 | 1 | 0/1 |
+ +-----+-----+-----+
+
+7. TCP Parameters
+
+ This section lists the options that affect the operation of the TCP
+ layer on a per-interface basis.
+
+7.1. TCP Default TTL Option
+
+ This option specifies the default TTL that the client should use when
+ sending TCP segments. The value is represented as an 8-bit unsigned
+ integer. The minimum value is 1.
+
+ The code for this option is 37, and its length is 1.
+
+ Code Len TTL
+ +-----+-----+-----+
+ | 37 | 1 | n |
+ +-----+-----+-----+
+
+7.2. TCP Keepalive Interval Option
+
+ This option specifies the interval (in seconds) that the client TCP
+ should wait before sending a keepalive message on a TCP connection.
+ The time is specified as a 32-bit unsigned integer. A value of zero
+ indicates that the client should not generate keepalive messages on
+ connections unless specifically requested by an application.
+
+ The code for this option is 38, and its length is 4.
+
+ Code Len Time
+ +-----+-----+-----+-----+-----+-----+
+ | 38 | 4 | t1 | t2 | t3 | t4 |
+ +-----+-----+-----+-----+-----+-----+
+
+7.3. TCP Keepalive Garbage Option
+
+ This option specifies the whether or not the client should send TCP
+ keepalive messages with a octet of garbage for compatibility with
+ older implementations. A value of 0 indicates that a garbage octet
+ should not be sent. A value of 1 indicates that a garbage octet
+ should be sent.
+
+
+
+
+Alexander & Droms Standards Track [Page 17]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ The code for this option is 39, and its length is 1.
+
+ Code Len Value
+ +-----+-----+-----+
+ | 39 | 1 | 0/1 |
+ +-----+-----+-----+
+
+8. Application and Service Parameters
+
+ This section details some miscellaneous options used to configure
+ miscellaneous applications and services.
+
+8.1. Network Information Service Domain Option
+
+ This option specifies the name of the client's NIS [17] domain. The
+ domain is formatted as a character string consisting of characters
+ from the NVT ASCII character set.
+
+ The code for this option is 40. Its minimum length is 1.
+
+ Code Len NIS Domain Name
+ +-----+-----+-----+-----+-----+-----+---
+ | 40 | n | n1 | n2 | n3 | n4 | ...
+ +-----+-----+-----+-----+-----+-----+---
+
+8.2. Network Information Servers Option
+
+ This option specifies a list of IP addresses indicating NIS servers
+ available to the client. Servers SHOULD be listed in order of
+ preference.
+
+ The code for this option is 41. Its minimum length is 4, and the
+ length MUST be a multiple of 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 41 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+8.3. Network Time Protocol Servers Option
+
+ This option specifies a list of IP addresses indicating NTP [18]
+ servers available to the client. Servers SHOULD be listed in order
+ of preference.
+
+ The code for this option is 42. Its minimum length is 4, and the
+ length MUST be a multiple of 4.
+
+
+
+
+Alexander & Droms Standards Track [Page 18]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 42 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+8.4. Vendor Specific Information
+
+ This option is used by clients and servers to exchange vendor-
+ specific information. The information is an opaque object of n
+ octets, presumably interpreted by vendor-specific code on the clients
+ and servers. The definition of this information is vendor specific.
+ The vendor is indicated in the vendor class identifier option.
+ Servers not equipped to interpret the vendor-specific information
+ sent by a client MUST ignore it (although it may be reported).
+ Clients which do not receive desired vendor-specific information
+ SHOULD make an attempt to operate without it, although they may do so
+ (and announce they are doing so) in a degraded mode.
+
+ If a vendor potentially encodes more than one item of information in
+ this option, then the vendor SHOULD encode the option using
+ "Encapsulated vendor-specific options" as described below:
+
+ The Encapsulated vendor-specific options field SHOULD be encoded as a
+ sequence of code/length/value fields of identical syntax to the DHCP
+ options field with the following exceptions:
+
+ 1) There SHOULD NOT be a "magic cookie" field in the encapsulated
+ vendor-specific extensions field.
+
+ 2) Codes other than 0 or 255 MAY be redefined by the vendor within
+ the encapsulated vendor-specific extensions field, but SHOULD
+ conform to the tag-length-value syntax defined in section 2.
+
+ 3) Code 255 (END), if present, signifies the end of the
+ encapsulated vendor extensions, not the end of the vendor
+ extensions field. If no code 255 is present, then the end of
+ the enclosing vendor-specific information field is taken as the
+ end of the encapsulated vendor-specific extensions field.
+
+ The code for this option is 43 and its minimum length is 1.
+
+ Code Len Vendor-specific information
+ +-----+-----+-----+-----+---
+ | 43 | n | i1 | i2 | ...
+ +-----+-----+-----+-----+---
+
+
+
+
+
+
+Alexander & Droms Standards Track [Page 19]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ When encapsulated vendor-specific extensions are used, the
+ information bytes 1-n have the following format:
+
+ Code Len Data item Code Len Data item Code
+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
+ | T1 | n | d1 | d2 | ... | T2 | n | D1 | D2 | ... | ... |
+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
+
+8.5. NetBIOS over TCP/IP Name Server Option
+
+ The NetBIOS name server (NBNS) option specifies a list of RFC
+ 1001/1002 [19] [20] NBNS name servers listed in order of preference.
+
+ The code for this option is 44. The minimum length of the option is
+ 4 octets, and the length must always be a multiple of 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+----
+ | 44 | n | a1 | a2 | a3 | a4 | b1 | b2 | b3 | b4 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+----
+
+8.6. NetBIOS over TCP/IP Datagram Distribution Server Option
+
+ The NetBIOS datagram distribution server (NBDD) option specifies a
+ list of RFC 1001/1002 NBDD servers listed in order of preference. The
+ code for this option is 45. The minimum length of the option is 4
+ octets, and the length must always be a multiple of 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+----
+ | 45 | n | a1 | a2 | a3 | a4 | b1 | b2 | b3 | b4 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+----
+
+8.7. NetBIOS over TCP/IP Node Type Option
+
+ The NetBIOS node type option allows NetBIOS over TCP/IP clients which
+ are configurable to be configured as described in RFC 1001/1002. The
+ value is specified as a single octet which identifies the client type
+ as follows:
+
+ Value Node Type
+ ----- ---------
+ 0x1 B-node
+ 0x2 P-node
+ 0x4 M-node
+ 0x8 H-node
+
+
+
+
+
+Alexander & Droms Standards Track [Page 20]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ In the above chart, the notation '0x' indicates a number in base-16
+ (hexadecimal).
+
+ The code for this option is 46. The length of this option is always
+ 1.
+
+ Code Len Node Type
+ +-----+-----+-----------+
+ | 46 | 1 | see above |
+ +-----+-----+-----------+
+
+8.8. NetBIOS over TCP/IP Scope Option
+
+ The NetBIOS scope option specifies the NetBIOS over TCP/IP scope
+ parameter for the client as specified in RFC 1001/1002. See [19],
+ [20], and [8] for character-set restrictions.
+
+ The code for this option is 47. The minimum length of this option is
+ 1.
+
+ Code Len NetBIOS Scope
+ +-----+-----+-----+-----+-----+-----+----
+ | 47 | n | s1 | s2 | s3 | s4 | ...
+ +-----+-----+-----+-----+-----+-----+----
+
+8.9. X Window System Font Server Option
+
+ This option specifies a list of X Window System [21] Font servers
+ available to the client. Servers SHOULD be listed in order of
+ preference.
+
+ The code for this option is 48. The minimum length of this option is
+ 4 octets, and the length MUST be a multiple of 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+---
+ | 48 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+---
+
+8.10. X Window System Display Manager Option
+
+ This option specifies a list of IP addresses of systems that are
+ running the X Window System Display Manager and are available to the
+ client.
+
+ Addresses SHOULD be listed in order of preference.
+
+
+
+
+
+Alexander & Droms Standards Track [Page 21]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ The code for the this option is 49. The minimum length of this option
+ is 4, and the length MUST be a multiple of 4.
+
+ Code Len Address 1 Address 2
+
+ +-----+-----+-----+-----+-----+-----+-----+-----+---
+ | 49 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+---
+
+8.11. Network Information Service+ Domain Option
+
+ This option specifies the name of the client's NIS+ [17] domain. The
+ domain is formatted as a character string consisting of characters
+ from the NVT ASCII character set.
+
+ The code for this option is 64. Its minimum length is 1.
+
+ Code Len NIS Client Domain Name
+ +-----+-----+-----+-----+-----+-----+---
+ | 64 | n | n1 | n2 | n3 | n4 | ...
+ +-----+-----+-----+-----+-----+-----+---
+
+8.12. Network Information Service+ Servers Option
+
+ This option specifies a list of IP addresses indicating NIS+ servers
+ available to the client. Servers SHOULD be listed in order of
+ preference.
+
+ The code for this option is 65. Its minimum length is 4, and the
+ length MUST be a multiple of 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 65 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+8.13. Mobile IP Home Agent option
+
+ This option specifies a list of IP addresses indicating mobile IP
+ home agents available to the client. Agents SHOULD be listed in
+ order of preference.
+
+ The code for this option is 68. Its minimum length is 0 (indicating
+ no home agents are available) and the length MUST be a multiple of 4.
+ It is expected that the usual length will be four octets, containing
+ a single home agent's address.
+
+
+
+
+
+Alexander & Droms Standards Track [Page 22]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ Code Len Home Agent Addresses (zero or more)
+ +-----+-----+-----+-----+-----+-----+--
+ | 68 | n | a1 | a2 | a3 | a4 | ...
+ +-----+-----+-----+-----+-----+-----+--
+
+8.14. Simple Mail Transport Protocol (SMTP) Server Option
+
+ The SMTP server option specifies a list of SMTP servers available to
+ the client. Servers SHOULD be listed in order of preference.
+
+ The code for the SMTP server option is 69. The minimum length for
+ this option is 4 octets, and the length MUST always be a multiple of
+ 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 69 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+8.15. Post Office Protocol (POP3) Server Option
+
+ The POP3 server option specifies a list of POP3 available to the
+ client. Servers SHOULD be listed in order of preference.
+
+ The code for the POP3 server option is 70. The minimum length for
+ this option is 4 octets, and the length MUST always be a multiple of
+ 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 70 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+8.16. Network News Transport Protocol (NNTP) Server Option
+
+ The NNTP server option specifies a list of NNTP available to the
+ client. Servers SHOULD be listed in order of preference.
+
+ The code for the NNTP server option is 71. The minimum length for
+ this option is 4 octets, and the length MUST always be a multiple of
+ 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 71 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+
+
+
+
+Alexander & Droms Standards Track [Page 23]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+8.17. Default World Wide Web (WWW) Server Option
+
+ The WWW server option specifies a list of WWW available to the
+ client. Servers SHOULD be listed in order of preference.
+
+ The code for the WWW server option is 72. The minimum length for
+ this option is 4 octets, and the length MUST always be a multiple of
+ 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 72 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+8.18. Default Finger Server Option
+
+ The Finger server option specifies a list of Finger available to the
+ client. Servers SHOULD be listed in order of preference.
+
+ The code for the Finger server option is 73. The minimum length for
+ this option is 4 octets, and the length MUST always be a multiple of
+ 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 73 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+8.19. Default Internet Relay Chat (IRC) Server Option
+
+ The IRC server option specifies a list of IRC available to the
+ client. Servers SHOULD be listed in order of preference.
+
+ The code for the IRC server option is 74. The minimum length for
+ this option is 4 octets, and the length MUST always be a multiple of
+ 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 74 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+8.20. StreetTalk Server Option
+
+ The StreetTalk server option specifies a list of StreetTalk servers
+ available to the client. Servers SHOULD be listed in order of
+ preference.
+
+
+
+
+Alexander & Droms Standards Track [Page 24]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ The code for the StreetTalk server option is 75. The minimum length
+ for this option is 4 octets, and the length MUST always be a multiple
+ of 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 75 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+8.21. StreetTalk Directory Assistance (STDA) Server Option
+
+ The StreetTalk Directory Assistance (STDA) server option specifies a
+ list of STDA servers available to the client. Servers SHOULD be
+ listed in order of preference.
+
+ The code for the StreetTalk Directory Assistance server option is 76.
+ The minimum length for this option is 4 octets, and the length MUST
+ always be a multiple of 4.
+
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 76 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+
+9. DHCP Extensions
+
+ This section details the options that are specific to DHCP.
+
+9.1. Requested IP Address
+
+ This option is used in a client request (DHCPDISCOVER) to allow the
+ client to request that a particular IP address be assigned.
+
+ The code for this option is 50, and its length is 4.
+
+ Code Len Address
+ +-----+-----+-----+-----+-----+-----+
+ | 50 | 4 | a1 | a2 | a3 | a4 |
+ +-----+-----+-----+-----+-----+-----+
+
+9.2. IP Address Lease Time
+
+ This option is used in a client request (DHCPDISCOVER or DHCPREQUEST)
+ to allow the client to request a lease time for the IP address. In a
+ server reply (DHCPOFFER), a DHCP server uses this option to specify
+ the lease time it is willing to offer.
+
+
+
+
+
+Alexander & Droms Standards Track [Page 25]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ The time is in units of seconds, and is specified as a 32-bit
+ unsigned integer.
+
+ The code for this option is 51, and its length is 4.
+
+ Code Len Lease Time
+ +-----+-----+-----+-----+-----+-----+
+ | 51 | 4 | t1 | t2 | t3 | t4 |
+ +-----+-----+-----+-----+-----+-----+
+
+9.3. Option Overload
+
+ This option is used to indicate that the DHCP 'sname' or 'file'
+ fields are being overloaded by using them to carry DHCP options. A
+ DHCP server inserts this option if the returned parameters will
+ exceed the usual space allotted for options.
+
+ If this option is present, the client interprets the specified
+ additional fields after it concludes interpretation of the standard
+ option fields.
+
+ The code for this option is 52, and its length is 1. Legal values
+ for this option are:
+
+ Value Meaning
+ ----- --------
+ 1 the 'file' field is used to hold options
+ 2 the 'sname' field is used to hold options
+ 3 both fields are used to hold options
+
+ Code Len Value
+ +-----+-----+-----+
+ | 52 | 1 |1/2/3|
+ +-----+-----+-----+
+
+9.4 TFTP server name
+
+ This option is used to identify a TFTP server when the 'sname' field
+ in the DHCP header has been used for DHCP options.
+
+ The code for this option is 66, and its minimum length is 1.
+
+ Code Len TFTP server
+ +-----+-----+-----+-----+-----+---
+ | 66 | n | c1 | c2 | c3 | ...
+ +-----+-----+-----+-----+-----+---
+
+
+
+
+
+Alexander & Droms Standards Track [Page 26]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+9.5 Bootfile name
+
+ This option is used to identify a bootfile when the 'file' field in
+ the DHCP header has been used for DHCP options.
+
+ The code for this option is 67, and its minimum length is 1.
+
+ Code Len Bootfile name
+ +-----+-----+-----+-----+-----+---
+ | 67 | n | c1 | c2 | c3 | ...
+ +-----+-----+-----+-----+-----+---
+
+9.6. DHCP Message Type
+
+ This option is used to convey the type of the DHCP message. The code
+ for this option is 53, and its length is 1. Legal values for this
+ option are:
+
+ Value Message Type
+ ----- ------------
+ 1 DHCPDISCOVER
+ 2 DHCPOFFER
+ 3 DHCPREQUEST
+ 4 DHCPDECLINE
+ 5 DHCPACK
+ 6 DHCPNAK
+ 7 DHCPRELEASE
+ 8 DHCPINFORM
+
+ Code Len Type
+ +-----+-----+-----+
+ | 53 | 1 | 1-9 |
+ +-----+-----+-----+
+
+9.7. Server Identifier
+
+ This option is used in DHCPOFFER and DHCPREQUEST messages, and may
+ optionally be included in the DHCPACK and DHCPNAK messages. DHCP
+ servers include this option in the DHCPOFFER in order to allow the
+ client to distinguish between lease offers. DHCP clients use the
+ contents of the 'server identifier' field as the destination address
+ for any DHCP messages unicast to the DHCP server. DHCP clients also
+ indicate which of several lease offers is being accepted by including
+ this option in a DHCPREQUEST message.
+
+ The identifier is the IP address of the selected server.
+
+ The code for this option is 54, and its length is 4.
+
+
+
+Alexander & Droms Standards Track [Page 27]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ Code Len Address
+ +-----+-----+-----+-----+-----+-----+
+ | 54 | 4 | a1 | a2 | a3 | a4 |
+ +-----+-----+-----+-----+-----+-----+
+
+9.8. Parameter Request List
+
+ This option is used by a DHCP client to request values for specified
+ configuration parameters. The list of requested parameters is
+ specified as n octets, where each octet is a valid DHCP option code
+ as defined in this document.
+
+ The client MAY list the options in order of preference. The DHCP
+ server is not required to return the options in the requested order,
+ but MUST try to insert the requested options in the order requested
+ by the client.
+
+ The code for this option is 55. Its minimum length is 1.
+
+ Code Len Option Codes
+ +-----+-----+-----+-----+---
+ | 55 | n | c1 | c2 | ...
+ +-----+-----+-----+-----+---
+
+9.9. Message
+
+ This option is used by a DHCP server to provide an error message to a
+ DHCP client in a DHCPNAK message in the event of a failure. A client
+ may use this option in a DHCPDECLINE message to indicate the why the
+ client declined the offered parameters. The message consists of n
+ octets of NVT ASCII text, which the client may display on an
+ available output device.
+
+ The code for this option is 56 and its minimum length is 1.
+
+ Code Len Text
+ +-----+-----+-----+-----+---
+ | 56 | n | c1 | c2 | ...
+ +-----+-----+-----+-----+---
+
+9.10. Maximum DHCP Message Size
+
+ This option specifies the maximum length DHCP message that it is
+ willing to accept. The length is specified as an unsigned 16-bit
+ integer. A client may use the maximum DHCP message size option in
+ DHCPDISCOVER or DHCPREQUEST messages, but should not use the option
+ in DHCPDECLINE messages.
+
+
+
+
+Alexander & Droms Standards Track [Page 28]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ The code for this option is 57, and its length is 2. The minimum
+ legal value is 576 octets.
+
+ Code Len Length
+ +-----+-----+-----+-----+
+ | 57 | 2 | l1 | l2 |
+ +-----+-----+-----+-----+
+
+9.11. Renewal (T1) Time Value
+
+ This option specifies the time interval from address assignment until
+ the client transitions to the RENEWING state.
+
+ The value is in units of seconds, and is specified as a 32-bit
+ unsigned integer.
+
+ The code for this option is 58, and its length is 4.
+
+ Code Len T1 Interval
+ +-----+-----+-----+-----+-----+-----+
+ | 58 | 4 | t1 | t2 | t3 | t4 |
+ +-----+-----+-----+-----+-----+-----+
+
+9.12. Rebinding (T2) Time Value
+
+ This option specifies the time interval from address assignment until
+ the client transitions to the REBINDING state.
+
+ The value is in units of seconds, and is specified as a 32-bit
+ unsigned integer.
+
+ The code for this option is 59, and its length is 4.
+
+ Code Len T2 Interval
+ +-----+-----+-----+-----+-----+-----+
+ | 59 | 4 | t1 | t2 | t3 | t4 |
+ +-----+-----+-----+-----+-----+-----+
+
+9.13. Vendor class identifier
+
+ This option is used by DHCP clients to optionally identify the vendor
+ type and configuration of a DHCP client. The information is a string
+ of n octets, interpreted by servers. Vendors may choose to define
+ specific vendor class identifiers to convey particular configuration
+ or other identification information about a client. For example, the
+ identifier may encode the client's hardware configuration. Servers
+ not equipped to interpret the class-specific information sent by a
+ client MUST ignore it (although it may be reported). Servers that
+
+
+
+Alexander & Droms Standards Track [Page 29]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ respond SHOULD only use option 43 to return the vendor-specific
+ information to the client.
+
+ The code for this option is 60, and its minimum length is 1.
+
+ Code Len Vendor class Identifier
+ +-----+-----+-----+-----+---
+ | 60 | n | i1 | i2 | ...
+ +-----+-----+-----+-----+---
+
+9.14. Client-identifier
+
+ This option is used by DHCP clients to specify their unique
+ identifier. DHCP servers use this value to index their database of
+ address bindings. This value is expected to be unique for all
+ clients in an administrative domain.
+
+ Identifiers SHOULD be treated as opaque objects by DHCP servers.
+
+ The client identifier MAY consist of type-value pairs similar to the
+ 'htype'/'chaddr' fields defined in [3]. For instance, it MAY consist
+ of a hardware type and hardware address. In this case the type field
+ SHOULD be one of the ARP hardware types defined in STD2 [22]. A
+ hardware type of 0 (zero) should be used when the value field
+ contains an identifier other than a hardware address (e.g. a fully
+ qualified domain name).
+
+ For correct identification of clients, each client's client-
+ identifier MUST be unique among the client-identifiers used on the
+ subnet to which the client is attached. Vendors and system
+ administrators are responsible for choosing client-identifiers that
+ meet this requirement for uniqueness.
+
+ The code for this option is 61, and its minimum length is 2.
+
+ Code Len Type Client-Identifier
+ +-----+-----+-----+-----+-----+---
+ | 61 | n | t1 | i1 | i2 | ...
+ +-----+-----+-----+-----+-----+---
+
+
+
+
+
+
+
+
+
+
+
+
+Alexander & Droms Standards Track [Page 30]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+10. Defining new extensions
+
+ The author of a new DHCP option will follow these steps to obtain
+ acceptance of the option as a part of the DHCP Internet Standard:
+
+ 1. The author devises the new option.
+ 2. The author requests a number for the new option from IANA by
+ contacting:
+ Internet Assigned Numbers Authority (IANA)
+ USC/Information Sciences Institute
+ 4676 Admiralty Way
+ Marina del Rey, California 90292-6695
+
+ or by email as: iana@iana.org
+
+ 3. The author documents the new option, using the newly obtained
+ option number, as an Internet Draft.
+ 4. The author submits the Internet Draft for review through the IETF
+ standards process as defined in "Internet Official Protocol
+ Standards" (STD 1). The new option will be submitted for eventual
+ acceptance as an Internet Standard.
+ 5. The new option progresses through the IETF standards process; the
+ new option will be reviewed by the Dynamic Host Configuration
+ Working Group (if that group still exists), or as an Internet
+ Draft not submitted by an IETF working group.
+ 6. If the new option fails to gain acceptance as an Internet
+ Standard, the assigned option number will be returned to IANA for
+ reassignment.
+
+ This procedure for defining new extensions will ensure that:
+
+ * allocation of new option numbers is coordinated from a single
+ authority,
+ * new options are reviewed for technical correctness and
+ appropriateness, and
+ * documentation for new options is complete and published.
+
+11. Acknowledgements
+
+ The author thanks the many (and too numerous to mention!) members of
+ the DHC WG for their tireless and ongoing efforts in the development
+ of DHCP and this document.
+
+ The efforts of J Allard, Mike Carney, Dave Lapp, Fred Lien and John
+ Mendonca in organizing DHCP interoperability testing sessions are
+ gratefully acknowledged.
+
+
+
+
+
+Alexander & Droms Standards Track [Page 31]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ The development of this document was supported in part by grants from
+ the Corporation for National Research Initiatives (CNRI), Bucknell
+ University and Sun Microsystems.
+
+12. References
+
+ [1] Droms, R., "Dynamic Host Configuration Protocol", RFC 2131,
+ Bucknell University, March 1997.
+
+ [2] Reynolds, J., "BOOTP Vendor Information Extensions", RFC 1497,
+ USC/Information Sciences Institute, August 1993.
+
+ [3] Croft, W., and J. Gilmore, "Bootstrap Protocol", RFC 951,
+ Stanford University and Sun Microsystems, September 1985.
+
+ [4] Braden, R., Editor, "Requirements for Internet Hosts -
+ Communication Layers", STD 3, RFC 1122, USC/Information Sciences
+ Institute, October 1989.
+
+ [5] Mogul, J., and J. Postel, "Internet Standard Subnetting
+ Procedure", STD 5, RFC 950, USC/Information Sciences Institute,
+ August 1985.
+
+ [6] Postel, J., and K. Harrenstien, "Time Protocol", STD 26, RFC
+ 868, USC/Information Sciences Institute, SRI, May 1983.
+
+ [7] Postel, J., "Name Server", IEN 116, USC/Information Sciences
+ Institute, August 1979.
+
+ [8] Mockapetris, P., "Domain Names - Implementation and
+ Specification", STD 13, RFC 1035, USC/Information Sciences
+ Institute, November 1987.
+
+ [9] Postel, J., "Quote of the Day Protocol", STD 23, RFC 865,
+ USC/Information Sciences Institute, May 1983.
+
+ [10] McLaughlin, L., "Line Printer Daemon Protocol", RFC 1179, The
+ Wollongong Group, August 1990.
+
+ [11] Accetta, M., "Resource Location Protocol", RFC 887, CMU,
+ December 1983.
+
+ [12] Mogul, J. and S. Deering, "Path MTU Discovery", RFC 1191,
+ DECWRL, Stanford University, November 1990.
+
+ [13] Deering, S., "ICMP Router Discovery Messages", RFC 1256,
+ Xerox PARC, September 1991.
+
+
+
+
+Alexander & Droms Standards Track [Page 32]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+ [14] Leffler, S. and M. Karels, "Trailer Encapsulations", RFC 893,
+ U. C. Berkeley, April 1984.
+
+ [15] Hornig, C., "Standard for the Transmission of IP Datagrams over
+ Ethernet Networks", RFC 894, Symbolics, April 1984.
+
+ [16] Postel, J. and J. Reynolds, "Standard for the Transmission of
+ IP Datagrams Over IEEE 802 Networks", RFC 1042, USC/Information
+ Sciences Institute, February 1988.
+
+ [17] Sun Microsystems, "System and Network Administration", March
+ 1990.
+
+ [18] Mills, D., "Internet Time Synchronization: The Network Time
+ Protocol", RFC 1305, UDEL, March 1992.
+
+ [19] NetBIOS Working Group, "Protocol Standard for a NetBIOS Service
+ on a TCP/UDP transport: Concepts and Methods", STD 19, RFC 1001,
+ March 1987.
+
+ [20] NetBIOS Working Group, "Protocol Standard for a NetBIOS Service
+ on a TCP/UDP transport: Detailed Specifications", STD 19, RFC
+ 1002, March 1987.
+
+ [21] Scheifler, R., "FYI On the X Window System", FYI 6, RFC 1198,
+ MIT Laboratory for Computer Science, January 1991.
+
+ [22] Reynolds, J., and J. Postel, "Assigned Numbers", STD 2, RFC 1700,
+ USC/Information Sciences Institute, July 1992.
+
+13. Security Considerations
+
+ Security issues are not discussed in this memo.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Alexander & Droms Standards Track [Page 33]
+\f
+RFC 2132 DHCP Options and BOOTP Vendor Extensions March 1997
+
+
+14. Authors' Addresses
+
+ Steve Alexander
+ Silicon Graphics, Inc.
+ 2011 N. Shoreline Boulevard
+ Mailstop 510
+ Mountain View, CA 94043-1389
+
+ Phone: (415) 933-6172
+ EMail: sca@engr.sgi.com
+
+
+ Ralph Droms
+ Bucknell University
+ Lewisburg, PA 17837
+
+ Phone: (717) 524-1145
+ EMail: droms@bucknell.edu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Alexander & Droms Standards Track [Page 34]
+\f
--- /dev/null
+Service hierarchy
+=================
+
+Service org.moblin.connman
+Interface org.moblin.connman.Service
+Object path [variable prefix]/{service0,service1,...}
+
+Methods dict GetProperties()
+
+ Returns properties for the service object. See
+ the properties section for available properties.
+
+ Possible Errors: [service].Error.InvalidArguments
+
+ void Connect()
+
+ Connect this service. It will attempt to connect
+ WiFi, WiMAX 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.
+
+ 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.
+
+ 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.
+
+ This is similar to setting the Favorite property
+ to false, but that is currently not supported.
+
+ 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
+
+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" and "ready".
+
+ 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.
+
+ For Ethernet devices and hidden WiFi networks it is
+ not guaranteed that this property is 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.
+
+ string Mode [readonly]
+
+ If the service type is WiFi, then this property is
+ present and contains the mode of the network. The
+ possible values are "managed" or "adhoc".
+
+ This property might be only present for WiFi
+ services.
+
+ string Security [readonly]
+
+ If the service type is WiFi, then this property is
+ present and contains the security method or key
+ management setting.
+
+ Possible values are "none", "wep", "wpa" and "rsn".
+
+ This property might be only present for WiFi
+ services.
+
+ string Passphrase [readwrite]
+
+ If the service type is WiFi, then this property
+ can be used to store a passphrase.
+
+ This property is still experimental and might be
+ removed in future version.
+
+ 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.
+
+ Setting this property to true has no effect at all
+ and setting it to false is similar to the Remove()
+ method. So for now it will be considered a read
+ only property.
--- /dev/null
+
+noinst_LTLIBRARIES = libgatchat.la
+
+libgatchat_la_SOURCES = gatchat.h gatchat.c gatresult.h gatresult.c \
+ ringbuffer.h ringbuffer.c
+
+AM_CFLAGS = @GLIB_CFLAGS@
+
+MAINTAINERCLEANFILES = Makefile.in
--- /dev/null
+/*
+ *
+ * AT chat library with GLib integration
+ *
+ * Copyright (C) 2008-2009 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 <string.h>
+#include <assert.h>
+
+#include <glib.h>
+
+#include "ringbuffer.h"
+#include "gatresult.h"
+#include "gatchat.h"
+
+/* #define WRITE_SCHEDULER_DEBUG 1 */
+
+static void g_at_chat_wakeup_writer(GAtChat *chat);
+
+enum chat_state {
+ PARSER_STATE_IDLE = 0,
+ PARSER_STATE_INITIAL_CR,
+ PARSER_STATE_INITIAL_LF,
+ PARSER_STATE_RESPONSE,
+ PARSER_STATE_TERMINATOR_CR,
+ PARSER_STATE_RESPONSE_COMPLETE,
+ PARSER_STATE_GUESS_MULTILINE_RESPONSE,
+ PARSER_STATE_MULTILINE_RESPONSE,
+ PARSER_STATE_MULTILINE_TERMINATOR_CR,
+ PARSER_STATE_MULTILINE_COMPLETE,
+ PARSER_STATE_PDU,
+ PARSER_STATE_PDU_CR,
+ PARSER_STATE_PDU_COMPLETE,
+ PARSER_STATE_PROMPT,
+ PARSER_STATE_PROMPT_COMPLETE
+};
+
+struct at_command {
+ char *cmd;
+ char **prefixes;
+ guint id;
+ GAtResultFunc callback;
+ gpointer user_data;
+ GDestroyNotify notify;
+};
+
+struct at_notify_node {
+ guint id;
+ GAtNotifyFunc callback;
+ gpointer user_data;
+ GDestroyNotify notify;
+};
+
+struct at_notify {
+ GSList *nodes;
+ gboolean pdu;
+};
+
+struct _GAtChat {
+ gint ref_count; /* Ref count */
+ guint next_cmd_id; /* Next command id */
+ guint next_notify_id; /* Next notify id */
+ guint read_watch; /* GSource read id, 0 if none */
+ guint write_watch; /* GSource write id, 0 if none */
+ GIOChannel *channel; /* channel */
+ GQueue *command_queue; /* Command queue */
+ guint cmd_bytes_written; /* bytes written from cmd */
+ GHashTable *notify_list; /* List of notification reg */
+ GAtDisconnectFunc user_disconnect; /* user disconnect func */
+ gpointer user_disconnect_data; /* user disconnect data */
+ struct ring_buffer *buf; /* Current read buffer */
+ guint read_so_far; /* Number of bytes processed */
+ gboolean disconnecting; /* Whether we're disconnecting */
+ enum chat_state state; /* Current chat state */
+ int flags;
+ char *pdu_notify; /* Unsolicited Resp w/ PDU */
+ GSList *response_lines; /* char * lines of the response */
+ char *wakeup; /* command sent to wakeup modem */
+ gdouble inactivity_time; /* Period of inactivity */
+ guint wakeup_timeout; /* How long to wait for resp */
+ GTimer *wakeup_timer; /* Keep track of elapsed time */
+};
+
+static gint at_notify_node_compare_by_id(gconstpointer a, gconstpointer b)
+{
+ const struct at_notify_node *node = a;
+ guint id = GPOINTER_TO_UINT(b);
+
+ if (node->id < id)
+ return -1;
+
+ if (node->id > id)
+ return 1;
+
+ return 0;
+}
+
+static void at_notify_node_destroy(struct at_notify_node *node)
+{
+ if (node->notify)
+ node->notify(node->user_data);
+
+ g_free(node);
+}
+
+static void at_notify_destroy(struct at_notify *notify)
+{
+ g_slist_foreach(notify->nodes, (GFunc) at_notify_node_destroy, NULL);
+ g_free(notify);
+}
+
+static gint at_command_compare_by_id(gconstpointer a, gconstpointer b)
+{
+ const struct at_command *command = a;
+ guint id = GPOINTER_TO_UINT(b);
+
+ if (command->id < id)
+ return -1;
+
+ if (command->id > id)
+ return 1;
+
+ return 0;
+}
+
+static struct at_command *at_command_create(const char *cmd,
+ const char **prefix_list,
+ GAtResultFunc func,
+ gpointer user_data,
+ GDestroyNotify notify)
+{
+ struct at_command *c;
+ gsize len;
+ char **prefixes = NULL;
+
+ if (prefix_list) {
+ int num_prefixes = 0;
+ int i;
+
+ while (prefix_list[num_prefixes])
+ num_prefixes += 1;
+
+ prefixes = g_new(char *, num_prefixes + 1);
+
+ for (i = 0; i < num_prefixes; i++)
+ prefixes[i] = strdup(prefix_list[i]);
+
+ prefixes[num_prefixes] = NULL;
+ }
+
+ c = g_try_new0(struct at_command, 1);
+
+ if (!c)
+ return 0;
+
+ len = strlen(cmd);
+ c->cmd = g_try_new(char, len + 2);
+
+ if (!c->cmd) {
+ g_free(c);
+ return 0;
+ }
+
+ memcpy(c->cmd, cmd, len);
+
+ /* If we have embedded '\r' then this is a command expecting a prompt
+ * from the modem. Embed Ctrl-Z at the very end automatically
+ */
+ if (strchr(cmd, '\r'))
+ c->cmd[len] = 26;
+ else
+ c->cmd[len] = '\r';
+
+ c->cmd[len+1] = '\0';
+
+ c->prefixes = prefixes;
+ c->callback = func;
+ c->user_data = user_data;
+ c->notify = notify;
+
+ return c;
+}
+
+static void at_command_destroy(struct at_command *cmd)
+{
+ if (cmd->notify)
+ cmd->notify(cmd->user_data);
+
+ g_strfreev(cmd->prefixes);
+ g_free(cmd->cmd);
+ g_free(cmd);
+}
+
+static void g_at_chat_cleanup(GAtChat *chat)
+{
+ struct at_command *c;
+
+ ring_buffer_free(chat->buf);
+ chat->buf = NULL;
+
+ /* Cleanup pending commands */
+ while ((c = g_queue_pop_head(chat->command_queue)))
+ at_command_destroy(c);
+
+ g_queue_free(chat->command_queue);
+ chat->command_queue = NULL;
+
+ /* Cleanup any response lines we have pending */
+ g_slist_foreach(chat->response_lines, (GFunc)g_free, NULL);
+ g_slist_free(chat->response_lines);
+ chat->response_lines = NULL;
+
+ /* Cleanup registered notifications */
+ g_hash_table_destroy(chat->notify_list);
+ chat->notify_list = NULL;
+
+ if (chat->pdu_notify) {
+ g_free(chat->pdu_notify);
+ chat->pdu_notify = NULL;
+ }
+
+ if (chat->wakeup) {
+ g_free(chat->wakeup);
+ chat->wakeup = NULL;
+ }
+
+ if (chat->wakeup_timer) {
+ g_timer_destroy(chat->wakeup_timer);
+ chat->wakeup_timer = 0;
+ }
+}
+
+static void read_watcher_destroy_notify(GAtChat *chat)
+{
+ chat->read_watch = 0;
+
+ if (chat->disconnecting)
+ return;
+
+ chat->channel = NULL;
+
+ g_at_chat_cleanup(chat);
+
+ if (chat->user_disconnect)
+ chat->user_disconnect(chat->user_disconnect_data);
+}
+
+static void write_watcher_destroy_notify(GAtChat *chat)
+{
+ chat->write_watch = 0;
+}
+
+static void at_notify_call_callback(gpointer data, gpointer user_data)
+{
+ struct at_notify_node *node = data;
+ GAtResult *result = user_data;
+
+ node->callback(result, node->user_data);
+}
+
+static gboolean g_at_chat_match_notify(GAtChat *chat, char *line)
+{
+ GHashTableIter iter;
+ struct at_notify *notify;
+ char *prefix;
+ gpointer key, value;
+ gboolean ret = FALSE;
+ GAtResult result;
+
+ g_hash_table_iter_init(&iter, chat->notify_list);
+ result.lines = 0;
+ result.final_or_pdu = 0;
+
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ prefix = key;
+ notify = value;
+
+ if (!g_str_has_prefix(line, key))
+ continue;
+
+ if (notify->pdu) {
+ chat->pdu_notify = line;
+ chat->state = PARSER_STATE_PDU;
+ return TRUE;
+ }
+
+ if (!result.lines)
+ result.lines = g_slist_prepend(NULL, line);
+
+ g_slist_foreach(notify->nodes, at_notify_call_callback,
+ &result);
+ ret = TRUE;
+ }
+
+ if (ret) {
+ g_slist_free(result.lines);
+ g_free(line);
+ chat->state = PARSER_STATE_IDLE;
+ }
+
+ return ret;
+}
+
+static void g_at_chat_finish_command(GAtChat *p, gboolean ok,
+ char *final)
+{
+ struct at_command *cmd = g_queue_pop_head(p->command_queue);
+
+ /* Cannot happen, but lets be paranoid */
+ if (!cmd)
+ return;
+
+ if (cmd->callback) {
+ GAtResult result;
+
+ p->response_lines = g_slist_reverse(p->response_lines);
+
+ result.final_or_pdu = final;
+ result.lines = p->response_lines;
+
+ cmd->callback(ok, &result, cmd->user_data);
+ }
+
+ g_slist_foreach(p->response_lines, (GFunc)g_free, NULL);
+ g_slist_free(p->response_lines);
+ p->response_lines = NULL;
+
+ g_free(final);
+
+ at_command_destroy(cmd);
+
+ p->cmd_bytes_written = 0;
+
+ if (g_queue_peek_head(p->command_queue))
+ g_at_chat_wakeup_writer(p);
+}
+
+struct terminator_info {
+ const char *terminator;
+ int len;
+ gboolean success;
+};
+
+static struct terminator_info terminator_table[] = {
+ { "OK", -1, TRUE },
+ { "ERROR", -1, FALSE },
+ { "NO DIALTONE", -1, FALSE },
+ { "BUSY", -1, FALSE },
+ { "NO CARRIER", -1, FALSE },
+ { "CONNECT", -1, TRUE },
+ { "NO ANSWER", -1, FALSE },
+ { "+CMS ERROR:", 11, FALSE },
+ { "+CME ERROR:", 11, FALSE },
+ { "+EXT ERROR:", 11, FALSE }
+};
+
+static gboolean g_at_chat_handle_command_response(GAtChat *p,
+ struct at_command *cmd,
+ char *line)
+{
+ int i;
+ int size = sizeof(terminator_table) / sizeof(struct terminator_info);
+
+ p->state = PARSER_STATE_IDLE;
+
+ for (i = 0; i < size; i++) {
+ struct terminator_info *info = &terminator_table[i];
+
+ if (info->len == -1 && !strcmp(line, info->terminator)) {
+ g_at_chat_finish_command(p, info->success, line);
+ return TRUE;
+ }
+
+ if (info->len > 0 &&
+ !strncmp(line, info->terminator, info->len)) {
+ g_at_chat_finish_command(p, info->success, line);
+ return TRUE;
+ }
+ }
+
+ if (cmd->prefixes) {
+ int i;
+
+ for (i = 0; cmd->prefixes[i]; i++)
+ if (g_str_has_prefix(line, cmd->prefixes[i]))
+ goto out;
+
+ return FALSE;
+ }
+
+out:
+ if (!(p->flags & G_AT_CHAT_FLAG_NO_LEADING_CRLF))
+ p->state = PARSER_STATE_GUESS_MULTILINE_RESPONSE;
+
+ p->response_lines = g_slist_prepend(p->response_lines,
+ line);
+
+ return TRUE;
+}
+
+static void have_line(GAtChat *p, gboolean strip_preceding)
+{
+ /* We're not going to copy terminal <CR><LF> */
+ unsigned int len = p->read_so_far - 2;
+ char *str;
+ struct at_command *cmd;
+
+ /* If we have preceding <CR><LF> modify the len */
+ if (strip_preceding)
+ len -= 2;
+
+ /* Make sure we have terminal null */
+ str = g_try_new(char, len + 1);
+
+ if (!str) {
+ ring_buffer_drain(p->buf, p->read_so_far);
+ return;
+ }
+
+ if (strip_preceding)
+ ring_buffer_drain(p->buf, 2);
+ ring_buffer_read(p->buf, str, len);
+ ring_buffer_drain(p->buf, 2);
+
+ str[len] = '\0';
+
+ /* Check for echo, this should not happen, but lets be paranoid */
+ if (!strncmp(str, "AT", 2) == TRUE)
+ goto done;
+
+ cmd = g_queue_peek_head(p->command_queue);
+
+ if (cmd && p->cmd_bytes_written == strlen(cmd->cmd) &&
+ g_at_chat_handle_command_response(p, cmd, str))
+ return;
+
+ if (g_at_chat_match_notify(p, str) == TRUE)
+ return;
+
+done:
+ /* No matches & no commands active, ignore line */
+ g_free(str);
+ p->state = PARSER_STATE_IDLE;
+}
+
+static void have_pdu(GAtChat *p)
+{
+ unsigned int len = p->read_so_far - 2;
+ char *pdu;
+ GHashTableIter iter;
+ struct at_notify *notify;
+ char *prefix;
+ gpointer key, value;
+ GAtResult result;
+
+ pdu = g_try_new(char, len + 1);
+
+ if (!pdu) {
+ ring_buffer_drain(p->buf, p->read_so_far);
+ goto out;
+ }
+
+ ring_buffer_read(p->buf, pdu, len);
+ ring_buffer_drain(p->buf, 2);
+
+ pdu[len] = '\0';
+
+ result.lines = g_slist_prepend(NULL, p->pdu_notify);
+ result.final_or_pdu = pdu;
+
+ g_hash_table_iter_init(&iter, p->notify_list);
+
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ prefix = key;
+ notify = value;
+
+ if (!g_str_has_prefix(p->pdu_notify, prefix))
+ continue;
+
+ if (!notify->pdu)
+ continue;
+
+ g_slist_foreach(notify->nodes, at_notify_call_callback,
+ &result);
+ }
+
+ g_slist_free(result.lines);
+
+out:
+ g_free(p->pdu_notify);
+ p->pdu_notify = NULL;
+
+ if (pdu)
+ g_free(pdu);
+
+ p->state = PARSER_STATE_IDLE;
+}
+
+static inline void parse_char(GAtChat *chat, char byte)
+{
+ switch (chat->state) {
+ case PARSER_STATE_IDLE:
+ if (byte == '\r')
+ chat->state = PARSER_STATE_INITIAL_CR;
+ else if (chat->flags & G_AT_CHAT_FLAG_NO_LEADING_CRLF) {
+ if (byte == '>')
+ chat->state = PARSER_STATE_PROMPT;
+ else
+ chat->state = PARSER_STATE_RESPONSE;
+ }
+ break;
+
+ case PARSER_STATE_INITIAL_CR:
+ if (byte == '\n')
+ chat->state = PARSER_STATE_INITIAL_LF;
+ else if (byte != '\r' && /* Echo & no <CR><LF>?! */
+ (chat->flags & G_AT_CHAT_FLAG_NO_LEADING_CRLF))
+ chat->state = PARSER_STATE_RESPONSE;
+ else if (byte != '\r')
+ chat->state = PARSER_STATE_IDLE;
+ break;
+
+ case PARSER_STATE_INITIAL_LF:
+ if (byte == '\r')
+ chat->state = PARSER_STATE_TERMINATOR_CR;
+ else if (byte == '>')
+ chat->state = PARSER_STATE_PROMPT;
+ else
+ chat->state = PARSER_STATE_RESPONSE;
+ break;
+
+ case PARSER_STATE_RESPONSE:
+ if (byte == '\r')
+ chat->state = PARSER_STATE_TERMINATOR_CR;
+ break;
+
+ case PARSER_STATE_TERMINATOR_CR:
+ if (byte == '\n')
+ chat->state = PARSER_STATE_RESPONSE_COMPLETE;
+ else
+ chat->state = PARSER_STATE_IDLE;
+ break;
+
+ case PARSER_STATE_GUESS_MULTILINE_RESPONSE:
+ if (byte == '\r')
+ chat->state = PARSER_STATE_INITIAL_CR;
+ else
+ chat->state = PARSER_STATE_MULTILINE_RESPONSE;
+ break;
+
+ case PARSER_STATE_MULTILINE_RESPONSE:
+ if (byte == '\r')
+ chat->state = PARSER_STATE_MULTILINE_TERMINATOR_CR;
+ break;
+
+ case PARSER_STATE_MULTILINE_TERMINATOR_CR:
+ if (byte == '\n')
+ chat->state = PARSER_STATE_MULTILINE_COMPLETE;
+ break;
+
+ case PARSER_STATE_PDU:
+ if (byte == '\r')
+ chat->state = PARSER_STATE_PDU_CR;
+ break;
+
+ case PARSER_STATE_PDU_CR:
+ if (byte == '\n')
+ chat->state = PARSER_STATE_PDU_COMPLETE;
+ break;
+
+ case PARSER_STATE_PROMPT:
+ if (byte == ' ')
+ chat->state = PARSER_STATE_PROMPT_COMPLETE;
+ else
+ chat->state = PARSER_STATE_RESPONSE;
+
+ case PARSER_STATE_RESPONSE_COMPLETE:
+ case PARSER_STATE_PDU_COMPLETE:
+ case PARSER_STATE_MULTILINE_COMPLETE:
+ default:
+ /* This really shouldn't happen */
+ assert(TRUE);
+ return;
+ }
+}
+
+static void new_bytes(GAtChat *p)
+{
+ unsigned int len = ring_buffer_len(p->buf);
+ unsigned int wrap = ring_buffer_len_no_wrap(p->buf);
+ unsigned char *buf = ring_buffer_read_ptr(p->buf, p->read_so_far);
+
+ while (p->read_so_far < len) {
+ parse_char(p, *buf);
+
+ buf += 1;
+ p->read_so_far += 1;
+
+ if (p->read_so_far == wrap) {
+ buf = ring_buffer_read_ptr(p->buf, p->read_so_far);
+ wrap = len;
+ }
+
+ if (p->state == PARSER_STATE_RESPONSE_COMPLETE) {
+ gboolean strip_preceding;
+
+ if (p->flags & G_AT_CHAT_FLAG_NO_LEADING_CRLF)
+ strip_preceding = FALSE;
+ else
+ strip_preceding = TRUE;
+
+ len -= p->read_so_far;
+ wrap -= p->read_so_far;
+
+ have_line(p, strip_preceding);
+
+ p->read_so_far = 0;
+ } else if (p->state == PARSER_STATE_MULTILINE_COMPLETE) {
+ len -= p->read_so_far;
+ wrap -= p->read_so_far;
+
+ have_line(p, FALSE);
+
+ p->read_so_far = 0;
+ } else if (p->state == PARSER_STATE_PDU_COMPLETE) {
+ len -= p->read_so_far;
+ wrap -= p->read_so_far;
+
+ have_pdu(p);
+
+ p->read_so_far = 0;
+ } else if (p->state == PARSER_STATE_INITIAL_CR) {
+ len -= p->read_so_far - 1;
+ wrap -= p->read_so_far - 1;
+
+ ring_buffer_drain(p->buf, p->read_so_far - 1);
+
+ p->read_so_far = 1;
+ } else if (p->state == PARSER_STATE_PROMPT_COMPLETE) {
+ len -= p->read_so_far;
+ wrap -= p->read_so_far;
+
+ g_at_chat_wakeup_writer(p);
+
+ ring_buffer_drain(p->buf, p->read_so_far);
+
+ p->read_so_far = 0;
+ }
+ }
+
+ if (p->state == PARSER_STATE_IDLE && p->read_so_far > 0) {
+ ring_buffer_drain(p->buf, p->read_so_far);
+ p->read_so_far = 0;
+ }
+}
+
+static gboolean received_data(GIOChannel *channel, GIOCondition cond,
+ gpointer data)
+{
+ unsigned char *buf;
+ GAtChat *chat = data;
+ GIOError err;
+ gsize rbytes;
+ gsize toread;
+ gsize total_read = 0;
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ /* Regardless of condition, try to read all the data available */
+ do {
+ rbytes = 0;
+
+ toread = ring_buffer_avail_no_wrap(chat->buf);
+
+ /* We're going to start overflowing the buffer
+ * this cannot happen under normal circumstances, so probably
+ * the channel is getting garbage, drop off
+ */
+ if (toread == 0) {
+ if (chat->state == PARSER_STATE_RESPONSE)
+ return FALSE;
+
+ err = G_IO_ERROR_AGAIN;
+ break;
+ }
+
+ buf = ring_buffer_write_ptr(chat->buf);
+
+ err = g_io_channel_read(channel, (char *) buf, toread, &rbytes);
+
+ total_read += rbytes;
+
+ if (rbytes > 0)
+ ring_buffer_write_advance(chat->buf, rbytes);
+
+ } while (err == G_IO_ERROR_NONE && rbytes > 0);
+
+ if (total_read > 0)
+ new_bytes(chat);
+
+ if (cond & (G_IO_HUP | G_IO_ERR))
+ return FALSE;
+
+ if (err == G_IO_ERROR_NONE && rbytes == 0)
+ return FALSE;
+
+ if (err != G_IO_ERROR_NONE && err != G_IO_ERROR_AGAIN)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean wakeup_no_response(gpointer user)
+{
+ GAtChat *chat = user;
+
+ g_at_chat_finish_command(chat, FALSE, NULL);
+
+ return FALSE;
+}
+
+static gboolean can_write_data(GIOChannel *channel, GIOCondition cond,
+ gpointer data)
+{
+ GAtChat *chat = data;
+ struct at_command *cmd;
+ GIOError err;
+ gsize bytes_written;
+ gsize towrite;
+ gsize len;
+ char *cr;
+ gboolean wakeup_first = FALSE;
+#ifdef WRITE_SCHEDULER_DEBUG
+ int limiter;
+#endif
+
+ if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
+ return FALSE;
+
+ /* Grab the first command off the queue and write as
+ * much of it as we can
+ */
+ cmd = g_queue_peek_head(chat->command_queue);
+
+ /* For some reason command queue is empty, cancel write watcher */
+ if (cmd == NULL)
+ return FALSE;
+
+ len = strlen(cmd->cmd);
+
+ /* For some reason write watcher fired, but we've already
+ * written the entire command out to the io channel,
+ * cancel write watcher
+ */
+ if (chat->cmd_bytes_written >= len)
+ return FALSE;
+
+ if (chat->wakeup) {
+ if (!chat->wakeup_timer) {
+ wakeup_first = TRUE;
+ chat->wakeup_timer = g_timer_new();
+
+ } else if (g_timer_elapsed(chat->wakeup_timer, NULL) >
+ chat->inactivity_time)
+ wakeup_first = TRUE;
+ }
+
+ if (chat->cmd_bytes_written == 0 && wakeup_first == TRUE) {
+ cmd = at_command_create(chat->wakeup, NULL, NULL, NULL, NULL);
+
+ if (!cmd)
+ return FALSE;
+
+ g_queue_push_head(chat->command_queue, cmd);
+
+ len = strlen(chat->wakeup);
+
+ g_timeout_add(chat->wakeup_timeout, wakeup_no_response,
+ chat);
+ }
+
+ towrite = len - chat->cmd_bytes_written;
+
+ cr = strchr(cmd->cmd + chat->cmd_bytes_written, '\r');
+
+ if (cr)
+ towrite = cr - (cmd->cmd + chat->cmd_bytes_written) + 1;
+
+#ifdef WRITE_SCHEDULER_DEBUG
+ limiter = towrite;
+
+ if (limiter > 5)
+ limiter = 5;
+#endif
+
+ err = g_io_channel_write(chat->channel,
+ cmd->cmd + chat->cmd_bytes_written,
+#ifdef WRITE_SCHEDULER_DEBUG
+ limiter,
+#else
+ towrite,
+#endif
+ &bytes_written);
+
+ if (err != G_IO_ERROR_NONE) {
+ g_at_chat_shutdown(chat);
+ return FALSE;
+ }
+
+ chat->cmd_bytes_written += bytes_written;
+
+ if (bytes_written < towrite)
+ return TRUE;
+
+ /* Full command submitted, update timer */
+ if (chat->wakeup_timer)
+ g_timer_start(chat->wakeup_timer);
+
+ return FALSE;
+}
+
+static void g_at_chat_wakeup_writer(GAtChat *chat)
+{
+ if (chat->write_watch != 0)
+ return;
+
+ chat->write_watch = g_io_add_watch_full(chat->channel,
+ G_PRIORITY_DEFAULT,
+ G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ can_write_data, chat,
+ (GDestroyNotify)write_watcher_destroy_notify);
+}
+
+GAtChat *g_at_chat_new(GIOChannel *channel, int flags)
+{
+ GAtChat *chat;
+ GIOFlags io_flags;
+
+ if (!channel)
+ return NULL;
+
+ chat = g_try_new0(GAtChat, 1);
+
+ if (!chat)
+ return chat;
+
+ chat->next_cmd_id = 1;
+ chat->next_notify_id = 1;
+ chat->flags = flags;
+
+ chat->buf = ring_buffer_new(4096);
+
+ if (!chat->buf)
+ goto error;
+
+ chat->command_queue = g_queue_new();
+
+ if (!chat->command_queue)
+ goto error;
+
+ chat->notify_list = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, (GDestroyNotify)at_notify_destroy);
+
+ if (g_io_channel_set_encoding(channel, NULL, NULL) !=
+ G_IO_STATUS_NORMAL)
+ goto error;
+
+ io_flags = g_io_channel_get_flags(channel);
+
+ io_flags |= G_IO_FLAG_NONBLOCK;
+
+ if (g_io_channel_set_flags(channel, io_flags, NULL) !=
+ G_IO_STATUS_NORMAL)
+ goto error;
+
+ g_io_channel_set_close_on_unref(channel, TRUE);
+
+ chat->channel = channel;
+ chat->read_watch = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ received_data, chat,
+ (GDestroyNotify)read_watcher_destroy_notify);
+
+ return chat;
+
+error:
+ if (chat->buf)
+ ring_buffer_free(chat->buf);
+
+ if (chat->command_queue)
+ g_queue_free(chat->command_queue);
+
+ if (chat->notify_list)
+ g_hash_table_destroy(chat->notify_list);
+
+ g_free(chat);
+ return NULL;
+}
+
+GAtChat *g_at_chat_ref(GAtChat *chat)
+{
+ if (chat == NULL)
+ return NULL;
+
+ g_atomic_int_inc(&chat->ref_count);
+
+ return chat;
+}
+
+void g_at_chat_unref(GAtChat *chat)
+{
+ gboolean is_zero;
+
+ if (chat == NULL)
+ return;
+
+ is_zero = g_atomic_int_dec_and_test(&chat->ref_count);
+
+ if (is_zero) {
+ g_at_chat_shutdown(chat);
+
+ g_at_chat_cleanup(chat);
+ g_free(chat);
+ }
+}
+
+gboolean g_at_chat_shutdown(GAtChat *chat)
+{
+ if (chat->channel == NULL)
+ return FALSE;
+
+ chat->disconnecting = TRUE;
+
+ if (chat->read_watch)
+ g_source_remove(chat->read_watch);
+
+ if (chat->write_watch)
+ g_source_remove(chat->write_watch);
+
+ return TRUE;
+}
+
+gboolean g_at_chat_set_disconnect_function(GAtChat *chat,
+ GAtDisconnectFunc disconnect, gpointer user_data)
+{
+ if (chat == NULL)
+ return FALSE;
+
+ chat->user_disconnect = disconnect;
+ chat->user_disconnect_data = user_data;
+
+ return TRUE;
+}
+
+guint g_at_chat_send(GAtChat *chat, const char *cmd,
+ const char **prefix_list, GAtResultFunc func,
+ gpointer user_data, GDestroyNotify notify)
+{
+ struct at_command *c;
+
+ if (chat == NULL || chat->command_queue == NULL)
+ return 0;
+
+ c = at_command_create(cmd, prefix_list, func, user_data, notify);
+
+ if (!c)
+ return 0;
+
+ c->id = chat->next_cmd_id++;
+
+ g_queue_push_tail(chat->command_queue, c);
+
+ if (g_queue_get_length(chat->command_queue) == 1)
+ g_at_chat_wakeup_writer(chat);
+
+ return c->id;
+}
+
+gboolean g_at_chat_cancel(GAtChat *chat, guint id)
+{
+ GList *l;
+
+ if (chat == NULL || chat->command_queue == NULL)
+ return FALSE;
+
+ l = g_queue_find_custom(chat->command_queue, GUINT_TO_POINTER(id),
+ at_command_compare_by_id);
+
+ if (!l)
+ return FALSE;
+
+ if (l == g_queue_peek_head(chat->command_queue)) {
+ struct at_command *c = l->data;
+
+ /* We can't actually remove it since it is most likely
+ * already in progress, just null out the callback
+ * so it won't be called
+ */
+ c->callback = NULL;
+ } else {
+ at_command_destroy(l->data);
+ g_queue_remove(chat->command_queue, l->data);
+ }
+
+ return TRUE;
+}
+
+static struct at_notify *at_notify_create(GAtChat *chat, const char *prefix,
+ gboolean pdu)
+{
+ struct at_notify *notify;
+ char *key;
+
+ key = g_strdup(prefix);
+
+ if (!key)
+ return 0;
+
+ notify = g_try_new0(struct at_notify, 1);
+
+ if (!notify) {
+ g_free(key);
+ return 0;
+ }
+
+ notify->pdu = pdu;
+
+ g_hash_table_insert(chat->notify_list, key, notify);
+
+ return notify;
+}
+
+guint g_at_chat_register(GAtChat *chat, const char *prefix,
+ GAtNotifyFunc func, gboolean expect_pdu,
+ gpointer user_data,
+ GDestroyNotify destroy_notify)
+{
+ struct at_notify *notify;
+ struct at_notify_node *node;
+
+ if (chat == NULL || chat->notify_list == NULL)
+ return 0;
+
+ if (func == NULL)
+ return 0;
+
+ if (prefix == NULL || strlen(prefix) == 0)
+ return 0;
+
+ notify = g_hash_table_lookup(chat->notify_list, prefix);
+
+ if (!notify)
+ notify = at_notify_create(chat, prefix, expect_pdu);
+
+ if (!notify || notify->pdu != expect_pdu)
+ return 0;
+
+ node = g_try_new0(struct at_notify_node, 1);
+
+ if (!node)
+ return 0;
+
+ node->id = chat->next_notify_id++;
+ node->callback = func;
+ node->user_data = user_data;
+ node->notify = destroy_notify;
+
+ notify->nodes = g_slist_prepend(notify->nodes, node);
+
+ return node->id;
+}
+
+gboolean g_at_chat_unregister(GAtChat *chat, guint id)
+{
+ GHashTableIter iter;
+ struct at_notify *notify;
+ char *prefix;
+ gpointer key, value;
+ GSList *l;
+
+ if (chat == NULL || chat->notify_list == NULL)
+ return FALSE;
+
+ g_hash_table_iter_init(&iter, chat->notify_list);
+
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ prefix = key;
+ notify = value;
+
+ l = g_slist_find_custom(notify->nodes, GUINT_TO_POINTER(id),
+ at_notify_node_compare_by_id);
+
+ if (!l)
+ continue;
+
+ at_notify_node_destroy(l->data);
+ notify->nodes = g_slist_remove(notify->nodes, l->data);
+
+ if (notify->nodes == NULL)
+ g_hash_table_iter_remove(&iter);
+
+ return TRUE;
+ }
+
+ return TRUE;
+}
+
+gboolean g_at_chat_set_wakeup_command(GAtChat *chat, const char *cmd,
+ unsigned int timeout, unsigned int msec)
+{
+ if (chat == NULL)
+ return FALSE;
+
+ if (chat->wakeup)
+ g_free(chat->wakeup);
+
+ chat->wakeup = g_strdup(cmd);
+ chat->inactivity_time = (gdouble)msec / 1000;
+ chat->wakeup_timeout = timeout;
+
+ return TRUE;
+}
--- /dev/null
+/*
+ *
+ * AT chat library with GLib integration
+ *
+ * Copyright (C) 2008-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __GATCHAT_H
+#define __GATCHAT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gatresult.h"
+
+struct _GAtChat;
+
+typedef struct _GAtChat GAtChat;
+
+typedef void (*GAtResultFunc)(gboolean success, GAtResult *result,
+ gpointer user_data);
+typedef void (*GAtNotifyFunc)(GAtResult *result, gpointer user_data);
+typedef void (*GAtDisconnectFunc)(gpointer user_data);
+
+enum _GAtChatFlags {
+ G_AT_CHAT_FLAG_NO_LEADING_CRLF = 1, /* Some emulators are broken */
+};
+
+typedef enum _GAtChatFlags GAtChatFlags;
+
+GAtChat *g_at_chat_new(GIOChannel *channel, int flags);
+
+GAtChat *g_at_chat_ref(GAtChat *chat);
+void g_at_chat_unref(GAtChat *chat);
+
+gboolean g_at_chat_shutdown(GAtChat *chat);
+
+gboolean g_at_chat_set_disconnect_function(GAtChat *chat,
+ GAtDisconnectFunc disconnect, gpointer user_data);
+
+/*!
+ * Queue an AT command for execution. The command contents are given
+ * in cmd. Once the command executes, the callback function given by
+ * func is called with user provided data in user_data.
+ *
+ * Returns an id of the queued command which can be canceled using
+ * g_at_chat_cancel. If an error occurred, an id of 0 is returned.
+ *
+ * This function can be used in three ways:
+ * - Send a simple command such as g_at_chat_send(p, "AT+CGMI?", ...
+ *
+ * - Send a compound command: g_at_chat_send(p, "AT+CMD1;+CMD2", ...
+ *
+ * - Send a command requiring a prompt. The command up to '\r' is sent
+ * after which time a '> ' prompt is expected from the modem. Further
+ * contents of the command are sent until a '\r' or end of string is
+ * encountered. If end of string is encountered, the Ctrl-Z character
+ * is sent automatically. There is no need to include the Ctrl-Z
+ * by the caller.
+ *
+ * The valid_resp field can be used to send an array of strings which will
+ * be accepted as a valid response for this command. This is treated as a
+ * simple prefix match. If a response line comes in from the modem and it
+ * does not match any of the prefixes in valid_resp, it is treated as an
+ * unsolicited notification. If valid_resp is NULL, then all response
+ * lines after command submission and final response line are treated as
+ * part of the command response. This can be used to get around broken
+ * modems which send unsolicited notifications during command processing.
+ */
+guint g_at_chat_send(GAtChat *chat, const char *cmd,
+ const char **valid_resp, GAtResultFunc func,
+ gpointer user_data, GDestroyNotify notify);
+
+gboolean g_at_chat_cancel(GAtChat *chat, guint id);
+
+guint g_at_chat_register(GAtChat *chat, const char *prefix,
+ GAtNotifyFunc func, gboolean expect_pdu,
+ gpointer user_data, GDestroyNotify notify);
+
+gboolean g_at_chat_unregister(GAtChat *chat, guint id);
+
+gboolean g_at_chat_set_wakeup_command(GAtChat *chat, const char *cmd,
+ guint timeout, guint msec);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GATCHAT_H */
--- /dev/null
+/*
+ *
+ * AT chat library with GLib integration
+ *
+ * Copyright (C) 2008-2009 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 <string.h>
+#include <stdio.h>
+
+#include <glib.h>
+
+#include "gatresult.h"
+
+void g_at_result_iter_init(GAtResultIter *iter, GAtResult *result)
+{
+ iter->result = result;
+ iter->pre.next = result->lines;
+ iter->pre.data = NULL;
+ iter->l = &iter->pre;
+ iter->line_pos = 0;
+}
+
+gboolean g_at_result_iter_next(GAtResultIter *iter, const char *prefix)
+{
+ char *line;
+ int prefix_len = prefix ? strlen(prefix) : 0;
+
+ while ((iter->l = iter->l->next)) {
+ line = iter->l->data;
+
+ if (prefix_len == 0) {
+ iter->line_pos = 0;
+ return TRUE;
+ }
+
+ if (g_str_has_prefix(line, prefix) == FALSE)
+ continue;
+
+ iter->line_pos = prefix_len;
+
+ while (iter->line_pos < strlen(line) &&
+ line[iter->line_pos] == ' ')
+ iter->line_pos += 1;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+const char *g_at_result_iter_raw_line(GAtResultIter *iter)
+{
+ const char *line;
+
+ if (!iter)
+ return NULL;
+
+ if (!iter->l)
+ return NULL;
+
+ line = iter->l->data;
+
+ line += iter->line_pos;
+
+ return line;
+}
+
+static inline int skip_to_next_field(const char *line, int pos, int len)
+{
+ if (pos < len && line[pos] == ',')
+ pos += 1;
+
+ while (pos < len && line[pos] == ' ')
+ pos += 1;
+
+ return pos;
+}
+
+gboolean g_at_result_iter_next_string(GAtResultIter *iter, const char **str)
+{
+ unsigned int pos;
+ unsigned int end;
+ unsigned int len;
+ char *line;
+
+ if (!iter)
+ return FALSE;
+
+ if (!iter->l)
+ return FALSE;
+
+ line = iter->l->data;
+ len = strlen(line);
+
+ pos = iter->line_pos;
+
+ /* Omitted string */
+ if (line[pos] == ',') {
+ end = pos;
+ memset(iter->buf, 0, sizeof(iter->buf));
+ goto out;
+ }
+
+ if (line[pos++] != '"')
+ return FALSE;
+
+ end = pos;
+
+ while (end < len && line[end] != '"')
+ end += 1;
+
+ if (line[end] != '"')
+ return FALSE;
+
+ if (end - pos >= sizeof(iter->buf))
+ return FALSE;
+
+ strncpy(iter->buf, line+pos, end-pos);
+ memset(iter->buf + end - pos, 0, sizeof(iter->buf) - end + pos);
+
+ /* Skip " */
+ end += 1;
+
+out:
+ iter->line_pos = skip_to_next_field(line, end, len);
+
+ if (str)
+ *str = iter->buf;
+
+ return TRUE;
+}
+
+gboolean g_at_result_iter_next_hexstring(GAtResultIter *iter,
+ const guint8 **str, gint *length)
+{
+ unsigned int pos;
+ unsigned int end;
+ unsigned int len;
+ char *line;
+ char *bufpos;
+
+ if (!iter)
+ return FALSE;
+
+ if (!iter->l)
+ return FALSE;
+
+ line = iter->l->data;
+ len = strlen(line);
+
+ pos = iter->line_pos;
+
+ /* Omitted string */
+ if (line[pos] == ',') {
+ end = pos;
+ memset(iter->buf, 0, sizeof(iter->buf));
+ goto out;
+ }
+
+ end = pos;
+
+ while (end < len && g_ascii_isxdigit(line[end]))
+ end += 1;
+
+ if ((end - pos) & 1)
+ return FALSE;
+
+ if ((end - pos) / 2 >= sizeof(iter->buf))
+ return FALSE;
+ *length = (end - pos) / 2;
+
+ for (bufpos = iter->buf; pos < end; pos += 2)
+ sscanf(line + pos, "%02hhx", bufpos++);
+ memset(bufpos, 0, sizeof(iter->buf) - (bufpos - iter->buf));
+
+out:
+ iter->line_pos = skip_to_next_field(line, end, len);
+
+ if (str)
+ *str = (guint8 *) iter->buf;
+
+ return TRUE;
+}
+
+gboolean g_at_result_iter_next_number(GAtResultIter *iter, gint *number)
+{
+ int pos;
+ int end;
+ int len;
+ int value = 0;
+ char *line;
+
+ if (!iter)
+ return FALSE;
+
+ if (!iter->l)
+ return FALSE;
+
+ line = iter->l->data;
+ len = strlen(line);
+
+ pos = iter->line_pos;
+ end = pos;
+
+ while (line[end] >= '0' && line[end] <= '9') {
+ value = value * 10 + (int)(line[end] - '0');
+ end += 1;
+ }
+
+ if (pos == end)
+ return FALSE;
+
+ iter->line_pos = skip_to_next_field(line, end, len);
+
+ if (number)
+ *number = value;
+
+ return TRUE;
+}
+
+gboolean g_at_result_iter_next_range(GAtResultIter *iter, gint *min, gint *max)
+{
+ int pos;
+ int end;
+ int len;
+ int low = 0;
+ int high = 0;
+ char *line;
+
+ if (!iter)
+ return FALSE;
+
+ if (!iter->l)
+ return FALSE;
+
+ line = iter->l->data;
+ len = strlen(line);
+
+ pos = iter->line_pos;
+
+ while (pos < len && line[pos] == ' ')
+ pos += 1;
+
+ end = pos;
+
+ while (line[end] >= '0' && line[end] <= '9') {
+ low = low * 10 + (int)(line[end] - '0');
+ end += 1;
+ }
+
+ if (pos == end)
+ return FALSE;
+
+ if (line[end] == ',') {
+ high = low;
+ goto out;
+ }
+
+ if (line[end] == '-')
+ pos = end = end + 1;
+ else
+ return FALSE;
+
+ while (line[end] >= '0' && line[end] <= '9') {
+ high = high * 10 + (int)(line[end] - '0');
+ end += 1;
+ }
+
+ if (pos == end)
+ return FALSE;
+
+out:
+ iter->line_pos = skip_to_next_field(line, end, len);
+
+ if (min)
+ *min = low;
+
+ if (max)
+ *max = high;
+
+ return TRUE;
+}
+
+static gint skip_until(const char *line, int start, const char delim)
+{
+ int len = strlen(line);
+ int i = start;
+
+ while (i < len) {
+ if (line[i] == delim)
+ return i;
+
+ if (line[i] != '(') {
+ i += 1;
+ continue;
+ }
+
+ i = skip_until(line, i+1, ')');
+
+ if (i < len)
+ i += 1;
+ }
+
+ return i;
+}
+
+gboolean g_at_result_iter_skip_next(GAtResultIter *iter)
+{
+ unsigned int skipped_to;
+ char *line;
+
+ if (!iter)
+ return FALSE;
+
+ if (!iter->l)
+ return FALSE;
+
+ line = iter->l->data;
+
+ skipped_to = skip_until(line, iter->line_pos, ',');
+
+ if (skipped_to == iter->line_pos && line[skipped_to] != ',')
+ return FALSE;
+
+ iter->line_pos = skip_to_next_field(line, skipped_to, strlen(line));
+
+ return TRUE;
+}
+
+gboolean g_at_result_iter_open_list(GAtResultIter *iter)
+{
+ char *line;
+ unsigned int len;
+
+ if (!iter)
+ return FALSE;
+
+ if (!iter->l)
+ return FALSE;
+
+ line = iter->l->data;
+ len = strlen(line);
+
+ if (iter->line_pos >= len)
+ return FALSE;
+
+ if (line[iter->line_pos] != '(')
+ return FALSE;
+
+ iter->line_pos += 1;
+
+ while (iter->line_pos < strlen(line) &&
+ line[iter->line_pos] == ' ')
+ iter->line_pos += 1;
+
+ return TRUE;
+}
+
+gboolean g_at_result_iter_close_list(GAtResultIter *iter)
+{
+ char *line;
+ unsigned int len;
+
+ if (!iter)
+ return FALSE;
+
+ if (!iter->l)
+ return FALSE;
+
+ line = iter->l->data;
+ len = strlen(line);
+
+ if (iter->line_pos >= len)
+ return FALSE;
+
+ if (line[iter->line_pos] != ')')
+ return FALSE;
+
+ iter->line_pos += 1;
+
+ iter->line_pos = skip_to_next_field(line, iter->line_pos, len);
+
+ return TRUE;
+}
+
+const char *g_at_result_final_response(GAtResult *result)
+{
+ if (!result)
+ return NULL;
+
+ return result->final_or_pdu;
+}
+
+const char *g_at_result_pdu(GAtResult *result)
+{
+ if (!result)
+ return NULL;
+
+ return result->final_or_pdu;
+}
+
+gint g_at_result_num_response_lines(GAtResult *result)
+{
+ if (!result)
+ return 0;
+
+ if (!result->lines)
+ return 0;
+
+ return g_slist_length(result->lines);
+}
--- /dev/null
+/*
+ *
+ * AT chat library with GLib integration
+ *
+ * Copyright (C) 2008-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __GATCHAT_RESULT_H
+#define __GATCHAT_RESULT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _GAtResult {
+ GSList *lines;
+ char *final_or_pdu;
+};
+
+typedef struct _GAtResult GAtResult;
+
+struct _GAtResultIter {
+ GAtResult *result;
+ GSList *l;
+ char buf[2048];
+ unsigned int line_pos;
+ GSList pre;
+};
+
+typedef struct _GAtResultIter GAtResultIter;
+
+void g_at_result_iter_init(GAtResultIter *iter, GAtResult *result);
+
+gboolean g_at_result_iter_next(GAtResultIter *iter, const char *prefix);
+gboolean g_at_result_iter_open_list(GAtResultIter *iter);
+gboolean g_at_result_iter_close_list(GAtResultIter *iter);
+
+gboolean g_at_result_iter_skip_next(GAtResultIter *iter);
+
+gboolean g_at_result_iter_next_range(GAtResultIter *iter, gint *min, gint *max);
+gboolean g_at_result_iter_next_string(GAtResultIter *iter, const char **str);
+gboolean g_at_result_iter_next_number(GAtResultIter *iter, gint *number);
+gboolean g_at_result_iter_next_hexstring(GAtResultIter *iter,
+ const guint8 **str, gint *length);
+
+const char *g_at_result_iter_raw_line(GAtResultIter *iter);
+
+const char *g_at_result_final_response(GAtResult *result);
+const char *g_at_result_pdu(GAtResult *result);
+
+gint g_at_result_num_response_lines(GAtResult *result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GATCHAT_RESULT_H */
--- /dev/null
+/*
+ *
+ * AT chat library with GLib integration
+ *
+ * Copyright (C) 2008-2009 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 <string.h>
+
+#include <glib.h>
+
+#include "ringbuffer.h"
+
+#define MAX_SIZE 262144
+
+struct ring_buffer *ring_buffer_new(unsigned int size)
+{
+ unsigned int real_size = 1;
+ struct ring_buffer *buffer;
+
+ /* Find the next power of two for size */
+ while (real_size < size && real_size < MAX_SIZE)
+ real_size = real_size << 1;
+
+ if (real_size > MAX_SIZE)
+ return NULL;
+
+ buffer = g_new(struct ring_buffer, 1);
+
+ if (!buffer)
+ return NULL;
+
+ buffer->buffer = g_new(unsigned char, real_size);
+
+ if (!buffer->buffer) {
+ g_free(buffer);
+ return NULL;
+ }
+
+ buffer->size = real_size;
+ buffer->in = 0;
+ buffer->out = 0;
+
+ return buffer;
+}
+
+int ring_buffer_write(struct ring_buffer *buf, const void *data,
+ unsigned int len)
+{
+ unsigned int end;
+ unsigned int offset;
+ const unsigned char *d = data; /* Needed to satisfy non-gcc compilers */
+
+ /* Determine how much we can actually write */
+ len = MIN(len, buf->size - buf->in + buf->out);
+
+ /* Determine how much to write before wrapping */
+ offset = buf->in % buf->size;
+ end = MIN(len, buf->size - offset);
+ memcpy(buf->buffer+offset, d, end);
+
+ /* Now put the remainder on the beginning of the buffer */
+ memcpy(buf->buffer, d + end, len - end);
+
+ buf->in += len;
+
+ return len;
+}
+
+unsigned char *ring_buffer_write_ptr(struct ring_buffer *buf)
+{
+ return buf->buffer + buf->in % buf->size;
+}
+
+int ring_buffer_avail_no_wrap(struct ring_buffer *buf)
+{
+ unsigned int offset = buf->in % buf->size;
+ unsigned int len = buf->size - buf->in + buf->out;
+
+ return MIN(len, buf->size - offset);
+}
+
+int ring_buffer_write_advance(struct ring_buffer *buf, unsigned int len)
+{
+ len = MIN(len, buf->size - buf->in + buf->out);
+ buf->in += len;
+
+ return len;
+}
+
+int ring_buffer_read(struct ring_buffer *buf, void *data, unsigned int len)
+{
+ unsigned int end;
+ unsigned int offset;
+ unsigned char *d = data;
+
+ len = MIN(len, buf->in - buf->out);
+
+ /* Grab data from buffer starting at offset until the end */
+ offset = buf->out % buf->size;
+ end = MIN(len, buf->size - offset);
+ memcpy(d, buf->buffer + offset, end);
+
+ /* Now grab remainder from the beginning */
+ memcpy(d + end, buf->buffer, len - end);
+
+ buf->out += len;
+
+ if (buf->out == buf->in)
+ buf->out = buf->in = 0;
+
+ return len;
+}
+
+int ring_buffer_drain(struct ring_buffer *buf, unsigned int len)
+{
+ len = MIN(len, buf->in - buf->out);
+
+ buf->out += len;
+
+ if (buf->out == buf->in)
+ buf->out = buf->in = 0;
+
+ return len;
+}
+
+int ring_buffer_len_no_wrap(struct ring_buffer *buf)
+{
+ unsigned int offset = buf->out % buf->size;
+ unsigned int len = buf->in - buf->out;
+
+ return MIN(len, buf->size - offset);
+}
+
+unsigned char *ring_buffer_read_ptr(struct ring_buffer *buf,
+ unsigned int offset)
+{
+ return buf->buffer + (buf->out + offset) % buf->size;
+}
+
+int ring_buffer_len(struct ring_buffer *buf)
+{
+ if (!buf)
+ return -1;
+
+ return buf->in - buf->out;
+}
+
+void ring_buffer_reset(struct ring_buffer *buf)
+{
+ if (!buf)
+ return;
+
+ buf->in = 0;
+ buf->out = 0;
+}
+
+int ring_buffer_avail(struct ring_buffer *buf)
+{
+ if (!buf)
+ return -1;
+
+ return buf->size - buf->in + buf->out;
+}
+
+int ring_buffer_capacity(struct ring_buffer *buf)
+{
+ if (!buf)
+ return -1;
+
+ return buf->size;
+}
+
+void ring_buffer_free(struct ring_buffer *buf)
+{
+ if (!buf)
+ return;
+
+ g_free(buf->buffer);
+ g_free(buf);
+}
--- /dev/null
+/*
+ *
+ * AT chat library with GLib integration
+ *
+ * Copyright (C) 2008-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __GATCHAT_RINGBUFFER_H
+#define __GATCHAT_RINGBUFFER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ring_buffer {
+ unsigned char *buffer;
+ unsigned int size;
+ unsigned int in;
+ unsigned int out;
+};
+
+/*!
+ * Creates a new ring buffer with capacity size
+ */
+struct ring_buffer *ring_buffer_new(unsigned int size);
+
+/*!
+ * Frees the resources allocated for the ring buffer
+ */
+void ring_buffer_free(struct ring_buffer *buf);
+
+/*!
+ * Returns the capacity of the ring buffer
+ */
+int ring_buffer_capacity(struct ring_buffer *buf);
+
+/*!
+ * Resets the ring buffer, all data inside the buffer is lost
+ */
+void ring_buffer_reset(struct ring_buffer *buf);
+
+/*!
+ * Writes data of size len into the ring buffer buf. Returns -1 if the
+ * write failed or the number of bytes written
+ */
+int ring_buffer_write(struct ring_buffer *buf, const void *data,
+ unsigned int len);
+
+/*!
+ * Advances the write counter by len, this is meant to be used with
+ * the ring_buffer_write_ptr function. Returns the number of bytes
+ * actually advanced (the capacity of the buffer)
+ */
+int ring_buffer_write_advance(struct ring_buffer *buf, unsigned int len);
+
+/*!
+ * Returns the write pointer. Careful not to write past the end of the
+ * buffer. Use the ring_buffer_avail_no_wrap function,
+ * ring_buffer_write_advance.
+ */
+unsigned char *ring_buffer_write_ptr(struct ring_buffer *buf);
+
+/*!
+ * Returns the number of free bytes available in the buffer
+ */
+int ring_buffer_avail(struct ring_buffer *buf);
+
+/*!
+ * Returns the number of free bytes available in the buffer without wrapping
+ */
+int ring_buffer_avail_no_wrap(struct ring_buffer *buf);
+
+/*!
+ * Reads data from the ring buffer buf into memory region pointed to by data.
+ * A maximum of len bytes will be read. Returns -1 if the read failed or
+ * the number of bytes read
+ */
+int ring_buffer_read(struct ring_buffer *buf, void *data,
+ unsigned int len);
+
+/*!
+ * Returns the read pointer with read offset specified by offset. No bounds
+ * checking is performed. Be careful not to read past the end of the buffer.
+ * Use the ring_buffer_len_no_wrap function, and ring_buffer_drain.
+ */
+unsigned char *ring_buffer_read_ptr(struct ring_buffer *buf,
+ unsigned int offset);
+
+/*!
+ * Returns the number of bytes currently available to be read in the buffer
+ */
+int ring_buffer_len(struct ring_buffer *buf);
+
+/*!
+ * Returns the number of bytes currently available to be read in the buffer
+ * without wrapping.
+ */
+int ring_buffer_len_no_wrap(struct ring_buffer *buf);
+
+/*!
+ * Drains the ring buffer of len bytes. Returns the number of bytes the
+ * read counter was actually advanced.
+ */
+int ring_buffer_drain(struct ring_buffer *buf, unsigned int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GATCHAT_RINGBUFFER_H */
--- /dev/null
+
+noinst_LTLIBRARIES = libgdbus.la
+
+libgdbus_la_SOURCES = gdbus.h mainloop.c object.c watch.c
+
+AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@
+
+MAINTAINERCLEANFILES = Makefile.in
--- /dev/null
+/*
+ *
+ * D-Bus helper library
+ *
+ * Copyright (C) 2004-2009 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 void (* GDBusWatchFunction) (DBusConnection *connection,
+ 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);
+
+gboolean g_dbus_request_name(DBusConnection *connection, const char *name,
+ DBusError *error);
+
+gboolean g_dbus_check_service(DBusConnection *connection, const char *name);
+
+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 enum {
+ G_DBUS_METHOD_FLAG_DEPRECATED = (1 << 0),
+ G_DBUS_METHOD_FLAG_NOREPLY = (1 << 1),
+ G_DBUS_METHOD_FLAG_ASYNC = (1 << 2),
+} GDBusMethodFlags;
+
+typedef enum {
+ G_DBUS_SIGNAL_FLAG_DEPRECATED = (1 << 0),
+} GDBusSignalFlags;
+
+typedef enum {
+ G_DBUS_PROPERTY_FLAG_DEPRECATED = (1 << 0),
+} GDBusPropertyFlags;
+
+typedef struct {
+ const char *name;
+ const char *signature;
+ const char *reply;
+ GDBusMethodFunction function;
+ GDBusMethodFlags flags;
+} GDBusMethodTable;
+
+typedef struct {
+ const char *name;
+ const char *signature;
+ GDBusSignalFlags flags;
+} GDBusSignalTable;
+
+typedef struct {
+ const char *name;
+ const char *type;
+ GDBusPropertyFlags flags;
+} GDBusPropertyTable;
+
+gboolean g_dbus_register_interface(DBusConnection *connection,
+ const char *path, const char *name,
+ GDBusMethodTable *methods,
+ GDBusSignalTable *signals,
+ GDBusPropertyTable *properties,
+ void *user_data,
+ GDBusDestroyFunction destroy);
+gboolean g_dbus_unregister_interface(DBusConnection *connection,
+ const char *path, const char *name);
+
+DBusMessage *g_dbus_create_error(DBusMessage *message, const char *name,
+ const char *format, ...);
+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_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 *rule, GDBusSignalFunction function,
+ void *user_data, GDBusDestroyFunction destroy);
+gboolean g_dbus_remove_watch(DBusConnection *connection, guint tag);
+void g_dbus_remove_all_watches(DBusConnection *connection);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GDBUS_H */
--- /dev/null
+/*
+ *
+ * D-Bus helper library
+ *
+ * Copyright (C) 2004-2009 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 <stdint.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+
+#ifdef NEED_DBUS_WATCH_GET_UNIX_FD
+#define dbus_watch_get_unix_fd dbus_watch_get_fd
+#endif
+
+#include "gdbus.h"
+
+#define DISPATCH_TIMEOUT 0
+
+#define info(fmt...)
+#define error(fmt...)
+#define debug(fmt...)
+
+typedef struct {
+ uint32_t id;
+ DBusTimeout *timeout;
+} timeout_handler_t;
+
+struct watch_info {
+ guint watch_id;
+ GIOChannel *io;
+ DBusConnection *conn;
+};
+
+struct server_info {
+ guint watch_id;
+ GIOChannel *io;
+ DBusServer *server;
+};
+
+struct disconnect_data {
+ GDBusWatchFunction disconnect_cb;
+ void *user_data;
+};
+
+static DBusHandlerResult disconnect_filter(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct disconnect_data *dc_data = data;
+
+ if (dbus_message_is_signal(msg,
+ DBUS_INTERFACE_LOCAL, "Disconnected") == TRUE) {
+ error("Got disconnected from the system message bus");
+ dc_data->disconnect_cb(conn, dc_data->user_data);
+ dbus_connection_unref(conn);
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static gboolean message_dispatch_cb(void *data)
+{
+ DBusConnection *connection = data;
+
+ dbus_connection_ref(connection);
+
+ /* Dispatch messages */
+ while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS);
+
+ dbus_connection_unref(connection);
+
+ return FALSE;
+}
+
+static gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ DBusWatch *watch = data;
+ struct watch_info *info = dbus_watch_get_data(watch);
+ int flags = 0;
+
+ 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(watch, flags);
+
+ if (dbus_connection_get_dispatch_status(info->conn) == DBUS_DISPATCH_DATA_REMAINS)
+ g_timeout_add(DISPATCH_TIMEOUT, message_dispatch_cb, info->conn);
+
+ return TRUE;
+}
+
+static dbus_bool_t add_watch(DBusWatch *watch, void *data)
+{
+ GIOCondition cond = G_IO_HUP | G_IO_ERR;
+ DBusConnection *conn = data;
+ struct watch_info *info;
+ int fd, flags;
+
+ if (!dbus_watch_get_enabled(watch))
+ return TRUE;
+
+ info = g_new(struct watch_info, 1);
+
+ fd = dbus_watch_get_unix_fd(watch);
+ info->io = g_io_channel_unix_new(fd);
+ info->conn = dbus_connection_ref(conn);
+
+ dbus_watch_set_data(watch, info, NULL);
+
+ 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->watch_id = g_io_add_watch(info->io, cond, watch_func, watch);
+
+ return TRUE;
+}
+
+static void remove_watch(DBusWatch *watch, void *data)
+{
+ struct watch_info *info = dbus_watch_get_data(watch);
+
+ dbus_watch_set_data(watch, NULL, NULL);
+
+ if (info) {
+ g_source_remove(info->watch_id);
+ g_io_channel_unref(info->io);
+ dbus_connection_unref(info->conn);
+ g_free(info);
+ }
+}
+
+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)
+{
+ timeout_handler_t *handler = data;
+
+ /* if not enabled should not be polled by the main loop */
+ if (dbus_timeout_get_enabled(handler->timeout) != TRUE)
+ return FALSE;
+
+ dbus_timeout_handle(handler->timeout);
+
+ return FALSE;
+}
+
+static void timeout_handler_free(void *data)
+{
+ timeout_handler_t *handler = data;
+ if (!handler)
+ return;
+
+ g_source_remove(handler->id);
+ g_free(handler);
+}
+
+static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
+{
+ timeout_handler_t *handler;
+
+ if (!dbus_timeout_get_enabled(timeout))
+ return TRUE;
+
+ handler = g_new0(timeout_handler_t, 1);
+
+ handler->timeout = timeout;
+ handler->id = g_timeout_add(dbus_timeout_get_interval(timeout),
+ timeout_handler_dispatch, handler);
+
+ dbus_timeout_set_data(timeout, handler, timeout_handler_free);
+
+ return TRUE;
+}
+
+static void remove_timeout(DBusTimeout *timeout, void *data)
+{
+}
+
+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_cb(DBusConnection *conn,
+ DBusDispatchStatus new_status, void *data)
+{
+ if (!dbus_connection_get_is_connected(conn))
+ return;
+
+ if (new_status == DBUS_DISPATCH_DATA_REMAINS)
+ g_timeout_add(DISPATCH_TIMEOUT, message_dispatch_cb, data);
+}
+
+static 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, conn, NULL);
+
+ dbus_connection_set_dispatch_status_function(conn, dispatch_status_cb,
+ conn, NULL);
+}
+
+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 (name != NULL) {
+ if (dbus_bus_request_name(conn, name,
+ DBUS_NAME_FLAG_DO_NOT_QUEUE, error) !=
+ DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER ) {
+ dbus_connection_unref(conn);
+ return NULL;
+ }
+
+ if (error != NULL) {
+ if (dbus_error_is_set(error) == TRUE) {
+ dbus_connection_unref(conn);
+ return NULL;
+ }
+ }
+ }
+
+ setup_dbus_with_main_loop(conn);
+
+ return conn;
+}
+
+gboolean g_dbus_request_name(DBusConnection *connection, const char *name,
+ DBusError *error)
+{
+ return TRUE;
+}
+
+gboolean g_dbus_check_service(DBusConnection *connection, const char *name)
+{
+ DBusMessage *message, *reply;
+ const char **names;
+ int i, count;
+ gboolean result = FALSE;
+
+ message = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "ListNames");
+ if (message == NULL) {
+ error("Can't allocate new message");
+ return FALSE;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(connection,
+ message, -1, NULL);
+
+ dbus_message_unref(message);
+
+ if (reply == NULL) {
+ error("Failed to execute method call");
+ return FALSE;
+ }
+
+ if (dbus_message_get_args(reply, NULL,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+ &names, &count, DBUS_TYPE_INVALID) == FALSE) {
+ error("Failed to read name list");
+ goto done;
+ }
+
+ for (i = 0; i < count; i++)
+ if (g_str_equal(names[i], name) == TRUE) {
+ result = TRUE;
+ break;
+ }
+
+done:
+ dbus_message_unref(reply);
+
+ return result;
+}
+
+gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
+ GDBusWatchFunction function,
+ void *user_data, DBusFreeFunction destroy)
+{
+ struct disconnect_data *dc_data;
+
+ dc_data = g_new(struct disconnect_data, 1);
+
+ dc_data->disconnect_cb = function;
+ dc_data->user_data = user_data;
+
+ dbus_connection_set_exit_on_disconnect(connection, FALSE);
+
+ if (dbus_connection_add_filter(connection, disconnect_filter,
+ dc_data, g_free) == FALSE) {
+ error("Can't add D-Bus disconnect filter");
+ g_free(dc_data);
+ return FALSE;
+ }
+
+ return TRUE;
+}
--- /dev/null
+/*
+ *
+ * D-Bus helper library
+ *
+ * Copyright (C) 2004-2009 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...)
+
+struct generic_data {
+ unsigned int refcount;
+ GSList *interfaces;
+ char *introspect;
+};
+
+struct interface_data {
+ char *name;
+ GDBusMethodTable *methods;
+ GDBusSignalTable *signals;
+ GDBusPropertyTable *properties;
+ void *user_data;
+ GDBusDestroyFunction destroy;
+};
+
+static void print_arguments(GString *gstr, const char *sig,
+ const char *direction)
+{
+ int i;
+
+ for (i = 0; sig[i]; i++) {
+ char type[32];
+ int struct_level, dict_level;
+ unsigned int len;
+ gboolean complete;
+
+ complete = FALSE;
+ struct_level = dict_level = 0;
+ memset(type, 0, sizeof(type));
+
+ /* Gather enough data to have a single complete type */
+ for (len = 0; len < (sizeof(type) - 1) && sig[i]; len++, i++) {
+ switch (sig[i]){
+ case '(':
+ struct_level++;
+ break;
+ case ')':
+ struct_level--;
+ if (struct_level <= 0 && dict_level <= 0)
+ complete = TRUE;
+ break;
+ case '{':
+ dict_level++;
+ break;
+ case '}':
+ dict_level--;
+ if (struct_level <= 0 && dict_level <= 0)
+ complete = TRUE;
+ break;
+ case 'a':
+ break;
+ default:
+ if (struct_level <= 0 && dict_level <= 0)
+ complete = TRUE;
+ break;
+ }
+
+ type[len] = sig[i];
+
+ if (complete)
+ break;
+ }
+
+
+ if (direction)
+ g_string_append_printf(gstr,
+ "\t\t\t<arg type=\"%s\" direction=\"%s\"/>\n",
+ type, direction);
+ else
+ g_string_append_printf(gstr,
+ "\t\t\t<arg type=\"%s\"/>\n",
+ type);
+ }
+}
+
+static void generate_interface_xml(GString *gstr, struct interface_data *iface)
+{
+ GDBusMethodTable *method;
+ GDBusSignalTable *signal;
+
+ for (method = iface->methods; method && method->name; method++) {
+ if (!strlen(method->signature) && !strlen(method->reply))
+ g_string_append_printf(gstr, "\t\t<method name=\"%s\"/>\n",
+ method->name);
+ else {
+ g_string_append_printf(gstr, "\t\t<method name=\"%s\">\n",
+ method->name);
+ print_arguments(gstr, method->signature, "in");
+ print_arguments(gstr, method->reply, "out");
+ g_string_append_printf(gstr, "\t\t</method>\n");
+ }
+ }
+
+ for (signal = iface->signals; signal && signal->name; signal++) {
+ if (!strlen(signal->signature))
+ g_string_append_printf(gstr, "\t\t<signal name=\"%s\"/>\n",
+ signal->name);
+ else {
+ g_string_append_printf(gstr, "\t\t<signal name=\"%s\">\n",
+ signal->name);
+ print_arguments(gstr, signal->signature, NULL);
+ g_string_append_printf(gstr, "\t\t</signal>\n");
+ }
+ }
+}
+
+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 name=\"%s\">\n", path);
+
+ for (list = data->interfaces; list; list = list->next) {
+ struct interface_data *iface = list->data;
+
+ g_string_append_printf(gstr, "\t<interface name=\"%s\">\n",
+ iface->name);
+
+ generate_interface_xml(gstr, iface);
+
+ g_string_append_printf(gstr, "\t</interface>\n");
+ }
+
+ if (!dbus_connection_list_registered(conn, path, &children))
+ goto done;
+
+ for (i = 0; children[i]; i++)
+ g_string_append_printf(gstr, "\t<node name=\"%s\"/>\n",
+ children[i]);
+
+ dbus_free_string_array(children);
+
+done:
+ g_string_append_printf(gstr, "</node>\n");
+
+ data->introspect = g_string_free(gstr, FALSE);
+}
+
+static DBusHandlerResult introspect(DBusConnection *connection,
+ DBusMessage *message, struct generic_data *data)
+{
+ DBusMessage *reply;
+
+ if (!dbus_message_has_signature(message, DBUS_TYPE_INVALID_AS_STRING)) {
+ error("Unexpected signature to introspect call");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ if (!data->introspect)
+ generate_introspection_xml(connection, data,
+ dbus_message_get_path(message));
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &data->introspect,
+ DBUS_TYPE_INVALID);
+
+ dbus_connection_send(connection, reply, NULL);
+
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static void generic_unregister(DBusConnection *connection, void *user_data)
+{
+ struct generic_data *data = user_data;
+
+ g_free(data->introspect);
+ g_free(data);
+}
+
+static struct interface_data *find_interface(GSList *interfaces,
+ const char *name)
+{
+ GSList *list;
+
+ if (!name)
+ 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 DBusHandlerResult generic_message(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ struct generic_data *data = user_data;
+ struct interface_data *iface;
+ GDBusMethodTable *method;
+ const char *interface;
+
+ if (dbus_message_is_method_call(message,
+ DBUS_INTERFACE_INTROSPECTABLE,
+ "Introspect"))
+ return introspect(connection, message, data);
+
+ interface = dbus_message_get_interface(message);
+
+ iface = find_interface(data->interfaces, interface);
+ if (!iface)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ for (method = iface->methods; method &&
+ method->name && method->function; method++) {
+ DBusMessage *reply;
+
+ if (dbus_message_is_method_call(message, iface->name,
+ method->name) == FALSE)
+ continue;
+
+ if (dbus_message_has_signature(message,
+ method->signature) == FALSE)
+ continue;
+
+ 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;
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusObjectPathVTable generic_table = {
+ .unregister_function = generic_unregister,
+ .message_function = generic_message,
+};
+
+static void invalidate_parent_data(DBusConnection *conn, const char *child_path)
+{
+ struct generic_data *data = NULL;
+ char *parent_path, *slash;
+
+ parent_path = g_strdup(child_path);
+ slash = strrchr(parent_path, '/');
+ if (!slash)
+ 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))
+ goto done;
+
+ if (!data)
+ goto done;
+
+ g_free(data->introspect);
+ data->introspect = NULL;
+
+done:
+ g_free(parent_path);
+}
+
+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->introspect = g_strdup(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "<node></node>");
+
+ data->refcount = 1;
+
+ 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);
+
+ 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;
+
+ invalidate_parent_data(connection, path);
+
+ dbus_connection_unregister_object_path(connection, path);
+}
+
+static gboolean check_signal(DBusConnection *conn, const char *path,
+ const char *interface, const char *name,
+ const char **args)
+{
+ struct generic_data *data = NULL;
+ struct interface_data *iface;
+ GDBusSignalTable *signal;
+
+ *args = NULL;
+ if (!dbus_connection_get_object_path_data(conn, path,
+ (void *) &data) || !data) {
+ error("dbus_connection_emit_signal: path %s isn't registered",
+ path);
+ return FALSE;
+ }
+
+ iface = find_interface(data->interfaces, interface);
+ if (!iface) {
+ 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)) {
+ *args = signal->signature;
+ break;
+ }
+ }
+
+ if (!*args) {
+ error("No signal named %s on interface %s", name, interface);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+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 char *signature, *args;
+
+ if (!check_signal(conn, path, interface, name, &args))
+ return FALSE;
+
+ signal = dbus_message_new_signal(path, interface, name);
+ if (!signal) {
+ 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;
+
+ signature = dbus_message_get_signature(signal);
+ if (strcmp(args, signature) != 0) {
+ error("%s.%s: expected signature'%s' but got '%s'",
+ interface, name, args, signature);
+ 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,
+ GDBusMethodTable *methods,
+ GDBusSignalTable *signals,
+ GDBusPropertyTable *properties,
+ void *user_data,
+ GDBusDestroyFunction destroy)
+{
+ struct generic_data *data;
+ struct interface_data *iface;
+
+ data = object_path_ref(connection, path);
+ if (data == NULL)
+ return FALSE;
+
+ if (find_interface(data->interfaces, name))
+ return FALSE;
+
+ 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);
+
+ 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;
+ struct interface_data *iface;
+
+ if (!path)
+ return FALSE;
+
+ if (dbus_connection_get_object_path_data(connection, path,
+ (void *) &data) == FALSE)
+ return FALSE;
+
+ if (data == NULL)
+ return FALSE;
+
+ iface = find_interface(data->interfaces, name);
+ if (!iface)
+ return FALSE;
+
+ data->interfaces = g_slist_remove(data->interfaces, iface);
+
+ if (iface->destroy)
+ iface->destroy(iface->user_data);
+
+ g_free(iface->name);
+ g_free(iface);
+
+ g_free(data->introspect);
+ data->introspect = NULL;
+
+ object_path_unref(connection, path);
+
+ 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);
+
+ result = dbus_connection_send(connection, message, NULL);
+
+ dbus_message_unref(message);
+
+ 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);
+}
--- /dev/null
+/*
+ *
+ * D-Bus helper library
+ *
+ * Copyright (C) 2004-2009 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 name_exit_filter(DBusConnection *connection,
+ DBusMessage *message, void *user_data);
+
+static guint listener_id = 0;
+static GSList *name_listeners = NULL;
+
+struct name_callback {
+ GDBusWatchFunction conn_func;
+ GDBusWatchFunction disc_func;
+ void *user_data;
+ guint id;
+};
+
+struct name_data {
+ DBusConnection *connection;
+ char *name;
+ GSList *callbacks;
+ GSList *processed;
+ gboolean lock;
+};
+
+static struct name_data *name_data_find(DBusConnection *connection,
+ const char *name)
+{
+ GSList *current;
+
+ for (current = name_listeners;
+ current != NULL; current = current->next) {
+ struct name_data *data = current->data;
+
+ if (connection != data->connection)
+ continue;
+
+ if (name == NULL || g_str_equal(name, data->name))
+ return data;
+ }
+
+ return NULL;
+}
+
+static struct name_callback *name_callback_find(GSList *callbacks, guint id)
+{
+ GSList *current;
+
+ for (current = callbacks; current != NULL; current = current->next) {
+ struct name_callback *cb = current->data;
+ if (cb->id == id)
+ return cb;
+ }
+
+ return NULL;
+}
+
+static void name_data_call_and_free(struct name_data *data)
+{
+ GSList *l;
+
+ for (l = data->callbacks; l != NULL; l = l->next) {
+ struct name_callback *cb = l->data;
+ if (cb->disc_func)
+ cb->disc_func(data->connection, cb->user_data);
+ g_free(cb);
+ }
+
+ g_slist_free(data->callbacks);
+ g_free(data->name);
+ g_free(data);
+}
+
+static void name_data_free(struct name_data *data)
+{
+ GSList *l;
+
+ for (l = data->callbacks; l != NULL; l = l->next)
+ g_free(l->data);
+
+ g_slist_free(data->callbacks);
+ g_free(data->name);
+ g_free(data);
+}
+
+static int name_data_add(DBusConnection *connection, const char *name,
+ GDBusWatchFunction connect,
+ GDBusWatchFunction disconnect,
+ void *user_data, guint id)
+{
+ int first = 1;
+ struct name_data *data = NULL;
+ struct name_callback *cb = NULL;
+
+ cb = g_new(struct name_callback, 1);
+
+ cb->conn_func = connect;
+ cb->disc_func = disconnect;
+ cb->user_data = user_data;
+ cb->id = id;
+
+ data = name_data_find(connection, name);
+ if (data) {
+ first = 0;
+ goto done;
+ }
+
+ data = g_new0(struct name_data, 1);
+
+ data->connection = connection;
+ data->name = g_strdup(name);
+
+ name_listeners = g_slist_append(name_listeners, data);
+
+done:
+ if (data->lock)
+ data->processed = g_slist_append(data->processed, cb);
+ else
+ data->callbacks = g_slist_append(data->callbacks, cb);
+
+ return first;
+}
+
+static void name_data_remove(DBusConnection *connection,
+ const char *name, guint id)
+{
+ struct name_data *data;
+ struct name_callback *cb = NULL;
+
+ data = name_data_find(connection, name);
+ if (!data)
+ return;
+
+ cb = name_callback_find(data->callbacks, id);
+ if (cb) {
+ data->callbacks = g_slist_remove(data->callbacks, cb);
+ g_free(cb);
+ }
+
+ if (data->callbacks)
+ return;
+
+ name_listeners = g_slist_remove(name_listeners, data);
+ name_data_free(data);
+
+ /* Remove filter if there are no listeners left for the connection */
+ data = name_data_find(connection, NULL);
+ if (!data)
+ dbus_connection_remove_filter(connection,
+ name_exit_filter,
+ NULL);
+}
+
+static gboolean add_match(DBusConnection *connection, const char *name)
+{
+ DBusError err;
+ char match_string[128];
+
+ snprintf(match_string, sizeof(match_string),
+ "interface=%s,member=NameOwnerChanged,arg0=%s",
+ DBUS_INTERFACE_DBUS, name);
+
+ dbus_error_init(&err);
+
+ dbus_bus_add_match(connection, match_string, &err);
+
+ if (dbus_error_is_set(&err)) {
+ error("Adding match rule \"%s\" failed: %s", match_string,
+ err.message);
+ dbus_error_free(&err);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean remove_match(DBusConnection *connection, const char *name)
+{
+ DBusError err;
+ char match_string[128];
+
+ snprintf(match_string, sizeof(match_string),
+ "interface=%s,member=NameOwnerChanged,arg0=%s",
+ DBUS_INTERFACE_DBUS, name);
+
+ dbus_error_init(&err);
+
+ dbus_bus_remove_match(connection, match_string, &err);
+
+ if (dbus_error_is_set(&err)) {
+ error("Removing owner match rule for %s failed: %s",
+ name, err.message);
+ dbus_error_free(&err);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static DBusHandlerResult name_exit_filter(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ struct name_data *data;
+ struct name_callback *cb;
+ char *name, *old, *new;
+
+ if (!dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
+ "NameOwnerChanged"))
+ 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)) {
+ error("Invalid arguments for NameOwnerChanged signal");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ data = name_data_find(connection, name);
+ if (!data) {
+ error("Got NameOwnerChanged signal for %s which has no listeners", name);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ data->lock = TRUE;
+
+ 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;
+
+ data->callbacks = g_slist_remove(data->callbacks, cb);
+
+ if (!cb->conn_func || !cb->disc_func) {
+ g_free(cb);
+ continue;
+ }
+
+ data->processed = g_slist_append(data->processed, cb);
+ }
+
+ data->callbacks = data->processed;
+ data->processed = NULL;
+ data->lock = FALSE;
+
+ if (data->callbacks)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ name_listeners = g_slist_remove(name_listeners, data);
+ name_data_free(data);
+
+ /* Remove filter if there no listener left for the connection */
+ data = name_data_find(connection, NULL);
+ if (!data)
+ dbus_connection_remove_filter(connection, name_exit_filter,
+ NULL);
+
+ remove_match(connection, name);
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+guint g_dbus_add_service_watch(DBusConnection *connection, const char *name,
+ GDBusWatchFunction connect,
+ GDBusWatchFunction disconnect,
+ void *user_data, GDBusDestroyFunction destroy)
+{
+ int first;
+
+ if (!name_data_find(connection, NULL)) {
+ if (!dbus_connection_add_filter(connection,
+ name_exit_filter, NULL, NULL)) {
+ error("dbus_connection_add_filter() failed");
+ return 0;
+ }
+ }
+
+ listener_id++;
+ first = name_data_add(connection, name, connect, disconnect,
+ user_data, listener_id);
+ /* The filter is already added if this is not the first callback
+ * registration for the name */
+ if (!first)
+ return listener_id;
+
+ if (name) {
+ debug("name_listener_add(%s)", name);
+
+ if (!add_match(connection, name)) {
+ name_data_remove(connection, name, listener_id);
+ return 0;
+ }
+ }
+
+ return listener_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 *rule, GDBusSignalFunction function,
+ void *user_data, GDBusDestroyFunction destroy)
+{
+ return 0;
+}
+
+gboolean g_dbus_remove_watch(DBusConnection *connection, guint id)
+{
+ struct name_data *data;
+ struct name_callback *cb;
+ GSList *ldata, *lcb;
+
+ if (id == 0)
+ return FALSE;
+
+ for (ldata = name_listeners; ldata; ldata = ldata->next) {
+ data = ldata->data;
+ for (lcb = data->callbacks; lcb; lcb = lcb->next) {
+ cb = lcb->data;
+ if (cb->id == id)
+ goto remove;
+ }
+ for (lcb = data->processed; lcb; lcb = lcb->next) {
+ cb = lcb->data;
+ if (cb->id == id)
+ goto remove;
+ }
+ }
+
+ return FALSE;
+
+remove:
+ data->callbacks = g_slist_remove(data->callbacks, cb);
+ data->processed = g_slist_remove(data->processed, cb);
+ 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->name) {
+ if (!remove_match(data->connection, data->name))
+ return FALSE;
+ }
+
+ name_listeners = g_slist_remove(name_listeners, data);
+ name_data_free(data);
+
+ /* Remove filter if there are no listeners left for the connection */
+ data = name_data_find(connection, NULL);
+ if (!data)
+ dbus_connection_remove_filter(connection, name_exit_filter,
+ NULL);
+
+ return TRUE;
+}
+
+void g_dbus_remove_all_watches(DBusConnection *connection)
+{
+ struct name_data *data;
+
+ while ((data = name_data_find(connection, NULL))) {
+ name_listeners = g_slist_remove(name_listeners, data);
+ name_data_call_and_free(data);
+ }
+
+ dbus_connection_remove_filter(connection, name_exit_filter, NULL);
+}
--- /dev/null
+
+includedir = @includedir@/connman
+
+include_HEADERS = types.h log.h plugin.h security.h notifier.h \
+ storage.h device.h network.h inet.h
+
+nodist_include_HEADERS = version.h
+
+noinst_HEADERS = driver.h element.h property.h ipv4.h rtnl.h dbus.h \
+ rfkill.h resolver.h ipconfig.h service.h option.h
+
+abs_top_srcdir=$(shell pwd)/..
+abs_top_builddir=$(shell pwd)/..
+
+MAINTAINERCLEANFILES = Makefile.in
+
+all-local:
+ @if [ ! -e connman ]; then \
+ mkdir connman; \
+ list='$(include_HEADERS) $(noinst_HEADERS)'; for i in $$list; \
+ do $(LN_S) $(abs_top_srcdir)/include/$$i connman/$$i; done; \
+ list='$(nodist_include_HEADERS)'; for i in $$list; \
+ do $(LN_S) $(abs_top_builddir)/include/$$i connman/$$i; done; \
+ fi
+
+clean-local:
+ @rm -rf connman
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_DBUS_H
+#define __CONNMAN_DBUS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <dbus/dbus.h>
+
+#define CONNMAN_SERVICE "org.moblin.connman"
+
+#define CONNMAN_DEBUG_INTERFACE CONNMAN_SERVICE ".Debug"
+#define CONNMAN_ERROR_INTERFACE CONNMAN_SERVICE ".Error"
+#define CONNMAN_AGENT_INTERFACE CONNMAN_SERVICE ".Agent"
+
+#define CONNMAN_MANAGER_INTERFACE CONNMAN_SERVICE ".Manager"
+#define CONNMAN_MANAGER_PATH "/"
+
+#define CONNMAN_PROFILE_INTERFACE CONNMAN_SERVICE ".Profile"
+#define CONNMAN_SERVICE_INTERFACE CONNMAN_SERVICE ".Service"
+#define CONNMAN_DEVICE_INTERFACE CONNMAN_SERVICE ".Device"
+#define CONNMAN_NETWORK_INTERFACE CONNMAN_SERVICE ".Network"
+#define CONNMAN_CONNECTION_INTERFACE CONNMAN_SERVICE ".Connection"
+
+extern DBusConnection *connman_dbus_get_connection(void);
+
+extern void connman_dbus_property_append_variant(DBusMessageIter *property,
+ const char *key, int type, void *val);
+
+extern void connman_dbus_dict_append_array(DBusMessageIter *dict,
+ const char *key, int type, void *val, int len);
+extern void connman_dbus_dict_append_variant(DBusMessageIter *dict,
+ const char *key, int type, void *val);
+
+extern char *connman_dbus_encode_string(const char *value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_DBUS_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_DEVICE_H
+#define __CONNMAN_DEVICE_H
+
+#include <connman/types.h>
+#include <connman/network.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * SECTION:device
+ * @title: Device premitives
+ * @short_description: Functions for handling devices
+ */
+
+enum connman_device_type {
+ CONNMAN_DEVICE_TYPE_UNKNOWN = 0,
+ CONNMAN_DEVICE_TYPE_ETHERNET = 1,
+ CONNMAN_DEVICE_TYPE_WIFI = 2,
+ CONNMAN_DEVICE_TYPE_WIMAX = 3,
+ CONNMAN_DEVICE_TYPE_BLUETOOTH = 4,
+ CONNMAN_DEVICE_TYPE_GPS = 5,
+ CONNMAN_DEVICE_TYPE_HSO = 15,
+ CONNMAN_DEVICE_TYPE_NOZOMI = 16,
+ CONNMAN_DEVICE_TYPE_HUAWEI = 17,
+ CONNMAN_DEVICE_TYPE_NOVATEL = 18,
+ CONNMAN_DEVICE_TYPE_VENDOR = 10000,
+};
+
+enum connman_device_mode {
+ CONNMAN_DEVICE_MODE_UNKNOWN = 0,
+ CONNMAN_DEVICE_MODE_NETWORK_SINGLE = 1,
+ CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE = 2,
+ CONNMAN_DEVICE_MODE_TRANSPORT_IP = 3,
+};
+
+enum connman_device_policy {
+ CONNMAN_DEVICE_POLICY_UNKNOWN = 0,
+ CONNMAN_DEVICE_POLICY_IGNORE = 1,
+ CONNMAN_DEVICE_POLICY_OFF = 2,
+ CONNMAN_DEVICE_POLICY_AUTO = 3,
+ CONNMAN_DEVICE_POLICY_MANUAL = 4,
+};
+
+struct connman_device;
+
+extern struct connman_device *connman_device_create(const char *node,
+ enum connman_device_type type);
+extern struct connman_device *connman_device_ref(struct connman_device *device);
+extern void connman_device_unref(struct connman_device *device);
+
+extern enum connman_device_type connman_device_get_type(struct connman_device *device);
+extern const char *connman_device_get_name(struct connman_device *device);
+extern const char *connman_device_get_path(struct connman_device *device);
+extern void connman_device_set_index(struct connman_device *device,
+ int index);
+extern int connman_device_get_index(struct connman_device *device);
+extern void connman_device_set_interface(struct connman_device *device,
+ const char *interface);
+extern const char *connman_device_get_interface(struct connman_device *device);
+
+extern void connman_device_set_ident(struct connman_device *device,
+ const char *ident);
+
+extern void connman_device_set_policy(struct connman_device *device,
+ enum connman_device_policy policy);
+extern void connman_device_set_mode(struct connman_device *device,
+ enum connman_device_mode mode);
+extern enum connman_device_mode connman_device_get_mode(struct connman_device *device);
+extern void connman_device_set_secondary(struct connman_device *device,
+ connman_bool_t secondary);
+extern connman_bool_t connman_device_get_secondary(struct connman_device *device);
+
+extern int connman_device_set_powered(struct connman_device *device,
+ connman_bool_t powered);
+extern int connman_device_set_carrier(struct connman_device *device,
+ connman_bool_t carrier);
+extern int connman_device_set_scanning(struct connman_device *device,
+ connman_bool_t scanning);
+extern int connman_device_set_disconnected(struct connman_device *device,
+ connman_bool_t disconnected);
+
+extern int connman_device_set_string(struct connman_device *device,
+ const char *key, const char *value);
+extern const char *connman_device_get_string(struct connman_device *device,
+ const char *key);
+
+extern int connman_device_add_network(struct connman_device *device,
+ struct connman_network *network);
+extern struct connman_network *connman_device_get_network(struct connman_device *device,
+ const char *identifier);
+extern int connman_device_remove_network(struct connman_device *device,
+ const char *identifier);
+
+extern int connman_device_register(struct connman_device *device);
+extern void connman_device_unregister(struct connman_device *device);
+
+extern void *connman_device_get_data(struct connman_device *device);
+extern void connman_device_set_data(struct connman_device *device, void *data);
+
+struct connman_device_driver {
+ const char *name;
+ enum connman_device_type type;
+ int priority;
+ int (*probe) (struct connman_device *device);
+ void (*remove) (struct connman_device *device);
+ int (*enable) (struct connman_device *device);
+ int (*disable) (struct connman_device *device);
+ int (*scan) (struct connman_device *device);
+ int (*join) (struct connman_device *device,
+ struct connman_network *network);
+};
+
+extern int connman_device_driver_register(struct connman_device_driver *driver);
+extern void connman_device_driver_unregister(struct connman_device_driver *driver);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_DEVICE_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_DRIVER_H
+#define __CONNMAN_DRIVER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <connman/element.h>
+
+/**
+ * SECTION:driver
+ * @title: Driver premitives
+ * @short_description: Functions for registering drivers
+ */
+
+#define CONNMAN_DRIVER_PRIORITY_LOW -100
+#define CONNMAN_DRIVER_PRIORITY_DEFAULT 0
+#define CONNMAN_DRIVER_PRIORITY_HIGH 100
+
+struct connman_driver {
+ const char *name;
+ enum connman_element_type type;
+ int priority;
+ int (*probe) (struct connman_element *element);
+ void (*remove) (struct connman_element *element);
+ void (*update) (struct connman_element *element);
+ void (*change) (struct connman_element *element);
+};
+
+extern int connman_driver_register(struct connman_driver *driver);
+extern void connman_driver_unregister(struct connman_driver *driver);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_DRIVER_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_ELEMENT_H
+#define __CONNMAN_ELEMENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <errno.h>
+#include <glib.h>
+
+#include <connman/property.h>
+#include <connman/types.h>
+#include <connman/ipv4.h>
+
+/**
+ * SECTION:element
+ * @title: Element premitives
+ * @short_description: Functions for handling elements
+ */
+
+enum connman_element_type {
+ CONNMAN_ELEMENT_TYPE_UNKNOWN = 0,
+ CONNMAN_ELEMENT_TYPE_ROOT = 1,
+ CONNMAN_ELEMENT_TYPE_PROFILE = 2,
+ CONNMAN_ELEMENT_TYPE_DEVICE = 3,
+ CONNMAN_ELEMENT_TYPE_NETWORK = 4,
+ CONNMAN_ELEMENT_TYPE_SERVICE = 5,
+ CONNMAN_ELEMENT_TYPE_PPP = 6,
+ CONNMAN_ELEMENT_TYPE_IPV4 = 7,
+ CONNMAN_ELEMENT_TYPE_IPV6 = 8,
+ CONNMAN_ELEMENT_TYPE_DHCP = 9,
+ CONNMAN_ELEMENT_TYPE_BOOTP = 10,
+ CONNMAN_ELEMENT_TYPE_ZEROCONF = 11,
+ CONNMAN_ELEMENT_TYPE_CONNECTION = 42,
+ CONNMAN_ELEMENT_TYPE_VENDOR = 10000,
+};
+
+enum connman_element_state {
+ CONNMAN_ELEMENT_STATE_UNKNOWN = 0,
+ CONNMAN_ELEMENT_STATE_ERROR = 1,
+ CONNMAN_ELEMENT_STATE_IDLE = 2,
+ CONNMAN_ELEMENT_STATE_DONE = 3,
+};
+
+enum connman_element_error {
+ CONNMAN_ELEMENT_ERROR_UNKNOWN = 0,
+ CONNMAN_ELEMENT_ERROR_FAILED = 1,
+ CONNMAN_ELEMENT_ERROR_DHCP_FAILED = 2,
+};
+
+struct connman_driver;
+
+struct connman_element {
+ gint refcount;
+ gint index;
+ gchar *name;
+ gchar *path;
+ enum connman_element_type type;
+ enum connman_element_state state;
+ enum connman_element_error error;
+ gboolean enabled;
+ gboolean configuring;
+ gchar *devname;
+
+ struct connman_element *parent;
+
+ struct connman_driver *driver;
+ void *driver_data;
+
+ void (*destruct) (struct connman_element *element);
+
+ union {
+ void *private;
+ struct connman_device *device;
+ struct connman_network *network;
+ };
+
+ GHashTable *properties;
+
+ struct {
+ enum connman_ipv4_method method;
+ gchar *address;
+ gchar *netmask;
+ gchar *gateway;
+ gchar *network;
+ gchar *broadcast;
+ gchar *nameserver;
+ } ipv4;
+};
+
+extern struct connman_element *connman_element_create(const char *name);
+extern struct connman_element *connman_element_ref(struct connman_element *element);
+extern void connman_element_unref(struct connman_element *element);
+
+extern int connman_element_get_value(struct connman_element *element,
+ enum connman_property_id id, void *value);
+
+extern int connman_element_set_string(struct connman_element *element,
+ const char *key, const char *value);
+extern const char *connman_element_get_string(struct connman_element *element,
+ const char *key);
+extern int connman_element_set_uint8(struct connman_element *element,
+ const char *key, connman_uint8_t value);
+extern connman_uint8_t connman_element_get_uint8(struct connman_element *element,
+ const char *key);
+extern int connman_element_set_blob(struct connman_element *element,
+ const char *key, const void *data, unsigned int size);
+extern const void *connman_element_get_blob(struct connman_element *element,
+ const char *key, unsigned int *size);
+
+extern int connman_element_register(struct connman_element *element,
+ struct connman_element *parent);
+extern void connman_element_unregister(struct connman_element *element);
+extern void connman_element_unregister_children(struct connman_element *element);
+extern void connman_element_update(struct connman_element *element);
+
+extern int connman_element_set_enabled(struct connman_element *element,
+ gboolean enabled);
+extern void connman_element_set_error(struct connman_element *element,
+ enum connman_element_error error);
+
+static inline void *connman_element_get_data(struct connman_element *element)
+{
+ return element->driver_data;
+}
+
+static inline void connman_element_set_data(struct connman_element *element,
+ void *data)
+{
+ element->driver_data = data;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_ELEMENT_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_INET_H
+#define __CONNMAN_INET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <connman/device.h>
+
+extern int connman_inet_ifindex(const char *name);
+extern char *connman_inet_ifname(int index);
+
+extern int connman_inet_ifup(int index);
+extern int connman_inet_ifdown(int index);
+
+extern struct connman_device *connman_inet_create_device(int index);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_INET_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_IPCONFIG_H
+#define __CONNMAN_IPCONFIG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * SECTION:ipconfig
+ * @title: IP configuration premitives
+ * @short_description: Functions for registering IP configuration modules
+ */
+
+#define CONNMAN_IPCONFIG_PRIORITY_LOW -100
+#define CONNMAN_IPCONFIG_PRIORITY_DEFAULT 0
+#define CONNMAN_IPCONFIG_PRIORITY_HIGH 100
+
+struct connman_ipconfig {
+ const char *name;
+ int priority;
+ int (*request) (const char *interface);
+ int (*release) (const char *interface);
+ int (*renew) (const char *interface);
+};
+
+extern int connman_ipconfig_register(struct connman_ipconfig *ipconfig);
+extern void connman_ipconfig_unregister(struct connman_ipconfig *ipconfig);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_IPCONFIG_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_IPV4_H
+#define __CONNMAN_IPV4_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * SECTION:ipv4
+ * @title: IPv4 premitives
+ * @short_description: Functions for handling IPv4
+ */
+
+enum connman_ipv4_method {
+ CONNMAN_IPV4_METHOD_UNKNOWN = 0,
+ CONNMAN_IPV4_METHOD_OFF = 1,
+ CONNMAN_IPV4_METHOD_STATIC = 2,
+ CONNMAN_IPV4_METHOD_DHCP = 3,
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_IPV4_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_LOG_H
+#define __CONNMAN_LOG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * SECTION:log
+ * @title: Logging premitives
+ * @short_description: Functions for logging error and debug information
+ */
+
+extern void connman_info(const char *format, ...)
+ __attribute__((format(printf, 1, 2)));
+extern void connman_error(const char *format, ...)
+ __attribute__((format(printf, 1, 2)));
+extern void connman_debug(const char *format, ...)
+ __attribute__((format(printf, 1, 2)));
+
+/**
+ * DBG:
+ * @fmt: format string
+ * @arg...: list of arguments
+ *
+ * Simple macro around connman_debug() which also include the function
+ * name it is called in.
+ */
+#define DBG(fmt, arg...) connman_debug("%s:%s() " fmt, __FILE__, __FUNCTION__ , ## arg)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_LOG_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_NETWORK_H
+#define __CONNMAN_NETWORK_H
+
+#include <connman/types.h>
+#include <connman/device.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * SECTION:network
+ * @title: Network premitives
+ * @short_description: Functions for handling networks
+ */
+
+enum connman_network_type {
+ CONNMAN_NETWORK_TYPE_UNKNOWN = 0,
+ CONNMAN_NETWORK_TYPE_WIFI = 1,
+ CONNMAN_NETWORK_TYPE_WIMAX = 2,
+ CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN = 8,
+ CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN = 9,
+ CONNMAN_NETWORK_TYPE_HSO = 23,
+ CONNMAN_NETWORK_TYPE_VENDOR = 10000,
+};
+
+enum connman_network_protocol {
+ CONNMAN_NETWORK_PROTOCOL_UNKNOWN = 0,
+ CONNMAN_NETWORK_PROTOCOL_IP = 1,
+ CONNMAN_NETWORK_PROTOCOL_PPP = 2,
+};
+
+struct connman_network;
+
+extern struct connman_network *connman_network_create(const char *identifier,
+ enum connman_network_type type);
+extern struct connman_network *connman_network_ref(struct connman_network *network);
+extern void connman_network_unref(struct connman_network *network);
+
+extern enum connman_network_type connman_network_get_type(struct connman_network *network);
+extern const char *connman_network_get_identifier(struct connman_network *network);
+
+extern const char *connman_network_get_path(struct connman_network *network);
+extern void connman_network_set_index(struct connman_network *network,
+ int index);
+extern int connman_network_get_index(struct connman_network *network);
+
+extern void connman_network_set_protocol(struct connman_network *network,
+ enum connman_network_protocol protocol);
+extern void connman_network_set_group(struct connman_network *network,
+ const char *group);
+
+extern int connman_network_set_available(struct connman_network *network,
+ connman_bool_t available);
+extern connman_bool_t connman_network_get_available(struct connman_network *network);
+extern int connman_network_set_associating(struct connman_network *network,
+ connman_bool_t associating);
+extern int connman_network_set_connected(struct connman_network *network,
+ connman_bool_t connected);
+extern connman_bool_t connman_network_get_connected(struct connman_network *network);
+
+extern int connman_network_set_address(struct connman_network *network,
+ const void *address, unsigned int size);
+extern int connman_network_set_name(struct connman_network *network,
+ const char *name);
+extern int connman_network_set_strength(struct connman_network *network,
+ connman_uint8_t strength);
+
+extern int connman_network_set_string(struct connman_network *network,
+ const char *key, const char *value);
+extern const char *connman_network_get_string(struct connman_network *network,
+ const char *key);
+extern int connman_network_set_uint8(struct connman_network *network,
+ const char *key, connman_uint8_t value);
+extern connman_uint8_t connman_network_get_uint8(struct connman_network *network,
+ const char *key);
+extern int connman_network_set_uint16(struct connman_network *network,
+ const char *key, connman_uint16_t value);
+extern connman_uint16_t connman_network_get_uint16(struct connman_network *network,
+ const char *key);
+extern int connman_network_set_blob(struct connman_network *network,
+ const char *key, const void *data, unsigned int size);
+extern const void *connman_network_get_blob(struct connman_network *network,
+ const char *key, unsigned int *size);
+
+extern struct connman_device *connman_network_get_device(struct connman_network *network);
+
+extern void *connman_network_get_data(struct connman_network *network);
+extern void connman_network_set_data(struct connman_network *network, void *data);
+
+struct connman_network_driver {
+ const char *name;
+ enum connman_network_type type;
+ int priority;
+ int (*probe) (struct connman_network *network);
+ void (*remove) (struct connman_network *network);
+ int (*connect) (struct connman_network *network);
+ int (*disconnect) (struct connman_network *network);
+};
+
+extern int connman_network_driver_register(struct connman_network_driver *driver);
+extern void connman_network_driver_unregister(struct connman_network_driver *driver);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_NETWORK_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_NOTIFIER_H
+#define __CONNMAN_NOTIFIER_H
+
+#include <connman/device.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * SECTION:notifier
+ * @title: Notifier premitives
+ * @short_description: Functions for registering notifier modules
+ */
+
+#define CONNMAN_NOTIFIER_PRIORITY_LOW -100
+#define CONNMAN_NOTIFIER_PRIORITY_DEFAULT 0
+#define CONNMAN_NOTIFIER_PRIORITY_HIGH 100
+
+struct connman_notifier {
+ const char *name;
+ int priority;
+ void (*device_enabled) (enum connman_device_type type,
+ connman_bool_t enabled);
+ void (*offline_mode) (connman_bool_t enabled);
+};
+
+extern int connman_notifier_register(struct connman_notifier *notifier);
+extern void connman_notifier_unregister(struct connman_notifier *notifier);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_NOTIFIER_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_OPTION_H
+#define __CONNMAN_OPTION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const char *connman_option_get_string(const char *key);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_OPTION_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_PLUGIN_H
+#define __CONNMAN_PLUGIN_H
+
+#include <connman/version.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CONNMAN_API_SUBJECT_TO_CHANGE
+#error "Please define CONNMAN_API_SUBJECT_TO_CHANGE to acknowledge your \
+understanding that ConnMan hasn't reached a stable API."
+#endif
+
+#define CONNMAN_PLUGIN_PRIORITY_LOW -100
+#define CONNMAN_PLUGIN_PRIORITY_DEFAULT 0
+#define CONNMAN_PLUGIN_PRIORITY_HIGH 100
+
+/**
+ * SECTION:plugin
+ * @title: Plugin premitives
+ * @short_description: Functions for declaring plugins
+ */
+
+struct connman_plugin_desc {
+ const char *name;
+ const char *description;
+ const char *version;
+ int priority;
+ int (*init) (void);
+ void (*exit) (void);
+};
+
+/**
+ * CONNMAN_PLUGIN_DEFINE:
+ * @name: plugin name
+ * @description: plugin description
+ * @version: plugin version string
+ * @init: init function called on plugin loading
+ * @exit: exit function called on plugin removal
+ *
+ * Macro for defining a plugin descriptor
+ *
+ * |[
+ * #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)
+ * ]|
+ */
+#ifdef CONNMAN_PLUGIN_BUILTIN
+#define CONNMAN_PLUGIN_DEFINE(name, description, version, priority, init, exit) \
+ struct connman_plugin_desc __connman_builtin_ ## name = { \
+ #name, description, version, priority, init, exit \
+ };
+#else
+#define CONNMAN_PLUGIN_DEFINE(name, description, version, priority, init, exit) \
+ extern struct connman_plugin_desc connman_plugin_desc \
+ __attribute__ ((visibility("default"))); \
+ struct connman_plugin_desc connman_plugin_desc = { \
+ #name, description, version, priority, init, exit \
+ };
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_PLUGIN_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_PROPERTY_H
+#define __CONNMAN_PROPERTY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * SECTION:property
+ * @title: Property premitives
+ * @short_description: Functions for handling properties
+ */
+
+#define CONNMAN_PROPERTY_ID_NAME "Name"
+#define CONNMAN_PROPERTY_ID_TYPE "Type"
+#define CONNMAN_PROPERTY_ID_PRIORITY "Priority"
+#define CONNMAN_PROPERTY_ID_STRENGTH "Strength"
+
+enum connman_property_id {
+ CONNMAN_PROPERTY_ID_INVALID = 0,
+
+ CONNMAN_PROPERTY_ID_IPV4_METHOD,
+ CONNMAN_PROPERTY_ID_IPV4_ADDRESS,
+ CONNMAN_PROPERTY_ID_IPV4_NETMASK,
+ CONNMAN_PROPERTY_ID_IPV4_GATEWAY,
+ CONNMAN_PROPERTY_ID_IPV4_BROADCAST,
+ CONNMAN_PROPERTY_ID_IPV4_NAMESERVER,
+};
+
+enum connman_property_type {
+ CONNMAN_PROPERTY_TYPE_INVALID = 0,
+ CONNMAN_PROPERTY_TYPE_STRING,
+ CONNMAN_PROPERTY_TYPE_UINT8,
+ CONNMAN_PROPERTY_TYPE_BLOB,
+};
+
+struct connman_property {
+ enum connman_property_id id;
+ int type;
+ int subtype;
+ void *value;
+ unsigned int size;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_PROPERTY_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_RESOLVER_H
+#define __CONNMAN_RESOLVER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * SECTION:resolver
+ * @title: Resolver premitives
+ * @short_description: Functions for registering resolver modules
+ */
+
+#define CONNMAN_RESOLVER_PRIORITY_LOW -100
+#define CONNMAN_RESOLVER_PRIORITY_DEFAULT 0
+#define CONNMAN_RESOLVER_PRIORITY_HIGH 100
+
+struct connman_resolver {
+ const char *name;
+ int priority;
+ int (*append) (const char *interface, const char *domain,
+ const char *server);
+ int (*remove) (const char *interface, const char *domain,
+ const char *server);
+};
+
+extern int connman_resolver_register(struct connman_resolver *resolver);
+extern void connman_resolver_unregister(struct connman_resolver *resolver);
+
+extern int connman_resolver_append(const char *interface, const char *domain,
+ const char *server);
+extern int connman_resolver_remove_all(const char *interface);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_RESOLVER_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_RFKILL_H
+#define __CONNMAN_RFKILL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_RFKILL_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_RTNL_H
+#define __CONNMAN_RTNL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * SECTION:rtnl
+ * @title: RTNL premitives
+ * @short_description: Functions for registering RTNL modules
+ */
+
+typedef void (* connman_rtnl_link_cb_t) (unsigned flags, unsigned change,
+ void *user_data);
+
+extern unsigned int connman_rtnl_add_newlink_watch(int index,
+ connman_rtnl_link_cb_t callback, void *user_data);
+extern void connman_rtnl_remove_watch(unsigned int id);
+
+#define CONNMAN_RTNL_PRIORITY_LOW -100
+#define CONNMAN_RTNL_PRIORITY_DEFAULT 0
+#define CONNMAN_RTNL_PRIORITY_HIGH 100
+
+struct connman_rtnl {
+ const char *name;
+ int priority;
+ void (*newlink) (unsigned short type, int index,
+ unsigned flags, unsigned change);
+ void (*dellink) (unsigned short type, int index,
+ unsigned flags, unsigned change);
+ void (*newgateway) (int index, const char *gateway);
+ void (*delgateway) (int index, const char *gateway);
+};
+
+extern int connman_rtnl_register(struct connman_rtnl *rtnl);
+extern void connman_rtnl_unregister(struct connman_rtnl *rtnl);
+
+extern int connman_rtnl_send_getlink(void);
+extern int connman_rtnl_send_getroute(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_RTNL_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_SECURITY_H
+#define __CONNMAN_SECURITY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * SECTION:security
+ * @title: Security premitives
+ * @short_description: Functions for registering security modules
+ */
+
+enum connman_security_privilege {
+ CONNMAN_SECURITY_PRIVILEGE_PUBLIC = 0,
+ CONNMAN_SECURITY_PRIVILEGE_MODIFY = 1,
+ CONNMAN_SECURITY_PRIVILEGE_SECRET = 2,
+};
+
+#define CONNMAN_SECURITY_PRIORITY_LOW -100
+#define CONNMAN_SECURITY_PRIORITY_DEFAULT 0
+#define CONNMAN_SECURITY_PRIORITY_HIGH 100
+
+struct connman_security {
+ const char *name;
+ int priority;
+ int (*authorize_sender) (const char *sender,
+ enum connman_security_privilege privilege);
+};
+
+extern int connman_security_register(struct connman_security *security);
+extern void connman_security_unregister(struct connman_security *security);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_SECURITY_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_SERVICE_H
+#define __CONNMAN_SERVICE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * SECTION:service
+ * @title: Service premitives
+ * @short_description: Functions for handling services
+ */
+
+enum connman_service_type {
+ CONNMAN_SERVICE_TYPE_UNKNOWN = 0,
+ CONNMAN_SERVICE_TYPE_ETHERNET = 1,
+ CONNMAN_SERVICE_TYPE_WIFI = 2,
+ CONNMAN_SERVICE_TYPE_WIMAX = 3,
+};
+
+enum connman_service_mode {
+ CONNMAN_SERVICE_MODE_UNKNOWN = 0,
+ CONNMAN_SERVICE_MODE_MANAGED = 1,
+ CONNMAN_SERVICE_MODE_ADHOC = 2,
+};
+
+enum connman_service_security {
+ CONNMAN_SERVICE_SECURITY_UNKNOWN = 0,
+ CONNMAN_SERVICE_SECURITY_NONE = 1,
+ CONNMAN_SERVICE_SECURITY_WEP = 2,
+ CONNMAN_SERVICE_SECURITY_WPA = 3,
+ CONNMAN_SERVICE_SECURITY_RSN = 4,
+};
+
+enum connman_service_state {
+ CONNMAN_SERVICE_STATE_UNKNOWN = 0,
+ CONNMAN_SERVICE_STATE_IDLE = 1,
+ CONNMAN_SERVICE_STATE_CARRIER = 2,
+ CONNMAN_SERVICE_STATE_ASSOCIATION = 3,
+ CONNMAN_SERVICE_STATE_CONFIGURATION = 4,
+ CONNMAN_SERVICE_STATE_READY = 5,
+ CONNMAN_SERVICE_STATE_DISCONNECT = 6,
+ CONNMAN_SERVICE_STATE_FAILURE = 7,
+};
+
+struct connman_service;
+
+extern struct connman_service *connman_service_create(void);
+extern struct connman_service *connman_service_ref(struct connman_service *service);
+extern void connman_service_unref(struct connman_service *service);
+
+extern int connman_service_set_favorite(struct connman_service *service,
+ connman_bool_t favorite);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_SERVICE_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_STORAGE_H
+#define __CONNMAN_STORAGE_H
+
+#include <connman/device.h>
+#include <connman/network.h>
+#include <connman/service.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * SECTION:storage
+ * @title: Storage premitives
+ * @short_description: Functions for registering storage modules
+ */
+
+#define CONNMAN_STORAGE_PRIORITY_LOW -100
+#define CONNMAN_STORAGE_PRIORITY_DEFAULT 0
+#define CONNMAN_STORAGE_PRIORITY_HIGH 100
+
+struct connman_storage {
+ const char *name;
+ int priority;
+ enum connman_device_type device_type;
+ int (*device_init) (void);
+ int (*device_load) (struct connman_device *device);
+ int (*device_save) (struct connman_device *device);
+ enum connman_network_type network_type;
+ int (*network_init) (struct connman_device *device);
+ int (*network_load) (struct connman_network *network);
+ int (*network_save) (struct connman_network *network);
+ enum connman_service_type service_type;
+ int (*service_load) (struct connman_service *service);
+ int (*service_save) (struct connman_service *service);
+};
+
+extern int connman_storage_register(struct connman_storage *storage);
+extern void connman_storage_unregister(struct connman_storage *storage);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_STORAGE_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_TYPES_H
+#define __CONNMAN_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+typedef int connman_bool_t;
+typedef unsigned char connman_uint8_t;
+typedef unsigned short connman_uint16_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_TYPES_H */
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __CONNMAN_VERSION_H
+#define __CONNMAN_VERSION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CONNMAN_VERSION "@VERSION@"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_VERSION_H */
--- /dev/null
+
+plugindir = $(libdir)/connman/plugins
+
+plugin_LTLIBRARIES =
+
+builtin_modules =
+builtin_sources =
+builtin_libadd =
+builtin_cflags =
+
+if LOOPBACK
+if LOOPBACK_BUILTIN
+builtin_modules += loopback
+builtin_sources += loopback.c
+else
+plugin_LTLIBRARIES += loopback.la
+endif
+endif
+
+if ETHERNET
+if ETHERNET_BUILTIN
+builtin_modules += ethernet
+builtin_sources += ethernet.c
+else
+plugin_LTLIBRARIES += ethernet.la
+ethernet_la_SOURCES = ethernet.c
+endif
+endif
+
+if WIFI
+if WIFI_BUILTIN
+builtin_modules += wifi
+builtin_sources += wifi.c supplicant.h supplicant.c
+else
+plugin_LTLIBRARIES += wifi.la
+wifi_la_SOURCES = wifi.c supplicant.h supplicant.c
+wifi_la_LIBADD = @GDBUS_LIBS@
+endif
+endif
+
+if BLUETOOTH
+if BLUETOOTH_BUILTIN
+builtin_modules += bluetooth
+builtin_sources += bluetooth.c
+else
+plugin_LTLIBRARIES += bluetooth.la
+bluetooth_la_SOURCES = bluetooth.c
+bluetooth_la_LIBADD = @GDBUS_LIBS@
+endif
+endif
+
+if OFONO
+if OFONO_BUILTIN
+builtin_modules += ofono
+builtin_sources += ofono.c
+else
+plugin_LTLIBRARIES += ofono.la
+bluetooth_la_LIBADD = @GDBUS_LIBS@
+endif
+endif
+
+if MODEMMGR
+if MODEMMGR_BUILTIN
+builtin_modules += modemmgr
+builtin_sources += modemmgr.c
+else
+plugin_LTLIBRARIES += modemmgr.la
+modemmgr_la_LIBADD = @GDBUS_LIBS@
+endif
+endif
+
+if NOVATEL
+plugin_LTLIBRARIES += novatel.la
+novatel_la_SOURCES = novatel.c modem.h modem.c
+endif
+
+if HUAWEI
+plugin_LTLIBRARIES += huawei.la
+huawei_la_SOURCES = huawei.c modem.h modem.c
+endif
+
+if HSO
+if HSO_BUILTIN
+builtin_modules += hso
+builtin_sources += hso.c modem.h modem.c
+builtin_libadd += @GATCHAT_LIBS@
+builtin_cflags += @GATCHAT_CFLAGS@
+else
+plugin_LTLIBRARIES += hso.la
+hso_la_SOURCES = hso.c modem.h modem.c
+hso_la_LIBADD = @GATCHAT_LIBS@
+hso_la_CFLAGS = $(AM_CFLAGS) @GATCHAT_CFLAGS@
+endif
+endif
+
+if UDHCP
+if UDHCP_BUILTIN
+builtin_modules += udhcp
+builtin_sources += udhcp.c task.h task.c
+builtin_cflags += -DUDHCPC=\"@UDHCPC@\"
+else
+plugin_LTLIBRARIES += udhcp.la
+udhcp_la_SOURCES = udhcp.c task.h task.c
+udhcp_la_CFLAGS = $(AM_CFLAGS) -DUDHCPC=\"@UDHCPC@\" \
+ -DSTATEDIR=\""$(statedir)"\" -DSCRIPTDIR=\""$(scriptdir)"\"
+endif
+endif
+
+if DHCLIENT
+if DHCLIENT_BUILTIN
+builtin_modules += dhclient
+builtin_sources += dhclient.c
+builtin_cflags += -DDHCLIENT=\"@DHCLIENT@\"
+else
+plugin_LTLIBRARIES += dhclient.la
+dhclient_la_SOURCES = dhclient.c
+dhclient_la_CFLAGS = $(AM_CFLAGS) -DDHCLIENT=\"@DHCLIENT@\" \
+ -DSTATEDIR=\""$(statedir)"\" -DSCRIPTDIR=\""$(scriptdir)"\"
+endif
+endif
+
+if PPPD
+plugin_LTLIBRARIES += pppd.la
+pppd_la_CFLAGS = $(AM_CFLAGS) -DPPPD=\"@PPPD@\"
+endif
+
+if RESOLVCONF
+if RESOLVCONF_BUILTIN
+builtin_modules += resolvconf
+builtin_sources += resolvconf.c
+builtin_cflags += -DRESOLVCONF=\"@RESOLVCONF@\"
+else
+plugin_LTLIBRARIES += resolvconf.la
+resolvconf_la_CFLAGS = $(AM_CFLAGS) -DRESOLVCONF=\"@RESOLVCONF@\"
+endif
+endif
+
+if DNSPROXY
+if DNSPROXY_BUILTIN
+builtin_modules += dnsproxy
+builtin_sources += dnsproxy.c
+else
+plugin_LTLIBRARIES += dnsproxy.la
+endif
+endif
+
+if POLKIT
+if POLKIT_BUILTIN
+builtin_modules += polkit
+builtin_sources += polkit.c
+builtin_libadd += @POLKIT_LIBS@
+builtin_cflags += @POLKIT_CFLAGS@
+else
+plugin_LTLIBRARIES += polkit.la
+polkit_la_LIBADD = @POLKIT_LIBS@ @GLIB_LIBS@
+polkit_la_CFLAGS = $(AM_CFLAGS) @POLKIT_CFLAGS@
+endif
+
+if DATAFILES
+policydir = @POLKIT_DATADIR@
+
+policy_DATA = connman.policy
+endif
+endif
+
+if IWMX
+plugin_LTLIBRARIES += iwmxsdk.la
+iwmxsdk_la_SOURCES = iwmx.h iwmx.c iwmxsdk.c
+iwmxsdk_la_LIBADD = @IWMXSDK_LIBS@ @GLIB_LIBS@
+iwmxsdk_la_CFLAGS = $(AM_CFLAGS) @IWMXSDK_CFLAGS@
+endif
+
+if IOSPM
+plugin_LTLIBRARIES += iospm.la
+endif
+
+if FAKE
+plugin_LTLIBRARIES += fake.la
+endif
+
+noinst_LTLIBRARIES = libbuiltin.la
+
+libbuiltin_la_SOURCES = $(builtin_sources)
+libbuiltin_la_LIBADD = $(builtin_libadd)
+libbuiltin_la_CFLAGS = $(AM_CFLAGS) \
+ $(builtin_cflags) -DCONNMAN_PLUGIN_BUILTIN \
+ -DSTATEDIR=\""$(statedir)"\" -DSCRIPTDIR=\""$(scriptdir)"\"
+
+BUILT_SOURCES = builtin.h
+
+nodist_libbuiltin_la_SOURCES = $(BUILT_SOURCES)
+
+AM_LDFLAGS = -no-undefined -module -avoid-version
+
+statedir = $(localstatedir)/run/connman
+
+if MAINTAINER_MODE
+scriptdir = $(abs_top_srcdir)/scripts
+else
+scriptdir = $(libdir)/connman/scripts
+endif
+
+AM_CFLAGS = -fvisibility=hidden @GLIB_CFLAGS@ @GDBUS_CFLAGS@
+
+INCLUDES = -I$(top_builddir)/include
+
+CLEANFILES = $(BUILT_SOURCES) connman.policy
+
+EXTRA_DIST = polkit.policy
+
+MAINTAINERCLEANFILES = Makefile.in
+
+builtin.h:
+ echo "" > $@
+ list='$(builtin_modules)'; for i in $$list; \
+ do echo "extern struct connman_plugin_desc __connman_builtin_$$i;" >> $@; done
+ echo "" >> $@
+ echo "static struct connman_plugin_desc *__connman_builtin[] = {" >> $@
+ list='$(builtin_modules)'; for i in $$list; \
+ do echo "&__connman_builtin_$$i," >> $@; done
+ echo "NULL };" >> $@
+
+connman.policy: polkit.policy
+ cp $< $@
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <stdlib.h>
+
+#include <gdbus.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/device.h>
+#include <connman/inet.h>
+#include <connman/dbus.h>
+#include <connman/log.h>
+
+#define BLUEZ_SERVICE "org.bluez"
+#define BLUEZ_MANAGER_INTERFACE BLUEZ_SERVICE ".Manager"
+#define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter"
+#define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device"
+#define BLUEZ_NETWORK_INTERFACE BLUEZ_SERVICE ".Network"
+
+#define LIST_ADAPTERS "ListAdapters"
+#define ADAPTER_ADDED "AdapterAdded"
+#define ADAPTER_REMOVED "AdapterRemoved"
+
+#define PROPERTY_CHANGED "PropertyChanged"
+#define GET_PROPERTIES "GetProperties"
+#define SET_PROPERTY "SetProperty"
+
+#define CONNECT "Connect"
+#define DISCONNECT "Disconnect"
+
+#define TIMEOUT 5000
+
+typedef void (* properties_callback_t) (DBusConnection *connection,
+ const char *path,
+ DBusMessage *message,
+ void *user_data);
+
+struct properties_data {
+ DBusConnection *connection;
+ DBusMessage *message;
+ properties_callback_t callback;
+ void *user_data;
+};
+
+static void get_properties_reply(DBusPendingCall *call, void *user_data)
+{
+ struct properties_data *data = user_data;
+ DBusMessage *reply;
+ const char *path;
+
+ reply = dbus_pending_call_steal_reply(call);
+ if (reply == NULL)
+ goto done;
+
+ path = dbus_message_get_path(data->message);
+
+ data->callback(data->connection, path, reply, data->user_data);
+
+ dbus_message_unref(reply);
+
+done:
+ dbus_message_unref(data->message);
+ g_free(data);
+}
+
+static void get_properties(DBusConnection *connection,
+ const char *path, const char *interface,
+ properties_callback_t callback, void *user_data)
+{
+ struct properties_data *data;
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ DBG("path %s interface %s", path, interface);
+
+ data = g_try_new0(struct properties_data, 1);
+ if (data == NULL)
+ return;
+
+ message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
+ interface, GET_PROPERTIES);
+ if (message == NULL) {
+ g_free(data);
+ return;
+ }
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, TIMEOUT) == FALSE) {
+ connman_error("Failed to get properties for %s", interface);
+ dbus_message_unref(message);
+ g_free(data);
+ return;
+ }
+
+ if (call == NULL) {
+ connman_error("D-Bus connection not available");
+ dbus_message_unref(message);
+ g_free(data);
+ return;
+ }
+
+ data->connection = connection;
+ data->message = message;
+ data->callback = callback;
+ data->user_data = user_data;
+
+ dbus_pending_call_set_notify(call, get_properties_reply, data, NULL);
+}
+
+struct adapter_data {
+ DBusConnection *connection;
+};
+
+struct network_data {
+ DBusConnection *connection;
+ char *interface;
+};
+
+static int pan_probe(struct connman_network *network)
+{
+ struct connman_device *device = connman_network_get_device(network);
+ struct adapter_data *adapter;
+ struct network_data *data;
+
+ DBG("network %p", network);
+
+ if (device == NULL)
+ return -EINVAL;
+
+ adapter = connman_device_get_data(device);
+ if (adapter == NULL)
+ return -EINVAL;
+
+ data = g_try_new0(struct network_data, 1);
+ if (data == NULL)
+ return -ENOMEM;
+
+ data->connection = adapter->connection;
+
+ connman_network_set_data(network, data);
+
+ return 0;
+}
+
+static void pan_remove(struct connman_network *network)
+{
+ struct network_data *data = connman_network_get_data(network);
+
+ DBG("network %p", network);
+
+ connman_network_set_data(network, NULL);
+
+ g_free(data);
+}
+
+static void connect_reply(DBusPendingCall *call, void *user_data)
+{
+ struct connman_network *network = user_data;
+ struct network_data *data = connman_network_get_data(network);
+ DBusMessage *reply;
+ DBusError error;
+ const char *interface = NULL;
+ int index;
+
+ DBG("network %p", network);
+
+ reply = dbus_pending_call_steal_reply(call);
+ if (reply == NULL)
+ return;
+
+ dbus_error_init(&error);
+
+ if (dbus_message_get_args(reply, &error,
+ DBUS_TYPE_STRING, &interface,
+ DBUS_TYPE_INVALID) == FALSE) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Wrong arguments for connect");
+ goto done;
+ }
+
+ if (interface == NULL)
+ goto done;
+
+ DBG("interface %s", interface);
+
+ data->interface = g_strdup(interface);
+
+ index = connman_inet_ifindex(interface);
+
+ connman_network_set_index(network, index);
+ connman_network_set_connected(network, TRUE);
+
+done:
+ dbus_message_unref(reply);
+}
+
+static int pan_connect(struct connman_network *network)
+{
+ struct network_data *data = connman_network_get_data(network);
+ const char *path = connman_network_get_string(network, "Node");
+ const char *uuid = "nap";
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ DBG("network %p", network);
+
+ message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
+ BLUEZ_NETWORK_INTERFACE, CONNECT);
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_message_append_args(message, DBUS_TYPE_STRING, &uuid,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(data->connection, message,
+ &call, TIMEOUT * 10) == FALSE) {
+ connman_error("Failed to connect service");
+ dbus_message_unref(message);
+ return -EINVAL;
+ }
+
+ if (call == NULL) {
+ connman_error("D-Bus connection not available");
+ dbus_message_unref(message);
+ return -EINVAL;
+ }
+
+ dbus_pending_call_set_notify(call, connect_reply, network, NULL);
+
+ dbus_message_unref(message);
+
+ return -EINPROGRESS;
+}
+
+static void disconnect_reply(DBusPendingCall *call, void *user_data)
+{
+ struct connman_network *network = user_data;
+ struct network_data *data = connman_network_get_data(network);
+ DBusMessage *reply;
+ DBusError error;
+
+ DBG("network %p", network);
+
+ reply = dbus_pending_call_steal_reply(call);
+ if (reply == NULL)
+ return;
+
+ dbus_error_init(&error);
+
+ if (dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) == FALSE) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Wrong arguments for disconnect");
+ goto done;
+ }
+
+ g_free(data->interface);
+ data->interface = NULL;
+
+ connman_network_set_connected(network, FALSE);
+ connman_network_set_index(network, -1);
+
+done:
+ dbus_message_unref(reply);
+}
+
+static int pan_disconnect(struct connman_network *network)
+{
+ struct network_data *data = connman_network_get_data(network);
+ const char *path = connman_network_get_string(network, "Node");
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ DBG("network %p", network);
+
+ if (data->interface == NULL)
+ return -EINVAL;
+
+ message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
+ BLUEZ_NETWORK_INTERFACE, DISCONNECT);
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_message_append_args(message, DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(data->connection, message,
+ &call, TIMEOUT) == FALSE) {
+ connman_error("Failed to disconnect service");
+ dbus_message_unref(message);
+ return -EINVAL;
+ }
+
+ if (call == NULL) {
+ connman_error("D-Bus connection not available");
+ dbus_message_unref(message);
+ return -EINVAL;
+ }
+
+ dbus_pending_call_set_notify(call, disconnect_reply, network, NULL);
+
+ dbus_message_unref(message);
+
+ return -EINPROGRESS;
+}
+
+static struct connman_network_driver pan_driver = {
+ .name = "bluetooth-pan",
+ .type = CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN,
+ .probe = pan_probe,
+ .remove = pan_remove,
+ .connect = pan_connect,
+ .disconnect = pan_disconnect,
+};
+
+static int bluetooth_probe(struct connman_device *adapter)
+{
+ struct adapter_data *data;
+
+ DBG("adapter %p", adapter);
+
+ data = g_try_new0(struct adapter_data, 1);
+ if (data == NULL)
+ return -ENOMEM;
+
+ data->connection = connman_dbus_get_connection();
+ if (data->connection == NULL) {
+ g_free(data);
+ return -EIO;
+ }
+
+ connman_device_set_data(adapter, data);
+
+ return 0;
+}
+
+static void bluetooth_remove(struct connman_device *adapter)
+{
+ struct adapter_data *data = connman_device_get_data(adapter);
+
+ DBG("adapter %p", adapter);
+
+ connman_device_set_data(adapter, NULL);
+
+ dbus_connection_unref(data->connection);
+
+ g_free(data);
+}
+
+static void powered_reply(DBusPendingCall *call, void *user_data)
+{
+ DBusMessage *reply;
+
+ DBG("");
+
+ reply = dbus_pending_call_steal_reply(call);
+
+ dbus_message_unref(reply);
+}
+
+static int change_powered(DBusConnection *connection, const char *path,
+ dbus_bool_t powered)
+{
+ DBusMessage *message;
+ DBusMessageIter iter;
+ DBusPendingCall *call;
+
+ DBG("");
+
+ message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
+ BLUEZ_ADAPTER_INTERFACE, SET_PROPERTY);
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_message_iter_init_append(message, &iter);
+ connman_dbus_property_append_variant(&iter, "Powered",
+ DBUS_TYPE_BOOLEAN, &powered);
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, TIMEOUT) == FALSE) {
+ connman_error("Failed to change Powered property");
+ dbus_message_unref(message);
+ return -EINVAL;
+ }
+
+ if (call == NULL) {
+ connman_error("D-Bus connection not available");
+ dbus_message_unref(message);
+ return -EINVAL;
+ }
+
+ dbus_pending_call_set_notify(call, powered_reply, NULL, NULL);
+
+ dbus_message_unref(message);
+
+ return -EINPROGRESS;
+}
+
+static int bluetooth_enable(struct connman_device *adapter)
+{
+ struct adapter_data *data = connman_device_get_data(adapter);
+ const char *path = connman_device_get_string(adapter, "Node");
+
+ DBG("adapter %p", adapter);
+
+ return change_powered(data->connection, path, TRUE);
+}
+
+static int bluetooth_disable(struct connman_device *adapter)
+{
+ struct adapter_data *data = connman_device_get_data(adapter);
+ const char *path = connman_device_get_string(adapter, "Node");
+
+ DBG("adapter %p", adapter);
+
+ return change_powered(data->connection, path, FALSE);
+}
+
+static int bluetooth_scan(struct connman_device *adapter)
+{
+ DBG("adapter %p", adapter);
+
+ return -EIO;
+}
+
+static struct connman_device_driver bluetooth_driver = {
+ .name = "bluetooth",
+ .type = CONNMAN_DEVICE_TYPE_BLUETOOTH,
+ .probe = bluetooth_probe,
+ .remove = bluetooth_remove,
+ .enable = bluetooth_enable,
+ .disable = bluetooth_disable,
+ .scan = bluetooth_scan,
+};
+
+static GSList *adapter_list = NULL;
+
+static void free_adapters(void)
+{
+ GSList *list;
+
+ DBG("");
+
+ for (list = adapter_list; list; list = list->next) {
+ struct connman_device *adapter = list->data;
+
+ connman_device_unregister(adapter);
+ connman_device_unref(adapter);
+ }
+
+ g_slist_free(adapter_list);
+ adapter_list = NULL;
+}
+
+static struct connman_device *find_adapter(const char *path)
+{
+ GSList *list;
+
+ DBG("path %s", path);
+
+ for (list = adapter_list; list; list = list->next) {
+ struct connman_device *adapter = list->data;
+ const char *adapter_path = connman_device_get_string(adapter,
+ "Node");
+
+ if (adapter_path == NULL)
+ continue;
+
+ if (g_str_equal(adapter_path, path) == TRUE)
+ return adapter;
+ }
+
+ return NULL;
+}
+
+static void device_properties(DBusConnection *connection, const char *path,
+ DBusMessage *message, void *user_data)
+{
+ struct connman_device *device = user_data;
+ const char *node = g_basename(path);
+ struct connman_network *network;
+
+ DBG("path %s", path);
+
+ network = connman_device_get_network(device, node);
+ if (network != NULL)
+ return;
+
+ network = connman_network_create(node,
+ CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN);
+ if (network == NULL)
+ return;
+
+ connman_network_set_protocol(network, CONNMAN_NETWORK_PROTOCOL_IP);
+
+ connman_network_set_string(network, "Node", path);
+
+ connman_device_add_network(device, network);
+}
+
+static void check_devices(struct connman_device *adapter,
+ DBusConnection *connection, DBusMessageIter *array)
+{
+ DBusMessageIter value;
+
+ if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
+ return;
+
+ dbus_message_iter_recurse(array, &value);
+
+ while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_OBJECT_PATH) {
+ const char *path;
+
+ dbus_message_iter_get_basic(&value, &path);
+
+ get_properties(connection, path, BLUEZ_DEVICE_INTERFACE,
+ device_properties, adapter);
+
+ dbus_message_iter_next(&value);
+ }
+}
+
+static void property_changed(DBusConnection *connection, DBusMessage *message)
+{
+ const char *path = dbus_message_get_path(message);
+ struct connman_device *adapter;
+ DBusMessageIter iter, value;
+ const char *key;
+
+ DBG("path %s", path);
+
+ adapter = find_adapter(path);
+ if (adapter == NULL)
+ return;
+
+ if (dbus_message_iter_init(message, &iter) == FALSE)
+ return;
+
+ dbus_message_iter_get_basic(&iter, &key);
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &value);
+
+ if (g_str_equal(key, "Powered") == TRUE) {
+ gboolean val;
+
+ dbus_message_iter_get_basic(&value, &val);
+ connman_device_set_powered(adapter, val);
+ } else if (g_str_equal(key, "Discovering") == TRUE) {
+ gboolean val;
+
+ dbus_message_iter_get_basic(&value, &val);
+ connman_device_set_scanning(adapter, val);
+ }
+}
+
+static void parse_adapter_properties(struct connman_device *adapter,
+ DBusConnection *connection,
+ DBusMessage *reply)
+{
+ DBusMessageIter array, dict;
+
+ if (dbus_message_iter_init(reply, &array) == FALSE)
+ return;
+
+ if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
+ return;
+
+ dbus_message_iter_recurse(&array, &dict);
+
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+ const char *key;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
+
+ if (g_str_equal(key, "Powered") == TRUE) {
+ gboolean val;
+
+ dbus_message_iter_get_basic(&value, &val);
+ connman_device_set_powered(adapter, val);
+ } else if (g_str_equal(key, "Discovering") == TRUE) {
+ gboolean val;
+
+ dbus_message_iter_get_basic(&value, &val);
+ connman_device_set_scanning(adapter, val);
+ } else if (g_str_equal(key, "Devices") == TRUE) {
+ check_devices(adapter, connection, &value);
+ }
+
+ dbus_message_iter_next(&dict);
+ }
+}
+
+static void adapter_properties(DBusConnection *connection, const char *path,
+ DBusMessage *message, void *user_data)
+{
+ const char *node = g_basename(path);
+ struct connman_device *adapter;
+
+ DBG("path %s", path);
+
+ adapter = find_adapter(path);
+ if (adapter != NULL)
+ goto done;
+
+ adapter = connman_device_create(node, CONNMAN_DEVICE_TYPE_BLUETOOTH);
+ if (adapter == NULL)
+ return;
+
+ connman_device_set_string(adapter, "Node", path);
+
+ if (node != NULL && g_str_has_prefix(node, "hci") == TRUE) {
+ int index;
+ errno = 0;
+ index = atoi(node + 3);
+ if (errno == 0)
+ connman_device_set_index(adapter, index);
+ }
+
+ connman_device_set_interface(adapter, node);
+
+ connman_device_set_policy(adapter, CONNMAN_DEVICE_POLICY_MANUAL);
+ connman_device_set_mode(adapter, CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE);
+
+ if (connman_device_register(adapter) < 0) {
+ connman_device_unref(adapter);
+ return;
+ }
+
+ adapter_list = g_slist_append(adapter_list, adapter);
+
+done:
+ parse_adapter_properties(adapter, connection, message);
+}
+
+static void add_adapter(DBusConnection *connection, const char *path)
+{
+ DBG("path %s", path);
+
+ get_properties(connection, path, BLUEZ_ADAPTER_INTERFACE,
+ adapter_properties, NULL);
+}
+
+static void remove_adapter(DBusConnection *connection, const char *path)
+{
+ struct connman_device *adapter;
+
+ DBG("path %s", path);
+
+ adapter = find_adapter(path);
+ if (adapter == NULL)
+ return;
+
+ adapter_list = g_slist_remove(adapter_list, adapter);
+
+ connman_device_unregister(adapter);
+ connman_device_unref(adapter);
+}
+
+static void list_adapters_reply(DBusPendingCall *call, void *user_data)
+{
+ DBusConnection *connection = user_data;
+ DBusMessage *reply;
+ DBusError error;
+ char **adapters;
+ int i, num_adapters;
+
+ DBG("");
+
+ reply = dbus_pending_call_steal_reply(call);
+
+ dbus_error_init(&error);
+
+ if (dbus_message_get_args(reply, &error,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
+ &adapters, &num_adapters,
+ DBUS_TYPE_INVALID) == FALSE) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Wrong arguments for adapter list");
+ goto done;
+ }
+
+ for (i = 0; i < num_adapters; i++)
+ get_properties(connection, adapters[i],
+ BLUEZ_ADAPTER_INTERFACE,
+ adapter_properties, NULL);
+
+ g_strfreev(adapters);
+
+done:
+ dbus_message_unref(reply);
+}
+
+static void bluetooth_connect(DBusConnection *connection, void *user_data)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ DBG("connection %p", connection);
+
+ message = dbus_message_new_method_call(BLUEZ_SERVICE, "/",
+ BLUEZ_MANAGER_INTERFACE, LIST_ADAPTERS);
+ if (message == NULL)
+ return;
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, TIMEOUT) == FALSE) {
+ connman_error("Failed to get Bluetooth adapters");
+ goto done;
+ }
+
+ if (call == NULL) {
+ connman_error("D-Bus connection not available");
+ goto done;
+ }
+
+ dbus_pending_call_set_notify(call, list_adapters_reply,
+ connection, NULL);
+
+done:
+ dbus_message_unref(message);
+}
+
+static void bluetooth_disconnect(DBusConnection *connection, void *user_data)
+{
+ DBG("connection %p", connection);
+
+ free_adapters();
+}
+
+static DBusHandlerResult bluetooth_signal(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ if (dbus_message_has_interface(message,
+ BLUEZ_MANAGER_INTERFACE) == FALSE &&
+ dbus_message_has_interface(message,
+ BLUEZ_ADAPTER_INTERFACE) == FALSE)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ DBG("connection %p", connection);
+
+ if (dbus_message_is_signal(message, BLUEZ_ADAPTER_INTERFACE,
+ PROPERTY_CHANGED) == TRUE) {
+ property_changed(connection, message);
+ } else if (dbus_message_is_signal(message, BLUEZ_MANAGER_INTERFACE,
+ ADAPTER_ADDED) == TRUE) {
+ const char *path;
+ dbus_message_get_args(message, NULL,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+ add_adapter(connection, path);
+ } else if (dbus_message_is_signal(message, BLUEZ_MANAGER_INTERFACE,
+ ADAPTER_REMOVED) == TRUE) {
+ const char *path;
+ dbus_message_get_args(message, NULL,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+ remove_adapter(connection, path);
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusConnection *connection;
+static guint watch;
+
+static const char *added_rule = "type=signal,member=" ADAPTER_ADDED
+ ",interface=" BLUEZ_MANAGER_INTERFACE;
+static const char *removed_rule = "type=signal,member=" ADAPTER_REMOVED
+ ",interface=" BLUEZ_MANAGER_INTERFACE;
+
+static const char *adapter_rule = "type=signal,member=" PROPERTY_CHANGED
+ ",interface=" BLUEZ_ADAPTER_INTERFACE;
+
+static int bluetooth_init(void)
+{
+ int err = -EIO;
+
+ connection = connman_dbus_get_connection();
+ if (connection == NULL)
+ return -EIO;
+
+ if (dbus_connection_add_filter(connection, bluetooth_signal,
+ NULL, NULL) == FALSE)
+ goto unref;
+
+ err = connman_network_driver_register(&pan_driver);
+ if (err < 0)
+ goto remove;
+
+ err = connman_device_driver_register(&bluetooth_driver);
+ if (err < 0) {
+ connman_network_driver_unregister(&pan_driver);
+ goto remove;
+ }
+
+ watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
+ bluetooth_connect, bluetooth_disconnect, NULL, NULL);
+ if (watch == 0) {
+ connman_device_driver_unregister(&bluetooth_driver);
+ connman_network_driver_unregister(&pan_driver);
+ err = -EIO;
+ goto remove;
+ }
+
+ if (g_dbus_check_service(connection, BLUEZ_SERVICE) == TRUE)
+ bluetooth_connect(connection, NULL);
+
+ dbus_bus_add_match(connection, added_rule, NULL);
+ dbus_bus_add_match(connection, removed_rule, NULL);
+ dbus_bus_add_match(connection, adapter_rule, NULL);
+ dbus_connection_flush(connection);
+
+ return 0;
+
+remove:
+ dbus_connection_remove_filter(connection, bluetooth_signal, NULL);
+
+unref:
+ dbus_connection_unref(connection);
+
+ return err;
+}
+
+static void bluetooth_exit(void)
+{
+ dbus_bus_remove_match(connection, adapter_rule, NULL);
+ dbus_bus_remove_match(connection, removed_rule, NULL);
+ dbus_bus_remove_match(connection, added_rule, NULL);
+ dbus_connection_flush(connection);
+
+ g_dbus_remove_watch(connection, watch);
+
+ free_adapters();
+
+ connman_device_driver_unregister(&bluetooth_driver);
+ connman_network_driver_unregister(&pan_driver);
+
+ dbus_connection_remove_filter(connection, bluetooth_signal, NULL);
+
+ dbus_connection_unref(connection);
+}
+
+CONNMAN_PLUGIN_DEFINE(bluetooth, "Bluetooth technology plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, bluetooth_init, bluetooth_exit)
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <unistd.h>
+#include <sys/wait.h>
+#include <glib/gstdio.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/driver.h>
+#include <connman/inet.h>
+#include <connman/dbus.h>
+#include <connman/log.h>
+
+#define DHCLIENT_INTF "org.isc.dhclient"
+#define DHCLIENT_PATH "/org/isc/dhclient"
+
+static const char *busname;
+
+struct dhclient_task {
+ GPid pid;
+ int ifindex;
+ gchar *ifname;
+ struct connman_element *element;
+};
+
+static GSList *task_list = NULL;
+
+static struct dhclient_task *find_task_by_pid(GPid pid)
+{
+ GSList *list;
+
+ for (list = task_list; list; list = list->next) {
+ struct dhclient_task *task = list->data;
+
+ if (task->pid == pid)
+ return task;
+ }
+
+ return NULL;
+}
+
+static struct dhclient_task *find_task_by_index(int index)
+{
+ GSList *list;
+
+ for (list = task_list; list; list = list->next) {
+ struct dhclient_task *task = list->data;
+
+ if (task->ifindex == index)
+ return task;
+ }
+
+ return NULL;
+}
+
+static void kill_task(struct dhclient_task *task)
+{
+ DBG("task %p name %s pid %d", task, task->ifname, task->pid);
+
+ if (task->pid > 0)
+ kill(task->pid, SIGTERM);
+}
+
+static void unlink_task(struct dhclient_task *task)
+{
+ gchar *pathname;
+
+ DBG("task %p name %s pid %d", task, task->ifname, task->pid);
+
+ pathname = g_strdup_printf("%s/dhclient.%s.pid",
+ STATEDIR, task->ifname);
+ g_unlink(pathname);
+ g_free(pathname);
+
+ pathname = g_strdup_printf("%s/dhclient.%s.leases",
+ STATEDIR, task->ifname);
+ g_unlink(pathname);
+ g_free(pathname);
+}
+
+static void task_died(GPid pid, gint status, gpointer data)
+{
+ struct dhclient_task *task = data;
+
+ if (WIFEXITED(status))
+ DBG("exit status %d for %s", WEXITSTATUS(status), task->ifname);
+ else
+ DBG("signal %d killed %s", WTERMSIG(status), task->ifname);
+
+ g_spawn_close_pid(pid);
+ task->pid = 0;
+
+ task_list = g_slist_remove(task_list, task);
+
+ unlink_task(task);
+
+ g_free(task->ifname);
+ g_free(task);
+}
+
+static void task_setup(gpointer data)
+{
+ struct dhclient_task *task = data;
+
+ DBG("task %p name %s", task, task->ifname);
+}
+
+static int dhclient_probe(struct connman_element *element)
+{
+ struct dhclient_task *task;
+ char *argv[16], *envp[1], address[128], pidfile[PATH_MAX];
+ char leases[PATH_MAX], config[PATH_MAX], script[PATH_MAX];
+
+ DBG("element %p name %s", element, element->name);
+
+ if (access(DHCLIENT, X_OK) < 0)
+ return -errno;
+
+ task = g_try_new0(struct dhclient_task, 1);
+ if (task == NULL)
+ return -ENOMEM;
+
+ task->ifindex = element->index;
+ task->ifname = connman_inet_ifname(element->index);
+ task->element = element;
+
+ if (task->ifname == NULL) {
+ g_free(task);
+ return -ENOMEM;
+ }
+
+ DBG("request %s", task->ifname);
+
+ snprintf(address, sizeof(address) - 1, "BUSNAME=%s", busname);
+ snprintf(pidfile, sizeof(pidfile) - 1,
+ "%s/dhclient.%s.pid", STATEDIR, task->ifname);
+ snprintf(leases, sizeof(leases) - 1,
+ "%s/dhclient.%s.leases", STATEDIR, task->ifname);
+ snprintf(config, sizeof(config) - 1, "%s/dhclient.conf", SCRIPTDIR);
+ snprintf(script, sizeof(script) - 1, "%s/dhclient-script", SCRIPTDIR);
+
+ argv[0] = DHCLIENT;
+ argv[1] = "-d";
+ argv[2] = "-q";
+ argv[3] = "-e";
+ argv[4] = address;
+ argv[5] = "-pf";
+ argv[6] = pidfile;
+ argv[7] = "-lf";
+ argv[8] = leases;
+ argv[9] = "-cf";
+ argv[10] = config;
+ argv[11] = "-sf";
+ argv[12] = script;
+ argv[13] = task->ifname;
+ argv[14] = "-n";
+ argv[15] = NULL;
+
+ envp[0] = NULL;
+
+ if (g_spawn_async(NULL, argv, envp, G_SPAWN_DO_NOT_REAP_CHILD,
+ task_setup, task, &task->pid, NULL) == FALSE) {
+ connman_error("Failed to spawn dhclient");
+ return -1;
+ }
+
+ task_list = g_slist_append(task_list, task);
+
+ g_child_watch_add(task->pid, task_died, task);
+
+ DBG("executed %s with pid %d", DHCLIENT, task->pid);
+
+ return 0;
+}
+
+static void dhclient_remove(struct connman_element *element)
+{
+ struct dhclient_task *task;
+
+ DBG("element %p name %s", element, element->name);
+
+ task = find_task_by_index(element->index);
+ if (task != NULL)
+ task_list = g_slist_remove(task_list, task);
+
+ if (task == NULL)
+ return;
+
+ DBG("release %s", task->ifname);
+
+ kill_task(task);
+}
+
+static void dhclient_change(struct connman_element *element)
+{
+ DBG("element %p name %s", element, element->name);
+
+ if (element->state == CONNMAN_ELEMENT_STATE_ERROR)
+ connman_element_set_error(element->parent,
+ CONNMAN_ELEMENT_ERROR_DHCP_FAILED);
+}
+
+static struct connman_driver dhclient_driver = {
+ .name = "dhclient",
+ .type = CONNMAN_ELEMENT_TYPE_DHCP,
+ .probe = dhclient_probe,
+ .remove = dhclient_remove,
+ .change = dhclient_change,
+};
+
+static DBusHandlerResult dhclient_filter(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessageIter iter, dict;
+ dbus_uint32_t pid;
+ struct dhclient_task *task;
+ const char *text, *key, *value;
+
+ if (dbus_message_is_method_call(msg, DHCLIENT_INTF, "notify") == FALSE)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ dbus_message_iter_init(msg, &iter);
+
+ dbus_message_iter_get_basic(&iter, &pid);
+ dbus_message_iter_next(&iter);
+
+ dbus_message_iter_get_basic(&iter, &text);
+ dbus_message_iter_next(&iter);
+
+ DBG("change %d to %s", pid, text);
+
+ task = find_task_by_pid(pid);
+
+ if (task == NULL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ dbus_message_iter_recurse(&iter, &dict);
+
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_get_basic(&entry, &value);
+
+ DBG("%s = %s", key, value);
+
+ if (g_ascii_strcasecmp(key, "new_ip_address") == 0) {
+ g_free(task->element->ipv4.address);
+ task->element->ipv4.address = g_strdup(value);
+ }
+
+ if (g_ascii_strcasecmp(key, "new_subnet_mask") == 0) {
+ g_free(task->element->ipv4.netmask);
+ task->element->ipv4.netmask = g_strdup(value);
+ }
+
+ if (g_ascii_strcasecmp(key, "new_routers") == 0) {
+ g_free(task->element->ipv4.gateway);
+ task->element->ipv4.gateway = g_strdup(value);
+ }
+
+ if (g_ascii_strcasecmp(key, "new_network_number") == 0) {
+ g_free(task->element->ipv4.network);
+ task->element->ipv4.network = g_strdup(value);
+ }
+
+ if (g_ascii_strcasecmp(key, "new_broadcast_address") == 0) {
+ g_free(task->element->ipv4.broadcast);
+ task->element->ipv4.broadcast = g_strdup(value);
+ }
+
+ if (g_ascii_strcasecmp(key, "new_domain_name_servers") == 0) {
+ g_free(task->element->ipv4.nameserver);
+ task->element->ipv4.nameserver = g_strdup(value);
+ }
+
+ if (g_ascii_strcasecmp(key, "new_domain_name") == 0) {
+ }
+
+ if (g_ascii_strcasecmp(key, "new_domain_search") == 0) {
+ }
+
+ if (g_ascii_strcasecmp(key, "new_host_name") == 0) {
+ }
+
+ dbus_message_iter_next(&dict);
+ }
+
+ if (g_ascii_strcasecmp(text, "PREINIT") == 0) {
+ } else if (g_ascii_strcasecmp(text, "BOUND") == 0 ||
+ g_ascii_strcasecmp(text, "REBOOT") == 0) {
+ struct connman_element *element;
+ element = connman_element_create(NULL);
+ element->type = CONNMAN_ELEMENT_TYPE_IPV4;
+ element->index = task->ifindex;
+ connman_element_update(task->element);
+ if (connman_element_register(element, task->element) < 0)
+ connman_element_unref(element);
+ } else if (g_ascii_strcasecmp(text, "RENEW") == 0 ||
+ g_ascii_strcasecmp(text, "REBIND") == 0) {
+ connman_element_update(task->element);
+ } else if (g_ascii_strcasecmp(text, "FAIL") == 0) {
+ connman_element_set_error(task->element,
+ CONNMAN_ELEMENT_ERROR_FAILED);
+ } else {
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusConnection *connection;
+
+static const char *dhclient_rule = "path=" DHCLIENT_PATH
+ ",interface=" DHCLIENT_INTF;
+
+static int dhclient_init(void)
+{
+ int err;
+
+ connection = connman_dbus_get_connection();
+
+ busname = dbus_bus_get_unique_name(connection);
+ busname = CONNMAN_SERVICE;
+
+ dbus_connection_add_filter(connection, dhclient_filter, NULL, NULL);
+
+ dbus_bus_add_match(connection, dhclient_rule, NULL);
+
+ err = connman_driver_register(&dhclient_driver);
+ if (err < 0) {
+ dbus_connection_unref(connection);
+ return err;
+ }
+
+ return 0;
+}
+
+static void dhclient_exit(void)
+{
+ GSList *list;
+
+ for (list = task_list; list; list = list->next) {
+ struct dhclient_task *task = list->data;
+
+ DBG("killing process %d", task->pid);
+
+ kill_task(task);
+ unlink_task(task);
+ }
+
+ g_slist_free(task_list);
+
+ connman_driver_unregister(&dhclient_driver);
+
+ dbus_bus_remove_match(connection, dhclient_rule, NULL);
+
+ dbus_connection_remove_filter(connection, dhclient_filter, NULL);
+
+ dbus_connection_unref(connection);
+}
+
+CONNMAN_PLUGIN_DEFINE(dhclient, "ISC DHCP client plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, dhclient_init, dhclient_exit)
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/resolver.h>
+#include <connman/log.h>
+
+#include <glib.h>
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+struct domain_hdr {
+ uint16_t id;
+ uint8_t rd:1;
+ uint8_t tc:1;
+ uint8_t aa:1;
+ uint8_t opcode:4;
+ uint8_t qr:1;
+ uint8_t rcode:4;
+ uint8_t z:3;
+ uint8_t ra:1;
+ uint16_t qdcount;
+ uint16_t ancount;
+ uint16_t nscount;
+ uint16_t arcount;
+} __attribute__ ((packed));
+#elif __BYTE_ORDER == __BIG_ENDIAN
+struct domain_hdr {
+ uint16_t id;
+ uint8_t qr:1;
+ uint8_t opcode:4;
+ uint8_t aa:1;
+ uint8_t tc:1;
+ uint8_t rd:1;
+ uint8_t ra:1;
+ uint8_t z:3;
+ uint8_t rcode:4;
+ uint16_t qdcount;
+ uint16_t ancount;
+ uint16_t nscount;
+ uint16_t arcount;
+} __attribute__ ((packed));
+#else
+#error "Unknown byte order"
+#endif
+
+struct server_data {
+ char *interface;
+ char *domain;
+ char *server;
+ GIOChannel *channel;
+ guint watch;
+};
+
+struct request_data {
+ struct sockaddr_in sin;
+ socklen_t len;
+ guint16 srcid;
+ guint16 dstid;
+ guint16 altid;
+ guint timeout;
+ guint numserv;
+ guint numresp;
+ gpointer resp;
+ gsize resplen;
+};
+
+static GSList *server_list = NULL;
+static GSList *request_list = NULL;
+static guint16 request_id = 0x0000;
+
+static GIOChannel *listener_channel = NULL;
+static guint listener_watch = 0;
+
+static struct request_data *find_request(guint16 id)
+{
+ GSList *list;
+
+ for (list = request_list; list; list = list->next) {
+ struct request_data *req = list->data;
+
+ if (req->dstid == id || req->altid == id)
+ return req;
+ }
+
+ return NULL;
+}
+
+static struct server_data *find_server(const char *interface,
+ const char *domain, const char *server)
+{
+ GSList *list;
+
+ DBG("interface %s server %s", interface, server);
+
+ for (list = server_list; list; list = list->next) {
+ struct server_data *data = list->data;
+
+ if (data->interface == NULL || data->server == NULL)
+ continue;
+
+ if (g_str_equal(data->interface, interface) == TRUE &&
+ g_str_equal(data->server, server) == TRUE) {
+ if (domain == NULL) {
+ if (data->domain == NULL)
+ return data;
+ continue;
+ }
+
+ if (g_str_equal(data->domain, domain) == TRUE)
+ return data;
+ }
+ }
+
+ return NULL;
+}
+
+static gboolean server_event(GIOChannel *channel, GIOCondition condition,
+ gpointer user_data)
+{
+ struct server_data *data = user_data;
+ struct request_data *req;
+ unsigned char buf[768];
+ struct domain_hdr *hdr = (void *) &buf;
+ int sk, err, len;
+
+ if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+ connman_error("Error with server channel");
+ data->watch = 0;
+ return FALSE;
+ }
+
+ sk = g_io_channel_unix_get_fd(channel);
+
+ len = recv(sk, buf, sizeof(buf), 0);
+ if (len < 12)
+ return TRUE;
+
+ DBG("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8);
+
+ req = find_request(buf[0] | buf[1] << 8);
+ if (req == NULL)
+ return TRUE;
+
+ DBG("id 0x%04x rcode %d", hdr->id, hdr->rcode);
+
+ buf[0] = req->srcid & 0xff;
+ buf[1] = req->srcid >> 8;
+
+ req->numresp++;
+
+ if (hdr->rcode == 0 || req->resp == NULL) {
+ g_free(req->resp);
+ req->resplen = 0;
+
+ req->resp = g_try_malloc(len);
+ if (req->resp == NULL)
+ return TRUE;
+
+ memcpy(req->resp, buf, len);
+ req->resplen = len;
+ }
+
+ if (hdr->rcode > 0 && req->numresp < req->numserv)
+ return TRUE;
+
+ if (req->timeout > 0)
+ g_source_remove(req->timeout);
+
+ request_list = g_slist_remove(request_list, req);
+
+ sk = g_io_channel_unix_get_fd(listener_channel);
+
+ err = sendto(sk, req->resp, req->resplen, 0,
+ (struct sockaddr *) &req->sin, req->len);
+
+ g_free(req->resp);
+ g_free(req);
+
+ return TRUE;
+}
+
+static struct server_data *create_server(const char *interface,
+ const char *domain, const char *server)
+{
+ struct server_data *data;
+ struct sockaddr_in sin;
+ int sk;
+
+ DBG("interface %s server %s", interface, server);
+
+ sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (sk < 0) {
+ connman_error("Failed to create server %s socket", server);
+ return NULL;
+ }
+
+ if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
+ interface, strlen(interface) + 1) < 0) {
+ connman_error("Failed to bind server %s to interface %s",
+ server, interface);
+ close(sk);
+ return NULL;
+ }
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(53);
+ sin.sin_addr.s_addr = inet_addr(server);
+
+ if (connect(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
+ connman_error("Failed to connect server %s", server);
+ close(sk);
+ return NULL;
+ }
+
+ data = g_try_new0(struct server_data, 1);
+ if (data == NULL) {
+ connman_error("Failed to allocate server %s data", server);
+ close(sk);
+ return NULL;
+ }
+
+ data->channel = g_io_channel_unix_new(sk);
+ if (data->channel == NULL) {
+ connman_error("Failed to create server %s channel", server);
+ close(sk);
+ g_free(data);
+ return NULL;
+ }
+
+ g_io_channel_set_close_on_unref(data->channel, TRUE);
+
+ data->watch = g_io_add_watch(data->channel, G_IO_IN,
+ server_event, data);
+
+ data->interface = g_strdup(interface);
+ data->domain = g_strdup(domain);
+ data->server = g_strdup(server);
+
+ return data;
+}
+
+static void destroy_server(struct server_data *data)
+{
+ DBG("interface %s server %s", data->interface, data->server);
+
+ if (data->watch > 0)
+ g_source_remove(data->watch);
+
+ g_io_channel_unref(data->channel);
+
+ g_free(data->server);
+ g_free(data->domain);
+ g_free(data->interface);
+ g_free(data);
+}
+
+static int dnsproxy_append(const char *interface, const char *domain,
+ const char *server)
+{
+ struct server_data *data;
+
+ DBG("interface %s server %s", interface, server);
+
+ if (g_str_equal(server, "127.0.0.1") == TRUE)
+ return -ENODEV;
+
+ data = create_server(interface, domain, server);
+ if (data == NULL)
+ return -EIO;
+
+ server_list = g_slist_append(server_list, data);
+
+ return 0;
+}
+
+static int dnsproxy_remove(const char *interface, const char *domain,
+ const char *server)
+{
+ struct server_data *data;
+
+ DBG("interface %s server %s", interface, server);
+
+ if (g_str_equal(server, "127.0.0.1") == TRUE)
+ return -ENODEV;
+
+ data = find_server(interface, domain, server);
+ if (data == NULL)
+ return 0;
+
+ server_list = g_slist_remove(server_list, data);
+
+ destroy_server(data);
+
+ return 0;
+}
+
+static struct connman_resolver dnsproxy_resolver = {
+ .name = "dnsproxy",
+ .priority = CONNMAN_RESOLVER_PRIORITY_HIGH,
+ .append = dnsproxy_append,
+ .remove = dnsproxy_remove,
+};
+
+static int parse_request(unsigned char *buf, int len,
+ char *name, unsigned int size)
+{
+ struct domain_hdr *hdr = (void *) buf;
+ uint16_t qdcount = ntohs(hdr->qdcount);
+ unsigned char *ptr;
+ char *last_label = NULL;
+ int label_count = 0;
+ unsigned int remain, used = 0;
+
+ if (len < 12)
+ return -EINVAL;
+
+ DBG("id 0x%04x qr %d opcode %d qdcount %d",
+ hdr->id, hdr->qr, hdr->opcode, qdcount);
+
+ if (hdr->qr != 0 || qdcount != 1)
+ return -EINVAL;
+
+ memset(name, 0, size);
+
+ ptr = buf + 12;
+ remain = len - 12;
+
+ while (remain > 0) {
+ uint8_t len = *ptr;
+
+ if (len == 0x00) {
+ if (label_count > 0)
+ last_label = (char *) (ptr + 1);
+ break;
+ }
+
+ label_count++;
+
+ if (used + len + 1 > size)
+ return -ENOBUFS;
+
+ strncat(name, (char *) (ptr + 1), len);
+ strcat(name, ".");
+
+ used += len + 1;
+
+ ptr += len + 1;
+ remain -= len + 1;
+ }
+
+ DBG("query %s (%d labels)", name, label_count);
+
+ return 0;
+}
+
+static void send_response(int sk, unsigned char *buf, int len,
+ const struct sockaddr *to, socklen_t tolen)
+{
+ struct domain_hdr *hdr = (void *) buf;
+ int err;
+
+ if (len < 12)
+ return;
+
+ DBG("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode);
+
+ hdr->qr = 1;
+ hdr->rcode = 2;
+
+ hdr->ancount = 0;
+ hdr->nscount = 0;
+ hdr->arcount = 0;
+
+ err = sendto(sk, buf, len, 0, to, tolen);
+}
+
+static int append_query(unsigned char *buf, unsigned int size,
+ const char *query, const char *domain)
+{
+ unsigned char *ptr = buf;
+ char *offset;
+
+ DBG("query %s domain %s", query, domain);
+
+ offset = (char *) query;
+ while (offset != NULL) {
+ char *tmp;
+
+ tmp = strchr(offset, '.');
+ if (tmp == NULL) {
+ if (strlen(offset) == 0)
+ break;
+ *ptr = strlen(offset);
+ memcpy(ptr + 1, offset, strlen(offset));
+ ptr += strlen(offset) + 1;
+ break;
+ }
+
+ *ptr = tmp - offset;
+ memcpy(ptr + 1, offset, tmp - offset);
+ ptr += tmp - offset + 1;
+
+ offset = tmp + 1;
+ }
+
+ offset = (char *) domain;
+ while (offset != NULL) {
+ char *tmp;
+
+ tmp = strchr(offset, '.');
+ if (tmp == NULL) {
+ if (strlen(offset) == 0)
+ break;
+ *ptr = strlen(offset);
+ memcpy(ptr + 1, offset, strlen(offset));
+ ptr += strlen(offset) + 1;
+ break;
+ }
+
+ *ptr = tmp - offset;
+ memcpy(ptr + 1, offset, tmp - offset);
+ ptr += tmp - offset + 1;
+
+ offset = tmp + 1;
+ }
+
+ *ptr++ = 0x00;
+
+ return ptr - buf;
+}
+
+static gboolean request_timeout(gpointer user_data)
+{
+ struct request_data *req = user_data;
+
+ DBG("id 0x%04x", req->srcid);
+
+ request_list = g_slist_remove(request_list, req);
+
+ if (req->resplen > 0 && req->resp != NULL) {
+ int sk, err;
+
+ sk = g_io_channel_unix_get_fd(listener_channel);
+
+ err = sendto(sk, req->resp, req->resplen, 0,
+ (struct sockaddr *) &req->sin, req->len);
+ }
+
+ g_free(req->resp);
+ g_free(req);
+
+ return FALSE;
+}
+
+static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
+ gpointer user_data)
+{
+ GSList *list;
+ unsigned char buf[768];
+ char query[512];
+ struct request_data *req;
+ struct sockaddr_in sin;
+ socklen_t size = sizeof(sin);
+ int sk, err, len;
+
+ if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+ connman_error("Error with listener channel");
+ listener_watch = 0;
+ return FALSE;
+ }
+
+ sk = g_io_channel_unix_get_fd(channel);
+
+ memset(&sin, 0, sizeof(sin));
+ len = recvfrom(sk, buf, sizeof(buf), 0,
+ (struct sockaddr *) &sin, &size);
+ if (len < 2)
+ return TRUE;
+
+ DBG("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8);
+
+ err = parse_request(buf, len, query, sizeof(query));
+ if (err < 0 || g_slist_length(server_list) == 0) {
+ send_response(sk, buf, len, (struct sockaddr *) &sin, size);
+ return TRUE;
+ }
+
+ req = g_try_new0(struct request_data, 1);
+ if (req == NULL)
+ return TRUE;
+
+ memcpy(&req->sin, &sin, sizeof(sin));
+ req->len = size;
+
+ request_id += 2;
+ if (request_id == 0x0000 || request_id == 0xffff)
+ request_id += 2;
+
+ req->srcid = buf[0] | (buf[1] << 8);
+ req->dstid = request_id;
+ req->altid = request_id + 1;
+
+ buf[0] = req->dstid & 0xff;
+ buf[1] = req->dstid >> 8;
+
+ request_list = g_slist_append(request_list, req);
+
+ req->numserv = 0;
+ req->timeout = g_timeout_add_seconds(5, request_timeout, req);
+
+ for (list = server_list; list; list = list->next) {
+ struct server_data *data = list->data;
+
+ DBG("server %s domain %s", data->server, data->domain);
+
+ sk = g_io_channel_unix_get_fd(data->channel);
+
+ err = send(sk, buf, len, 0);
+
+ req->numserv++;
+
+ if (data->domain != NULL) {
+ unsigned char alt[1024];
+ struct domain_hdr *hdr = (void *) &alt;
+ int altlen;
+
+ alt[0] = req->altid & 0xff;
+ alt[1] = req->altid >> 8;
+
+ memcpy(alt + 2, buf + 2, 10);
+ hdr->qdcount = htons(1);
+
+ altlen = append_query(alt + 12, sizeof(alt) - 12,
+ query, data->domain);
+ if (altlen < 0)
+ continue;
+
+ alt[altlen + 12] = 0x00;
+ alt[altlen + 13] = 0x01;
+ alt[altlen + 14] = 0x00;
+ alt[altlen + 15] = 0x01;
+
+ err = send(sk, alt, altlen + 12 + 4, 0);
+
+ req->numserv++;
+ }
+ }
+
+ return TRUE;
+}
+
+static int create_listener(void)
+{
+ const char *ifname = "lo";
+ struct sockaddr_in sin;
+ int sk;
+
+ DBG("");
+
+ sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (sk < 0) {
+ connman_error("Failed to create listener socket");
+ return -EIO;
+ }
+
+ //setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+ //setsockopt(sk, SOL_IP, IP_PKTINFO, &opt, sizeof(opt));
+
+ if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
+ ifname, strlen(ifname) + 1) < 0) {
+ connman_error("Failed to bind listener interface");
+ close(sk);
+ return -EIO;
+ }
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(53);
+ sin.sin_addr.s_addr = inet_addr("127.0.0.1");
+ //sin.sin_addr.s_addr = INADDR_ANY;
+
+ if (bind(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
+ connman_error("Failed to bind listener socket");
+ close(sk);
+ return -EIO;
+ }
+
+ listener_channel = g_io_channel_unix_new(sk);
+ if (listener_channel == NULL) {
+ connman_error("Failed to create listener channel");
+ close(sk);
+ return -EIO;
+ }
+
+ g_io_channel_set_close_on_unref(listener_channel, TRUE);
+
+ listener_watch = g_io_add_watch(listener_channel, G_IO_IN,
+ listener_event, NULL);
+
+ connman_resolver_append("lo", NULL, "127.0.0.1");
+
+ return 0;
+}
+
+static void destroy_listener(void)
+{
+ GSList *list;
+
+ DBG("");
+
+ connman_resolver_remove_all("lo");
+
+ if (listener_watch > 0)
+ g_source_remove(listener_watch);
+
+ for (list = request_list; list; list = list->next) {
+ struct request_data *req = list->data;
+
+ DBG("Dropping request (id 0x%04x -> 0x%04x)",
+ req->srcid, req->dstid);
+
+ g_free(req->resp);
+ g_free(req);
+ list->data = NULL;
+ }
+
+ g_slist_free(request_list);
+ request_list = NULL;
+
+ g_io_channel_unref(listener_channel);
+}
+
+static int dnsproxy_init(void)
+{
+ int err;
+
+ err = create_listener();
+ if (err < 0)
+ return err;
+
+ err = connman_resolver_register(&dnsproxy_resolver);
+ if (err < 0)
+ destroy_listener();
+
+ return err;
+}
+
+static void dnsproxy_exit(void)
+{
+ destroy_listener();
+
+ connman_resolver_unregister(&dnsproxy_resolver);
+}
+
+CONNMAN_PLUGIN_DEFINE(dnsproxy, "DNS proxy resolver plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, dnsproxy_init, dnsproxy_exit)
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <net/if.h>
+
+#ifndef IFF_LOWER_UP
+#define IFF_LOWER_UP 0x10000
+#endif
+
+#include <glib.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/device.h>
+#include <connman/inet.h>
+#include <connman/rtnl.h>
+#include <connman/log.h>
+
+struct ethernet_data {
+ int index;
+ unsigned flags;
+ unsigned int watch;
+};
+
+static void ethernet_newlink(unsigned flags, unsigned change, void *user_data)
+{
+ struct connman_device *device = user_data;
+ struct ethernet_data *ethernet = connman_device_get_data(device);
+
+ DBG("index %d flags %d change %d", ethernet->index, flags, change);
+
+ if ((ethernet->flags & IFF_UP) != (flags & IFF_UP)) {
+ if (flags & IFF_UP) {
+ DBG("power on");
+ connman_device_set_powered(device, TRUE);
+ } else {
+ DBG("power off");
+ connman_device_set_powered(device, FALSE);
+ }
+ }
+
+ if ((ethernet->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
+ if (flags & IFF_LOWER_UP) {
+ DBG("carrier on");
+ connman_device_set_carrier(device, TRUE);
+ } else {
+ DBG("carrier off");
+ connman_device_set_carrier(device, FALSE);
+ }
+ }
+
+ ethernet->flags = flags;
+}
+
+static int ethernet_probe(struct connman_device *device)
+{
+ struct ethernet_data *ethernet;
+
+ DBG("device %p", device);
+
+ ethernet = g_try_new0(struct ethernet_data, 1);
+ if (ethernet == NULL)
+ return -ENOMEM;
+
+ connman_device_set_data(device, ethernet);
+
+ ethernet->index = connman_device_get_index(device);
+ ethernet->flags = 0;
+
+ ethernet->watch = connman_rtnl_add_newlink_watch(ethernet->index,
+ ethernet_newlink, device);
+
+ connman_rtnl_send_getlink();
+
+ return 0;
+}
+
+static void ethernet_remove(struct connman_device *device)
+{
+ struct ethernet_data *ethernet = connman_device_get_data(device);
+
+ DBG("device %p", device);
+
+ connman_device_set_data(device, NULL);
+
+ connman_rtnl_remove_watch(ethernet->watch);
+
+ g_free(ethernet);
+}
+
+static int ethernet_enable(struct connman_device *device)
+{
+ struct ethernet_data *ethernet = connman_device_get_data(device);
+
+ DBG("device %p", device);
+
+ return connman_inet_ifup(ethernet->index);
+}
+
+static int ethernet_disable(struct connman_device *device)
+{
+ struct ethernet_data *ethernet = connman_device_get_data(device);
+
+ DBG("device %p", device);
+
+ return connman_inet_ifdown(ethernet->index);
+}
+
+static struct connman_device_driver ethernet_driver = {
+ .name = "ethernet",
+ .type = CONNMAN_DEVICE_TYPE_ETHERNET,
+ .probe = ethernet_probe,
+ .remove = ethernet_remove,
+ .enable = ethernet_enable,
+ .disable = ethernet_disable,
+};
+
+static int ethernet_init(void)
+{
+ return connman_device_driver_register(ðernet_driver);
+}
+
+static void ethernet_exit(void)
+{
+ connman_device_driver_unregister(ðernet_driver);
+}
+
+CONNMAN_PLUGIN_DEFINE(ethernet, "Ethernet interface plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, ethernet_init, ethernet_exit)
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/device.h>
+#include <connman/log.h>
+
+static void create_network(struct connman_device *device, const char *name)
+{
+ struct connman_network *network;
+
+ network = connman_network_create(name, CONNMAN_NETWORK_TYPE_VENDOR);
+ if (network == NULL)
+ return;
+
+ connman_device_add_network(device, network);
+ connman_network_unref(network);
+}
+
+static int device_probe(struct connman_device *device)
+{
+ DBG("");
+
+ return 0;
+}
+
+static void device_remove(struct connman_device *device)
+{
+ DBG("");
+}
+
+static int device_enable(struct connman_device *device)
+{
+ DBG("");
+
+ create_network(device, "network_one");
+ create_network(device, "network_two");
+
+ return 0;
+}
+
+static int device_disable(struct connman_device *device)
+{
+ DBG("");
+
+ return 0;
+}
+
+static struct connman_device_driver device_driver = {
+ .name = "fake",
+ .type = CONNMAN_DEVICE_TYPE_VENDOR,
+ .probe = device_probe,
+ .remove = device_remove,
+ .enable = device_enable,
+ .disable = device_disable,
+};
+
+static void create_device(const char *name)
+{
+ struct connman_device *device;
+
+ device = connman_device_create(name, CONNMAN_DEVICE_TYPE_VENDOR);
+ if (device == NULL)
+ return;
+
+ connman_device_set_mode(device, CONNMAN_DEVICE_MODE_NETWORK_SINGLE);
+
+ connman_device_register(device);
+ connman_device_unref(device);
+}
+
+static int fake_init(void)
+{
+ create_device("fake");
+
+ return connman_device_driver_register(&device_driver);
+}
+
+static void fake_exit(void)
+{
+ connman_device_driver_unregister(&device_driver);
+}
+
+CONNMAN_PLUGIN_DEFINE(fake, "Tesing plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, fake_init, fake_exit)
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <string.h>
+
+#include <glib.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/device.h>
+#include <connman/resolver.h>
+#include <connman/log.h>
+
+#include "modem.h"
+
+struct hso_data {
+ int index;
+ struct modem_data *modem;
+};
+
+static void owandata_callback(const char *buf, void *user_data)
+{
+ //struct hso_data *data = user_data;
+ char *str, ip[16], nm[16], ns1[16], ns2[16], ns3[16], ns4[16], val[20];
+ int err, num;
+
+ str = g_strrstr(buf, "_OWANDATA");
+ if (str == NULL || strstr(buf, "ERROR") != NULL)
+ return;
+
+ err = sscanf(str, "_OWANDATA: %d, %[^,], %[^,], "
+ "%[^,], %[^,], %[^,], %[^,], %s",
+ &num, ip, nm, ns1, ns2, ns3, ns4, val);
+
+ if (err != 8) {
+ DBG("parsed %d arguments", err);
+ return;
+ }
+
+ DBG("ip %s dns %s %s val %s", ip, ns1, ns2, val);
+
+ //connman_resolver_append(data->iface, NULL, ns1);
+ //connman_resolver_append(data->iface, NULL, ns2);
+}
+
+static void owancall_callback(const char *buf, void *user_data)
+{
+ struct hso_data *data = user_data;
+
+ DBG("");
+
+ if (g_strrstr(buf, "_OWANCALL: 1, 3") != NULL) {
+ DBG("%s", buf);
+ //modem_command(modem, owancall_callback, data,
+ // "_OWANCALL", "%d,%d,%d", 1, 1, 1);
+ }
+
+ if (g_strrstr(buf, "_OWANCALL: 1, 1") != NULL) {
+ DBG("%s", buf);
+ modem_command(data->modem, owandata_callback, data,
+ "_OWANDATA", "%d", 1);
+ }
+
+ if (g_strrstr(buf, "\r\nOK\r\n") != NULL) {
+ modem_command(data->modem, owandata_callback, data,
+ "_OWANDATA", "%d", 1);
+ }
+}
+
+static int network_probe(struct connman_network *network)
+{
+ DBG("network %p", network);
+
+ return 0;
+}
+
+static void network_remove(struct connman_network *network)
+{
+ DBG("network %p", network);
+}
+
+static int network_connect(struct connman_network *network)
+{
+ DBG("network %p", network);
+
+ return 0;
+}
+
+static int network_disconnect(struct connman_network *network)
+{
+ DBG("network %p", network);
+
+ return 0;
+}
+
+static struct connman_network_driver network_driver = {
+ .name = "hso-network",
+ .type = CONNMAN_NETWORK_TYPE_HSO,
+ .probe = network_probe,
+ .remove = network_remove,
+ .connect = network_connect,
+ .disconnect = network_disconnect,
+};
+
+static int hso_probe(struct connman_device *device)
+{
+ struct hso_data *data;
+
+ DBG("device %p", device);
+
+ data = g_try_new0(struct hso_data, 1);
+ if (data == NULL)
+ return -ENOMEM;
+
+ data->index = connman_device_get_index(device);
+
+ data->modem = modem_create("/dev/ttyHS0");
+ if (data->modem == NULL) {
+ g_free(data);
+ return -EIO;
+ }
+
+ connman_device_set_data(device, data);
+
+ modem_add_callback(data->modem, "_OWANCALL",
+ owancall_callback, data);
+
+ return 0;
+}
+
+static void hso_remove(struct connman_device *device)
+{
+ struct hso_data *data = connman_device_get_data(device);
+
+ DBG("device %p", device);
+
+ connman_device_set_data(device, NULL);
+
+ modem_destroy(data->modem);
+
+ g_free(data);
+}
+
+static int hso_enable(struct connman_device *device)
+{
+ struct hso_data *data = connman_device_get_data(device);
+ struct connman_network *network;
+ int err;
+
+ DBG("device %p", device);
+
+ err = modem_open(data->modem);
+ if (err < 0)
+ return err;
+
+ connman_device_set_powered(device, TRUE);
+
+ modem_command(data->modem, NULL, NULL, "Z", NULL);
+ modem_command(data->modem, NULL, NULL, "I", NULL);
+
+ modem_command(data->modem, owancall_callback, data,
+ "_OWANCALL", "%d,%d,%d", 1, 1, 1);
+
+ network = connman_network_create("internet", CONNMAN_NETWORK_TYPE_HSO);
+ connman_device_add_network(device, network);
+
+ return 0;
+}
+
+static int hso_disable(struct connman_device *device)
+{
+ struct hso_data *data = connman_device_get_data(device);
+ //const char *iface = connman_device_get_interface(device);
+
+ DBG("device %p", device);
+
+ //connman_resolver_remove_all(iface);
+
+ modem_command(data->modem, owancall_callback, data,
+ "_OWANCALL", "%d,%d,%d", 1, 0, 0);
+
+ connman_device_set_powered(device, FALSE);
+
+ modem_close(data->modem);
+
+ return 0;
+}
+
+static struct connman_device_driver hso_driver = {
+ .name = "hso",
+ .type = CONNMAN_DEVICE_TYPE_HSO,
+ .probe = hso_probe,
+ .remove = hso_remove,
+ .enable = hso_enable,
+ .disable = hso_disable,
+};
+
+static int hso_init(void)
+{
+ int err;
+
+ err = connman_network_driver_register(&network_driver);
+ if (err < 0)
+ return err;
+
+ err = connman_device_driver_register(&hso_driver);
+ if (err < 0) {
+ connman_network_driver_unregister(&network_driver);
+ return err;
+ }
+
+ return 0;
+}
+
+static void hso_exit(void)
+{
+ connman_device_driver_unregister(&hso_driver);
+ connman_network_driver_register(&network_driver);
+}
+
+CONNMAN_PLUGIN_DEFINE(hso, "Option HSO device plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, hso_init, hso_exit)
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/device.h>
+#include <connman/log.h>
+
+#include "modem.h"
+
+static int huawei_probe(struct connman_device *device)
+{
+ DBG("device %p", device);
+
+ return 0;
+}
+
+static void huawei_remove(struct connman_device *device)
+{
+ DBG("device %p", device);
+}
+
+static int huawei_enable(struct connman_device *device)
+{
+ DBG("device %p", device);
+
+ connman_device_set_powered(device, TRUE);
+
+ return 0;
+}
+
+static int huawei_disable(struct connman_device *device)
+{
+ DBG("device %p", device);
+
+ connman_device_set_powered(device, FALSE);
+
+ return 0;
+}
+
+static struct connman_device_driver huawei_driver = {
+ .name = "huawei",
+ .type = CONNMAN_DEVICE_TYPE_HUAWEI,
+ .probe = huawei_probe,
+ .remove = huawei_remove,
+ .enable = huawei_enable,
+ .disable = huawei_disable,
+};
+
+static int huawei_init(void)
+{
+ return connman_device_driver_register(&huawei_driver);
+}
+
+static void huawei_exit(void)
+{
+ connman_device_driver_unregister(&huawei_driver);
+}
+
+CONNMAN_PLUGIN_DEFINE(huawei, "HUAWEI Mobile device plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, huawei_init, huawei_exit)
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/notifier.h>
+#include <connman/dbus.h>
+#include <connman/log.h>
+
+#define IOSPM_SERVICE "com.intel.mid.ospm"
+#define IOSPM_INTERFACE IOSPM_SERVICE ".Comms"
+
+#define IOSPM_BLUETOOTH "/com/intel/mid/ospm/bluetooth"
+#define IOSPM_FLIGHT_MODE "/com/intel/mid/ospm/flight_mode"
+
+static DBusConnection *connection;
+
+static void send_indication(const char *path, connman_bool_t enabled)
+{
+ DBusMessage *message;
+ const char *method;
+
+ DBG("path %s enabled %d", path, enabled);
+
+ if (enabled == TRUE)
+ method = "IndicateStart";
+ else
+ method = "IndicateStop";
+
+ message = dbus_message_new_method_call(IOSPM_SERVICE, path,
+ IOSPM_INTERFACE, method);
+ if (message == NULL)
+ return;
+
+ dbus_message_set_no_reply(message, TRUE);
+
+ dbus_connection_send(connection, message, NULL);
+
+ dbus_message_unref(message);
+}
+
+static void iospm_device_enabled(enum connman_device_type type,
+ connman_bool_t enabled)
+{
+ switch (type) {
+ case CONNMAN_DEVICE_TYPE_UNKNOWN:
+ case CONNMAN_DEVICE_TYPE_VENDOR:
+ case CONNMAN_DEVICE_TYPE_ETHERNET:
+ case CONNMAN_DEVICE_TYPE_WIFI:
+ case CONNMAN_DEVICE_TYPE_WIMAX:
+ case CONNMAN_DEVICE_TYPE_GPS:
+ case CONNMAN_DEVICE_TYPE_HSO:
+ case CONNMAN_DEVICE_TYPE_NOZOMI:
+ case CONNMAN_DEVICE_TYPE_HUAWEI:
+ case CONNMAN_DEVICE_TYPE_NOVATEL:
+ break;
+ case CONNMAN_DEVICE_TYPE_BLUETOOTH:
+ send_indication(IOSPM_BLUETOOTH, enabled);
+ break;
+ }
+}
+
+static void iospm_offline_mode(connman_bool_t enabled)
+{
+ send_indication(IOSPM_FLIGHT_MODE, enabled);
+}
+
+static struct connman_notifier iospm_notifier = {
+ .name = "iospm",
+ .priority = CONNMAN_NOTIFIER_PRIORITY_DEFAULT,
+ .device_enabled = iospm_device_enabled,
+ .offline_mode = iospm_offline_mode,
+};
+
+static int iospm_init(void)
+{
+ connection = connman_dbus_get_connection();
+
+ return connman_notifier_register(&iospm_notifier);
+}
+
+static void iospm_exit(void)
+{
+ connman_notifier_unregister(&iospm_notifier);
+
+ dbus_connection_unref(connection);
+}
+
+CONNMAN_PLUGIN_DEFINE(ospm, "Intel OSPM notification plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, iospm_init, iospm_exit)
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <string.h>
+
+#include <glib.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/device.h>
+#include <connman/inet.h>
+#include <connman/log.h>
+
+#include <WiMaxAPI.h>
+#include <WiMaxAPIEx.h>
+
+#include "iwmx.h"
+
+/*
+ * Connman plugin interface
+ *
+ * This part deals with the connman internals
+ */
+
+/* WiMAX network driver probe/remove, nops */
+static int iwmx_cm_network_probe(struct connman_network *nw)
+{
+ return 0;
+}
+
+static void iwmx_cm_network_remove(struct connman_network *nw)
+{
+}
+
+/*
+ * Called by connman when it wants us to tell the device to connect to
+ * the network @network_el; the device is @network_el->parent.
+ *
+ * We do a synchronous call to start the connection; the logic
+ * attached to the status change callback will update the connman
+ * internals once the change happens.
+ */
+static int iwmx_cm_network_connect(struct connman_network *nw)
+{
+ int result;
+ struct wmxsdk *wmxsdk;
+ const char *station_name = connman_network_get_identifier(nw);
+
+ wmxsdk = connman_device_get_data(connman_network_get_device(nw));
+ result = iwmx_sdk_connect(wmxsdk, nw);
+ DBG("(nw %p [%s] wmxsdk %p) = %d\n", nw, station_name, wmxsdk, result);
+ return result;
+}
+
+/*
+ * Called by connman to have the device @nw->parent
+ * disconnected from @nw.
+ *
+ * We do a synchronous call to start the disconnection; the logic
+ * attached to the status change callback will update the connman
+ * internals once the change happens.
+ */
+static int iwmx_cm_network_disconnect(struct connman_network *nw)
+{
+ int result;
+ struct wmxsdk *wmxsdk;
+ const char *station_name = connman_network_get_identifier(nw);
+
+ wmxsdk = connman_device_get_data(connman_network_get_device(nw));
+ result = iwmx_sdk_disconnect(wmxsdk);
+ DBG("(nw %p [%s] wmxsdk %p) = %d\n", nw, station_name, wmxsdk, result);
+ return 0;
+}
+
+/*
+ * "Driver" for the networks detected by a device.
+ */
+static struct connman_network_driver iwmx_cm_network_driver = {
+ .name = "iwmx",
+ .type = CONNMAN_NETWORK_TYPE_WIMAX,
+ .probe = iwmx_cm_network_probe,
+ .remove = iwmx_cm_network_remove,
+ .connect = iwmx_cm_network_connect,
+ .disconnect = iwmx_cm_network_disconnect,
+};
+
+/*
+ * A (maybe) new network is available, create/update its data
+ *
+ * If the network is new, we create and register a new element; if it
+ * is not, we reuse the one in the list.
+ *
+ * NOTE:
+ * wmxsdk->network_mutex has to be locked
+ */
+struct connman_network *__iwmx_cm_network_available(
+ struct wmxsdk *wmxsdk, const char *station_name,
+ const char *station_type,
+ const void *sdk_nspname, size_t sdk_nspname_size,
+ int strength)
+{
+ struct connman_network *nw = NULL;
+ struct connman_device *dev = wmxsdk->dev;
+ char group[3 * strlen(station_name) + 1];
+ unsigned cnt;
+
+ nw = connman_device_get_network(dev, station_name);
+ if (nw == NULL) {
+ DBG("new network %s", station_name);
+ nw = connman_network_create(station_name,
+ CONNMAN_NETWORK_TYPE_WIMAX);
+ connman_network_set_index(nw, connman_device_get_index(dev));
+ connman_network_set_protocol(nw, CONNMAN_NETWORK_PROTOCOL_IP);
+ connman_network_set_name(nw, station_name);
+ connman_network_set_blob(nw, "WiMAX.NSP.name",
+ sdk_nspname, sdk_nspname_size);
+ /* FIXME: add roaming info? */
+ /* Set the group name -- this has to be a unique
+ * [a-zA-Z0-9_] string common to all the networks that
+ * are actually the same provider. In WiMAX each
+ * network from the CAPI is a single provider, so we
+ * just set this as the network name, encoded in
+ * hex. */
+ for (cnt = 0; station_name[cnt] != 0; cnt++)
+ sprintf(group + 3 * cnt, "%02x", station_name[cnt]);
+ group[3 * cnt + 1] = 0;
+ connman_network_set_group(nw, station_name);
+ if (connman_device_add_network(dev, nw) < 0) {
+ connman_network_unref(nw);
+ goto error_add;
+ }
+ } else
+ DBG("updating network %s nw %p\n", station_name, nw);
+ connman_network_set_available(nw, TRUE);
+ connman_network_set_strength(nw, strength);
+ connman_network_set_string(nw, "WiMAX Network Type", station_type);
+error_add:
+ return nw;
+}
+
+/*
+ * A new network is available [locking version]
+ *
+ * See __iwmx_cm_network_available() for docs
+ */
+struct connman_network *iwmx_cm_network_available(
+ struct wmxsdk *wmxsdk, const char *station_name,
+ const char *station_type,
+ const void *sdk_nspname, size_t sdk_nspname_size,
+ int strength)
+{
+ struct connman_network *nw;
+
+ g_static_mutex_lock(&wmxsdk->network_mutex);
+ nw = __iwmx_cm_network_available(wmxsdk, station_name, station_type,
+ sdk_nspname, sdk_nspname_size,
+ strength);
+ g_static_mutex_unlock(&wmxsdk->network_mutex);
+ return nw;
+}
+
+/*
+ * The device has been enabled, make sure connman knows
+ */
+static void iwmx_cm_dev_enabled(struct wmxsdk *wmxsdk)
+{
+ struct connman_device *dev = wmxsdk->dev;
+ connman_inet_ifup(connman_device_get_index(dev));
+ connman_device_set_powered(dev, TRUE);
+}
+
+/*
+ * The device has been disabled, make sure connman is aware of it.
+ */
+static void iwmx_cm_dev_disabled(struct wmxsdk *wmxsdk)
+{
+ struct connman_device *dev = wmxsdk->dev;
+ connman_inet_ifdown(connman_device_get_index(dev));
+ connman_device_set_powered(dev, FALSE);
+}
+
+/*
+ * The device has been (externally to connman) connnected to a
+ * network, make sure connman knows.
+ *
+ * When the device is connected to a network, this function is called
+ * to change connman's internal state to reflect the fact.
+ *
+ * If the change came from an external entity, that means that our
+ * connect code wasn't called. Our connect code sets
+ * @wmxsdk->connecting_nw to the network we were connecting
+ * to. If it is unset, it means an external entity forced the device
+ * to connect. In that case, we need to find out which network it was
+ * connected to, and create/lookup a @nw for it.
+ *
+ * Once the nw is set, then we are done.
+ */
+static void iwmx_cm_dev_connected(struct wmxsdk *wmxsdk)
+{
+ struct connman_network *nw;
+
+ g_mutex_lock(wmxsdk->connect_mutex);
+ nw = wmxsdk->connecting_nw;
+ if (nw == NULL) {
+ nw = __iwmx_sdk_get_connected_network(wmxsdk);
+ if (nw == NULL) {
+ connman_error("wmxsdk: can't find connected network\n");
+ goto error_nw_find;
+ }
+ }
+ wmxsdk->nw = connman_network_ref(nw);
+ wmxsdk->connecting_nw = NULL;
+ connman_network_set_connected(nw, TRUE);
+ DBG("connected to network %s\n",
+ connman_network_get_identifier(nw));
+error_nw_find:
+ g_mutex_unlock(wmxsdk->connect_mutex);
+}
+
+/*
+ * The device has been (externally to connman) disconnnected, make
+ * sure connman knows
+ *
+ * We need to reverse the steps done in iwmx_cm_dev_connected().
+ * If the event was caused by an external entity and we had no record
+ * of being connected to a network...well, bad luck. We'll just
+ * pretend it happened ok.
+ */
+static void __iwmx_cm_dev_disconnected(struct wmxsdk *wmxsdk)
+{
+ struct connman_network *nw = wmxsdk->nw;
+
+ if (nw != NULL) {
+ DBG("disconnected from network %s\n",
+ connman_network_get_identifier(nw));
+ connman_network_set_connected(nw, FALSE);
+ connman_network_unref(nw);
+ wmxsdk->nw = NULL;
+ } else
+ DBG("disconnected from unknown network\n");
+}
+
+/*
+ * The device has been disconnnected, make sure connman knows
+ *
+ * See __iwmx_cm_dev_disconnect() for more information.
+ */
+static void iwmx_cm_dev_disconnected(struct wmxsdk *wmxsdk)
+{
+ g_mutex_lock(wmxsdk->connect_mutex);
+ __iwmx_cm_dev_disconnected(wmxsdk);
+ g_mutex_unlock(wmxsdk->connect_mutex);
+}
+
+/*
+ * Handle a change in state
+ *
+ * This is were most of the action happens. When the device changes
+ * state, this will catch it (through the state change callback or an
+ * explicit call) and call iwmx_cm_dev_*ed() to indicate to connman what
+ * happened.
+ *
+ * Finally, cache the new device status.
+ */
+void __iwmx_cm_state_change(struct wmxsdk *wmxsdk,
+ WIMAX_API_DEVICE_STATUS __new_status)
+{
+ WIMAX_API_DEVICE_STATUS __old_status = wmxsdk->status;
+ WIMAX_API_DEVICE_STATUS old_status;
+ WIMAX_API_DEVICE_STATUS new_status;
+
+ /*
+ * Simplify state transition computations.
+ *
+ * For practical effects, some states are the same
+ */
+
+ /* Conection_Idle is the same as Data_Connected */
+ if (__old_status == WIMAX_API_DEVICE_STATUS_Connection_Idle)
+ old_status = WIMAX_API_DEVICE_STATUS_Data_Connected;
+ else
+ old_status = __old_status;
+ if (__new_status == WIMAX_API_DEVICE_STATUS_Connection_Idle)
+ new_status = WIMAX_API_DEVICE_STATUS_Data_Connected;
+ else
+ new_status = __new_status;
+
+ /* Radio off: all are just RF_OFF_SW (the highest) */
+ switch (__old_status) {
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW:
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_HW:
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
+ old_status = WIMAX_API_DEVICE_STATUS_RF_OFF_SW;
+ break;
+ default:
+ old_status = __old_status;
+ break;
+ }
+
+ switch (__new_status) {
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW:
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_HW:
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
+ new_status = WIMAX_API_DEVICE_STATUS_RF_OFF_SW;
+ break;
+ default:
+ new_status = __new_status;
+ break;
+ }
+
+ /* If no real state change, do nothing */
+ if (old_status == new_status) {
+ DBG("no state changed\n");
+ return;
+ } else
+ DBG("state change from %d (%d: %s) to %d (%d: %s)\n",
+ old_status, __old_status,
+ iwmx_sdk_dev_status_to_str(__old_status),
+ new_status, __new_status,
+ iwmx_sdk_dev_status_to_str(__new_status));
+
+ /* Cleanup old state */
+ switch (old_status) {
+ case WIMAX_API_DEVICE_STATUS_UnInitialized:
+ /* This means the plugin is starting but the device is
+ * in some state already, so we need to update our
+ * internal knowledge of it. */
+ if (new_status > WIMAX_API_DEVICE_STATUS_RF_OFF_SW)
+ iwmx_cm_dev_enabled(wmxsdk);
+ break;
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
+ /* This means the radio is being turned on, so enable
+ * the device ( unless going to uninitialized). */
+ if (new_status != WIMAX_API_DEVICE_STATUS_RF_OFF_SW)
+ iwmx_cm_dev_enabled(wmxsdk);
+ break;
+ case WIMAX_API_DEVICE_STATUS_Ready:
+ break;
+ case WIMAX_API_DEVICE_STATUS_Scanning:
+ break;
+ case WIMAX_API_DEVICE_STATUS_Connecting:
+ break;
+ case WIMAX_API_DEVICE_STATUS_Data_Connected:
+ iwmx_cm_dev_disconnected(wmxsdk);
+ break;
+ default:
+ connman_error("wmxsdk: unknown old status %d\n", old_status);
+ return;
+ };
+
+ /* Implement new state */
+ switch (new_status) {
+ case WIMAX_API_DEVICE_STATUS_UnInitialized:
+ break;
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
+ /* This means the radio is being turned off, so
+ * disable the device unless coming from uninitialized. */
+ if (old_status != WIMAX_API_DEVICE_STATUS_UnInitialized)
+ iwmx_cm_dev_disabled(wmxsdk);
+ break;
+ case WIMAX_API_DEVICE_STATUS_Ready:
+ break;
+ case WIMAX_API_DEVICE_STATUS_Scanning:
+ break;
+ case WIMAX_API_DEVICE_STATUS_Connecting:
+ break;
+ case WIMAX_API_DEVICE_STATUS_Data_Connected:
+ iwmx_cm_dev_connected(wmxsdk);
+ break;
+ default:
+ connman_error("wmxsdk: unknown new status %d\n", old_status);
+ return;
+ };
+ wmxsdk->status = __new_status;
+}
+
+/*
+ * Implement a device state transition [locking version]
+ *
+ * See __iwmx_cm_state_change()
+ */
+void iwmx_cm_state_change(struct wmxsdk *wmxsdk,
+ WIMAX_API_DEVICE_STATUS __new_status)
+{
+ g_mutex_lock(wmxsdk->status_mutex);
+ __iwmx_cm_state_change(wmxsdk, __new_status);
+ g_mutex_unlock(wmxsdk->status_mutex);
+}
+
+/*
+ * Read the cached device status
+ */
+WIMAX_API_DEVICE_STATUS iwmx_cm_status_get(struct wmxsdk *wmxsdk)
+{
+ WIMAX_API_DEVICE_STATUS status;
+
+ g_mutex_lock(wmxsdk->status_mutex);
+ status = wmxsdk->status;
+ g_mutex_unlock(wmxsdk->status_mutex);
+ return status;
+}
+
+/*
+ * Called by connman when a device is enabled by the user
+ *
+ * We need to turn the radio on; the state change function will poke
+ * the internals.
+ */
+static int iwmx_cm_enable(struct connman_device *dev)
+{
+ int result;
+ struct wmxsdk *wmxsdk = connman_device_get_data(dev);
+
+ connman_inet_ifup(connman_device_get_index(dev));
+ result = iwmx_sdk_rf_state_set(wmxsdk, WIMAX_API_RF_ON);
+ return result;
+}
+
+/*
+ * Called by connman when a device is disabled by the user
+ *
+ * Simple: just make sure the radio is off; the state change function
+ * will poke the internals.
+ */
+static int iwmx_cm_disable(struct connman_device *dev)
+{
+ int result;
+ struct wmxsdk *wmxsdk = connman_device_get_data(dev);
+
+ result = iwmx_sdk_rf_state_set(wmxsdk, WIMAX_API_RF_OFF);
+ connman_inet_ifdown(connman_device_get_index(dev));
+ return 0;
+}
+
+/*
+ * Probe deferred call from when the mainloop is idle
+ *
+ * probe() schedules this to be called from the mainloop when idle to
+ * do a device status evaluation. Needed because of an internal race
+ * condition in connman. FIXME: deploy into _probe() when fixed.
+ */
+static gboolean __iwmx_cm_probe_dpc(gpointer _wmxsdk)
+{
+ int result;
+ struct wmxsdk *wmxsdk = _wmxsdk;
+ result = iwmx_sdk_get_device_status(wmxsdk);
+ if (result < 0)
+ connman_error("wmxsdk: can't get status: %d\n", result);
+ else
+ iwmx_cm_state_change(wmxsdk, result);
+ return FALSE;
+}
+
+/*
+ * Called by connman when a new device pops in
+ *
+ * We allocate our private structure, register with the WiMAX API,
+ * open their device, subscribe to all the callbacks.
+ *
+ * At the end, we launch a deferred call (to work around current
+ * connman issues that need to be fixed in the future) and update the
+ * device's status. This allows us to pick up the current status and
+ * adapt connman's idea of the device to it.
+ */
+static int iwmx_cm_probe(struct connman_device *dev)
+{
+ int result;
+ struct wmxsdk *wmxsdk = NULL;
+
+ wmxsdk = connman_device_get_data(dev);
+ if (wmxsdk == NULL)
+ /* not called from a discovery done by the WiMAX
+ * Network Service, ignore */
+ return -ENODEV;
+
+ result = iwmx_sdk_setup(wmxsdk);
+ if (result < 0)
+ goto error_setup;
+
+ /* There is a race condition in the connman core that doesn't
+ * allow us to call this directly and things to work properly
+ * FIXME FIXME FIXME: merge _dpc call in here when connman is fixed */
+ g_idle_add(__iwmx_cm_probe_dpc, wmxsdk);
+ return 0;
+
+ iwmx_sdk_remove(wmxsdk);
+error_setup:
+ return result;
+}
+
+/*
+ * Called when a device is removed from connman
+ *
+ * Cleanup all that is done in _probe. Remove callbacks, unregister
+ * from the WiMAX API.
+ */
+static void iwmx_cm_remove(struct connman_device *dev)
+{
+ struct wmxsdk *wmxsdk = connman_device_get_data(dev);
+ iwmx_sdk_remove(wmxsdk);
+}
+
+/*
+ * Called by connman to ask the device to scan for networks
+ *
+ * We have set in the WiMAX API the scan result callbacks, so we just
+ * start a simple scan (not a wide one).
+ *
+ * First we obtain the current list of networks and pass it to the
+ * callback processor. Then we start an scan cycle.
+ */
+static int iwmx_cm_scan(struct connman_device *dev)
+{
+ struct wmxsdk *wmxsdk = connman_device_get_data(dev);
+ return iwmx_sdk_scan(wmxsdk);
+}
+
+/*
+ * Driver for a WiMAX API based device.
+ */
+static struct connman_device_driver iwmx_cm_device_driver = {
+ .name = "iwmx",
+ .type = CONNMAN_DEVICE_TYPE_WIMAX,
+ .probe = iwmx_cm_probe,
+ .remove = iwmx_cm_remove,
+ .enable = iwmx_cm_enable,
+ .disable = iwmx_cm_disable,
+ .scan = iwmx_cm_scan,
+};
+
+static int iwmx_cm_init(void)
+{
+ int result;
+
+ result = connman_device_driver_register(&iwmx_cm_device_driver);
+ if (result < 0)
+ goto error_driver_register;
+ result = connman_network_driver_register(&iwmx_cm_network_driver);
+ if (result < 0)
+ goto error_network_driver_register;
+ result = iwmx_sdk_api_init();
+ if (result < 0)
+ goto error_iwmx_sdk_init;
+ return 0;
+
+error_iwmx_sdk_init:
+ connman_network_driver_unregister(&iwmx_cm_network_driver);
+error_network_driver_register:
+ connman_device_driver_unregister(&iwmx_cm_device_driver);
+error_driver_register:
+ return result;
+}
+
+static void iwmx_cm_exit(void)
+{
+ iwmx_sdk_api_exit();
+ connman_network_driver_unregister(&iwmx_cm_network_driver);
+ connman_device_driver_unregister(&iwmx_cm_device_driver);
+}
+
+CONNMAN_PLUGIN_DEFINE(iwmx, "Intel WiMAX SDK / Common API plugin",
+ CONNMAN_VERSION, CONNMAN_PLUGIN_PRIORITY_LOW,
+ iwmx_cm_init, iwmx_cm_exit);
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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
+ *
+ */
+
+/*
+ *
+ * The plugin is broken in two main parts: the glue to connman
+ * (iwmx_cm_*() functions) and the glue to the libiWmxSdk (iwmx_sdk_*()
+ * functions). They connect using a well defined interface.
+ *
+ * The plugin is state based and operates reactively to state
+ * transtitions on the WiMAX device or to user requests, even from
+ * external control tools that are not aware of connman.
+ *
+ * When the user requests connman to do something, it goes into a call
+ * implemented by the 'struct connman_driver iwmx_cm_driver' (or
+ * iwmx_cm_network_driver) that will instruct libiWmxSDK to change the
+ * device's state.
+ *
+ * When the device changes state, a state change callback is sent back
+ * by libiWmxSDK, which gets fed to iwmx_cm_state_change(), which
+ * evaluates the state change and updates connman's internal state in
+ * response.
+ *
+ * This allows the device to be also controlled by external tools
+ * without driving connman out of state.
+ *
+ * Device's state changes can be caused through:
+ *
+ * - connman (by user request)
+ *
+ * - any other external utility (eg: WmxSDK's wimaxcu)
+ *
+ * - external stimuli: network connection broken when going out of
+ * range
+ *
+ * Functions named __*() normally indicate that require locking. See
+ * their doc header.
+ *
+ * ENUMERATION
+ *
+ * When we receive a normal probe request [iwmx_cm_probe()] from
+ * connman, we ignore it (we can tell based on the connman device
+ * having NULL data).
+ *
+ * The plugin has registered with the WiMAX Network Service and it
+ * will listen to its device add/rm messages [iwmx_sdk_addremove_cb()]
+ * and use that to create a device [iwmx_sdk_dev_add()] which will be
+ * registered with connman. [iwmx_cm_dev_add()]. Then connman will
+ * enumerate the device, call again iwmx_cm_probe() and at this time,
+ * we'll recognize it, pass through iwmx_sdk_setup() and complete the
+ * probe process.
+ *
+ * If the daemon dies, in theory the plugin will realize and remove
+ * the WiMAX device.
+ */
+
+struct wmxsdk {
+ struct WIMAX_API_DEVICE_ID device_id;
+ struct connman_device *dev;
+
+ GStaticMutex network_mutex;
+
+ WIMAX_API_DEVICE_STATUS status;
+ GMutex *status_mutex;
+
+ /*
+ * nw points to the network we are connected to. connecting_nw
+ * points to the network we have requested to connect.
+ */
+ GMutex *connect_mutex;
+ struct connman_network *connecting_nw, *nw;
+
+ char name[100];
+ char ifname[16];
+};
+
+/* Initialize a [zeroed] struct wmxsdk */
+static inline void wmxsdk_init(struct wmxsdk *wmxsdk)
+{
+ g_static_mutex_init(&wmxsdk->network_mutex);
+
+ wmxsdk->status = WIMAX_API_DEVICE_STATUS_UnInitialized;
+ wmxsdk->status_mutex = g_mutex_new();
+ g_assert(wmxsdk->status_mutex);
+
+ wmxsdk->connect_mutex = g_mutex_new();
+ g_assert(wmxsdk->connect_mutex);
+}
+
+/* Misc utilities */
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+#define container_of(pointer, type, member) \
+({ \
+ type *object = NULL; \
+ size_t offset = (void *) &object->member - (void *) object; \
+ (type *) ((void *) pointer - offset); \
+})
+
+/* Misc values */
+enum {
+ /**
+ * Time we wait for callbacks: 5s
+ *
+ * I know, it is huge, but L4 and the device sometimes take
+ * some time, especially when there is crypto involved.
+ */
+ IWMX_SDK_L4_TIMEOUT_US = 5 * 1000 * 1000,
+
+ /*
+ * WARNING!!!!!
+ *
+ * ONLY ONE DEVICE SUPPORTED
+ *
+ * - on removal, there is no way to know which device was
+ * removed (the removed device is removed from the list and
+ * the callback doesn't have any more information than the
+ * index in the list that getlistdevice would return -- racy
+ * as hell).
+ *
+ * - on insertion, there is not enough information provided.
+ */
+ IWMX_SDK_DEV_MAX = 1,
+};
+
+struct connman_network *__iwmx_cm_network_available(
+ struct wmxsdk *wmxsdk, const char *station_name,
+ const char *station_type,
+ const void *sdk_nspname, size_t sdk_nspname_size,
+ int strength);
+
+struct connman_network *iwmx_cm_network_available(
+ struct wmxsdk *wmxsdk, const char *station_name,
+ const char *station_type,
+ const void *sdk_nspname, size_t sdk_nspname_size,
+ int strength);
+
+WIMAX_API_DEVICE_STATUS iwmx_cm_status_get(struct wmxsdk *wmxsdk);
+void __iwmx_cm_state_change(struct wmxsdk *wmxsdk,
+ WIMAX_API_DEVICE_STATUS __new_status);
+void iwmx_cm_state_change(struct wmxsdk *wmxsdk,
+ WIMAX_API_DEVICE_STATUS __new_status);
+
+int iwmx_sdk_connect(struct wmxsdk *wmxsdk, struct connman_network *nw);
+int iwmx_sdk_disconnect(struct wmxsdk *wmxsdk);
+struct connman_network *__iwmx_sdk_get_connected_network(struct wmxsdk *wmxsdk);
+const char *iwmx_sdk_dev_status_to_str(WIMAX_API_DEVICE_STATUS status);
+int iwmx_sdk_rf_state_set(struct wmxsdk *wmxsdk, WIMAX_API_RF_STATE rf_state);
+WIMAX_API_DEVICE_STATUS iwmx_sdk_get_device_status(struct wmxsdk *wmxsdk);
+int iwmx_sdk_setup(struct wmxsdk *wmxsdk);
+void iwmx_sdk_remove(struct wmxsdk *wmxsdk);
+int iwmx_sdk_scan(struct wmxsdk *wmxsdk);
+int iwmx_sdk_api_init(void);
+void iwmx_sdk_api_exit(void);
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <string.h>
+#include <net/if.h>
+
+#include <glib.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/device.h>
+#include <connman/inet.h>
+#include <connman/log.h>
+
+#include <WiMaxAPI.h>
+#include <WiMaxAPIEx.h>
+
+#include "iwmx.h"
+
+/* Yes, this is dirty; see above on IWMX_SDK_DEV_MAX*/
+static struct wmxsdk g_iwmx_sdk_devs[IWMX_SDK_DEV_MAX];
+
+static struct wmxsdk *deviceid_to_wmxsdk(struct WIMAX_API_DEVICE_ID *device_id)
+{
+ return container_of(device_id, struct wmxsdk, device_id);
+}
+
+static struct WIMAX_API_DEVICE_ID g_api;
+
+
+/*
+ * FIXME: pulled it it out of some hole
+ *
+ * the cinr to percentage computation comes from the L3/L4 doc
+ *
+ * But some other places (L4 code) have a more complex, seemingly
+ * logarithmical computation.
+ *
+ * Oh well...
+ *
+ */
+static int cinr_to_percentage(int cinr)
+{
+ int strength;
+ if (cinr <= -5)
+ strength = 0;
+ else if (cinr >= 25)
+ strength = 100;
+ else /* Calc percentage on the value from -5 to 25 */
+ strength = ((100UL * (cinr - -5)) / (25 - -5));
+ return strength;
+}
+
+/*
+ * Convert a WiMAX API status to an string.
+ */
+const char *iwmx_sdk_dev_status_to_str(WIMAX_API_DEVICE_STATUS status)
+{
+ switch (status) {
+ case WIMAX_API_DEVICE_STATUS_UnInitialized:
+ return "Uninitialized";
+ break;
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW:
+ return "Device RF Off(both H/W and S/W)";
+ break;
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_HW:
+ return "Device RF Off(via H/W switch)";
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
+ return "Device RF Off(via S/W switch)";
+ case WIMAX_API_DEVICE_STATUS_Ready:
+ return "Device is ready";
+ case WIMAX_API_DEVICE_STATUS_Scanning:
+ return "Device is scanning";
+ case WIMAX_API_DEVICE_STATUS_Connecting:
+ return "Connection in progress";
+ case WIMAX_API_DEVICE_STATUS_Data_Connected:
+ return "Layer 2 connected";
+ case WIMAX_API_DEVICE_STATUS_Connection_Idle:
+ return "Idle connection";
+ default:
+ return "unknown state";
+ }
+}
+
+/*
+ * Get the device's status from the device
+ *
+ * Does NOT cache the result
+ * Does NOT trigger a state change in connman
+ *
+ * Returns < 0 errno code on error, status code if ok.
+ */
+WIMAX_API_DEVICE_STATUS iwmx_sdk_get_device_status(struct wmxsdk *wmxsdk)
+{
+ WIMAX_API_RET r;
+ char errstr[512];
+ UINT32 errstr_size = sizeof(errstr);
+
+ WIMAX_API_DEVICE_STATUS dev_status;
+ WIMAX_API_CONNECTION_PROGRESS_INFO pi;
+
+ r = GetDeviceStatus(&wmxsdk->device_id, &dev_status, &pi);
+ if (r != WIMAX_API_RET_SUCCESS) {
+ GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+ connman_error("wmxsdk: Cannot read device state: %d (%s)\n",
+ r, errstr);
+ dev_status = -EIO;
+ }
+ return dev_status;
+}
+
+/*
+ * Get the device's status from the device but return a string describing it
+ *
+ * Same conditions as iwmx_sdk_get_device_status().
+ */
+static const char *iwmx_sdk_get_device_status_str(struct wmxsdk *wmxsdk)
+{
+ const char *result;
+ WIMAX_API_DEVICE_STATUS dev_status;
+
+ dev_status = iwmx_sdk_get_device_status(wmxsdk);
+ if ((int) dev_status < 0)
+ result = "cannot read device state";
+ else
+ result = iwmx_sdk_dev_status_to_str(dev_status);
+ return result;
+}
+
+/*
+ * Translate a WiMAX network type to a readable name.
+ */
+static const char *iwmx_sdk_network_type_name(enum _WIMAX_API_NETWORK_TYPE network_type)
+{
+ static char *network_type_name[] = {
+ [WIMAX_API_HOME] = "",
+ [WIMAX_API_PARTNER] = " (partner network)",
+ [WIMAX_API_ROAMING_PARTNER] = " (roaming partner network)",
+ [WIMAX_API_UNKNOWN] = " (unknown network)",
+ };
+ if (network_type > WIMAX_API_UNKNOWN)
+ return "(BUG! UNKNOWN NETWORK_TYPE MODE)";
+ else
+ return network_type_name[network_type];
+}
+
+/*
+ * If the device is connected but we don't know about the network,
+ * create the knowledge of it.
+ *
+ * Asks the WiMAX API to report which NSP we are connected to and we
+ * create/update a network_el in the device's network list. Then
+ * return it.
+ *
+ * Returns NULL on error.
+ *
+ * NOTE: wmxsdk->network_mutex has to be taken
+ */
+struct connman_network *__iwmx_sdk_get_connected_network(struct wmxsdk *wmxsdk)
+{
+ struct connman_network *nw;
+
+ struct WIMAX_API_CONNECTED_NSP_INFO nsp_info;
+ WIMAX_API_RET r;
+ char errstr[512];
+ UINT32 errstr_size = sizeof(errstr);
+
+ /* The device is getting connected due to an external (to
+ * connman) event; find which is the nw we are getting
+ * connected to. if we don't have it, add it */
+ r = GetConnectedNSP(&wmxsdk->device_id, &nsp_info);
+ if (r != WIMAX_API_RET_SUCCESS) {
+ GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+ connman_error(
+ "wmxsdk: Cannot get connected NSP info: %d (%s)\n",
+ r, errstr);
+ strcpy((char *) nsp_info.NSPName, "unknown");
+ nw = iwmx_cm_network_available(
+ wmxsdk, "unknown",
+ iwmx_sdk_network_type_name(WIMAX_API_UNKNOWN),
+ nsp_info.NSPName, strlen((char *) nsp_info.NSPName) + 1,
+ cinr_to_percentage(nsp_info.CINR - 10));
+ } else {
+ nw = iwmx_cm_network_available(
+ wmxsdk, (char *) nsp_info.NSPName,
+ iwmx_sdk_network_type_name(nsp_info.networkType),
+ nsp_info.NSPName, strlen((char *) nsp_info.NSPName) + 1,
+ cinr_to_percentage(nsp_info.CINR - 10));
+ }
+ return nw;
+}
+
+/*
+ * Callback for a RF State command
+ *
+ * Called by the WiMAX API when a command sent to change the RF state
+ * is completed. This is just a confirmation of what happened with the
+ * command.
+ *
+ * We don't do anything, as when the device changes state, the state
+ * change callback is called and that will fiddle with the connman
+ * internals.
+ */
+static void __iwmx_sdk_rf_state_cb(struct WIMAX_API_DEVICE_ID *device_id,
+ WIMAX_API_RF_STATE rf_state)
+{
+ DBG("rf_state changed to %d\n", rf_state);
+}
+
+/*
+ * Turn the radio on or off
+ *
+ * First it checks that we are in the right state before doing
+ * anything; there might be no need to do anything.
+ *
+ * Issue a command to the WiMAX API, wait for a callback confirming it
+ * is done. Sometimes the callback is missed -- in that case, do force
+ * a state change evaluation.
+ *
+ * Frustration note:
+ *
+ * Geezoos efing Xist, they make difficult even the most simple
+ * of the operations
+ *
+ * This thing is definitely a pain. If the radio is ON already
+ * and you switch it on again...well, there is no way to tell
+ * because you don't get a callback saying it basically
+ * suceeded. But on the other hand, if the thing was in a
+ * different state and action needs to be taken, you have to wait
+ * for a callback to confirm it's done. However, there is also an
+ * state change callback, which is almost the same, so now you
+ * have to handle things in two "unrelated" threads of execution.
+ *
+ * How the shpx are you expected to tell the difference? Check
+ * status first? On timeout? Nice gap (eighteen wheeler size) for
+ * race conditions.
+ */
+int iwmx_sdk_rf_state_set(struct wmxsdk *wmxsdk, WIMAX_API_RF_STATE rf_state)
+{
+ int result;
+
+ WIMAX_API_RET r;
+ char errstr[512];
+ UINT32 errstr_size = sizeof(errstr);
+ WIMAX_API_DEVICE_STATUS dev_status;
+
+ g_assert(rf_state == WIMAX_API_RF_ON || rf_state == WIMAX_API_RF_OFF);
+
+ /* Guess what the current radio state is; if it is ON
+ * already, don't redo it. */
+ dev_status = iwmx_sdk_get_device_status(wmxsdk);
+ if ((int) dev_status < 0) {
+ result = dev_status;
+ goto error_get_status;
+ }
+ switch (dev_status) {
+ case WIMAX_API_DEVICE_STATUS_UnInitialized:
+ result = -EINVAL;
+ goto error_cant_do;
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW:
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_HW:
+ connman_error(
+ "wmxsdk: cannot turn on radio: hw switch is off\n");
+ result = -EPERM;
+ goto error_cant_do;
+ break;
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
+ if (rf_state == WIMAX_API_RF_OFF) {
+ result = 0;
+ DBG("radio is already off\n");
+ goto out_done;
+ }
+ break;
+ case WIMAX_API_DEVICE_STATUS_Ready:
+ case WIMAX_API_DEVICE_STATUS_Scanning:
+ case WIMAX_API_DEVICE_STATUS_Connecting:
+ case WIMAX_API_DEVICE_STATUS_Data_Connected:
+ case WIMAX_API_DEVICE_STATUS_Connection_Idle:
+ if (rf_state == WIMAX_API_RF_ON) {
+ result = 0;
+ DBG("radio is already on\n");
+ goto out_done;
+ }
+ break;
+ default:
+ g_assert(1);
+ }
+ /* Ok, flip the radio */
+ r = CmdControlPowerManagement(&wmxsdk->device_id, rf_state);
+ if (r != WIMAX_API_RET_SUCCESS) {
+ GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+ connman_error("wmxsdk: Cannot flip radio to %d: %d (%s) "
+ "[device is in state %s]\n",
+ rf_state, r, errstr,
+ iwmx_sdk_get_device_status_str(wmxsdk));
+ result = -EIO;
+ } else
+ result = -EINPROGRESS;
+out_done:
+error_cant_do:
+error_get_status:
+ return result;
+}
+
+/*
+ * Callback for a Connect command
+ *
+ * Called by the WiMAX API when a command sent to connect is
+ * completed. This is just a confirmation of what happened with the
+ * command.
+ *
+ * WE DON'T DO MUCH HERE -- the real meat happens when a state change
+ * callback is sent, where we detect we move to connected state (or
+ * from disconnecting to something else); the state change callback is
+ * called and that will fiddle with the connman internals.
+ */
+static void __iwmx_sdk_connect_cb(struct WIMAX_API_DEVICE_ID *device_id,
+ WIMAX_API_NETWORK_CONNECTION_RESP resp)
+{
+ WIMAX_API_DEVICE_STATUS status;
+ struct wmxsdk *wmxsdk = deviceid_to_wmxsdk(device_id);
+
+ status = iwmx_cm_status_get(wmxsdk);
+ if (resp == WIMAX_API_CONNECTION_SUCCESS) {
+ if (status != WIMAX_API_DEVICE_STATUS_Data_Connected
+ && status != WIMAX_API_DEVICE_STATUS_Connection_Idle)
+ connman_error("wmxsdk: error: connect worked, but state"
+ " didn't change (now it is %d [%s])\n",
+ status,
+ iwmx_sdk_dev_status_to_str(status));
+ } else
+ connman_error("wmxsdk: failed to connect (status %d: %s)\n",
+ status, iwmx_sdk_dev_status_to_str(status));
+}
+
+/*
+ * Connect to a network
+ *
+ * This function starts the connection process to a given network;
+ * when the device changes status, the status change callback will
+ * tell connman if the network is finally connected or not.
+ *
+ * One of the reasons it is done like that is to allow external tools
+ * to control the device and the plugin just passing the status so
+ * connman displays the right info.
+ */
+int iwmx_sdk_connect(struct wmxsdk *wmxsdk, struct connman_network *nw)
+{
+ int result;
+
+ WIMAX_API_RET r;
+ char errstr[512];
+ UINT32 errstr_size = sizeof(errstr);
+ WIMAX_API_DEVICE_STATUS dev_status;
+ const char *station_name = connman_network_get_identifier(nw);
+ const void *sdk_nspname;
+ unsigned int sdk_nspname_size;
+
+ g_mutex_lock(wmxsdk->connect_mutex);
+ /* Guess what the current radio state is; if it is ON
+ * already, don't redo it. */
+ dev_status = iwmx_cm_status_get(wmxsdk);
+ if ((int) dev_status < 0) {
+ result = dev_status;
+ goto error_get_status;
+ }
+ switch (dev_status) {
+ case WIMAX_API_DEVICE_STATUS_UnInitialized:
+ connman_error("wmxsdk: SW BUG? HW is uninitialized\n");
+ result = -EINVAL;
+ goto error_cant_do;
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW:
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_HW:
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
+ connman_error("wmxsdk: Cannot connect: radio is off\n");
+ result = -EPERM;
+ goto error_cant_do;
+ case WIMAX_API_DEVICE_STATUS_Ready:
+ case WIMAX_API_DEVICE_STATUS_Scanning:
+ break;
+ case WIMAX_API_DEVICE_STATUS_Connecting:
+ DBG("Connect already pending, waiting for it\n");
+ result = -EINPROGRESS;
+ goto error_cant_do;
+ case WIMAX_API_DEVICE_STATUS_Data_Connected:
+ case WIMAX_API_DEVICE_STATUS_Connection_Idle:
+ connman_error("wmxsdk: BUG? need to disconnect?\n");
+ result = -EINVAL;
+ goto error_cant_do;
+ default:
+ g_assert(1);
+ }
+
+ /* Ok, do the connection, wait for a callback */
+ wmxsdk->connecting_nw = connman_network_ref(nw);
+ sdk_nspname = connman_network_get_blob(nw, "WiMAX.NSP.name",
+ &sdk_nspname_size);
+ g_assert(sdk_nspname != NULL);
+ r = CmdConnectToNetwork(&wmxsdk->device_id, (void *) sdk_nspname, 0, 0);
+ if (r != WIMAX_API_RET_SUCCESS) {
+ GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+ connman_error("wmxsdk: Cannot connect to network %s: %d (%s)"
+ " - device is in state '%s'\n",
+ station_name, r, errstr,
+ iwmx_sdk_get_device_status_str(wmxsdk));
+ result = -EIO;
+ connman_network_unref(nw);
+ wmxsdk->connecting_nw = NULL;
+ } else
+ result = -EINPROGRESS;
+error_cant_do:
+error_get_status:
+ g_mutex_unlock(wmxsdk->connect_mutex);
+ return result;
+}
+
+/*
+ * Callback for a Disconnect command
+ *
+ * Called by the WiMAX API when a command sent to connect is
+ * completed. This is just a confirmation of what happened with the
+ * command.
+ *
+ * When the device changes state, the state change callback is called
+ * and that will fiddle with the connman internals.
+ *
+ * We just update the result of the command and wake up anybody who is
+ * waiting for this conditional variable.
+ */
+static void __iwmx_sdk_disconnect_cb(struct WIMAX_API_DEVICE_ID *device_id,
+ WIMAX_API_NETWORK_CONNECTION_RESP resp)
+{
+ struct wmxsdk *wmxsdk = deviceid_to_wmxsdk(device_id);
+ WIMAX_API_DEVICE_STATUS status;
+
+ status = iwmx_cm_status_get(wmxsdk);
+ if (resp == WIMAX_API_CONNECTION_SUCCESS) {
+ if (status == WIMAX_API_DEVICE_STATUS_Data_Connected
+ || status == WIMAX_API_DEVICE_STATUS_Connection_Idle)
+ connman_error("wmxsdk: error: disconnect worked, "
+ "but state didn't change (now it is "
+ "%d [%s])\n", status,
+ iwmx_sdk_dev_status_to_str(status));
+ } else
+ connman_error("wmxsdk: failed to disconnect (status %d: %s)\n",
+ status, iwmx_sdk_dev_status_to_str(status));
+}
+
+/*
+ * Disconnect from a network
+ *
+ * This function tells the device to disconnect; the state change
+ * callback will take care of inform connman's internals.
+ */
+int iwmx_sdk_disconnect(struct wmxsdk *wmxsdk)
+{
+ int result;
+
+ WIMAX_API_RET r;
+ char errstr[512];
+ UINT32 errstr_size = sizeof(errstr);
+ WIMAX_API_DEVICE_STATUS dev_status;
+
+ g_mutex_lock(wmxsdk->connect_mutex);
+ /* Guess what the current radio state is; if it is ON
+ * already, don't redo it. */
+ dev_status = iwmx_sdk_get_device_status(wmxsdk);
+ if ((int) dev_status < 0) {
+ result = dev_status;
+ goto error_get_status;
+ }
+ switch (dev_status) {
+ case WIMAX_API_DEVICE_STATUS_UnInitialized:
+ connman_error("wmxsdk: SW BUG? HW is uninitialized\n");
+ result = -EINVAL;
+ goto error_cant_do;
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW:
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_HW:
+ case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
+ DBG("Cannot disconnect, radio is off; ignoring\n");
+ result = 0;
+ goto error_cant_do;
+ case WIMAX_API_DEVICE_STATUS_Ready:
+ case WIMAX_API_DEVICE_STATUS_Scanning:
+ DBG("Cannot disconnect, already disconnected; ignoring\n");
+ result = 0;
+ goto error_cant_do;
+ case WIMAX_API_DEVICE_STATUS_Connecting:
+ case WIMAX_API_DEVICE_STATUS_Data_Connected:
+ case WIMAX_API_DEVICE_STATUS_Connection_Idle:
+ break;
+ default:
+ g_assert(1);
+ }
+ /* Ok, flip the radio */
+ r = CmdDisconnectFromNetwork(&wmxsdk->device_id);
+ if (r != WIMAX_API_RET_SUCCESS) {
+ GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+ connman_error("wmxsdk: Cannot disconnect from network: "
+ "%d (%s)\n", r, errstr);
+ result = -EIO;
+ } else
+ result = -EINPROGRESS;
+error_cant_do:
+error_get_status:
+ g_mutex_unlock(wmxsdk->connect_mutex);
+ return result;
+}
+
+/*
+ * Callback for state change messages
+ *
+ * Just pass them to the state transition handler
+ */
+static void __iwmx_sdk_state_change_cb(struct WIMAX_API_DEVICE_ID *device_id,
+ WIMAX_API_DEVICE_STATUS status,
+ WIMAX_API_STATUS_REASON reason,
+ WIMAX_API_CONNECTION_PROGRESS_INFO pi)
+{
+ struct wmxsdk *wmxsdk = deviceid_to_wmxsdk(device_id);
+ iwmx_cm_state_change(wmxsdk, status);
+}
+
+/*
+ * Called by _iwmx_sdk_*scan_cb() when [wide or preferred] scan results
+ * are available.
+ *
+ * From here we update the connman core idea of which networks are
+ * available.
+ */
+static void __iwmx_sdk_scan_common_cb(struct WIMAX_API_DEVICE_ID *device_id,
+ struct WIMAX_API_NSP_INFO_EX *nsp_list,
+ UINT32 nsp_list_size)
+{
+ struct wmxsdk *wmxsdk = deviceid_to_wmxsdk(device_id);
+ unsigned itr;
+ char station_name[256];
+
+ g_static_mutex_lock(&wmxsdk->network_mutex);
+ for (itr = 0; itr < nsp_list_size; itr++) {
+ int strength;
+ struct WIMAX_API_NSP_INFO_EX *nsp_info = &nsp_list[itr];
+ snprintf(station_name, sizeof(station_name),
+ "%s", (char *)nsp_info->NSPName);
+ /* CAPI is reporing link quality as zero -- if it is
+ * zero, check if it is a bug by computing it based on
+ * CINR. If it is different, use the computed one. */
+ strength = nsp_info->linkQuality;
+ if (strength == 0) { /* huh */
+ int linkq_expected =
+ cinr_to_percentage(nsp_info->CINR - 10);
+ if (linkq_expected != strength)
+ strength = linkq_expected;
+ }
+
+ __iwmx_cm_network_available(
+ wmxsdk, station_name,
+ iwmx_sdk_network_type_name(nsp_info->networkType),
+ nsp_info->NSPName,
+ strlen((char *) nsp_info->NSPName) + 1,
+ strength);
+ }
+ g_static_mutex_unlock(&wmxsdk->network_mutex);
+}
+
+/*
+ * Called by the WiMAX API when we get a wide scan result
+ *
+ * We treat them same as wide, so we just call that.
+ */
+static void __iwmx_sdk_wide_scan_cb(struct WIMAX_API_DEVICE_ID *device_id,
+ struct WIMAX_API_NSP_INFO_EX *nsp_list,
+ UINT32 nsp_list_size)
+{
+ __iwmx_sdk_scan_common_cb(device_id, nsp_list, nsp_list_size);
+}
+
+/*
+ * Called by the WiMAX API when we get a normal (non wide) scan result
+ *
+ * We treat them same as wide, so we just call that.
+ */
+static void __iwmx_sdk_scan_cb(struct WIMAX_API_DEVICE_ID *device_id,
+ struct WIMAX_API_NSP_INFO_EX *nsp_list,
+ UINT32 nsp_list_size, UINT32 searchProgress)
+{
+ __iwmx_sdk_scan_common_cb(device_id, nsp_list, nsp_list_size);
+}
+
+/*
+ * Called to ask the device to scan for networks
+ *
+ * We don't really scan as the WiMAX SDK daemon scans in the
+ * background for us. We just get the results. See iwmx_sdk_setup().
+ */
+int iwmx_sdk_scan(struct wmxsdk *wmxsdk)
+{
+ int result;
+
+ UINT32 nsp_list_length = 10;
+ struct WIMAX_API_NSP_INFO_EX nsp_list[10]; /* FIXME: up to 32? */
+
+ WIMAX_API_RET r;
+ char errstr[512];
+ UINT32 errstr_size = sizeof(errstr);
+
+ r = GetNetworkListEx(&wmxsdk->device_id, nsp_list, &nsp_list_length);
+ if (r != WIMAX_API_RET_SUCCESS) {
+ GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+ connman_error("wmxsdk: Cannot get network list: %d (%s)\n",
+ r, errstr);
+ result = -EIO;
+ goto error_scan;
+ }
+
+ if (nsp_list_length == 0)
+ DBG("no networks\n");
+ else
+ __iwmx_sdk_scan_common_cb(&wmxsdk->device_id, nsp_list,
+ nsp_list_length);
+ result = 0;
+error_scan:
+ return result;
+}
+
+/*
+ * Initialize the WiMAX API, register with it, setup callbacks
+ *
+ * Called through
+ *
+ * iwmx_sdk_dev_add
+ * connman_inet_create_device
+ * connman_register
+ * iwmx_cm_probe()
+ */
+int iwmx_sdk_setup(struct wmxsdk *wmxsdk)
+{
+ int result;
+
+ WIMAX_API_RET r;
+
+ char errstr[512];
+ UINT32 errstr_size = sizeof(errstr);
+
+ result = -ENFILE;
+
+ /* device_id initialized by iwmx_sdk_dev_add */
+
+ r = WiMaxDeviceOpen(&wmxsdk->device_id);
+ if (r != WIMAX_API_RET_SUCCESS) {
+ GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+ connman_error("wmxsdk: Cannot open device: %d (%s)\n",
+ r, errstr);
+ goto error_wimaxdeviceopen;
+ }
+
+ /*
+ * We scan in auto mode (in the background)
+ *
+ * Otherwise is messy -- if we have connman triggering a scan
+ * when we call iwmx_cm_scan() -> iwmx_sdk_scan(), most of the
+ * times that causes a race condition when the UI asks for a
+ * scan right before displaying the network menu. As there is
+ * no way to cancel an ongoing scan before connecting, we are
+ * stuck. So we do auto bg and have iwmx_sdk_scan() just return
+ * the current network list.
+ */
+ r = SetConnectionMode(&wmxsdk->device_id,
+ WIMAX_API_CONNECTION_AUTO_SCAN_MANUAL_CONNECT);
+ if (r != WIMAX_API_RET_SUCCESS) {
+ GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+ connman_error("wmxsdk: Cannot set connectin mode to manual: "
+ "%d (%s)\n", r, errstr);
+ goto error_connection_mode;
+ }
+
+ r = SubscribeControlPowerManagement(&wmxsdk->device_id,
+ __iwmx_sdk_rf_state_cb);
+ if (r != WIMAX_API_RET_SUCCESS) {
+ GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+ connman_error("wmxsdk: Cannot subscribe to radio change "
+ "events: %u (%s)\n", r, errstr);
+ result = -EIO;
+ goto error_subscribe_rf_state;
+ }
+
+ r = SubscribeDeviceStatusChange(&wmxsdk->device_id,
+ __iwmx_sdk_state_change_cb);
+ if (r != WIMAX_API_RET_SUCCESS) {
+ GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+ connman_error("wmxsdk: Cannot subscribe to state chaneg events:"
+ "%d (%s)\n", r, errstr);
+ goto error_subscribe_state_change;
+ }
+
+ r = SubscribeNetworkSearchWideScanEx(&wmxsdk->device_id,
+ __iwmx_sdk_wide_scan_cb);
+ if (r != WIMAX_API_RET_SUCCESS) {
+ GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+ connman_error("wmxsdk: Cannot subscribe to wide scan events: "
+ "%d (%s)\n", r, errstr);
+ goto error_subscribe_wide_scan;
+ }
+ r = SubscribeNetworkSearchEx(&wmxsdk->device_id, __iwmx_sdk_scan_cb);
+ if (r != WIMAX_API_RET_SUCCESS) {
+ GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+ connman_error("wmxsdk: Cannot subscribe to scan events: "
+ "%d (%s)\n", r, errstr);
+ goto error_subscribe_scan;
+ }
+
+ r = SubscribeConnectToNetwork(&wmxsdk->device_id,
+ __iwmx_sdk_connect_cb);
+ if (r != WIMAX_API_RET_SUCCESS) {
+ GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+ connman_error("wmxsdk: Cannot subscribe to connect events: "
+ "%d (%s)\n", r, errstr);
+ goto error_subscribe_connect;
+ }
+
+ r = SubscribeDisconnectToNetwork(&wmxsdk->device_id,
+ __iwmx_sdk_disconnect_cb);
+ if (r != WIMAX_API_RET_SUCCESS) {
+ GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
+ connman_error("wmxsdk: Cannot subscribe to disconnect events: "
+ "%d (%s)\n", r, errstr);
+ goto error_subscribe_disconnect;
+ }
+ result = 0;
+out:
+ return result;
+
+ UnsubscribeDisconnectToNetwork(&wmxsdk->device_id);
+error_subscribe_disconnect:
+ UnsubscribeConnectToNetwork(&wmxsdk->device_id);
+error_subscribe_connect:
+ UnsubscribeNetworkSearchEx(&wmxsdk->device_id);
+error_subscribe_scan:
+ UnsubscribeNetworkSearchWideScanEx(&wmxsdk->device_id);
+error_subscribe_wide_scan:
+ UnsubscribeDeviceStatusChange(&wmxsdk->device_id);
+error_subscribe_state_change:
+ UnsubscribeControlPowerManagement(&wmxsdk->device_id);
+error_subscribe_rf_state:
+error_connection_mode:
+ WiMaxDeviceClose(&wmxsdk->device_id);
+error_wimaxdeviceopen:
+ goto out;
+}
+
+/*
+ * Called when a device is removed from connman
+ *
+ * Cleanup all that is done in iwmx_sdk_setup(). Remove callbacks,
+ * unregister from the WiMAX API.
+ */
+void iwmx_sdk_remove(struct wmxsdk *wmxsdk)
+{
+ UnsubscribeDisconnectToNetwork(&wmxsdk->device_id);
+ UnsubscribeConnectToNetwork(&wmxsdk->device_id);
+ UnsubscribeNetworkSearchEx(&wmxsdk->device_id);
+ UnsubscribeNetworkSearchWideScanEx(&wmxsdk->device_id);
+ UnsubscribeDeviceStatusChange(&wmxsdk->device_id);
+ UnsubscribeControlPowerManagement(&wmxsdk->device_id);
+ WiMaxDeviceClose(&wmxsdk->device_id);
+}
+
+static void iwmx_sdk_dev_add(unsigned idx, unsigned api_idx, const char *name)
+{
+ int result, ifindex;
+ struct wmxsdk *wmxsdk;
+ const char *s;
+
+ if (idx >= IWMX_SDK_DEV_MAX) {
+ connman_error("BUG! idx (%u) >= IWMX_SDK_DEV_MAX (%u)\n",
+ idx, IWMX_SDK_DEV_MAX);
+ goto error_bug;
+ }
+ wmxsdk = &g_iwmx_sdk_devs[idx];
+ if (wmxsdk->dev != NULL) {
+ connman_error("BUG! device index %u already enumerated?\n",
+ idx);
+ goto error_bug;
+ }
+
+ memset(wmxsdk, 0, sizeof(*wmxsdk));
+ wmxsdk_init(wmxsdk);
+ /*
+ * This depends on a hack in the WiMAX Network Service; it has
+ * to return, as part of the device name, a string "if:IFNAME"
+ * where the OS's device name is stored.
+ */
+ s = strstr(name, "if:");
+ if (s == NULL
+ || sscanf(s, "if:%15[^ \f\n\r\t\v]", wmxsdk->ifname) != 1) {
+ connman_error("Cannot extract network interface name off '%s'",
+ name);
+ goto error_noifname;
+ }
+ DBG("network interface name: '%s'", wmxsdk->ifname);
+
+ ifindex = if_nametoindex(wmxsdk->ifname);
+ if (ifindex <= 0) {
+ result = -ENFILE;
+ connman_error("wxmsdk: %s: cannot find interface index\n",
+ wmxsdk->ifname);
+ goto error_noifname;
+ }
+
+ wmxsdk->dev = connman_inet_create_device(ifindex);
+ if (wmxsdk->dev == NULL) {
+ connman_error("wmxsdk: %s: failed to create connman_device\n",
+ name);
+ goto error_create;
+ }
+ strncpy(wmxsdk->name, name, sizeof(wmxsdk->name));
+ connman_device_set_data(wmxsdk->dev, wmxsdk);
+
+ wmxsdk->device_id.privilege = WIMAX_API_PRIVILEGE_READ_WRITE;
+ wmxsdk->device_id.deviceIndex = api_idx;
+
+ result = connman_device_register(wmxsdk->dev);
+ if (result < 0) {
+ connman_error("wmxsdk: %s: failed to register: %d\n",
+ wmxsdk->ifname, result);
+ goto error_dev_add;
+ }
+ return;
+
+error_dev_add:
+ wmxsdk->name[0] = 0;
+ connman_device_unref(wmxsdk->dev);
+ wmxsdk->dev = NULL;
+error_noifname:
+error_create:
+error_bug:
+ return;
+}
+
+static void iwmx_sdk_dev_rm(unsigned idx)
+{
+ struct wmxsdk *wmxsdk;
+
+ if (idx >= IWMX_SDK_DEV_MAX) {
+ connman_error("BUG! idx (%u) >= IWMX_SDK_DEV_MAX (%u)\n",
+ idx, IWMX_SDK_DEV_MAX);
+ goto error_bug;
+ }
+ wmxsdk = &g_iwmx_sdk_devs[idx];
+ if (wmxsdk->dev == NULL) {
+ DBG("device index %u not enumerated? ignoring\n", idx);
+ goto error_bug;
+ }
+
+ connman_device_unregister(wmxsdk->dev);
+ wmxsdk->name[0] = 0;
+ connman_device_unref(wmxsdk->dev);
+ memset(wmxsdk, 0, sizeof(*wmxsdk));
+error_bug:
+ return;
+}
+
+static void iwmx_sdk_addremove_cb(struct WIMAX_API_DEVICE_ID *devid,
+ BOOL presence)
+{
+ unsigned int cnt;
+ WIMAX_API_RET r;
+ struct WIMAX_API_HW_DEVICE_ID device_id_list[5];
+ UINT32 device_id_list_size = ARRAY_SIZE(device_id_list);
+
+ char errstr[512];
+ UINT32 errstr_size = sizeof(errstr);
+
+ DBG("cb: handle %u index #%u is %d\n", devid->sdkHandle,
+ devid->deviceIndex, presence);
+
+ r = GetListDevice(devid, device_id_list, &device_id_list_size);
+ if (r != WIMAX_API_RET_SUCCESS) {
+ GetErrorString(devid, r, errstr, &errstr_size);
+ connman_error("wmxsdk: Cannot obtain list "
+ "of devices: %d (%s)\n", r, errstr);
+ return;
+ }
+
+ if (device_id_list_size == 0)
+ DBG("No WiMAX devices reported\n");
+ else
+ for (cnt = 0; cnt < device_id_list_size; cnt++) {
+ struct WIMAX_API_HW_DEVICE_ID *dev =
+ device_id_list + cnt;
+ DBG("#%u index #%u device %s\n",
+ cnt, dev->deviceIndex, dev->deviceName);
+ }
+ if (device_id_list_size < devid->deviceIndex) {
+ connman_error("wmxsdk: changed device (%u) not in the list? "
+ "(%u items)\n",
+ devid->deviceIndex, device_id_list_size);
+ return;
+ }
+
+ if (presence) {
+ struct WIMAX_API_HW_DEVICE_ID *dev =
+ device_id_list + devid->deviceIndex;
+ iwmx_sdk_dev_add(devid->deviceIndex, dev->deviceIndex,
+ dev->deviceName);
+ } else {
+ iwmx_sdk_dev_rm(devid->deviceIndex);
+ }
+}
+
+/*
+ * Initialize the WiMAX API, register with it, setup callbacks for
+ * device coming up / dissapearing
+ */
+int iwmx_sdk_api_init(void)
+{
+ int result;
+ unsigned int cnt;
+ WIMAX_API_RET r;
+ char errstr[512];
+ UINT32 errstr_size = sizeof(errstr);
+
+ struct WIMAX_API_HW_DEVICE_ID device_id_list[5];
+ UINT32 device_id_list_size = ARRAY_SIZE(device_id_list);
+
+ memset(&g_api, 0, sizeof(g_api));
+ g_api.privilege = WIMAX_API_PRIVILEGE_READ_WRITE;
+
+ result = -EIO;
+ r = WiMaxAPIOpen(&g_api);
+ if (r != WIMAX_API_RET_SUCCESS) {
+ GetErrorString(&g_api, r, errstr, &errstr_size);
+ connman_error("wmxsdk: WiMaxAPIOpen failed with %d (%s)\n",
+ r, errstr);
+ goto error_wimaxapiopen;
+ }
+
+ r = SubscribeDeviceInsertRemove(&g_api, iwmx_sdk_addremove_cb);
+ if (r != WIMAX_API_RET_SUCCESS) {
+ GetErrorString(&g_api, r, errstr, &errstr_size);
+ connman_error("wmxsdk: insert/remove subscribe failed with "
+ "%d (%s)\n", r, errstr);
+ goto error_close;
+ }
+
+ r = GetListDevice(&g_api, device_id_list, &device_id_list_size);
+ if (r != WIMAX_API_RET_SUCCESS) {
+ GetErrorString(&g_api, r, errstr, &errstr_size);
+ connman_error("wmxsdk: Cannot obtain list "
+ "of devices: %d (%s)\n", r, errstr);
+ goto error_close;
+ }
+ if (device_id_list_size < g_api.deviceIndex) {
+ connman_error("wmxsdk: changed device (%u) not in the list? "
+ "(%u items)\n",
+ g_api.deviceIndex, device_id_list_size);
+ }
+
+ if (device_id_list_size == 0)
+ DBG("No WiMAX devices reported\n");
+ else
+ for (cnt = 0; cnt < device_id_list_size; cnt++) {
+ struct WIMAX_API_HW_DEVICE_ID *dev =
+ device_id_list + cnt;
+ DBG("#%u index #%u device %s\n",
+ cnt, dev->deviceIndex, dev->deviceName);
+ iwmx_sdk_dev_add(cnt, dev->deviceIndex,
+ dev->deviceName);
+ }
+ return 0;
+
+error_close:
+ WiMaxAPIClose(&g_api);
+error_wimaxapiopen:
+ return result;
+}
+
+void iwmx_sdk_api_exit(void)
+{
+ WIMAX_API_RET r;
+
+ char errstr[512];
+ UINT32 errstr_size = sizeof(errstr);
+
+ r = WiMaxAPIClose(&g_api);
+ if (r != WIMAX_API_RET_SUCCESS) {
+ GetErrorString(&g_api, r, errstr, &errstr_size);
+ connman_error("wmxsdk: WiMaxAPIClose failed with %d (%s)\n",
+ r, errstr);
+ }
+ return;
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/inotify.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+
+#include <glib.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/log.h>
+
+#if 0
+static GIOChannel *inotify_channel = NULL;
+
+static int hostname_descriptor = -1;
+
+static gboolean inotify_event(GIOChannel *channel,
+ GIOCondition condition, gpointer data)
+{
+ unsigned char buf[129], *ptr = buf;
+ gsize len;
+ GIOError err;
+
+ if (condition & (G_IO_HUP | G_IO_ERR))
+ return FALSE;
+
+ memset(buf, 0, sizeof(buf));
+
+ err = g_io_channel_read(channel, (gchar *) buf, sizeof(buf) - 1, &len);
+ if (err != G_IO_ERROR_NONE) {
+ if (err == G_IO_ERROR_AGAIN)
+ return TRUE;
+ connman_error("Reading from inotify channel failed");
+ return FALSE;
+ }
+
+ while (len >= sizeof(struct inotify_event)) {
+ struct inotify_event *evt = (struct inotify_event *) ptr;
+
+ if (evt->wd == hostname_descriptor) {
+ if (evt->mask & (IN_CREATE | IN_MOVED_TO))
+ connman_info("create hostname file");
+
+ if (evt->mask & (IN_DELETE | IN_MOVED_FROM))
+ connman_info("delete hostname file");
+
+ if (evt->mask & (IN_MODIFY | IN_MOVE_SELF))
+ connman_info("modify hostname file");
+ }
+
+ len -= sizeof(struct inotify_event) + evt->len;
+ ptr += sizeof(struct inotify_event) + evt->len;
+ }
+
+ return TRUE;
+}
+
+static int create_watch(void)
+{
+ int fd;
+
+ fd = inotify_init();
+ if (fd < 0) {
+ connman_error("Creation of inotify context failed");
+ return -EIO;
+ }
+
+ inotify_channel = g_io_channel_unix_new(fd);
+ if (inotify_channel == NULL) {
+ connman_error("Creation of inotify channel failed");
+ close(fd);
+ return -EIO;
+ }
+
+ hostname_descriptor = inotify_add_watch(fd, "/etc/hostname",
+ IN_MODIFY | IN_DELETE_SELF | IN_MOVE_SELF);
+ if (hostname_descriptor < 0) {
+ connman_error("Creation of hostname watch failed");
+ g_io_channel_unref(inotify_channel);
+ inotify_channel = NULL;
+ close(fd);
+ return -EIO;
+ }
+
+ g_io_add_watch(inotify_channel, G_IO_IN | G_IO_ERR | G_IO_HUP,
+ inotify_event, NULL);
+
+ return 0;
+}
+
+static void remove_watch(void)
+{
+ int fd;
+
+ if (inotify_channel == NULL)
+ return;
+
+ fd = g_io_channel_unix_get_fd(inotify_channel);
+
+ if (hostname_descriptor >= 0)
+ inotify_rm_watch(fd, hostname_descriptor);
+
+ g_io_channel_unref(inotify_channel);
+
+ close(fd);
+}
+#endif
+
+static void create_hostname(void)
+{
+ const char *name = "localhost";
+
+ if (sethostname(name, strlen(name)) < 0)
+ connman_error("Failed to set hostname to %s", name);
+}
+
+static int setup_hostname(void)
+{
+ char name[HOST_NAME_MAX + 1];
+
+ memset(name, 0, sizeof(name));
+
+ if (gethostname(name, HOST_NAME_MAX) < 0) {
+ connman_error("Failed to get current hostname");
+ return -EIO;
+ }
+
+ if (strlen(name) > 0 && strcmp(name, "(none)") != 0)
+ connman_info("System hostname is %s", name);
+ else
+ create_hostname();
+
+ memset(name, 0, sizeof(name));
+
+ if (getdomainname(name, HOST_NAME_MAX) < 0) {
+ connman_error("Failed to get current domainname");
+ return -EIO;
+ }
+
+ if (strlen(name) > 0 && strcmp(name, "(none)") != 0)
+ connman_info("System domainname is %s", name);
+
+ return 0;
+}
+
+static int setup_loopback(void)
+{
+ struct ifreq ifr;
+ struct sockaddr_in *addr;
+ int sk, err;
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, "lo");
+
+ if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0) {
+ err = -errno;
+ goto done;
+ }
+
+ if (ifr.ifr_flags & IFF_UP) {
+ err = -EALREADY;
+ connman_info("The loopback interface is already up");
+ goto done;
+ }
+
+ addr = (struct sockaddr_in *) &ifr.ifr_addr;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = inet_addr("127.0.0.1");
+
+ err = ioctl(sk, SIOCSIFADDR, &ifr);
+ if (err < 0) {
+ err = -errno;
+ connman_error("Setting address failed (%s)", strerror(-err));
+ goto done;
+ }
+
+ addr = (struct sockaddr_in *) &ifr.ifr_netmask;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = inet_addr("255.0.0.0");
+
+ err = ioctl(sk, SIOCSIFNETMASK, &ifr);
+ if (err < 0) {
+ err = -errno;
+ connman_error("Setting netmask failed (%s)", strerror(-err));
+ goto done;
+ }
+
+ if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0) {
+ err = -errno;
+ goto done;
+ }
+
+ ifr.ifr_flags |= IFF_UP;
+
+ if (ioctl(sk, SIOCSIFFLAGS, &ifr) < 0) {
+ err = -errno;
+ connman_error("Activating loopback interface failed (%s)",
+ strerror(-err));
+ goto done;
+ }
+
+done:
+ close(sk);
+
+ return err;
+}
+
+static int loopback_init(void)
+{
+ setup_loopback();
+
+ setup_hostname();
+
+ //create_watch();
+
+ return 0;
+}
+
+static void loopback_exit(void)
+{
+ //remove_watch();
+}
+
+CONNMAN_PLUGIN_DEFINE(loopback, "Loopback device plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_HIGH, loopback_init, loopback_exit)
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <string.h>
+#include <termios.h>
+
+#include <glib.h>
+
+#include <connman/log.h>
+
+#include "modem.h"
+
+struct modem_data {
+ char *device;
+ GIOChannel *channel;
+ guint watch;
+ GSList *callbacks;
+ GSList *commands;
+ char buf[1024];
+ int offset;
+};
+
+struct modem_callback {
+ char *command;
+ modem_cb_t function;
+ void *user_data;
+};
+
+struct modem_cmd {
+ char *cmd;
+ char *arg;
+ modem_cb_t callback;
+ void *user_data;
+};
+
+static int send_command(struct modem_data *modem, struct modem_cmd *cmd)
+{
+ char *buf;
+ int fd, err;
+
+ if (cmd->arg == NULL) {
+ DBG("AT%s", cmd->cmd);
+ buf = g_strdup_printf("AT%s\r\n", cmd->cmd);
+ } else {
+ DBG("AT%s=%s", cmd->cmd, cmd->arg);
+ buf = g_strdup_printf("AT%s=%s\r\n", cmd->cmd, cmd->arg);
+ }
+
+ fd = g_io_channel_unix_get_fd(modem->channel);
+ err = write(fd, buf, strlen(buf));
+
+ fsync(fd);
+
+ g_free(buf);
+
+ return err;
+}
+
+static int queue_command(struct modem_data *modem, struct modem_cmd *cmd)
+{
+ modem->commands = g_slist_append(modem->commands, cmd);
+
+ if (g_slist_length(modem->commands) > 1)
+ return 0;
+
+ return send_command(modem, cmd);
+}
+
+struct modem_data *modem_create(const char *device)
+{
+ struct modem_data *modem;
+
+ DBG("device %s", device);
+
+ modem = g_try_new0(struct modem_data, 1);
+ if (modem == NULL)
+ return NULL;
+
+ modem->device = g_strdup(device);
+
+ DBG("modem %p", modem);
+
+ return modem;
+}
+
+void modem_destroy(struct modem_data *modem)
+{
+ DBG("modem %p", modem);
+
+ if (modem == NULL)
+ return;
+
+ g_free(modem->device);
+ g_free(modem);
+}
+
+static gboolean modem_event(GIOChannel *channel,
+ GIOCondition condition, gpointer user_data)
+{
+ struct modem_data *modem = user_data;
+ struct modem_cmd *cmd;
+ GSList *list;
+ gsize len;
+ GIOError err;
+
+ if (condition & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
+ return FALSE;
+
+ err = g_io_channel_read(channel, modem->buf + modem->offset,
+ sizeof(modem->buf) - modem->offset, &len);
+ if (err) {
+ if (err == G_IO_ERROR_AGAIN)
+ return TRUE;
+ return FALSE;
+ }
+
+ DBG("Read %zu bytes (offset %d)", len, modem->offset);
+
+ if (g_str_has_suffix(modem->buf, "\r\n") == TRUE) {
+ for (list = modem->callbacks; list; list = list->next) {
+ struct modem_callback *callback = list->data;
+
+ if (callback->function == NULL)
+ continue;
+
+ if (g_strrstr(modem->buf, callback->command) != NULL)
+ callback->function(modem->buf,
+ callback->user_data);
+ }
+ }
+
+ if (g_strrstr(modem->buf, "\r\nERROR\r\n") == NULL &&
+ g_strrstr(modem->buf, "\r\nOK\r\n") == NULL) {
+ modem->offset += len;
+ return TRUE;
+ }
+
+ memset(modem->buf, 0, sizeof(modem->buf));
+ modem->offset = 0;
+
+ cmd = g_slist_nth_data(modem->commands, 0);
+ if (cmd == NULL)
+ return TRUE;
+
+ modem->commands = g_slist_remove(modem->commands, cmd);
+
+ DBG("AT%s", cmd->cmd);
+
+ if (cmd->callback)
+ cmd->callback(modem->buf, cmd->user_data);
+
+ g_free(cmd->arg);
+ g_free(cmd->cmd);
+ g_free(cmd);
+
+ cmd = g_slist_nth_data(modem->commands, 0);
+ if (cmd == NULL)
+ return TRUE;
+
+ send_command(modem, cmd);
+
+ return TRUE;
+}
+
+static int open_device(const char *device)
+{
+ struct termios ti;
+ int fd;
+
+ fd = open(device, O_RDWR | O_NOCTTY);
+ if (fd < 0)
+ return -1;
+
+ tcflush(fd, TCIOFLUSH);
+
+ /* Switch TTY to raw mode */
+ memset(&ti, 0, sizeof(ti));
+ cfmakeraw(&ti);
+
+ tcsetattr(fd, TCSANOW, &ti);
+
+ return fd;
+}
+
+int modem_open(struct modem_data *modem)
+{
+ int fd, try = 5;
+
+ DBG("modem %p", modem);
+
+ if (modem == NULL)
+ return -ENOENT;
+
+ while (try-- > 0) {
+ fd = open_device(modem->device);
+ if (fd < 0) {
+ sleep(1);
+ continue;
+ }
+ try = 0;
+ }
+
+ if (fd < 0) {
+ connman_error("Can't open %s device", modem->device);
+ return -EIO;
+ }
+
+ modem->channel = g_io_channel_unix_new(fd);
+ g_io_channel_set_close_on_unref(modem->channel, TRUE);
+
+ modem->watch = g_io_add_watch(modem->channel,
+ G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
+ modem_event, modem);
+
+ return 0;
+}
+
+int modem_close(struct modem_data *modem)
+{
+ DBG("modem %p", modem);
+
+ if (modem == NULL)
+ return -ENOENT;
+
+ g_source_remove(modem->watch);
+ modem->watch = 0;
+
+ g_io_channel_unref(modem->channel);
+ modem->channel = NULL;
+
+ return 0;
+}
+
+int modem_add_callback(struct modem_data *modem, const char *command,
+ modem_cb_t function, void *user_data)
+{
+ struct modem_callback *callback;
+
+ callback = g_try_new0(struct modem_callback, 1);
+ if (callback == NULL)
+ return -ENOMEM;
+
+ callback->command = g_strdup(command);
+ callback->function = function;
+ callback->user_data = user_data;
+
+ modem->callbacks = g_slist_append(modem->callbacks, callback);
+
+ return 0;
+}
+
+static int modem_command_valist(struct modem_data *modem, modem_cb_t callback,
+ void *user_data, const char *command,
+ const char *format, va_list var_args)
+{
+ struct modem_cmd *cmd;
+
+ cmd = g_try_new0(struct modem_cmd, 1);
+ if (cmd == NULL)
+ return -ENOMEM;
+
+ cmd->cmd = g_strdup(command);
+ if (format != NULL)
+ cmd->arg = g_strdup_vprintf(format, var_args);
+
+ cmd->callback = callback;
+ cmd->user_data = user_data;
+
+ return queue_command(modem, cmd);
+}
+
+int modem_command(struct modem_data *modem,
+ modem_cb_t callback, void *user_data,
+ const char *command, const char *format, ...)
+{
+ va_list args;
+ int err;
+
+ DBG("modem %p", modem);
+
+ if (modem == NULL)
+ return -ENOENT;
+
+ va_start(args, format);
+ err = modem_command_valist(modem, callback, user_data,
+ command, format, args);
+ va_end(args);
+
+ return err;
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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
+ *
+ */
+
+typedef struct modem_data modem_t;
+
+struct modem_data;
+
+struct modem_data *modem_create(const char *device);
+void modem_destroy(struct modem_data *modem);
+
+int modem_open(struct modem_data *modem);
+int modem_close(struct modem_data *modem);
+
+typedef void (* modem_cb_t) (const char *buf, void *user_data);
+
+int modem_add_callback(struct modem_data *modem, const char *command,
+ modem_cb_t function, void *user_data);
+
+int modem_command(struct modem_data *modem,
+ modem_cb_t callback, void *user_data,
+ const char *command, const char *format, ...);
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+
+#include <gdbus.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/dbus.h>
+#include <connman/log.h>
+
+#define MODEMMGR_SERVICE "org.freedesktop.ModemManager"
+#define MODEMMGR_INTERFACE MODEMMGR_SERVICE
+
+#define ENUMERATE_DEVICES "EnumerateDevices"
+
+#define TIMEOUT 5000
+
+static void enumerate_devices_reply(DBusPendingCall *call, void *user_data)
+{
+ DBusMessage *reply;
+
+ DBG("");
+
+ reply = dbus_pending_call_steal_reply(call);
+
+ dbus_message_unref(reply);
+}
+
+static void modemmgr_connect(DBusConnection *connection, void *user_data)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ DBG("connection %p", connection);
+
+ message = dbus_message_new_method_call(MODEMMGR_SERVICE, "/",
+ MODEMMGR_INTERFACE, ENUMERATE_DEVICES);
+ if (message == NULL)
+ return;
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, TIMEOUT) == FALSE) {
+ connman_error("Failed to get modem devices");
+ goto done;
+ }
+
+ if (call == NULL) {
+ connman_error("D-Bus connection not available");
+ goto done;
+ }
+
+ dbus_pending_call_set_notify(call, enumerate_devices_reply,
+ NULL, NULL);
+
+done:
+ dbus_message_unref(message);
+}
+
+static void modemmgr_disconnect(DBusConnection *connection, void *user_data)
+{
+ DBG("connection %p", connection);
+}
+
+static DBusConnection *connection;
+static guint watch;
+
+static int modemmgr_init(void)
+{
+ connection = connman_dbus_get_connection();
+ if (connection == NULL)
+ return -EIO;
+
+ watch = g_dbus_add_service_watch(connection, MODEMMGR_SERVICE,
+ modemmgr_connect, modemmgr_disconnect, NULL, NULL);
+ if (watch == 0) {
+ dbus_connection_unref(connection);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void modemmgr_exit(void)
+{
+ g_dbus_remove_watch(connection, watch);
+
+ dbus_connection_unref(connection);
+}
+
+CONNMAN_PLUGIN_DEFINE(modemmgr, "Modem Manager plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, modemmgr_init, modemmgr_exit)
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/device.h>
+#include <connman/log.h>
+
+#include "modem.h"
+
+static int novatel_probe(struct connman_device *device)
+{
+ DBG("device %p", device);
+
+ return 0;
+}
+
+static void novatel_remove(struct connman_device *device)
+{
+ DBG("device %p", device);
+}
+
+static int novatel_enable(struct connman_device *device)
+{
+ DBG("device %p", device);
+
+ connman_device_set_powered(device, TRUE);
+
+ return 0;
+}
+
+static int novatel_disable(struct connman_device *device)
+{
+ DBG("device %p", device);
+
+ connman_device_set_powered(device, FALSE);
+
+ return 0;
+}
+
+static struct connman_device_driver novatel_driver = {
+ .name = "novatel",
+ .type = CONNMAN_DEVICE_TYPE_NOVATEL,
+ .probe = novatel_probe,
+ .remove = novatel_remove,
+ .enable = novatel_enable,
+ .disable = novatel_disable,
+};
+
+static int novatel_init(void)
+{
+ return connman_device_driver_register(&novatel_driver);
+}
+
+static void novatel_exit(void)
+{
+ connman_device_driver_unregister(&novatel_driver);
+}
+
+CONNMAN_PLUGIN_DEFINE(novatel, "Novatel Wireless device plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, novatel_init, novatel_exit)
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+
+static int ofono_init(void)
+{
+ return 0;
+}
+
+static void ofono_exit(void)
+{
+}
+
+CONNMAN_PLUGIN_DEFINE(ofono, "oFono telephony plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, ofono_init, ofono_exit)
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+
+#include <glib.h>
+#include <polkit-dbus/polkit-dbus.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/security.h>
+#include <connman/dbus.h>
+#include <connman/log.h>
+
+#define ACTION_MODIFY "org.moblin.connman.modify"
+#define ACTION_SECRET "org.moblin.connman.secret"
+
+static DBusConnection *connection;
+static PolKitContext *polkit_context;
+
+static int polkit_authorize(const char *sender,
+ enum connman_security_privilege privilege)
+{
+ DBusError error;
+ PolKitCaller *caller;
+ PolKitAction *action;
+ PolKitResult result;
+ const char *id = NULL;
+
+ DBG("sender %s", sender);
+
+ switch (privilege) {
+ case CONNMAN_SECURITY_PRIVILEGE_PUBLIC:
+ return 0;
+ case CONNMAN_SECURITY_PRIVILEGE_MODIFY:
+ id = ACTION_MODIFY;
+ break;
+ case CONNMAN_SECURITY_PRIVILEGE_SECRET:
+ id = ACTION_SECRET;
+ break;
+ }
+
+ dbus_error_init(&error);
+
+ caller = polkit_caller_new_from_dbus_name(connection, sender, &error);
+ if (caller == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to get caller information");
+ return -EIO;
+ }
+
+ action = polkit_action_new();
+ polkit_action_set_action_id(action, id);
+
+ result = polkit_context_is_caller_authorized(polkit_context,
+ action, caller, TRUE, NULL);
+
+ polkit_action_unref(action);
+ polkit_caller_unref(caller);
+
+ DBG("result %s", polkit_result_to_string_representation(result));
+
+ if (result == POLKIT_RESULT_NO)
+ return -EPERM;
+
+ return 0;
+}
+
+static struct connman_security polkit_security = {
+ .name = "polkit",
+ .authorize_sender = polkit_authorize,
+};
+
+static gboolean watch_event(GIOChannel *channel, GIOCondition condition,
+ gpointer user_data)
+{
+ PolKitContext *context = user_data;
+ int fd;
+
+ DBG("context %p", context);
+
+ fd = g_io_channel_unix_get_fd(channel);
+
+ polkit_context_io_func(context, fd);
+
+ return TRUE;
+}
+
+static int add_watch(PolKitContext *context, int fd)
+{
+ GIOChannel *channel;
+ guint id = 0;
+
+ DBG("context %p", context);
+
+ channel = g_io_channel_unix_new(fd);
+ if (channel == NULL)
+ return 0;
+
+ id = g_io_add_watch(channel, G_IO_IN, watch_event, context);
+
+ g_io_channel_unref(channel);
+
+ return id;
+}
+
+static void remove_watch(PolKitContext *context, int id)
+{
+ DBG("context %p", context);
+
+ g_source_remove(id);
+}
+
+static int polkit_init(void)
+{
+ int err;
+
+ connection = connman_dbus_get_connection();
+ if (connection == NULL)
+ return -EIO;
+
+ polkit_context = polkit_context_new();
+
+ polkit_context_set_io_watch_functions(polkit_context,
+ add_watch, remove_watch);
+
+ if (polkit_context_init(polkit_context, NULL) == FALSE) {
+ connman_error("Can't initialize PolicyKit");
+ polkit_context_unref(polkit_context);
+ dbus_connection_unref(connection);
+ return -EIO;
+ }
+
+ err = connman_security_register(&polkit_security);
+ if (err < 0) {
+ polkit_context_unref(polkit_context);
+ dbus_connection_unref(connection);
+ return err;
+ }
+
+ return 0;
+}
+
+static void polkit_exit(void)
+{
+ connman_security_unregister(&polkit_security);
+
+ polkit_context_unref(polkit_context);
+
+ dbus_connection_unref(connection);
+}
+
+CONNMAN_PLUGIN_DEFINE(polkit, "PolicyKit authorization plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, polkit_init, polkit_exit)
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE policyconfig PUBLIC
+ "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
+
+<policyconfig>
+
+ <vendor>Connection Manager</vendor>
+ <icon_name>network-wireless</icon_name>
+
+ <action id="org.moblin.connman.modify">
+ <description>Settings configuration</description>
+ <message>Policy prevents modification of settings</message>
+ <defaults>
+ <allow_inactive>no</allow_inactive>
+ <allow_active>auth_self_keep_session</allow_active>
+ </defaults>
+ </action>
+
+ <action id="org.moblin.connman.secret">
+ <description>Secrets configuration</description>
+ <message>Policy prevents modification of secrets</message>
+ <defaults>
+ <allow_inactive>no</allow_inactive>
+ <allow_active>auth_admin_keep_session</allow_active>
+ </defaults>
+ </action>
+
+</policyconfig>
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/driver.h>
+#include <connman/log.h>
+
+static int pppd_probe(struct connman_element *element)
+{
+ DBG("element %p name %s", element, element->name);
+
+ return -ENODEV;
+}
+
+static void pppd_remove(struct connman_element *element)
+{
+ DBG("element %p name %s", element, element->name);
+}
+
+static struct connman_driver pppd_driver = {
+ .name = "pppd",
+ .type = CONNMAN_ELEMENT_TYPE_PPP,
+ .probe = pppd_probe,
+ .remove = pppd_remove,
+};
+
+static int pppd_init(void)
+{
+ return connman_driver_register(&pppd_driver);
+}
+
+static void pppd_exit(void)
+{
+ connman_driver_unregister(&pppd_driver);
+}
+
+CONNMAN_PLUGIN_DEFINE(pppd, "Point-to-point protocol plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, pppd_init, pppd_exit)
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/resolver.h>
+#include <connman/log.h>
+
+#include <glib.h>
+
+static int resolvconf_append(const char *interface, const char *domain,
+ const char *server)
+{
+ char *cmd;
+ int err;
+
+ DBG("interface %s server %s", interface, server);
+
+ if (access(RESOLVCONF, X_OK) < 0)
+ return -errno;
+
+ cmd = g_strdup_printf("echo \"nameserver %s\" | %s -a %s",
+ server, RESOLVCONF, interface);
+
+ DBG("%s", cmd);
+
+ err = system(cmd);
+
+ g_free(cmd);
+
+ return err;
+}
+
+static int resolvconf_remove(const char *interface, const char *domain,
+ const char *server)
+{
+ char *cmd;
+ int err;
+
+ DBG("interface %s server %s", interface, server);
+
+ cmd = g_strdup_printf("%s -d %s", RESOLVCONF, interface);
+
+ DBG("%s", cmd);
+
+ err = system(cmd);
+
+ g_free(cmd);
+
+ return err;
+}
+
+static struct connman_resolver resolvconf_resolver = {
+ .name = "resolvconf",
+ .priority = CONNMAN_RESOLVER_PRIORITY_DEFAULT,
+ .append = resolvconf_append,
+ .remove = resolvconf_remove,
+};
+
+static int resolvconf_init(void)
+{
+ return connman_resolver_register(&resolvconf_resolver);
+}
+
+static void resolvconf_exit(void)
+{
+ connman_resolver_unregister(&resolvconf_resolver);
+}
+
+CONNMAN_PLUGIN_DEFINE(resolvconf, "Name resolver plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, resolvconf_init, resolvconf_exit)
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <net/ethernet.h>
+
+#include <gdbus.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/device.h>
+#include <connman/option.h>
+#include <connman/inet.h>
+#include <connman/dbus.h>
+#include <connman/log.h>
+
+#include "supplicant.h"
+
+#define TIMEOUT 5000
+
+#define IEEE80211_CAP_ESS 0x0001
+#define IEEE80211_CAP_IBSS 0x0002
+#define IEEE80211_CAP_PRIVACY 0x0010
+
+#define SUPPLICANT_NAME "fi.epitest.hostap.WPASupplicant"
+#define SUPPLICANT_INTF "fi.epitest.hostap.WPASupplicant"
+#define SUPPLICANT_PATH "/fi/epitest/hostap/WPASupplicant"
+
+/* Taken from "WPA Supplicant - Common definitions" */
+enum supplicant_state {
+ /**
+ * WPA_DISCONNECTED - Disconnected state
+ *
+ * This state indicates that client is not associated, but is likely to
+ * start looking for an access point. This state is entered when a
+ * connection is lost.
+ */
+ WPA_DISCONNECTED,
+
+ /**
+ * WPA_INACTIVE - Inactive state (wpa_supplicant disabled)
+ *
+ * This state is entered if there are no enabled networks in the
+ * configuration. wpa_supplicant is not trying to associate with a new
+ * network and external interaction (e.g., ctrl_iface call to add or
+ * enable a network) is needed to start association.
+ */
+ WPA_INACTIVE,
+
+ /**
+ * WPA_SCANNING - Scanning for a network
+ *
+ * This state is entered when wpa_supplicant starts scanning for a
+ * network.
+ */
+ WPA_SCANNING,
+
+ /**
+ * WPA_ASSOCIATING - Trying to associate with a BSS/SSID
+ *
+ * This state is entered when wpa_supplicant has found a suitable BSS
+ * to associate with and the driver is configured to try to associate
+ * with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this
+ * state is entered when the driver is configured to try to associate
+ * with a network using the configured SSID and security policy.
+ */
+ WPA_ASSOCIATING,
+
+ /**
+ * WPA_ASSOCIATED - Association completed
+ *
+ * This state is entered when the driver reports that association has
+ * been successfully completed with an AP. If IEEE 802.1X is used
+ * (with or without WPA/WPA2), wpa_supplicant remains in this state
+ * until the IEEE 802.1X/EAPOL authentication has been completed.
+ */
+ WPA_ASSOCIATED,
+
+ /**
+ * WPA_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress
+ *
+ * This state is entered when WPA/WPA2 4-Way Handshake is started. In
+ * case of WPA-PSK, this happens when receiving the first EAPOL-Key
+ * frame after association. In case of WPA-EAP, this state is entered
+ * when the IEEE 802.1X/EAPOL authentication has been completed.
+ */
+ WPA_4WAY_HANDSHAKE,
+
+ /**
+ * WPA_GROUP_HANDSHAKE - WPA Group Key Handshake in progress
+ *
+ * This state is entered when 4-Way Key Handshake has been completed
+ * (i.e., when the supplicant sends out message 4/4) and when Group
+ * Key rekeying is started by the AP (i.e., when supplicant receives
+ * message 1/2).
+ */
+ WPA_GROUP_HANDSHAKE,
+
+ /**
+ * WPA_COMPLETED - All authentication completed
+ *
+ * This state is entered when the full authentication process is
+ * completed. In case of WPA2, this happens when the 4-Way Handshake is
+ * successfully completed. With WPA, this state is entered after the
+ * Group Key Handshake; with IEEE 802.1X (non-WPA) connection is
+ * completed after dynamic keys are received (or if not used, after
+ * the EAP authentication has been completed). With static WEP keys and
+ * plaintext connections, this state is entered when an association
+ * has been completed.
+ *
+ * This state indicates that the supplicant has completed its
+ * processing for the association phase and that data connection is
+ * fully configured.
+ */
+ WPA_COMPLETED,
+
+ /**
+ * WPA_INVALID - Invalid state (parsing error)
+ *
+ * This state is returned if the string input is invalid. It is not
+ * an official wpa_supplicant state.
+ */
+ WPA_INVALID,
+};
+
+struct supplicant_result {
+ char *path;
+ char *name;
+ unsigned char *addr;
+ unsigned int addr_len;
+ unsigned char *ssid;
+ unsigned int ssid_len;
+ dbus_uint16_t capabilities;
+ gboolean adhoc;
+ gboolean has_wep;
+ gboolean has_wpa;
+ gboolean has_rsn;
+ gboolean has_wps;
+ dbus_int32_t frequency;
+ dbus_int32_t quality;
+ dbus_int32_t noise;
+ dbus_int32_t level;
+ dbus_int32_t maxrate;
+};
+
+struct supplicant_task {
+ int ifindex;
+ char *ifname;
+ struct connman_device *device;
+ struct connman_network *network;
+ char *path;
+ char *netpath;
+ gboolean created;
+ enum supplicant_state state;
+ gboolean noscan;
+ GSList *scan_results;
+};
+
+static GSList *task_list = NULL;
+
+static DBusConnection *connection;
+
+static void free_task(struct supplicant_task *task)
+{
+ DBG("task %p", task);
+
+ g_free(task->ifname);
+ g_free(task->path);
+ g_free(task);
+}
+
+static struct supplicant_task *find_task_by_index(int index)
+{
+ GSList *list;
+
+ for (list = task_list; list; list = list->next) {
+ struct supplicant_task *task = list->data;
+
+ if (task->ifindex == index)
+ return task;
+ }
+
+ return NULL;
+}
+
+static struct supplicant_task *find_task_by_path(const char *path)
+{
+ GSList *list;
+
+ for (list = task_list; list; list = list->next) {
+ struct supplicant_task *task = list->data;
+
+ if (g_strcmp0(task->path, path) == 0)
+ return task;
+ }
+
+ return NULL;
+}
+
+static void add_interface_reply(DBusPendingCall *call, void *user_data)
+{
+ struct supplicant_task *task = user_data;
+ DBusMessage *reply;
+ DBusError error;
+ const char *path;
+
+ DBG("task %p", task);
+
+ reply = dbus_pending_call_steal_reply(call);
+ if (reply == NULL)
+ return;
+
+ if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
+ goto failed;
+
+ dbus_error_init(&error);
+
+ if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID) == FALSE) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Wrong arguments for add interface");
+ goto failed;
+ }
+
+ DBG("path %s", path);
+
+ task->path = g_strdup(path);
+ task->created = TRUE;
+
+ connman_device_set_powered(task->device, TRUE);
+
+ dbus_message_unref(reply);
+
+ return;
+
+failed:
+ task_list = g_slist_remove(task_list, task);
+
+ connman_device_unref(task->device);
+
+ free_task(task);
+}
+
+static int add_interface(struct supplicant_task *task)
+{
+ const char *driver = connman_option_get_string("wifi");
+ DBusMessage *message;
+ DBusMessageIter array, dict;
+ DBusPendingCall *call;
+
+ DBG("task %p", task);
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
+ SUPPLICANT_INTF, "addInterface");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_message_iter_init_append(message, &array);
+
+ dbus_message_iter_append_basic(&array,
+ DBUS_TYPE_STRING, &task->ifname);
+
+ dbus_message_iter_open_container(&array, 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);
+
+ connman_dbus_dict_append_variant(&dict, "driver",
+ DBUS_TYPE_STRING, &driver);
+
+ dbus_message_iter_close_container(&array, &dict);
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, TIMEOUT) == FALSE) {
+ connman_error("Failed to add interface");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ if (call == NULL) {
+ connman_error("D-Bus connection not available");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_pending_call_set_notify(call, add_interface_reply, task, NULL);
+
+ dbus_message_unref(message);
+
+ return -EINPROGRESS;
+}
+
+static void get_interface_reply(DBusPendingCall *call, void *user_data)
+{
+ struct supplicant_task *task = user_data;
+ DBusMessage *reply;
+ DBusError error;
+ const char *path;
+
+ DBG("task %p", task);
+
+ reply = dbus_pending_call_steal_reply(call);
+ if (reply == NULL)
+ return;
+
+ if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
+ add_interface(task);
+ goto done;
+ }
+
+ dbus_error_init(&error);
+
+ if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID) == FALSE) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Wrong arguments for get interface");
+ goto done;
+ }
+
+ DBG("path %s", path);
+
+ task->path = g_strdup(path);
+ task->created = FALSE;
+
+ connman_device_set_powered(task->device, TRUE);
+
+done:
+ dbus_message_unref(reply);
+}
+
+static int create_interface(struct supplicant_task *task)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ DBG("task %p", task);
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
+ SUPPLICANT_INTF, "getInterface");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_message_append_args(message, DBUS_TYPE_STRING, &task->ifname,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, TIMEOUT) == FALSE) {
+ connman_error("Failed to get interface");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ if (call == NULL) {
+ connman_error("D-Bus connection not available");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_pending_call_set_notify(call, get_interface_reply, task, NULL);
+
+ dbus_message_unref(message);
+
+ return -EINPROGRESS;
+}
+
+static void remove_interface_reply(DBusPendingCall *call, void *user_data)
+{
+ struct supplicant_task *task = user_data;
+ DBusMessage *reply;
+
+ DBG("task %p", task);
+
+ reply = dbus_pending_call_steal_reply(call);
+
+ connman_device_set_powered(task->device, FALSE);
+
+ connman_device_unref(task->device);
+
+ connman_inet_ifdown(task->ifindex);
+
+ free_task(task);
+
+ dbus_message_unref(reply);
+}
+
+static int remove_interface(struct supplicant_task *task)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ DBG("task %p", task);
+
+ if (task->created == FALSE) {
+ connman_device_set_powered(task->device, FALSE);
+ return 0;
+ }
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
+ SUPPLICANT_INTF, "removeInterface");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->path,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, TIMEOUT) == FALSE) {
+ connman_error("Failed to remove interface");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ if (call == NULL) {
+ connman_error("D-Bus connection not available");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_pending_call_set_notify(call, remove_interface_reply, task, NULL);
+
+ dbus_message_unref(message);
+
+ return -EINPROGRESS;
+}
+
+#if 0
+static int set_ap_scan(struct supplicant_task *task)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+ guint32 ap_scan = 1;
+
+ DBG("task %p", task);
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
+ SUPPLICANT_INTF ".Interface", "setAPScan");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_message_append_args(message, DBUS_TYPE_UINT32, &ap_scan,
+ DBUS_TYPE_INVALID);
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(connection,
+ message, -1, &error);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to set AP scan");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_message_unref(message);
+
+ dbus_message_unref(reply);
+
+ return 0;
+}
+#endif
+
+static int add_network(struct supplicant_task *task)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+ const char *path;
+
+ DBG("task %p", task);
+
+ if (task->netpath != NULL)
+ return -EALREADY;
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
+ SUPPLICANT_INTF ".Interface", "addNetwork");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(connection,
+ message, -1, &error);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to add network");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_message_unref(message);
+
+ dbus_error_init(&error);
+
+ if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID) == FALSE) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Wrong arguments for network");
+ dbus_message_unref(reply);
+ return -EIO;
+ }
+
+ DBG("path %s", path);
+
+ task->netpath = g_strdup(path);
+
+ dbus_message_unref(reply);
+
+ return 0;
+}
+
+static int remove_network(struct supplicant_task *task)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+
+ DBG("task %p", task);
+
+ if (task->netpath == NULL)
+ return -EINVAL;
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
+ SUPPLICANT_INTF ".Interface", "removeNetwork");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->netpath,
+ DBUS_TYPE_INVALID);
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(connection,
+ message, -1, &error);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to remove network");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_message_unref(message);
+
+ dbus_message_unref(reply);
+
+ g_free(task->netpath);
+ task->netpath = NULL;
+
+ return 0;
+}
+
+static int select_network(struct supplicant_task *task)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+
+ DBG("task %p", task);
+
+ if (task->netpath == NULL)
+ return -EINVAL;
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
+ SUPPLICANT_INTF ".Interface", "selectNetwork");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->netpath,
+ DBUS_TYPE_INVALID);
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(connection,
+ message, -1, &error);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to select network");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_message_unref(message);
+
+ dbus_message_unref(reply);
+
+ return 0;
+}
+
+static int enable_network(struct supplicant_task *task)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+
+ DBG("task %p", task);
+
+ if (task->netpath == NULL)
+ return -EINVAL;
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, task->netpath,
+ SUPPLICANT_INTF ".Network", "enable");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(connection,
+ message, -1, &error);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to enable network");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_message_unref(message);
+
+ dbus_message_unref(reply);
+
+ return 0;
+}
+
+static int disable_network(struct supplicant_task *task)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+
+ DBG("task %p", task);
+
+ if (task->netpath == NULL)
+ return -EINVAL;
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, task->netpath,
+ SUPPLICANT_INTF ".Network", "disable");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(connection,
+ message, -1, &error);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to disable network");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_message_unref(message);
+
+ dbus_message_unref(reply);
+
+ return 0;
+}
+
+static int set_network(struct supplicant_task *task,
+ const unsigned char *network, int len,
+ const char *address, const char *security,
+ const char *passphrase)
+{
+ DBusMessage *message, *reply;
+ DBusMessageIter array, dict;
+ DBusError error;
+
+ DBG("task %p", task);
+
+ if (task->netpath == NULL)
+ return -EINVAL;
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, task->netpath,
+ SUPPLICANT_INTF ".Network", "set");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_message_iter_init_append(message, &array);
+
+ dbus_message_iter_open_container(&array, 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);
+
+ if (address == NULL) {
+ dbus_uint32_t scan_ssid = 1;
+ connman_dbus_dict_append_variant(&dict, "scan_ssid",
+ DBUS_TYPE_UINT32, &scan_ssid);
+ } else
+ connman_dbus_dict_append_variant(&dict, "bssid",
+ DBUS_TYPE_STRING, &address);
+
+ connman_dbus_dict_append_array(&dict, "ssid",
+ DBUS_TYPE_BYTE, &network, len);
+
+ if (g_ascii_strcasecmp(security, "wpa") == 0 ||
+ g_ascii_strcasecmp(security, "rsn") == 0) {
+ const char *key_mgmt = "WPA-PSK";
+ connman_dbus_dict_append_variant(&dict, "key_mgmt",
+ DBUS_TYPE_STRING, &key_mgmt);
+
+ if (passphrase && strlen(passphrase) > 0)
+ connman_dbus_dict_append_variant(&dict, "psk",
+ DBUS_TYPE_STRING, &passphrase);
+ } else if (g_ascii_strcasecmp(security, "wep") == 0) {
+ const char *key_mgmt = "NONE", *index = "0";
+ connman_dbus_dict_append_variant(&dict, "key_mgmt",
+ DBUS_TYPE_STRING, &key_mgmt);
+
+ if (passphrase) {
+ int size = strlen(passphrase);
+ if (size == 10 || size == 26) {
+ unsigned char *key = malloc(13);
+ char tmp[3];
+ int i;
+ memset(tmp, 0, sizeof(tmp));
+ if (key == NULL)
+ size = 0;
+ for (i = 0; i < size / 2; i++) {
+ memcpy(tmp, passphrase + (i * 2), 2);
+ key[i] = (unsigned char) strtol(tmp,
+ NULL, 16);
+ }
+ connman_dbus_dict_append_array(&dict,
+ "wep_key0", DBUS_TYPE_BYTE,
+ &key, size / 2);
+ free(key);
+ } else
+ connman_dbus_dict_append_variant(&dict,
+ "wep_key0", DBUS_TYPE_STRING,
+ &passphrase);
+ connman_dbus_dict_append_variant(&dict, "wep_tx_keyidx",
+ DBUS_TYPE_STRING, &index);
+ }
+ } else {
+ const char *key_mgmt = "NONE";
+ connman_dbus_dict_append_variant(&dict, "key_mgmt",
+ DBUS_TYPE_STRING, &key_mgmt);
+ }
+
+ dbus_message_iter_close_container(&array, &dict);
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(connection,
+ message, -1, &error);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to set network options");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_message_unref(message);
+
+ dbus_message_unref(reply);
+
+ return 0;
+}
+
+static int initiate_scan(struct supplicant_task *task)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ DBG("task %p", task);
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
+ SUPPLICANT_INTF ".Interface", "scan");
+ if (message == NULL)
+ return -ENOMEM;
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, TIMEOUT) == FALSE) {
+ connman_error("Failed to initiate scan");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_message_unref(message);
+
+ return 0;
+}
+
+static struct {
+ char *name;
+ char *value;
+} special_ssid[] = {
+ { "<hidden>", "hidden" },
+ { "default", "linksys" },
+ { "wireless" },
+ { "linksys" },
+ { "netgear" },
+ { "dlink" },
+ { "2wire" },
+ { "compaq" },
+ { "tsunami" },
+ { "comcomcom", "3com" },
+ { "3Com", "3com" },
+ { "Symbol", "symbol" },
+ { "Motorola", "motorola" },
+ { "Wireless" , "wireless" },
+ { "WLAN", "wlan" },
+ { }
+};
+
+static char *build_group(const char *addr, const char *name,
+ const unsigned char *ssid, unsigned int ssid_len,
+ const char *mode, const char *security)
+{
+ GString *str;
+ unsigned int i;
+
+ if (addr == NULL)
+ return NULL;
+
+ str = g_string_sized_new((ssid_len * 2) + 24);
+ if (str == NULL)
+ return NULL;
+
+ for (i = 0; special_ssid[i].name; i++) {
+ if (g_strcmp0(special_ssid[i].name, name) == 0) {
+ if (special_ssid[i].value == NULL)
+ g_string_append_printf(str, "%s_%s",
+ name, addr);
+ else
+ g_string_append_printf(str, "%s_%s",
+ special_ssid[i].value, addr);
+ goto done;
+ }
+ }
+
+ if (ssid_len > 0 && ssid[0] != '\0') {
+ for (i = 0; i < ssid_len; i++)
+ g_string_append_printf(str, "%02x", ssid[i]);
+ } else
+ g_string_append_printf(str, "hidden_%s", addr);
+
+done:
+ g_string_append_printf(str, "_%s_%s", mode, security);
+
+ return g_string_free(str, FALSE);
+}
+
+static void extract_addr(DBusMessageIter *value,
+ struct supplicant_result *result)
+{
+ DBusMessageIter array;
+ struct ether_addr *eth;
+ unsigned char *addr;
+ int addr_len;
+
+ dbus_message_iter_recurse(value, &array);
+ dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
+
+ if (addr_len != 6)
+ return;
+
+ result->addr = g_try_malloc(addr_len);
+ if (result->addr == NULL)
+ return;
+
+ memcpy(result->addr, addr, addr_len);
+ result->addr_len = addr_len;
+
+ result->path = g_try_malloc0(13);
+ if (result->path == NULL)
+ return;
+
+ eth = (void *) addr;
+
+ snprintf(result->path, 13, "%02x%02x%02x%02x%02x%02x",
+ eth->ether_addr_octet[0],
+ eth->ether_addr_octet[1],
+ eth->ether_addr_octet[2],
+ eth->ether_addr_octet[3],
+ eth->ether_addr_octet[4],
+ eth->ether_addr_octet[5]);
+}
+
+static void extract_ssid(DBusMessageIter *value,
+ struct supplicant_result *result)
+{
+ DBusMessageIter array;
+ unsigned char *ssid;
+ int ssid_len;
+
+ dbus_message_iter_recurse(value, &array);
+ dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
+
+ if (ssid_len < 1)
+ return;
+
+ result->ssid = g_try_malloc(ssid_len);
+ if (result->ssid == NULL)
+ return;
+
+ memcpy(result->ssid, ssid, ssid_len);
+ result->ssid_len = ssid_len;
+
+ result->name = g_try_malloc0(ssid_len + 1);
+ if (result->name == NULL)
+ return;
+
+ memcpy(result->name, ssid, ssid_len);
+}
+
+static void extract_wpaie(DBusMessageIter *value,
+ struct supplicant_result *result)
+{
+ DBusMessageIter array;
+ unsigned char *ie;
+ int ie_len;
+
+ dbus_message_iter_recurse(value, &array);
+ dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
+
+ if (ie_len > 0)
+ result->has_wpa = TRUE;
+}
+
+static void extract_rsnie(DBusMessageIter *value,
+ struct supplicant_result *result)
+{
+ DBusMessageIter array;
+ unsigned char *ie;
+ int ie_len;
+
+ dbus_message_iter_recurse(value, &array);
+ dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
+
+ if (ie_len > 0)
+ result->has_rsn = TRUE;
+}
+
+static void extract_wpsie(DBusMessageIter *value,
+ struct supplicant_result *result)
+{
+ DBusMessageIter array;
+ unsigned char *ie;
+ int ie_len;
+
+ dbus_message_iter_recurse(value, &array);
+ dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
+
+ if (ie_len > 0)
+ result->has_wps = TRUE;
+}
+
+static void extract_capabilites(DBusMessageIter *value,
+ struct supplicant_result *result)
+{
+ dbus_message_iter_get_basic(value, &result->capabilities);
+
+ if (result->capabilities & IEEE80211_CAP_ESS)
+ result->adhoc = FALSE;
+ else if (result->capabilities & IEEE80211_CAP_IBSS)
+ result->adhoc = TRUE;
+
+ if (result->capabilities & IEEE80211_CAP_PRIVACY)
+ result->has_wep = TRUE;
+}
+
+static unsigned char calculate_strength(struct supplicant_result *result)
+{
+ if (result->quality < 0) {
+ unsigned char strength;
+
+ if (result->level > 0)
+ strength = 100 - result->level;
+ else
+ strength = 120 + result->level;
+
+ if (strength > 100)
+ strength = 100;
+
+ return strength;
+ }
+
+ return result->quality;
+}
+
+static unsigned short calculate_channel(struct supplicant_result *result)
+{
+ if (result->frequency < 0)
+ return 0;
+
+ return (result->frequency - 2407) / 5;
+}
+
+static void get_properties(struct supplicant_task *task);
+
+static void properties_reply(DBusPendingCall *call, void *user_data)
+{
+ struct supplicant_task *task = user_data;
+ struct supplicant_result result;
+ struct connman_network *network;
+ DBusMessage *reply;
+ DBusMessageIter array, dict;
+ unsigned char strength;
+ unsigned short channel, frequency;
+ const char *mode, *security;
+ char *group;
+
+ DBG("task %p", task);
+
+ reply = dbus_pending_call_steal_reply(call);
+ if (reply == NULL) {
+ get_properties(task);
+ return;
+ }
+
+ if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
+ dbus_message_unref(reply);
+ get_properties(task);
+ return;
+ }
+
+ memset(&result, 0, sizeof(result));
+ result.frequency = -1;
+ result.quality = -1;
+ result.level = 0;
+ result.noise = 0;
+
+ dbus_message_iter_init(reply, &array);
+
+ dbus_message_iter_recurse(&array, &dict);
+
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+ const char *key;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+
+ dbus_message_iter_recurse(&entry, &value);
+
+ //type = dbus_message_iter_get_arg_type(&value);
+ //dbus_message_iter_get_basic(&value, &val);
+
+ /*
+ * bssid : a (97)
+ * ssid : a (97)
+ * wpaie : a (97)
+ * rsnie : a (97)
+ * wpsie : a (97)
+ * frequency : i (105)
+ * capabilities : q (113)
+ * quality : i (105)
+ * noise : i (105)
+ * level : i (105)
+ * maxrate : i (105)
+ */
+
+ if (g_str_equal(key, "bssid") == TRUE)
+ extract_addr(&value, &result);
+ else if (g_str_equal(key, "ssid") == TRUE)
+ extract_ssid(&value, &result);
+ else if (g_str_equal(key, "wpaie") == TRUE)
+ extract_wpaie(&value, &result);
+ else if (g_str_equal(key, "rsnie") == TRUE)
+ extract_rsnie(&value, &result);
+ else if (g_str_equal(key, "wpsie") == TRUE)
+ extract_wpsie(&value, &result);
+ else if (g_str_equal(key, "capabilities") == TRUE)
+ extract_capabilites(&value, &result);
+ else if (g_str_equal(key, "frequency") == TRUE)
+ dbus_message_iter_get_basic(&value, &result.frequency);
+ else if (g_str_equal(key, "quality") == TRUE)
+ dbus_message_iter_get_basic(&value, &result.quality);
+ else if (g_str_equal(key, "noise") == TRUE)
+ dbus_message_iter_get_basic(&value, &result.noise);
+ else if (g_str_equal(key, "level") == TRUE)
+ dbus_message_iter_get_basic(&value, &result.level);
+ else if (g_str_equal(key, "maxrate") == TRUE)
+ dbus_message_iter_get_basic(&value, &result.maxrate);
+
+ dbus_message_iter_next(&dict);
+ }
+
+ if (result.path == NULL)
+ goto done;
+
+ if (result.path[0] == '\0')
+ goto done;
+
+ if (result.frequency > 0 && result.frequency < 14)
+ result.frequency = 2407 + (5 * result.frequency);
+ else if (result.frequency == 14)
+ result.frequency = 2484;
+
+ strength = calculate_strength(&result);
+ channel = calculate_channel(&result);
+
+ frequency = (result.frequency < 0) ? 0 : result.frequency;
+
+ if (result.has_rsn == TRUE)
+ security = "rsn";
+ else if (result.has_wpa == TRUE)
+ security = "wpa";
+ else if (result.has_wep == TRUE)
+ security = "wep";
+ else
+ security = "none";
+
+ mode = (result.adhoc == TRUE) ? "adhoc" : "managed";
+
+ group = build_group(result.path, result.name,
+ result.ssid, result.ssid_len,
+ mode, security);
+
+ network = connman_device_get_network(task->device, result.path);
+ if (network == NULL) {
+ int index;
+
+ network = connman_network_create(result.path,
+ CONNMAN_NETWORK_TYPE_WIFI);
+ if (network == NULL)
+ goto done;
+
+ index = connman_device_get_index(task->device);
+ connman_network_set_index(network, index);
+
+ connman_network_set_protocol(network,
+ CONNMAN_NETWORK_PROTOCOL_IP);
+
+ connman_network_set_address(network, result.addr,
+ result.addr_len);
+
+ if (connman_device_add_network(task->device, network) < 0) {
+ connman_network_unref(network);
+ goto done;
+ }
+ }
+
+ if (result.name != NULL && result.name[0] != '\0')
+ connman_network_set_name(network, result.name);
+
+ connman_network_set_blob(network, "WiFi.SSID",
+ result.ssid, result.ssid_len);
+
+ connman_network_set_string(network, "WiFi.Mode", mode);
+
+ DBG("%s (%s %s) strength %d (%s)",
+ result.name, mode, security, strength,
+ (result.has_wps == TRUE) ? "WPS" : "no WPS");
+
+ connman_network_set_available(network, TRUE);
+ connman_network_set_strength(network, strength);
+
+ connman_network_set_uint16(network, "Frequency", frequency);
+ connman_network_set_uint16(network, "WiFi.Channel", channel);
+ connman_network_set_string(network, "WiFi.Security", security);
+
+ connman_network_set_group(network, group);
+
+ g_free(group);
+
+done:
+ g_free(result.path);
+ g_free(result.addr);
+ g_free(result.name);
+ g_free(result.ssid);
+
+ dbus_message_unref(reply);
+
+ get_properties(task);
+}
+
+static void get_properties(struct supplicant_task *task)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+ char *path;
+
+ path = g_slist_nth_data(task->scan_results, 0);
+ if (path == NULL)
+ goto noscan;
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, path,
+ SUPPLICANT_INTF ".BSSID",
+ "properties");
+
+ task->scan_results = g_slist_remove(task->scan_results, path);
+ g_free(path);
+
+ if (message == NULL)
+ goto noscan;
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, TIMEOUT) == FALSE) {
+ connman_error("Failed to get network properties");
+ dbus_message_unref(message);
+ goto noscan;
+ }
+
+ if (call == NULL) {
+ connman_error("D-Bus connection not available");
+ dbus_message_unref(message);
+ goto noscan;
+ }
+
+ dbus_pending_call_set_notify(call, properties_reply, task, NULL);
+
+ dbus_message_unref(message);
+
+ return;
+
+noscan:
+ if (task->noscan == FALSE)
+ connman_device_set_scanning(task->device, FALSE);
+}
+
+static void scan_results_reply(DBusPendingCall *call, void *user_data)
+{
+ struct supplicant_task *task = user_data;
+ DBusMessage *reply;
+ DBusError error;
+ char **results;
+ int i, num_results;
+
+ DBG("task %p", task);
+
+ reply = dbus_pending_call_steal_reply(call);
+ if (reply == NULL)
+ goto noscan;
+
+ if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
+ goto done;
+
+ dbus_error_init(&error);
+
+ if (dbus_message_get_args(reply, &error,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
+ &results, &num_results,
+ DBUS_TYPE_INVALID) == FALSE) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Wrong arguments for scan result");
+ goto done;
+ }
+
+ if (num_results == 0)
+ goto done;
+
+ for (i = 0; i < num_results; i++) {
+ char *path = g_strdup(results[i]);
+ if (path == NULL)
+ continue;
+
+ task->scan_results = g_slist_append(task->scan_results, path);
+ }
+
+ g_strfreev(results);
+
+ dbus_message_unref(reply);
+
+ get_properties(task);
+
+ return;
+
+done:
+ dbus_message_unref(reply);
+
+noscan:
+ if (task->noscan == FALSE)
+ connman_device_set_scanning(task->device, FALSE);
+}
+
+static void scan_results_available(struct supplicant_task *task)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ DBG("task %p", task);
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
+ SUPPLICANT_INTF ".Interface",
+ "scanResults");
+ if (message == NULL)
+ return;
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, TIMEOUT) == FALSE) {
+ connman_error("Failed to request scan result");
+ goto done;
+ }
+
+ if (task->noscan == FALSE)
+ connman_device_set_scanning(task->device, TRUE);
+
+ if (call == NULL) {
+ connman_error("D-Bus connection not available");
+ goto done;
+ }
+
+ dbus_pending_call_set_notify(call, scan_results_reply, task, NULL);
+
+done:
+ dbus_message_unref(message);
+}
+
+static enum supplicant_state string2state(const char *state)
+{
+ if (g_str_equal(state, "INACTIVE") == TRUE)
+ return WPA_INACTIVE;
+ else if (g_str_equal(state, "SCANNING") == TRUE)
+ return WPA_SCANNING;
+ else if (g_str_equal(state, "ASSOCIATING") == TRUE)
+ return WPA_ASSOCIATING;
+ else if (g_str_equal(state, "ASSOCIATED") == TRUE)
+ return WPA_ASSOCIATED;
+ else if (g_str_equal(state, "GROUP_HANDSHAKE") == TRUE)
+ return WPA_GROUP_HANDSHAKE;
+ else if (g_str_equal(state, "4WAY_HANDSHAKE") == TRUE)
+ return WPA_4WAY_HANDSHAKE;
+ else if (g_str_equal(state, "COMPLETED") == TRUE)
+ return WPA_COMPLETED;
+ else if (g_str_equal(state, "DISCONNECTED") == TRUE)
+ return WPA_DISCONNECTED;
+ else
+ return WPA_INVALID;
+}
+
+static void state_change(struct supplicant_task *task, DBusMessage *msg)
+{
+ DBusError error;
+ const char *newstate, *oldstate;
+ enum supplicant_state state;
+
+ dbus_error_init(&error);
+
+ if (dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &newstate,
+ DBUS_TYPE_STRING, &oldstate,
+ DBUS_TYPE_INVALID) == FALSE) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Wrong arguments for state change");
+ return;
+ }
+
+ DBG("state %s ==> %s", oldstate, newstate);
+
+ state = string2state(newstate);
+ if (state == WPA_INVALID)
+ return;
+
+ task->state = state;
+
+ switch (task->state) {
+ case WPA_SCANNING:
+ task->noscan = TRUE;
+ connman_device_set_scanning(task->device, TRUE);
+ break;
+ case WPA_ASSOCIATING:
+ case WPA_ASSOCIATED:
+ case WPA_4WAY_HANDSHAKE:
+ case WPA_GROUP_HANDSHAKE:
+ task->noscan = TRUE;
+ break;
+ case WPA_COMPLETED:
+ case WPA_DISCONNECTED:
+ task->noscan = FALSE;
+ break;
+ case WPA_INACTIVE:
+ task->noscan = FALSE;
+ connman_device_set_scanning(task->device, FALSE);
+ break;
+ case WPA_INVALID:
+ break;
+ }
+
+ if (task->network == NULL)
+ return;
+
+ switch (task->state) {
+ case WPA_COMPLETED:
+ /* carrier on */
+ connman_network_set_connected(task->network, TRUE);
+ connman_device_set_scanning(task->device, FALSE);
+ break;
+ case WPA_DISCONNECTED:
+ /* carrier off */
+ connman_network_set_connected(task->network, FALSE);
+ connman_device_set_scanning(task->device, FALSE);
+ break;
+ case WPA_ASSOCIATING:
+ connman_network_set_associating(task->network, TRUE);
+ break;
+ default:
+ connman_network_set_associating(task->network, FALSE);
+ break;
+ }
+}
+
+static DBusHandlerResult supplicant_filter(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct supplicant_task *task;
+ const char *member, *path;
+
+ if (dbus_message_has_interface(msg,
+ SUPPLICANT_INTF ".Interface") == FALSE)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ member = dbus_message_get_member(msg);
+ if (member == NULL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ path = dbus_message_get_path(msg);
+ if (path == NULL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ task = find_task_by_path(path);
+ if (task == NULL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ DBG("task %p member %s", task, member);
+
+ if (g_str_equal(member, "ScanResultsAvailable") == TRUE)
+ scan_results_available(task);
+ else if (g_str_equal(member, "StateChange") == TRUE)
+ state_change(task, msg);
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+int supplicant_start(struct connman_device *device)
+{
+ struct supplicant_task *task;
+
+ DBG("device %p", device);
+
+ task = g_try_new0(struct supplicant_task, 1);
+ if (task == NULL)
+ return -ENOMEM;
+
+ task->ifindex = connman_device_get_index(device);
+ task->ifname = connman_inet_ifname(task->ifindex);
+
+ if (task->ifname == NULL) {
+ g_free(task);
+ return -ENOMEM;
+ }
+
+ task->device = connman_device_ref(device);
+
+ task->created = FALSE;
+ task->noscan = FALSE;
+ task->state = WPA_INVALID;
+
+ task_list = g_slist_append(task_list, task);
+
+ return create_interface(task);
+}
+
+int supplicant_stop(struct connman_device *device)
+{
+ int index = connman_device_get_index(device);
+ struct supplicant_task *task;
+
+ DBG("device %p", device);
+
+ task = find_task_by_index(index);
+ if (task == NULL)
+ return -ENODEV;
+
+ task_list = g_slist_remove(task_list, task);
+
+ disable_network(task);
+
+ remove_network(task);
+
+ return remove_interface(task);
+}
+
+int supplicant_scan(struct connman_device *device)
+{
+ int index = connman_device_get_index(device);
+ struct supplicant_task *task;
+ int err;
+
+ DBG("device %p", device);
+
+ task = find_task_by_index(index);
+ if (task == NULL)
+ return -ENODEV;
+
+ switch (task->state) {
+ case WPA_SCANNING:
+ return -EALREADY;
+ case WPA_ASSOCIATING:
+ case WPA_ASSOCIATED:
+ case WPA_4WAY_HANDSHAKE:
+ case WPA_GROUP_HANDSHAKE:
+ return -EBUSY;
+ default:
+ break;
+ }
+
+ err = initiate_scan(task);
+
+ return 0;
+}
+
+int supplicant_connect(struct connman_network *network)
+{
+ struct supplicant_task *task;
+ const char *address, *security, *passphrase;
+ const void *ssid;
+ unsigned int ssid_len;
+ int index;
+
+ DBG("network %p", network);
+
+ address = connman_network_get_string(network, "Address");
+ security = connman_network_get_string(network, "WiFi.Security");
+ passphrase = connman_network_get_string(network, "WiFi.Passphrase");
+
+ ssid = connman_network_get_blob(network, "WiFi.SSID", &ssid_len);
+
+ DBG("address %s security %s passphrase %s",
+ address, security, passphrase);
+
+ if (security == NULL && passphrase == NULL)
+ return -EINVAL;
+
+ if (g_str_equal(security, "none") == FALSE && passphrase == NULL)
+ return -EINVAL;
+
+ index = connman_network_get_index(network);
+
+ task = find_task_by_index(index);
+ if (task == NULL)
+ return -ENODEV;
+
+ task->network = connman_network_ref(network);
+
+ add_network(task);
+
+ select_network(task);
+ disable_network(task);
+
+ set_network(task, ssid, ssid_len, address, security, passphrase);
+
+ enable_network(task);
+
+ connman_network_set_associating(task->network, TRUE);
+
+ return 0;
+}
+
+int supplicant_disconnect(struct connman_network *network)
+{
+ struct supplicant_task *task;
+ int index;
+
+ DBG("network %p", network);
+
+ index = connman_network_get_index(network);
+
+ task = find_task_by_index(index);
+ if (task == NULL)
+ return -ENODEV;
+
+ disable_network(task);
+
+ remove_network(task);
+
+ connman_network_set_connected(task->network, FALSE);
+
+ connman_network_unref(task->network);
+
+ return 0;
+}
+
+static void supplicant_activate(DBusConnection *conn)
+{
+ DBusMessage *message;
+
+ DBG("conn %p", conn);
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, "/",
+ DBUS_INTERFACE_INTROSPECTABLE, "Introspect");
+ if (message == NULL)
+ return;
+
+ dbus_message_set_no_reply(message, TRUE);
+
+ dbus_connection_send(conn, message, NULL);
+
+ dbus_message_unref(message);
+}
+
+static GSList *driver_list = NULL;
+
+static void supplicant_probe(DBusConnection *conn, void *user_data)
+{
+ GSList *list;
+
+ DBG("conn %p", conn);
+
+ for (list = driver_list; list; list = list->next) {
+ struct supplicant_driver *driver = list->data;
+
+ DBG("driver %p name %s", driver, driver->name);
+
+ if (driver->probe)
+ driver->probe();
+ }
+}
+
+static void supplicant_remove(DBusConnection *conn, void *user_data)
+{
+ GSList *list;
+
+ DBG("conn %p", conn);
+
+ for (list = driver_list; list; list = list->next) {
+ struct supplicant_driver *driver = list->data;
+
+ DBG("driver %p name %s", driver, driver->name);
+
+ if (driver->remove)
+ driver->remove();
+ }
+}
+
+static const char *supplicant_rule = "type=signal,"
+ "interface=" SUPPLICANT_INTF ".Interface";
+static guint watch;
+
+static int supplicant_create(void)
+{
+ if (g_slist_length(driver_list) > 0)
+ return 0;
+
+ connection = connman_dbus_get_connection();
+ if (connection == NULL)
+ return -EIO;
+
+ DBG("connection %p", connection);
+
+ if (dbus_connection_add_filter(connection,
+ supplicant_filter, NULL, NULL) == FALSE) {
+ connection = connman_dbus_get_connection();
+ return -EIO;
+ }
+
+ dbus_bus_add_match(connection, supplicant_rule, NULL);
+ dbus_connection_flush(connection);
+
+ watch = g_dbus_add_service_watch(connection, SUPPLICANT_NAME,
+ supplicant_probe, supplicant_remove, NULL, NULL);
+
+ return 0;
+}
+
+static void supplicant_destroy(void)
+{
+ if (g_slist_length(driver_list) > 0)
+ return;
+
+ DBG("connection %p", connection);
+
+ if (watch > 0)
+ g_dbus_remove_watch(connection, watch);
+
+ dbus_bus_remove_match(connection, supplicant_rule, NULL);
+ dbus_connection_flush(connection);
+
+ dbus_connection_remove_filter(connection, supplicant_filter, NULL);
+
+ dbus_connection_unref(connection);
+ connection = NULL;
+}
+
+int supplicant_register(struct supplicant_driver *driver)
+{
+ int err;
+
+ DBG("driver %p name %s", driver, driver->name);
+
+ err = supplicant_create();
+ if (err < 0)
+ return err;
+
+ driver_list = g_slist_append(driver_list, driver);
+
+ if (g_dbus_check_service(connection, SUPPLICANT_NAME) == TRUE)
+ supplicant_probe(connection, NULL);
+ else
+ supplicant_activate(connection);
+
+ return 0;
+}
+
+void supplicant_unregister(struct supplicant_driver *driver)
+{
+ DBG("driver %p name %s", driver, driver->name);
+
+ supplicant_remove(connection, NULL);
+
+ driver_list = g_slist_remove(driver_list, driver);
+
+ supplicant_destroy();
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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
+ *
+ */
+
+#include <connman/device.h>
+#include <connman/network.h>
+
+struct supplicant_driver {
+ const char *name;
+ void (*probe) (void);
+ void (*remove) (void);
+};
+
+int supplicant_register(struct supplicant_driver *driver);
+void supplicant_unregister(struct supplicant_driver *driver);
+
+int supplicant_start(struct connman_device *device);
+int supplicant_stop(struct connman_device *device);
+int supplicant_scan(struct connman_device *device);
+
+int supplicant_connect(struct connman_network *network);
+int supplicant_disconnect(struct connman_network *network);
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <unistd.h>
+#include <sys/wait.h>
+
+#include <glib.h>
+
+#include <connman/log.h>
+
+#include "task.h"
+
+struct task_data {
+ pid_t pid;
+ int index;
+ task_cb_t callback;
+ void *user_data;
+};
+
+static GSList *task_list = NULL;
+
+struct task_data *task_find_by_pid(pid_t pid)
+{
+ GSList *list;
+
+ for (list = task_list; list; list = list->next) {
+ struct task_data *task = list->data;
+
+ if (task->pid == pid)
+ return task;
+ }
+
+ return NULL;
+}
+
+struct task_data *task_find_by_index(int index)
+{
+ GSList *list;
+
+ for (list = task_list; list; list = list->next) {
+ struct task_data *task = list->data;
+
+ if (task->index == index)
+ return task;
+ }
+
+ return NULL;
+}
+
+static void task_died(GPid pid, gint status, gpointer user_data)
+{
+ struct task_data *task = user_data;
+
+ if (WIFEXITED(status))
+ DBG("task %p exit status %d", task, WEXITSTATUS(status));
+ else
+ DBG("task %p signal %d", task, WTERMSIG(status));
+
+ g_spawn_close_pid(pid);
+ task->pid = 0;
+
+ task_list = g_slist_remove(task_list, task);
+
+ if (task->callback)
+ task->callback(task->index, task->user_data);
+
+ g_free(task);
+}
+
+static void task_setup(gpointer user_data)
+{
+ struct task_data *task = user_data;
+
+ DBG("task %p", task);
+}
+
+struct task_data *task_spawn(int index, char **argv, char **envp,
+ task_cb_t callback, void *user_data)
+{
+ GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD |
+ G_SPAWN_STDOUT_TO_DEV_NULL;
+ struct task_data *task;
+
+ DBG("index %d", index);
+
+ task = g_try_new0(struct task_data, 1);
+ if (task == NULL)
+ return NULL;
+
+ task->index = index;
+
+ task->callback = callback;
+ task->user_data = user_data;
+
+ if (g_spawn_async(NULL, argv, envp, flags,
+ task_setup, task, &task->pid, NULL) == FALSE) {
+ connman_error("Failed to spawn task");
+ return NULL;
+ }
+
+ task_list = g_slist_append(task_list, task);
+
+ g_child_watch_add(task->pid, task_died, task);
+
+ DBG("task %p pid %d", task, task->pid);
+
+ return task;
+}
+
+int task_kill(struct task_data *task)
+{
+ DBG("task %p", task);
+
+ if (task->pid > 0)
+ kill(task->pid, SIGTERM);
+
+ return 0;
+}
+
+void *task_get_data(struct task_data *task)
+{
+ return task->user_data;
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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
+ *
+ */
+
+#include <sys/types.h>
+
+struct task_data;
+
+typedef void (* task_cb_t) (int index, void *user_data);
+
+struct task_data *task_find_by_pid(pid_t pid);
+struct task_data *task_find_by_index(int index);
+
+struct task_data *task_spawn(int index, char **argv, char **envp,
+ task_cb_t callback, void *user_data);
+int task_kill(struct task_data *task);
+
+void *task_get_data(struct task_data *task);
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <unistd.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/driver.h>
+#include <connman/inet.h>
+#include <connman/dbus.h>
+#include <connman/log.h>
+
+#include "task.h"
+
+#define UDHCPC_INTF "net.busybox.udhcpc"
+#define UDHCPC_PATH "/net/busybox/udhcpc"
+
+static int udhcp_probe(struct connman_element *element)
+{
+ struct task_data *task;
+ char *argv[9], *envp[2], *ifname;
+ char pidfile[PATH_MAX], script[PATH_MAX];
+
+ DBG("element %p name %s", element, element->name);
+
+ if (access(UDHCPC, X_OK) < 0)
+ return -errno;
+
+ ifname = connman_inet_ifname(element->index);
+ if (ifname == NULL)
+ return -ENOMEM;
+
+ snprintf(pidfile, sizeof(pidfile) - 1,
+ "%s/udhcpc.%s.pid", STATEDIR, ifname);
+ snprintf(script, sizeof(script) - 1, "%s/udhcpc-script", SCRIPTDIR);
+
+ argv[0] = UDHCPC;
+ argv[1] = "-f";
+ argv[2] = "-i";
+ argv[3] = ifname;
+ argv[4] = "-p";
+ argv[5] = pidfile;
+ argv[6] = "-s";
+ argv[7] = script;
+ argv[8] = NULL;
+
+ envp[0] = NULL;
+
+ task = task_spawn(element->index, argv, envp, NULL, element);
+ if (task == NULL) {
+ g_free(ifname);
+ return -EIO;
+ }
+
+ g_free(ifname);
+
+ return 0;
+}
+
+static void udhcp_remove(struct connman_element *element)
+{
+ struct task_data *task;
+
+ DBG("element %p name %s", element, element->name);
+
+ task = task_find_by_index(element->index);
+ if (task == NULL)
+ return;
+
+ task_kill(task);
+}
+
+static struct connman_driver udhcp_driver = {
+ .name = "udhcp",
+ .type = CONNMAN_ELEMENT_TYPE_DHCP,
+ .priority = CONNMAN_DRIVER_PRIORITY_HIGH,
+ .probe = udhcp_probe,
+ .remove = udhcp_remove,
+};
+
+static void udhcp_bound(DBusMessage *msg, gboolean renew)
+{
+ struct task_data *task;
+ struct connman_element *element, *parent;
+ const char *interface, *address, *netmask, *broadcast, *gateway, *dns;
+ int index;
+
+ dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &interface,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_STRING, &netmask,
+ DBUS_TYPE_STRING, &broadcast,
+ DBUS_TYPE_STRING, &gateway,
+ DBUS_TYPE_STRING, &dns,
+ DBUS_TYPE_INVALID);
+
+ DBG("%s ==> address %s gateway %s", interface, address, gateway);
+
+ index = connman_inet_ifindex(interface);
+ if (index < 0)
+ return;
+
+ task = task_find_by_index(index);
+ if (task == NULL)
+ return;
+
+ parent = task_get_data(task);
+ if (parent == NULL)
+ return;
+
+ g_free(parent->ipv4.address);
+ parent->ipv4.address = g_strdup(address);
+
+ g_free(parent->ipv4.netmask);
+ parent->ipv4.netmask = g_strdup(netmask);
+
+ g_free(parent->ipv4.broadcast);
+ parent->ipv4.broadcast = g_strdup(broadcast);
+
+ g_free(parent->ipv4.gateway);
+ parent->ipv4.gateway = g_strdup(gateway);
+
+ g_free(parent->ipv4.nameserver);
+ parent->ipv4.nameserver = g_strdup(dns);
+
+ connman_element_update(parent);
+
+ if (renew == TRUE)
+ return;
+
+ element = connman_element_create(NULL);
+ if (element == NULL)
+ return;
+
+ element->type = CONNMAN_ELEMENT_TYPE_IPV4;
+ element->index = index;
+
+ if (connman_element_register(element, parent) < 0)
+ connman_element_unref(element);
+}
+
+static DBusHandlerResult udhcp_filter(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ if (dbus_message_is_method_call(msg, UDHCPC_INTF, "bound") == TRUE) {
+ udhcp_bound(msg, FALSE);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ if (dbus_message_is_method_call(msg, UDHCPC_INTF, "renew") == TRUE) {
+ udhcp_bound(msg, TRUE);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusConnection *connection;
+
+static const char *udhcp_rule = "path=" UDHCPC_PATH ",interface=" UDHCPC_INTF;
+
+static int udhcp_init(void)
+{
+ int err;
+
+ connection = connman_dbus_get_connection();
+
+ dbus_connection_add_filter(connection, udhcp_filter, NULL, NULL);
+
+ dbus_bus_add_match(connection, udhcp_rule, NULL);
+
+ err = connman_driver_register(&udhcp_driver);
+ if (err < 0) {
+ dbus_connection_unref(connection);
+ return err;
+ }
+
+ return 0;
+}
+
+static void udhcp_exit(void)
+{
+ connman_driver_unregister(&udhcp_driver);
+
+ dbus_bus_remove_match(connection, udhcp_rule, NULL);
+
+ dbus_connection_remove_filter(connection, udhcp_filter, NULL);
+
+ dbus_connection_unref(connection);
+}
+
+CONNMAN_PLUGIN_DEFINE(udhcp, "uDHCP client plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, udhcp_init, udhcp_exit)
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+
+#include <dbus/dbus.h>
+#include <glib.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/device.h>
+#include <connman/log.h>
+
+#include "supplicant.h"
+
+#define CLEANUP_TIMEOUT 8 /* in seconds */
+#define INACTIVE_TIMEOUT 12 /* in seconds */
+
+struct wifi_data {
+ char *identifier;
+ connman_bool_t connected;
+};
+
+static int network_probe(struct connman_network *network)
+{
+ DBG("network %p", network);
+
+ return 0;
+}
+
+static void network_remove(struct connman_network *network)
+{
+ DBG("network %p", network);
+}
+
+static int network_connect(struct connman_network *network)
+{
+ DBG("network %p", network);
+
+ return supplicant_connect(network);
+}
+
+static int network_disconnect(struct connman_network *network)
+{
+ DBG("network %p", network);
+
+ return supplicant_disconnect(network);
+}
+
+static struct connman_network_driver network_driver = {
+ .name = "wifi",
+ .type = CONNMAN_NETWORK_TYPE_WIFI,
+ .probe = network_probe,
+ .remove = network_remove,
+ .connect = network_connect,
+ .disconnect = network_disconnect,
+};
+
+static int wifi_probe(struct connman_device *device)
+{
+ struct wifi_data *data;
+
+ DBG("device %p", device);
+
+ data = g_try_new0(struct wifi_data, 1);
+ if (data == NULL)
+ return -ENOMEM;
+
+ data->connected = FALSE;
+
+ connman_device_set_data(device, data);
+
+ return 0;
+}
+
+static void wifi_remove(struct connman_device *device)
+{
+ struct wifi_data *data = connman_device_get_data(device);
+
+ DBG("device %p", device);
+
+ connman_device_set_data(device, NULL);
+
+ g_free(data->identifier);
+ g_free(data);
+}
+
+static int wifi_enable(struct connman_device *device)
+{
+ DBG("device %p", device);
+
+ return supplicant_start(device);
+}
+
+static int wifi_disable(struct connman_device *device)
+{
+ struct wifi_data *data = connman_device_get_data(device);
+
+ DBG("device %p", device);
+
+ data->connected = FALSE;
+
+ return supplicant_stop(device);
+}
+
+static int wifi_scan(struct connman_device *device)
+{
+ DBG("device %p", device);
+
+ return supplicant_scan(device);
+}
+
+static int wifi_join(struct connman_device *device,
+ struct connman_network *network)
+{
+ int err;
+
+ DBG("device %p", device);
+
+ err = supplicant_connect(network);
+ if (err < 0)
+ return err;
+
+ connman_network_ref(network);
+
+ connman_device_add_network(device, network);
+
+ connman_network_set_available(network, TRUE);
+
+ return 0;
+}
+
+static struct connman_device_driver wifi_driver = {
+ .name = "wifi",
+ .type = CONNMAN_DEVICE_TYPE_WIFI,
+ .probe = wifi_probe,
+ .remove = wifi_remove,
+ .enable = wifi_enable,
+ .disable = wifi_disable,
+ .scan = wifi_scan,
+ .join = wifi_join,
+};
+
+static void wifi_register(void)
+{
+ DBG("");
+
+ if (connman_device_driver_register(&wifi_driver) < 0)
+ connman_error("Failed to register WiFi driver");
+}
+
+static void wifi_unregister(void)
+{
+ DBG("");
+
+ connman_device_driver_unregister(&wifi_driver);
+}
+
+static struct supplicant_driver supplicant = {
+ .name = "wifi",
+ .probe = wifi_register,
+ .remove = wifi_unregister,
+};
+
+static int wifi_init(void)
+{
+ int err;
+
+ err = connman_network_driver_register(&network_driver);
+ if (err < 0)
+ return err;
+
+ err = supplicant_register(&supplicant);
+ if (err < 0) {
+ connman_network_driver_unregister(&network_driver);
+ return err;
+ }
+
+ return 0;
+}
+
+static void wifi_exit(void)
+{
+ supplicant_unregister(&supplicant);
+
+ connman_network_driver_unregister(&network_driver);
+}
+
+CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, wifi_init, wifi_exit)
--- /dev/null
+
+initdir = $(sysconfdir)/init.d
+
+init_SCRIPTS = connman
+
+DISTCLEANFILES = $(init_SCRIPTS)
+
+scriptdir = $(libdir)/connman/scripts
+
+script_DATA =
+script_PROGRAMS =
+script_LTLIBRARIES =
+
+if UDHCP
+script_PROGRAMS += udhcpc-script
+
+udhcpc_script_LDADD = @DBUS_LIBS@
+endif
+
+if DHCLIENT
+script_DATA += dhclient.conf
+script_PROGRAMS += dhclient-script
+
+dhclient_script_LDADD = @DBUS_LIBS@
+endif
+
+if PPPD
+script_LTLIBRARIES += pppd-plugin.la
+
+pppd_plugin_la_LDFLAGS = -module -avoid-version
+endif
+
+AM_CFLAGS = @DBUS_CFLAGS@
+
+EXTRA_DIST = dhclient.conf
+
+MAINTAINERCLEANFILES = Makefile.in
--- /dev/null
+#!/bin/sh
+
+DAEMON=@prefix@/sbin/connmand
+DESC="Connection Manager"
+
+. /lib/lsb/init-functions
+
+if [ -f @sysconfdir@/default/connman ] ; then
+ . @sysconfdir@/default/connman
+fi
+
+set -e
+
+do_start() {
+ start-stop-daemon --start --oknodo --exec $DAEMON -- $DAEMON_OPTS
+}
+
+do_stop() {
+ start-stop-daemon --stop --oknodo --quiet --exec $DAEMON
+}
+
+case "$1" in
+ start)
+ log_daemon_msg "Starting $DESC"
+ do_start
+ log_end_msg $?
+ ;;
+ stop)
+ log_daemon_msg "Stopping $DESC"
+ do_stop
+ log_end_msg $?
+ ;;
+ restart|force-reload)
+ log_daemon_msg "Restarting $DESC"
+ do_stop
+ sleep 1
+ do_start
+ log_end_msg $?
+ ;;
+ *)
+ log_success_msg "Usage: $0 {start|stop|restart|force-reload}" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <string.h>
+
+#include <dbus/dbus.h>
+
+#define DHCLIENT_INTF "org.isc.dhclient"
+#define DHCLIENT_PATH "/org/isc/dhclient"
+
+extern char **environ;
+
+static void append(DBusMessageIter *dict, const char *pattern)
+{
+ DBusMessageIter entry;
+ const char *key, *value;
+ char *delim;
+
+ delim = strchr(pattern, '=');
+ *delim = '\0';
+
+ key = pattern;
+ value = delim + 1;
+
+ 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_append_basic(&entry, DBUS_TYPE_STRING, &value);
+
+ dbus_message_iter_close_container(dict, &entry);
+}
+
+int main(int argc, char *argv[])
+{
+ DBusConnection *conn;
+ DBusError error;
+ DBusMessage *msg;
+ DBusMessageIter iter, dict;
+ dbus_uint32_t pid;
+ char **envp, *busname, *reason, *interface;
+
+ busname = getenv("BUSNAME");
+
+ pid = atoi(getenv("pid"));
+ reason = getenv("reason");
+ interface = getenv("interface");
+
+ dbus_error_init(&error);
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
+ if (conn == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ fprintf(stderr, "%s\n", error.message);
+ dbus_error_free(&error);
+ } else
+ fprintf(stderr, "Failed to get on system bus\n");
+ return 0;
+ }
+
+ msg = dbus_message_new_method_call(busname, DHCLIENT_PATH,
+ DHCLIENT_INTF, "notify");
+ if (msg == NULL) {
+ dbus_connection_unref(conn);
+ fprintf(stderr, "Failed to allocate method call\n");
+ return 0;
+ }
+
+ dbus_message_set_no_reply(msg, TRUE);
+
+ dbus_message_append_args(msg, DBUS_TYPE_UINT32, &pid,
+ DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID);
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ 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);
+
+ for (envp = environ; envp && *envp; envp++) {
+ if (strlen(*envp) < 5)
+ continue;
+
+ if (strncmp(*envp, "new_", 4) == 0 ||
+ strncmp(*envp, "old_", 4) == 0 ||
+ strncmp(*envp, "alia", 4) == 0)
+ append(&dict, *envp);
+ }
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ if (dbus_connection_send(conn, msg, NULL) == FALSE)
+ fprintf(stderr, "Failed to send message\n");
+
+ dbus_connection_flush(conn);
+
+ dbus_message_unref(msg);
+
+ dbus_connection_unref(conn);
+
+ return 0;
+}
--- /dev/null
+send host-name "<hostname>";
+request subnet-mask, broadcast-address, time-offset, routers,
+ domain-name, domain-name-servers, host-name;
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <pppd/pppd.h>
+#include <pppd/fsm.h>
+#include <pppd/ipcp.h>
+
+static void notifier_phasechange(void *data, int arg)
+{
+ printf("phasechange: data %p arg %d\n", data, arg);
+}
+
+static void notifier_exit(void *data, int arg)
+{
+ printf("exitnotify: data %p arg %d\n", data, arg);
+}
+
+static void notifier_ipup(void *data, int arg)
+{
+ ipcp_options opts = ipcp_gotoptions[0];
+ ipcp_options peer = ipcp_hisoptions[0];
+
+ printf("ipup: data %p arg %d\n", data, arg);
+
+ printf("%s: %s -> %s\n", ifname,
+ inet_ntoa(*((struct in_addr *) &opts.ouraddr)),
+ inet_ntoa(*((struct in_addr *) &peer.hisaddr)));
+
+ script_unsetenv("USEPEERDNS");
+ script_unsetenv("DNS1");
+ script_unsetenv("DNS2");
+}
+
+static void notifier_ipdown(void *data, int arg)
+{
+ printf("ipdown: data %p arg %d\n", data, arg);
+}
+
+char pppd_version[] = VERSION;
+
+int plugin_init(void);
+
+int plugin_init(void)
+{
+#if 0
+ path_ipup[0] = '\0';
+ path_ipdown[0] = '\0';
+#endif
+
+ add_notifier(&phasechange, notifier_phasechange, NULL);
+ add_notifier(&exitnotify, notifier_exit, NULL);
+
+ add_notifier(&ip_up_notifier, notifier_ipup, NULL);
+ add_notifier(&ip_down_notifier, notifier_ipdown, NULL);
+
+ return 0;
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <string.h>
+
+#include <dbus/dbus.h>
+
+#define UDHCPC_INTF "net.busybox.udhcpc"
+#define UDHCPC_PATH "/net/busybox/udhcpc"
+
+int main(int argc, char *argv[])
+{
+ DBusConnection *conn;
+ DBusError error;
+ DBusMessage *msg;
+ char *busname, *interface, *address, *netmask, *broadcast;
+ char *gateway, *dns;
+
+ if (argc < 2)
+ return 0;
+
+ if (strcmp(argv[1], "bound") != 0 && strcmp(argv[1], "renew") != 0)
+ return 0;
+
+ busname = "org.moblin.connman";
+
+ interface = getenv("interface");
+
+ address = getenv("ip");
+ if (address == NULL)
+ address = "";
+
+ netmask = getenv("subnet");
+ if (netmask == NULL)
+ netmask = "";
+
+ broadcast = getenv("broadcast");
+ if (broadcast == NULL)
+ broadcast = "";
+
+ gateway = getenv("router");
+ if (gateway == NULL)
+ gateway = "";
+
+ dns = getenv("dns");
+ if (dns == NULL)
+ dns = "";
+
+ dbus_error_init(&error);
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
+ if (conn == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ fprintf(stderr, "%s\n", error.message);
+ dbus_error_free(&error);
+ } else
+ fprintf(stderr, "Failed to get on system bus\n");
+ return 0;
+ }
+
+ msg = dbus_message_new_method_call(busname, UDHCPC_PATH,
+ UDHCPC_INTF, argv[1]);
+ if (msg == NULL) {
+ dbus_connection_unref(conn);
+ fprintf(stderr, "Failed to allocate method call\n");
+ return 0;
+ }
+
+ dbus_message_set_no_reply(msg, TRUE);
+
+ dbus_message_append_args(msg, DBUS_TYPE_STRING, &interface,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_STRING, &netmask,
+ DBUS_TYPE_STRING, &broadcast,
+ DBUS_TYPE_STRING, &gateway,
+ DBUS_TYPE_STRING, &dns,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send(conn, msg, NULL) == FALSE)
+ fprintf(stderr, "Failed to send message\n");
+
+ dbus_connection_flush(conn);
+
+ dbus_message_unref(msg);
+
+ dbus_connection_unref(conn);
+
+ return 0;
+}
--- /dev/null
+#!/bin/sh
+
+# we need sed
+SED=@SED@
+if test -z "$SED" ; then
+SED=sed
+fi
+
+lt_unmangle ()
+{
+ last_result=`echo $1 | $SED -e 's#.libs/##' -e 's#[0-9a-zA-Z_\-\.]*_la-##'`
+}
+
+# the real libtool to use
+LIBTOOL="$1"
+shift
+
+# if 1, don't print anything, the underlaying wrapper will do it
+pass_though=0
+
+# scan the arguments, keep the right ones for libtool, and discover the mode
+preserved_args=
+while test "$#" -gt 0; do
+ opt="$1"
+ shift
+
+ case $opt in
+ --mode=*)
+ mode=`echo $opt | $SED -e 's/[-_a-zA-Z0-9]*=//'`
+ preserved_args="$preserved_args $opt"
+ ;;
+ -o)
+ lt_output="$1"
+ preserved_args="$preserved_args $opt"
+ ;;
+ *)
+ preserved_args="$preserved_args $opt"
+ ;;
+ esac
+done
+
+case "$mode" in
+compile)
+ # shave will be called and print the actual CC/CXX/LINK line
+ preserved_args="$preserved_args --shave-mode=$mode"
+ pass_though=1
+ ;;
+link)
+ preserved_args="$preserved_args --shave-mode=$mode"
+ Q=" LINK "
+ ;;
+*)
+ # let's u
+ # echo "*** libtool: Unimplemented mode: $mode, fill a bug report"
+ ;;
+esac
+
+lt_unmangle "$lt_output"
+output=$last_result
+
+if test -z $V; then
+ if test $pass_though -eq 0; then
+ echo "$Q$output"
+ fi
+ $LIBTOOL --silent $preserved_args
+else
+ echo $LIBTOOL $preserved_args
+ $LIBTOOL $preserved_args
+fi
--- /dev/null
+#!/bin/sh
+
+# we need sed
+SED=@SED@
+if test -z "$SED" ; then
+SED=sed
+fi
+
+lt_unmangle ()
+{
+ last_result=`echo $1 | $SED -e 's#.libs/##' -e 's#[0-9a-zA-Z_\-\.]*_la-##'`
+}
+
+# the tool to wrap (cc, cxx, ar, ranlib, ..)
+tool="$1"
+shift
+
+# the reel tool (to call)
+REEL_TOOL="$1"
+shift
+
+pass_through=0
+preserved_args=
+while test "$#" -gt 0; do
+ opt="$1"
+ shift
+
+ case $opt in
+ --shave-mode=*)
+ mode=`echo $opt | $SED -e 's/[-_a-zA-Z0-9]*=//'`
+ ;;
+ -o)
+ lt_output="$1"
+ preserved_args="$preserved_args $opt"
+ ;;
+ *)
+ preserved_args="$preserved_args $opt"
+ ;;
+ esac
+done
+
+# mode=link is handled in the libtool wrapper
+case "$mode,$tool" in
+link,*)
+ pass_through=1
+ ;;
+*,cxx)
+ Q=" CXX "
+ ;;
+*,cc)
+ Q=" CC "
+ ;;
+*,fc)
+ Q=" FC "
+ ;;
+*,f77)
+ Q=" F77 "
+ ;;
+*,*)
+ # should not happen
+ Q=" CC "
+ ;;
+esac
+
+lt_unmangle "$lt_output"
+output=$last_result
+
+if test -z $V; then
+ if test $pass_through -eq 0; then
+ echo "$Q$output"
+ fi
+ $REEL_TOOL $preserved_args
+else
+ echo $REEL_TOOL $preserved_args
+ $REEL_TOOL $preserved_args
+fi
--- /dev/null
+
+if DATAFILES
+dbusdir = @DBUS_DATADIR@
+
+dbus_DATA = connman.conf
+endif
+
+sbin_PROGRAMS = connmand
+
+connmand_SOURCES = main.c connman.h log.c selftest.c error.c plugin.c \
+ element.c device.c network.c connection.c \
+ manager.c profile.c service.c agent.c notifier.c \
+ security.c resolver.c ipconfig.c rfkill.c \
+ storage.c ipv4.c detect.c rtnl.c inet.c dbus.c
+
+if UDEV
+connmand_SOURCES += udev.c
+
+if DATAFILES
+rulesdir = @UDEV_DATADIR@
+
+rules_DATA = 92-connman.rules
+endif
+endif
+
+connmand_LDADD = $(top_builddir)/plugins/libbuiltin.la \
+ @GDBUS_LIBS@ @GLIB_LIBS@ @GTHREAD_LIBS@ @UDEV_LIBS@ -ldl
+
+connmand_LDFLAGS = -Wl,--export-dynamic -Wl,--version-script=connman.ver
+
+connmand_DEPENDENCIES = connman.ver $(top_builddir)/plugins/libbuiltin.la
+
+CLEANFILES = connman.ver connman.exp connman.conf 92-connman.rules
+
+statedir = $(localstatedir)/run/connman
+
+storagedir = $(localstatedir)/lib/connman
+
+if MAINTAINER_MODE
+plugindir = $(abs_top_srcdir)/plugins/.libs
+else
+plugindir = $(libdir)/connman/plugins
+endif
+
+AM_CFLAGS = @UDEV_CFLAGS@ @GTHREAD_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@ \
+ -DSTATEDIR=\""$(statedir)"\" \
+ -DPLUGINDIR=\""$(plugindir)"\" \
+ -DSTORAGEDIR=\""$(storagedir)\""
+
+INCLUDES = -I$(top_builddir)/include -I$(top_builddir)/plugins
+
+EXTRA_DIST = connman-dbus.conf connman-polkit.conf connman.rules
+
+MAINTAINERCLEANFILES = Makefile.in
+
+connman.exp: $(connmand_OBJECTS)
+ nm -B *.o | awk '{ print $$3 }' | sort -u | grep -E -e '^connman_' > $@
+
+connman.ver: connman.exp
+ echo "{ global:" > $@
+ cat $< | sed -e "s/\(.*\)/\1;/" >> $@
+ echo "local: *; };" >> $@
+
+connman.conf: connman-dbus.conf connman-polkit.conf
+if POLKIT
+ cp $(top_srcdir)/src/connman-polkit.conf $@
+else
+ cp $(top_srcdir)/src/connman-dbus.conf $@
+endif
+
+92-connman.rules: connman.rules
+ cp $< $@
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gdbus.h>
+
+#include "connman.h"
+
+static DBusConnection *connection = NULL;
+static guint agent_watch = 0;
+static gchar *agent_path = NULL;
+static gchar *agent_sender = NULL;
+
+static void agent_free(void)
+{
+ agent_watch = 0;
+
+ g_free(agent_sender);
+ agent_sender = NULL;
+
+ g_free(agent_path);
+ agent_path = NULL;
+}
+
+static void agent_disconnect(DBusConnection *connection, void *data)
+{
+ DBG("data %p", data);
+
+ agent_free();
+}
+
+int __connman_agent_register(const char *sender, const char *path)
+{
+ DBG("sender %s path %s", sender, path);
+
+ if (agent_path != NULL)
+ return -EEXIST;
+
+ agent_sender = g_strdup(sender);
+ agent_path = g_strdup(path);
+
+ agent_watch = g_dbus_add_disconnect_watch(connection, sender,
+ agent_disconnect, NULL, NULL);
+
+ return 0;
+}
+
+int __connman_agent_unregister(const char *sender, const char *path)
+{
+ DBG("sender %s path %s", sender, path);
+
+ if (agent_path == NULL)
+ return -ENOENT;
+
+ if (agent_watch > 0)
+ g_dbus_remove_watch(connection, agent_watch);
+
+ agent_free();
+
+ return 0;
+}
+
+int __connman_agent_init(DBusConnection *conn)
+{
+ DBG("conn %p", conn);
+
+ connection = dbus_connection_ref(conn);
+ if (connection == NULL)
+ return -1;
+
+ return 0;
+}
+
+void __connman_agent_cleanup(void)
+{
+ DBusMessage *msg;
+
+ DBG("conn %p", connection);
+
+ if (agent_watch > 0)
+ g_dbus_remove_watch(connection, agent_watch);
+
+ if (agent_path == NULL)
+ return;
+
+ msg = dbus_message_new_method_call(agent_sender, agent_path,
+ CONNMAN_AGENT_INTERFACE, "Release");
+ if (msg == NULL)
+ return;
+
+ dbus_message_set_no_reply(msg, TRUE);
+
+ dbus_connection_send(connection, msg, NULL);
+
+ dbus_message_unref(msg);
+
+ agent_free();
+
+ dbus_connection_unref(connection);
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <net/route.h>
+
+#include <gdbus.h>
+
+#include "connman.h"
+
+struct gateway_data {
+ int index;
+ char *gateway;
+};
+
+static GSList *gateway_list = NULL;
+
+static struct gateway_data *find_gateway(int index, const char *gateway)
+{
+ GSList *list;
+
+ if (gateway == NULL)
+ return NULL;
+
+ for (list = gateway_list; list; list = list->next) {
+ struct gateway_data *data = list->data;
+
+ if (data->gateway == NULL)
+ continue;
+
+ if (data->index == index &&
+ g_str_equal(data->gateway, gateway) == TRUE)
+ return data;
+ }
+
+ return NULL;
+}
+
+static void remove_gateway(int index, const char *gateway)
+{
+ struct gateway_data *data;
+
+ data = find_gateway(index, gateway);
+ if (data == NULL)
+ return;
+
+ gateway_list = g_slist_remove(gateway_list, data);
+}
+
+static int set_route(struct connman_element *element, const char *gateway)
+{
+ struct ifreq ifr;
+ struct rtentry rt;
+ struct sockaddr_in *addr;
+ int sk, err;
+
+ DBG("element %p", element);
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = element->index;
+
+ if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
+ close(sk);
+ return -1;
+ }
+
+ DBG("ifname %s", ifr.ifr_name);
+
+ memset(&rt, 0, sizeof(rt));
+ rt.rt_flags = RTF_UP | RTF_HOST;
+
+ addr = (struct sockaddr_in *) &rt.rt_dst;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = inet_addr(gateway);
+
+ addr = (struct sockaddr_in *) &rt.rt_gateway;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = INADDR_ANY;
+
+ addr = (struct sockaddr_in *) &rt.rt_genmask;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = INADDR_ANY;
+
+ rt.rt_dev = ifr.ifr_name;
+
+ err = ioctl(sk, SIOCADDRT, &rt);
+ if (err < 0)
+ connman_error("Setting host gateway route failed (%s)",
+ strerror(errno));
+
+ memset(&rt, 0, sizeof(rt));
+ rt.rt_flags = RTF_UP | RTF_GATEWAY;
+
+ addr = (struct sockaddr_in *) &rt.rt_dst;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = INADDR_ANY;
+
+ addr = (struct sockaddr_in *) &rt.rt_gateway;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = inet_addr(gateway);
+
+ addr = (struct sockaddr_in *) &rt.rt_genmask;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = INADDR_ANY;
+
+ err = ioctl(sk, SIOCADDRT, &rt);
+ if (err < 0)
+ connman_error("Setting default route failed (%s)",
+ strerror(errno));
+
+ close(sk);
+
+ return err;
+}
+
+static int del_route(struct connman_element *element, const char *gateway)
+{
+ struct ifreq ifr;
+ struct rtentry rt;
+ struct sockaddr_in *addr;
+ int sk, err;
+
+ DBG("element %p", element);
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = element->index;
+
+ if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
+ close(sk);
+ return -1;
+ }
+
+ DBG("ifname %s", ifr.ifr_name);
+
+ memset(&rt, 0, sizeof(rt));
+ rt.rt_flags = RTF_UP | RTF_GATEWAY;
+
+ addr = (struct sockaddr_in *) &rt.rt_dst;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = INADDR_ANY;
+
+ addr = (struct sockaddr_in *) &rt.rt_gateway;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = inet_addr(gateway);
+
+ addr = (struct sockaddr_in *) &rt.rt_genmask;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = INADDR_ANY;
+
+ err = ioctl(sk, SIOCDELRT, &rt);
+ if (err < 0)
+ connman_error("Removing default route failed (%s)",
+ strerror(errno));
+
+ close(sk);
+
+ return err;
+}
+
+static DBusConnection *connection;
+
+static void emit_default_signal(struct connman_element *element)
+{
+ DBusMessage *signal;
+ DBusMessageIter entry, value;
+ const char *key = "Default";
+
+ signal = dbus_message_new_signal(element->path,
+ CONNMAN_CONNECTION_INTERFACE, "PropertyChanged");
+ if (signal == NULL)
+ return;
+
+ dbus_message_iter_init_append(signal, &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_BOOLEAN_AS_STRING, &value);
+ dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN,
+ &element->enabled);
+ dbus_message_iter_close_container(&entry, &value);
+
+ g_dbus_send_message(connection, signal);
+}
+
+static void set_default(struct connman_element *element, gpointer user_data)
+{
+ struct gateway_data *data = user_data;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (element->index != data->index)
+ return;
+
+ if (element->enabled == TRUE)
+ return;
+
+ connman_element_set_enabled(element, TRUE);
+ emit_default_signal(element);
+}
+
+static void del_default(struct connman_element *element, gpointer user_data)
+{
+ struct gateway_data *data = user_data;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (element->index != data->index)
+ return;
+
+ if (element->enabled == FALSE)
+ return;
+
+ connman_element_set_enabled(element, FALSE);
+ emit_default_signal(element);
+}
+
+static void new_default(struct connman_element *element, gpointer user_data)
+{
+ struct connman_service *service;
+ const char *gateway;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (g_slist_length(gateway_list) > 0)
+ return;
+
+ connman_element_get_value(element,
+ CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
+
+ DBG("gateway %s", gateway);
+
+ if (gateway == NULL)
+ return;
+
+ if (set_route(element, gateway) < 0)
+ return;
+
+ service = __connman_element_get_service(element);
+ __connman_service_indicate_default(service);
+
+ connman_element_set_enabled(element, TRUE);
+ emit_default_signal(element);
+}
+
+static void connection_newgateway(int index, const char *gateway)
+{
+ struct gateway_data *data;
+
+ DBG("index %d gateway %s", index, gateway);
+
+ data = find_gateway(index, gateway);
+ if (data != NULL)
+ return;
+
+ data = g_try_new0(struct gateway_data, 1);
+ if (data == NULL)
+ return;
+
+ data->index = index;
+ data->gateway = g_strdup(gateway);
+
+ gateway_list = g_slist_append(gateway_list, data);
+
+ __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION,
+ set_default, data);
+}
+
+static void connection_delgateway(int index, const char *gateway)
+{
+ struct gateway_data *data;
+
+ DBG("index %d gateway %s", index, gateway);
+
+ data = find_gateway(index, gateway);
+ if (data == NULL)
+ return;
+
+ gateway_list = g_slist_remove(gateway_list, data);
+
+ __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION,
+ del_default, data);
+
+ g_free(data->gateway);
+ g_free(data);
+
+ if (g_slist_length(gateway_list) > 0)
+ return;
+
+ DBG("selecting new default gateway");
+
+ __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION,
+ new_default, NULL);
+}
+
+static struct connman_rtnl connection_rtnl = {
+ .name = "connection",
+ .newgateway = connection_newgateway,
+ .delgateway = connection_delgateway,
+};
+
+static DBusMessage *get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_element *element = data;
+ DBusMessage *reply;
+ DBusMessageIter array, dict;
+ connman_uint8_t strength;
+ const char *device, *network;
+ const char *type;
+
+ DBG("conn %p", conn);
+
+ if (__connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
+ return __connman_error_permission_denied(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &array);
+
+ dbus_message_iter_open_container(&array, 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);
+
+ type = connman_element_get_string(element, "Type");
+ if (type != NULL)
+ connman_dbus_dict_append_variant(&dict, "Type",
+ DBUS_TYPE_STRING, &type);
+
+ strength = connman_element_get_uint8(element, "Strength");
+ if (strength > 0)
+ connman_dbus_dict_append_variant(&dict, "Strength",
+ DBUS_TYPE_BYTE, &strength);
+
+ if (element->devname != NULL)
+ connman_dbus_dict_append_variant(&dict, "Interface",
+ DBUS_TYPE_STRING, &element->devname);
+
+ connman_dbus_dict_append_variant(&dict, "Default",
+ DBUS_TYPE_BOOLEAN, &element->enabled);
+
+ device = __connman_element_get_device_path(element);
+ if (device != NULL)
+ connman_dbus_dict_append_variant(&dict, "Device",
+ DBUS_TYPE_OBJECT_PATH, &device);
+
+ network = __connman_element_get_network_path(element);
+ if (network != NULL)
+ connman_dbus_dict_append_variant(&dict, "Network",
+ DBUS_TYPE_OBJECT_PATH, &network);
+
+ __connman_element_append_ipv4(element, &dict);
+
+ dbus_message_iter_close_container(&array, &dict);
+
+ return reply;
+}
+
+static DBusMessage *set_property(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessageIter iter, value;
+ const char *name;
+ int type;
+
+ DBG("conn %p", conn);
+
+ if (dbus_message_iter_init(msg, &iter) == FALSE)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&iter, &name);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &value);
+
+ if (__connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
+ return __connman_error_permission_denied(msg);
+
+ type = dbus_message_iter_get_arg_type(&value);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static GDBusMethodTable connection_methods[] = {
+ { "GetProperties", "", "a{sv}", get_properties },
+ { "SetProperty", "sv", "", set_property },
+ { },
+};
+
+static GDBusSignalTable connection_signals[] = {
+ { "PropertyChanged", "sv" },
+ { },
+};
+
+static void append_connections(DBusMessageIter *entry)
+{
+ DBusMessageIter value, iter;
+ const char *key = "Connections";
+
+ dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
+
+ dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
+ &value);
+
+ dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
+ __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
+ dbus_message_iter_close_container(&value, &iter);
+
+ dbus_message_iter_close_container(entry, &value);
+}
+
+static void emit_connections_signal(void)
+{
+ DBusMessage *signal;
+ DBusMessageIter entry;
+
+ signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
+ CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
+ if (signal == NULL)
+ return;
+
+ dbus_message_iter_init_append(signal, &entry);
+
+ append_connections(&entry);
+
+ g_dbus_send_message(connection, signal);
+}
+
+static int register_interface(struct connman_element *element)
+{
+ DBG("element %p name %s", element, element->name);
+
+ if (g_dbus_register_interface(connection, element->path,
+ CONNMAN_CONNECTION_INTERFACE,
+ connection_methods, connection_signals,
+ NULL, element, NULL) == FALSE) {
+ connman_error("Failed to register %s connection", element->path);
+ return -EIO;
+ }
+
+ emit_connections_signal();
+
+ return 0;
+}
+
+static void unregister_interface(struct connman_element *element)
+{
+ DBG("element %p name %s", element, element->name);
+
+ emit_connections_signal();
+
+ g_dbus_unregister_interface(connection, element->path,
+ CONNMAN_CONNECTION_INTERFACE);
+}
+
+static int connection_probe(struct connman_element *element)
+{
+ struct connman_service *service;
+ const char *gateway = NULL;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (element->parent == NULL)
+ return -ENODEV;
+
+ if (element->parent->type != CONNMAN_ELEMENT_TYPE_IPV4)
+ return -ENODEV;
+
+ connman_element_get_value(element,
+ CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
+
+ DBG("gateway %s", gateway);
+
+ if (register_interface(element) < 0)
+ return -ENODEV;
+
+ service = __connman_element_get_service(element);
+ __connman_service_indicate_state(service,
+ CONNMAN_SERVICE_STATE_READY);
+
+ if (gateway == NULL)
+ return 0;
+
+ if (find_gateway(element->index, gateway) != NULL) {
+ DBG("previous gateway still present");
+ goto done;
+ }
+
+ if (g_slist_length(gateway_list) > 0) {
+ DBG("default gateway already present");
+ return 0;
+ }
+
+ if (set_route(element, gateway) < 0)
+ return 0;
+
+done:
+ service = __connman_element_get_service(element);
+ __connman_service_indicate_default(service);
+
+ connman_element_set_enabled(element, TRUE);
+ emit_default_signal(element);
+
+ return 0;
+}
+
+static void connection_remove(struct connman_element *element)
+{
+ struct connman_service *service;
+ const char *gateway = NULL;
+
+ DBG("element %p name %s", element, element->name);
+
+ service = __connman_element_get_service(element);
+ __connman_service_indicate_state(service,
+ CONNMAN_SERVICE_STATE_DISCONNECT);
+
+ unregister_interface(element);
+
+ connman_element_get_value(element,
+ CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
+
+ DBG("gateway %s", gateway);
+
+ if (gateway == NULL)
+ return;
+
+ remove_gateway(element->index, gateway);
+
+ connman_element_set_enabled(element, FALSE);
+ emit_default_signal(element);
+
+ del_route(element, gateway);
+}
+
+static struct connman_driver connection_driver = {
+ .name = "connection",
+ .type = CONNMAN_ELEMENT_TYPE_CONNECTION,
+ .priority = CONNMAN_DRIVER_PRIORITY_LOW,
+ .probe = connection_probe,
+ .remove = connection_remove,
+};
+
+int __connman_connection_init(void)
+{
+ DBG("");
+
+ connection = connman_dbus_get_connection();
+
+ if (connman_rtnl_register(&connection_rtnl) < 0)
+ connman_error("Failed to setup RTNL gateway driver");
+
+ connman_rtnl_send_getroute();
+
+ return connman_driver_register(&connection_driver);
+}
+
+void __connman_connection_cleanup(void)
+{
+ GSList *list;
+
+ DBG("");
+
+ connman_driver_unregister(&connection_driver);
+
+ connman_rtnl_unregister(&connection_rtnl);
+
+ for (list = gateway_list; list; list = list->next) {
+ struct gateway_data *data = list->data;
+
+ DBG("index %d gateway %s", data->index, data->gateway);
+
+ g_free(data->gateway);
+ g_free(data);
+ list->data = NULL;
+ }
+
+ g_slist_free(gateway_list);
+ gateway_list = NULL;
+
+ dbus_connection_unref(connection);
+}
--- /dev/null
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <policy user="root">
+ <allow own="org.moblin.connman"/>
+ <allow send_destination="org.moblin.connman"/>
+ <allow send_interface="org.moblin.connman.Agent"/>
+ </policy>
+ <policy at_console="true">
+ <allow send_destination="org.moblin.connman"/>
+ </policy>
+ <policy context="default">
+ <deny send_destination="org.moblin.connman"/>
+ </policy>
+</busconfig>
--- /dev/null
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <policy user="root">
+ <allow own="org.moblin.connman"/>
+ <allow send_interface="org.moblin.connman.Agent"/>
+ </policy>
+ <policy context="default">
+ <allow send_destination="org.moblin.connman"/>
+ </policy>
+</busconfig>
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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
+ *
+ */
+
+#include <glib.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+
+#include <connman/dbus.h>
+
+#define NM_SERVICE "org.freedesktop.NetworkManager"
+#define NM_PATH "/org/freedesktop/NetworkManager"
+#define NM_INTERFACE NM_SERVICE
+
+int __connman_dbus_init(DBusConnection *conn);
+void __connman_dbus_cleanup(void);
+
+DBusMessage *__connman_error_failed(DBusMessage *msg, int errnum);
+DBusMessage *__connman_error_invalid_arguments(DBusMessage *msg);
+DBusMessage *__connman_error_permission_denied(DBusMessage *msg);
+DBusMessage *__connman_error_not_supported(DBusMessage *msg);
+DBusMessage *__connman_error_not_implemented(DBusMessage *msg);
+DBusMessage *__connman_error_no_carrier(DBusMessage *msg);
+DBusMessage *__connman_error_in_progress(DBusMessage *msg);
+DBusMessage *__connman_error_already_connected(DBusMessage *msg);
+DBusMessage *__connman_error_operation_aborted(DBusMessage *msg);
+DBusMessage *__connman_error_operation_timeout(DBusMessage *msg);
+DBusMessage *__connman_error_invalid_service(DBusMessage *msg);
+
+int __connman_selftest(void);
+
+int __connman_manager_init(DBusConnection *conn, gboolean compat);
+void __connman_manager_cleanup(void);
+
+int __connman_agent_init(DBusConnection *conn);
+void __connman_agent_cleanup(void);
+
+int __connman_agent_register(const char *sender, const char *path);
+int __connman_agent_unregister(const char *sender, const char *path);
+
+int __connman_profile_init(DBusConnection *conn);
+void __connman_profile_cleanup(void);
+
+void __connman_profile_list(DBusMessageIter *iter);
+const char *__connman_profile_active_ident(void);
+const char *__connman_profile_active_path(void);
+
+void __connman_profile_changed(void);
+
+#include <connman/log.h>
+
+int __connman_log_init(gboolean detach, gboolean debug);
+void __connman_log_cleanup(void);
+
+void __connman_toggle_debug(void);
+gboolean __connman_debug_enabled(void);
+
+#include <connman/option.h>
+
+#include <connman/plugin.h>
+
+int __connman_plugin_init(const char *pattern, const char *exclude);
+void __connman_plugin_cleanup(void);
+
+#include <connman/security.h>
+
+int __connman_security_check_privilege(DBusMessage *message,
+ enum connman_security_privilege privilege);
+
+#include <connman/ipv4.h>
+
+const char *__connman_ipv4_method2string(enum connman_ipv4_method method);
+enum connman_ipv4_method __connman_ipv4_string2method(const char *method);
+
+#include <connman/inet.h>
+
+#include <connman/rfkill.h>
+
+int __connman_rfkill_init(void);
+void __connman_rfkill_cleanup(void);
+
+#include <connman/ipconfig.h>
+
+#include <connman/resolver.h>
+
+int __connman_resolver_init(void);
+void __connman_resolver_cleanup(void);
+
+int __connman_resolver_selftest(void);
+
+#include <connman/storage.h>
+
+int __connman_storage_init(void);
+void __connman_storage_cleanup(void);
+
+int __connman_storage_init_device();
+int __connman_storage_load_device(struct connman_device *device);
+int __connman_storage_save_device(struct connman_device *device);
+int __connman_storage_init_network(struct connman_device *device);
+int __connman_storage_load_network(struct connman_network *network);
+int __connman_storage_save_network(struct connman_network *network);
+int __connman_storage_init_service();
+int __connman_storage_load_service(struct connman_service *service);
+int __connman_storage_save_service(struct connman_service *service);
+
+#include <connman/driver.h>
+
+void __connman_driver_rescan(struct connman_driver *driver);
+
+#include <connman/element.h>
+
+int __connman_element_init(DBusConnection *conn, const char *device,
+ const char *nodevice);
+void __connman_element_start(void);
+void __connman_element_stop(void);
+void __connman_element_cleanup(void);
+
+void __connman_element_initialize(struct connman_element *element);
+
+typedef void (* element_cb_t) (struct connman_element *element,
+ gpointer user_data);
+
+void __connman_element_foreach(struct connman_element *element,
+ enum connman_element_type type,
+ element_cb_t callback, gpointer user_data);
+void __connman_element_list(struct connman_element *element,
+ enum connman_element_type type,
+ DBusMessageIter *iter);
+int __connman_element_count(struct connman_element *element,
+ enum connman_element_type type);
+
+struct connman_service *__connman_element_get_service(struct connman_element *element);
+struct connman_device *__connman_element_get_device(struct connman_element *element);
+const char *__connman_element_get_device_path(struct connman_element *element);
+const char *__connman_element_get_network_path(struct connman_element *element);
+
+const char *__connman_element_type2string(enum connman_element_type type);
+
+static inline void __connman_element_lock(struct connman_element *element)
+{
+}
+
+static inline void __connman_element_unlock(struct connman_element *element)
+{
+}
+
+int __connman_element_append_ipv4(struct connman_element *element,
+ DBusMessageIter *dict);
+int __connman_element_set_ipv4(struct connman_element *element,
+ const char *name, DBusMessageIter *value);
+
+int __connman_detect_init(void);
+void __connman_detect_cleanup(void);
+
+int __connman_ipv4_init(void);
+void __connman_ipv4_cleanup(void);
+
+int __connman_connection_init(void);
+void __connman_connection_cleanup(void);
+
+#ifdef HAVE_UDEV
+int __connman_udev_init(void);
+void __connman_udev_cleanup(void);
+#else
+static inline int __connman_udev_init(void)
+{
+ return 0;
+}
+
+static inline void __connman_udev_cleanup(void)
+{
+}
+#endif
+
+#include <connman/device.h>
+
+int __connman_device_init(void);
+void __connman_device_cleanup(void);
+
+void __connman_device_increase_connections(struct connman_device *device);
+void __connman_device_decrease_connections(struct connman_device *device);
+
+void __connman_device_set_network(struct connman_device *device,
+ struct connman_network *network);
+
+int __connman_device_connect(struct connman_device *device);
+int __connman_device_disconnect(struct connman_device *device);
+
+connman_bool_t __connman_device_has_driver(struct connman_device *device);
+
+const char *__connman_device_get_type(struct connman_device *device);
+const char *__connman_device_get_ident(struct connman_device *device);
+
+int __connman_device_set_offlinemode(connman_bool_t offlinemode);
+
+int __connman_profile_add_device(struct connman_device *device);
+int __connman_profile_remove_device(struct connman_device *device);
+
+#include <connman/network.h>
+
+int __connman_network_init(void);
+void __connman_network_cleanup(void);
+
+void __connman_network_set_device(struct connman_network *network,
+ struct connman_device *device);
+
+int __connman_network_connect(struct connman_network *network);
+int __connman_network_disconnect(struct connman_network *network);
+
+connman_bool_t __connman_network_has_driver(struct connman_network *network);
+
+const char *__connman_network_get_type(struct connman_network *network);
+const char *__connman_network_get_group(struct connman_network *network);
+const char *__connman_network_get_ident(struct connman_network *network);
+
+int __connman_profile_add_network(struct connman_network *network);
+int __connman_profile_remove_network(struct connman_network *network);
+
+#include <connman/service.h>
+
+int __connman_service_init(void);
+void __connman_service_cleanup(void);
+
+void __connman_service_list(DBusMessageIter *iter);
+
+void __connman_service_put(struct connman_service *service);
+
+struct connman_service *__connman_service_lookup_from_device(struct connman_device *device);
+struct connman_service *__connman_service_create_from_device(struct connman_device *device);
+
+struct connman_service *__connman_service_lookup_from_network(struct connman_network *network);
+struct connman_service *__connman_service_create_from_network(struct connman_network *network);
+
+int __connman_service_set_carrier(struct connman_service *service,
+ connman_bool_t carrier);
+int __connman_service_indicate_state(struct connman_service *service,
+ enum connman_service_state state);
+int __connman_service_indicate_default(struct connman_service *service);
+
+#include <connman/notifier.h>
+
+int __connman_notifier_init(void);
+void __connman_notifier_cleanup(void);
+
+void __connman_notifier_device_type_increase(enum connman_device_type type);
+void __connman_notifier_device_type_decrease(enum connman_device_type type);
+void __connman_notifier_offline_mode(connman_bool_t enabled);
+
+#include <connman/rtnl.h>
+
+int __connman_rtnl_init(void);
+void __connman_rtnl_cleanup(void);
+
+int __connman_rtnl_send(const void *buf, size_t len);
--- /dev/null
+
+SUBSYSTEM=="rfkill", ENV{CONNMAN_TYPE}="rfkill"
+
+SUBSYSTEM=="net", KERNEL=="eth*", ENV{CONNMAN_TYPE}="ethernet"
+SUBSYSTEM=="net", KERNEL=="wlan*", ENV{CONNMAN_TYPE}="wifi"
+
+SUBSYSTEM=="net", DRIVERS=="hso", ENV{CONNMAN_TYPE}="hso"
+
+SUBSYSTEM=="tty", KERNEL=="noz[0-9]*", ENV{CONNMAN_TYPE}="nozomi"
+
+SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1003", \
+ ENV{CONNMAN_TYPE}="huawei"
+
+SUBSYSTEM=="tty", ATTRS{idVendor}=="1410", ATTRS{idProduct}=="4400", \
+ ENV{CONNMAN_TYPE}="novatel"
+
+ENV{CONNMAN_TYPE}=="?*", ENV{CONNMAN_INTERFACE}="$kernel", \
+ RUN+="socket:@/org/moblin/connman/udev"
--- /dev/null
+[D-BUS Service]
+Name=org.moblin.connman
+Exec=@prefix@/sbin/connmand
+User=root
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <string.h>
+
+#include "connman.h"
+
+char *connman_dbus_encode_string(const char *value)
+{
+ GString *str;
+ unsigned int i, size;
+
+ if (value == NULL)
+ return NULL;
+
+ size = strlen(value);
+
+ str = g_string_new(NULL);
+ if (str == NULL)
+ return NULL;
+
+ for (i = 0; i < size; i++) {
+ const char tmp = value[i];
+ if ((tmp < '0' || tmp > '9') && (tmp < 'A' || tmp > 'Z') &&
+ (tmp < 'a' || tmp > 'z'))
+ g_string_append_printf(str, "_%02x", tmp);
+ else
+ str = g_string_append_c(str, tmp);
+ }
+
+ return g_string_free(str, FALSE);
+}
+
+void connman_dbus_property_append_variant(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_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);
+}
+
+void connman_dbus_dict_append_array(DBusMessageIter *dict,
+ const char *key, int type, void *val, int len)
+{
+ DBusMessageIter entry, value, array;
+ const char *variant_sig, *array_sig;
+
+ switch (type) {
+ case DBUS_TYPE_BYTE:
+ variant_sig = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING;
+ array_sig = DBUS_TYPE_BYTE_AS_STRING;
+ break;
+ default:
+ return;
+ }
+
+ 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,
+ variant_sig, &value);
+
+ dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
+ array_sig, &array);
+ dbus_message_iter_append_fixed_array(&array, type, val, len);
+ dbus_message_iter_close_container(&value, &array);
+
+ dbus_message_iter_close_container(&entry, &value);
+
+ dbus_message_iter_close_container(dict, &entry);
+}
+
+void connman_dbus_dict_append_variant(DBusMessageIter *dict,
+ const char *key, int type, void *val)
+{
+ DBusMessageIter entry;
+
+ dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+
+ connman_dbus_property_append_variant(&entry, key, type, val);
+
+ dbus_message_iter_close_container(dict, &entry);
+}
+
+static DBusConnection *connection = NULL;
+
+DBusConnection *connman_dbus_get_connection(void)
+{
+ if (connection == NULL)
+ return NULL;
+
+ return dbus_connection_ref(connection);
+}
+
+int __connman_dbus_init(DBusConnection *conn)
+{
+ connection = conn;
+
+ return 0;
+}
+
+void __connman_dbus_cleanup(void)
+{
+ connection = NULL;
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <glib.h>
+
+#include "connman.h"
+
+static GSList *device_list = NULL;
+
+static struct connman_device *find_device(int index)
+{
+ GSList *list;
+
+ for (list = device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+
+ if (connman_device_get_index(device) == index)
+ return device;
+ }
+
+ return NULL;
+}
+
+static void detect_newlink(unsigned short type, int index,
+ unsigned flags, unsigned change)
+{
+ struct connman_device *device;
+
+ DBG("type %d index %d", type, index);
+
+ device = find_device(index);
+ if (device != NULL)
+ return;
+
+ device = connman_inet_create_device(index);
+ if (device == NULL)
+ return;
+
+ if (connman_device_register(device) < 0) {
+ connman_device_unref(device);
+ return;
+ }
+
+ device_list = g_slist_append(device_list, device);
+}
+
+static void detect_dellink(unsigned short type, int index,
+ unsigned flags, unsigned change)
+{
+ struct connman_device *device;
+
+ DBG("type %d index %d", type, index);
+
+ device = find_device(index);
+ if (device == NULL)
+ return;
+
+ device_list = g_slist_remove(device_list, device);
+
+ connman_device_unregister(device);
+ connman_device_unref(device);
+}
+
+static struct connman_rtnl detect_rtnl = {
+ .name = "detect",
+ .priority = CONNMAN_RTNL_PRIORITY_LOW,
+ .newlink = detect_newlink,
+ .dellink = detect_dellink,
+};
+
+int __connman_detect_init(void)
+{
+ int err;
+
+ DBG("");
+
+ err = connman_rtnl_register(&detect_rtnl);
+ if (err < 0)
+ return err;
+
+ connman_rtnl_send_getlink();
+
+ return 0;
+}
+
+void __connman_detect_cleanup(void)
+{
+ GSList *list;
+
+ DBG("");
+
+ connman_rtnl_unregister(&detect_rtnl);
+
+ for (list = device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+
+ connman_device_unregister(device);
+ connman_device_unref(device);
+ }
+
+ g_slist_free(device_list);
+ device_list = NULL;
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <string.h>
+
+#include <gdbus.h>
+
+#include "connman.h"
+
+struct connman_device {
+ struct connman_element element;
+ enum connman_device_type type;
+ enum connman_device_mode mode;
+ enum connman_device_policy policy;
+ connman_bool_t secondary;
+ connman_bool_t powered;
+ connman_bool_t carrier;
+ connman_bool_t scanning;
+ connman_bool_t disconnected;
+ connman_uint8_t priority;
+ connman_uint16_t scan_interval;
+ char *name;
+ char *node;
+ char *address;
+ char *interface;
+ char *ident;
+ unsigned int connections;
+ guint scan_timeout;
+
+ struct connman_device_driver *driver;
+ void *driver_data;
+
+ connman_bool_t registered;
+
+ char *last_network;
+ struct connman_network *network;
+ GHashTable *networks;
+};
+
+static gboolean device_scan_trigger(gpointer user_data)
+{
+ struct connman_device *device = user_data;
+
+ DBG("device %p", device);
+
+ if (device->driver == NULL) {
+ device->scan_timeout = 0;
+ return FALSE;
+ }
+
+ if (device->driver->scan)
+ device->driver->scan(device);
+
+ return TRUE;
+}
+
+static const char *type2description(enum connman_device_type type)
+{
+ switch (type) {
+ case CONNMAN_DEVICE_TYPE_UNKNOWN:
+ case CONNMAN_DEVICE_TYPE_VENDOR:
+ break;
+ case CONNMAN_DEVICE_TYPE_ETHERNET:
+ return "Ethernet";
+ case CONNMAN_DEVICE_TYPE_WIFI:
+ return "Wireless";
+ case CONNMAN_DEVICE_TYPE_WIMAX:
+ return "WiMAX";
+ case CONNMAN_DEVICE_TYPE_BLUETOOTH:
+ return "Bluetooth";
+ case CONNMAN_DEVICE_TYPE_GPS:
+ return "GPS";
+ case CONNMAN_DEVICE_TYPE_HSO:
+ case CONNMAN_DEVICE_TYPE_NOZOMI:
+ case CONNMAN_DEVICE_TYPE_HUAWEI:
+ case CONNMAN_DEVICE_TYPE_NOVATEL:
+ return "Cellular";
+ }
+
+ return NULL;
+}
+
+static const char *type2string(enum connman_device_type type)
+{
+ switch (type) {
+ case CONNMAN_DEVICE_TYPE_UNKNOWN:
+ case CONNMAN_DEVICE_TYPE_VENDOR:
+ break;
+ case CONNMAN_DEVICE_TYPE_ETHERNET:
+ return "ethernet";
+ case CONNMAN_DEVICE_TYPE_WIFI:
+ return "wifi";
+ case CONNMAN_DEVICE_TYPE_WIMAX:
+ return "wimax";
+ case CONNMAN_DEVICE_TYPE_BLUETOOTH:
+ return "bluetooth";
+ case CONNMAN_DEVICE_TYPE_GPS:
+ return "gps";
+ case CONNMAN_DEVICE_TYPE_HSO:
+ case CONNMAN_DEVICE_TYPE_HUAWEI:
+ case CONNMAN_DEVICE_TYPE_NOZOMI:
+ case CONNMAN_DEVICE_TYPE_NOVATEL:
+ return "cellular";
+ }
+
+ return NULL;
+}
+
+static const char *policy2string(enum connman_device_policy policy)
+{
+ switch (policy) {
+ case CONNMAN_DEVICE_POLICY_UNKNOWN:
+ break;
+ case CONNMAN_DEVICE_POLICY_IGNORE:
+ return "ignore";
+ case CONNMAN_DEVICE_POLICY_OFF:
+ return "off";
+ case CONNMAN_DEVICE_POLICY_AUTO:
+ return "auto";
+ case CONNMAN_DEVICE_POLICY_MANUAL:
+ return "manual";
+ }
+
+ return NULL;
+}
+
+static enum connman_device_policy string2policy(const char *policy)
+{
+ if (g_str_equal(policy, "ignore") == TRUE)
+ return CONNMAN_DEVICE_POLICY_IGNORE;
+ else if (g_str_equal(policy, "off") == TRUE)
+ return CONNMAN_DEVICE_POLICY_OFF;
+ else if (g_str_equal(policy, "auto") == TRUE)
+ return CONNMAN_DEVICE_POLICY_AUTO;
+ else if (g_str_equal(policy, "manual") == TRUE)
+ return CONNMAN_DEVICE_POLICY_MANUAL;
+ else
+ return CONNMAN_DEVICE_POLICY_UNKNOWN;
+}
+
+static int set_carrier(struct connman_device *device, connman_bool_t carrier)
+{
+ struct connman_service *service;
+
+ service = __connman_service_lookup_from_device(device);
+ __connman_service_set_carrier(service, carrier);
+
+ if (carrier == TRUE) {
+ enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
+ struct connman_element *element;
+
+ device->disconnected = TRUE;
+
+ switch (device->policy) {
+ case CONNMAN_DEVICE_POLICY_UNKNOWN:
+ case CONNMAN_DEVICE_POLICY_IGNORE:
+ case CONNMAN_DEVICE_POLICY_OFF:
+ case CONNMAN_DEVICE_POLICY_MANUAL:
+ return 0;
+ case CONNMAN_DEVICE_POLICY_AUTO:
+ break;
+ }
+
+ switch (device->element.ipv4.method) {
+ case CONNMAN_IPV4_METHOD_UNKNOWN:
+ case CONNMAN_IPV4_METHOD_OFF:
+ return 0;
+ case CONNMAN_IPV4_METHOD_STATIC:
+ type = CONNMAN_ELEMENT_TYPE_IPV4;
+ break;
+ case CONNMAN_IPV4_METHOD_DHCP:
+ type = CONNMAN_ELEMENT_TYPE_DHCP;
+ break;
+ }
+
+ element = connman_element_create(NULL);
+ if (element != NULL) {
+ element->type = type;
+ element->index = device->element.index;
+
+ if (connman_element_register(element,
+ &device->element) < 0)
+ connman_element_unref(element);
+
+ device->disconnected = FALSE;
+
+ __connman_service_indicate_state(service,
+ CONNMAN_SERVICE_STATE_CONFIGURATION);
+ }
+ } else
+ connman_element_unregister_children(&device->element);
+
+ return 0;
+}
+
+static int set_powered(struct connman_device *device, connman_bool_t powered)
+{
+ struct connman_device_driver *driver = device->driver;
+ int err;
+
+ DBG("device %p powered %d", device, powered);
+
+ if (!driver)
+ return -EINVAL;
+
+ if (powered == TRUE) {
+ if (driver->enable) {
+ err = driver->enable(device);
+ __connman_notifier_device_type_increase(device->type);
+ } else
+ err = -EINVAL;
+ } else {
+ g_hash_table_remove_all(device->networks);
+
+ set_carrier(device, FALSE);
+
+ if (driver->disable) {
+ err = driver->disable(device);
+ __connman_notifier_device_type_decrease(device->type);
+ } else
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+static int set_policy(DBusConnection *connection,
+ struct connman_device *device,
+ enum connman_device_policy policy)
+{
+ DBusMessage *signal;
+ DBusMessageIter entry, value;
+ const char *str, *key = "Policy";
+ int err = 0;
+
+ DBG("device %p policy %d", device, policy);
+
+ if (device->policy == policy)
+ return 0;
+
+ switch (policy) {
+ case CONNMAN_DEVICE_POLICY_UNKNOWN:
+ return -EINVAL;
+ case CONNMAN_DEVICE_POLICY_IGNORE:
+ break;
+ case CONNMAN_DEVICE_POLICY_OFF:
+ if (device->powered == TRUE)
+ err = set_powered(device, FALSE);
+ break;
+ case CONNMAN_DEVICE_POLICY_AUTO:
+ case CONNMAN_DEVICE_POLICY_MANUAL:
+ if (device->powered == FALSE)
+ err = set_powered(device, TRUE);
+ else
+ err = set_carrier(device, device->carrier);
+ break;
+ }
+
+ if (err < 0)
+ return err;
+
+ device->policy = policy;
+
+ signal = dbus_message_new_signal(device->element.path,
+ CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
+ if (signal == NULL)
+ return 0;
+
+ dbus_message_iter_init_append(signal, &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+ str = policy2string(policy);
+
+ 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);
+
+ g_dbus_send_message(connection, signal);
+
+ return 0;
+}
+
+static void append_path(gpointer key, gpointer value, gpointer user_data)
+{
+ struct connman_element *element = value;
+ DBusMessageIter *iter = user_data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
+ &element->path);
+}
+
+static void append_networks(struct connman_device *device,
+ DBusMessageIter *entry)
+{
+ DBusMessageIter value, iter;
+ const char *key = "Networks";
+
+ dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
+
+ dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
+ &value);
+
+ dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
+ g_hash_table_foreach(device->networks, append_path, &iter);
+ dbus_message_iter_close_container(&value, &iter);
+
+ dbus_message_iter_close_container(entry, &value);
+}
+
+static DBusMessage *get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_device *device = data;
+ DBusMessage *reply;
+ DBusMessageIter array, dict, entry;
+ const char *str;
+
+ DBG("conn %p", conn);
+
+ if (__connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
+ return __connman_error_permission_denied(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &array);
+
+ dbus_message_iter_open_container(&array, 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);
+
+ if (device->name != NULL)
+ connman_dbus_dict_append_variant(&dict, "Name",
+ DBUS_TYPE_STRING, &device->name);
+
+ str = type2string(device->type);
+ if (str != NULL)
+ connman_dbus_dict_append_variant(&dict, "Type",
+ DBUS_TYPE_STRING, &str);
+
+ if (device->address != NULL)
+ connman_dbus_dict_append_variant(&dict, "Address",
+ DBUS_TYPE_STRING, &device->address);
+
+ if (device->interface != NULL)
+ connman_dbus_dict_append_variant(&dict, "Interface",
+ DBUS_TYPE_STRING, &device->interface);
+
+ str = policy2string(device->policy);
+ if (str != NULL)
+ connman_dbus_dict_append_variant(&dict, "Policy",
+ DBUS_TYPE_STRING, &str);
+
+ if (device->priority > 0)
+ connman_dbus_dict_append_variant(&dict, "Priority",
+ DBUS_TYPE_BYTE, &device->priority);
+
+ connman_dbus_dict_append_variant(&dict, "Powered",
+ DBUS_TYPE_BOOLEAN, &device->powered);
+
+ if (device->driver && device->driver->scan)
+ connman_dbus_dict_append_variant(&dict, "Scanning",
+ DBUS_TYPE_BOOLEAN, &device->scanning);
+
+ switch (device->mode) {
+ case CONNMAN_DEVICE_MODE_UNKNOWN:
+ break;
+ case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
+ __connman_element_append_ipv4(&device->element, &dict);
+ break;
+ case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
+ case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
+ if (device->scan_interval > 0)
+ connman_dbus_dict_append_variant(&dict, "ScanInterval",
+ DBUS_TYPE_UINT16, &device->scan_interval);
+
+ dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+ append_networks(device, &entry);
+ dbus_message_iter_close_container(&dict, &entry);
+ break;
+ }
+
+ dbus_message_iter_close_container(&array, &dict);
+
+ return reply;
+}
+
+static DBusMessage *set_property(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_device *device = data;
+ DBusMessageIter iter, value;
+ const char *name;
+ int type;
+
+ DBG("conn %p", conn);
+
+ if (dbus_message_iter_init(msg, &iter) == FALSE)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&iter, &name);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &value);
+
+ if (__connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
+ return __connman_error_permission_denied(msg);
+
+ type = dbus_message_iter_get_arg_type(&value);
+
+ if (g_str_equal(name, "Powered") == TRUE) {
+ connman_bool_t powered;
+ int err;
+
+ if (type != DBUS_TYPE_BOOLEAN)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value, &powered);
+
+ if (device->powered == powered)
+ return __connman_error_invalid_arguments(msg);
+
+ err = set_powered(device, powered);
+ if (err < 0 && err != -EINPROGRESS)
+ return __connman_error_failed(msg, -err);
+ } else if (g_str_equal(name, "Policy") == TRUE) {
+ enum connman_device_policy policy;
+ const char *str;
+ int err;
+
+ if (type != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value, &str);
+ policy = string2policy(str);
+ if (policy == CONNMAN_DEVICE_POLICY_UNKNOWN)
+ return __connman_error_invalid_arguments(msg);
+
+ err = set_policy(conn, device, policy);
+ if (err < 0)
+ return __connman_error_failed(msg, -err);
+ } else if (g_str_equal(name, "Priority") == TRUE) {
+ connman_uint8_t priority;
+
+ if (type != DBUS_TYPE_BYTE)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value, &priority);
+
+ device->priority = priority;
+ } else if (g_str_equal(name, "ScanInterval") == TRUE) {
+ connman_uint16_t interval;
+
+ switch (device->mode) {
+ case CONNMAN_DEVICE_MODE_UNKNOWN:
+ case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
+ return __connman_error_invalid_arguments(msg);
+ case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
+ case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
+ break;
+ }
+
+ if (type != DBUS_TYPE_UINT16)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value, &interval);
+
+ device->scan_interval = interval;
+
+ if (device->scan_timeout > 0) {
+ g_source_remove(device->scan_timeout);
+ device->scan_timeout = 0;
+ }
+
+ if (device->scan_interval > 0) {
+ guint interval = device->scan_interval;
+ device->scan_timeout = g_timeout_add_seconds(interval,
+ device_scan_trigger, device);
+ }
+ } else if (g_str_has_prefix(name, "IPv4") == TRUE) {
+ switch (device->mode) {
+ case CONNMAN_DEVICE_MODE_UNKNOWN:
+ case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
+ case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
+ return __connman_error_invalid_arguments(msg);
+ case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
+ __connman_element_set_ipv4(&device->element,
+ name, &value);
+ break;
+ }
+ }
+
+ __connman_storage_save_device(device);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *join_network(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_device *device = data;
+ struct connman_network *network;
+ enum connman_network_type type;
+ DBusMessageIter iter, array;
+ int err, index;
+
+ DBG("conn %p", conn);
+
+ if (__connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
+ return __connman_error_permission_denied(msg);
+
+ if (!device->driver || !device->driver->join)
+ return __connman_error_not_supported(msg);
+
+ dbus_message_iter_init(msg, &iter);
+ dbus_message_iter_recurse(&iter, &array);
+
+ switch (device->type) {
+ case CONNMAN_DEVICE_TYPE_WIFI:
+ type = CONNMAN_NETWORK_TYPE_WIFI;
+ break;
+ default:
+ return __connman_error_not_supported(msg);
+ }
+
+ network = connman_network_create("00_00_00_00_00_00", type);
+ if (network == NULL)
+ return __connman_error_failed(msg, ENOMEM);
+
+ while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+ const char *key, *str;
+
+ dbus_message_iter_recurse(&array, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
+
+ switch (dbus_message_iter_get_arg_type(&value)) {
+ case DBUS_TYPE_STRING:
+ dbus_message_iter_get_basic(&value, &str);
+ if (g_str_equal(key, "WiFi.SSID") == TRUE)
+ connman_network_set_blob(network, key,
+ str, strlen(str));
+ else
+ connman_network_set_string(network, key, str);
+ break;
+ }
+
+ dbus_message_iter_next(&array);
+ }
+
+ index = connman_device_get_index(device);
+ connman_network_set_index(network, index);
+
+ connman_network_set_protocol(network, CONNMAN_NETWORK_PROTOCOL_IP);
+
+ err = device->driver->join(device, network);
+
+ connman_network_unref(network);
+
+ if (err < 0)
+ return __connman_error_failed(msg, -err);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *create_network(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBG("conn %p", conn);
+
+ if (__connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
+ return __connman_error_permission_denied(msg);
+
+ return __connman_error_invalid_arguments(msg);
+}
+
+static DBusMessage *remove_network(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBG("conn %p", conn);
+
+ if (__connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
+ return __connman_error_permission_denied(msg);
+
+ return __connman_error_invalid_arguments(msg);
+}
+
+static DBusMessage *propose_scan(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_device *device = data;
+ int err;
+
+ DBG("conn %p", conn);
+
+ switch (device->mode) {
+ case CONNMAN_DEVICE_MODE_UNKNOWN:
+ case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
+ return __connman_error_not_supported(msg);
+ case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
+ case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
+ break;
+ }
+
+ if (!device->driver || !device->driver->scan)
+ return __connman_error_not_supported(msg);
+
+ if (device->powered == FALSE)
+ return __connman_error_failed(msg, EINVAL);
+
+ err = device->driver->scan(device);
+ if (err < 0)
+ return __connman_error_failed(msg, -err);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static GDBusMethodTable device_methods[] = {
+ { "GetProperties", "", "a{sv}", get_properties },
+ { "SetProperty", "sv", "", set_property },
+ { "JoinNetwork", "a{sv}", "", join_network },
+ { "CreateNetwork", "a{sv}", "o", create_network },
+ { "RemoveNetwork", "o", "", remove_network },
+ { "ProposeScan", "", "", propose_scan },
+ { },
+};
+
+static GDBusSignalTable device_signals[] = {
+ { "PropertyChanged", "sv" },
+ { },
+};
+
+static DBusConnection *connection;
+
+static void append_devices(DBusMessageIter *entry)
+{
+ DBusMessageIter value, iter;
+ const char *key = "Devices";
+
+ dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
+
+ dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
+ &value);
+
+ dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
+ __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
+ dbus_message_iter_close_container(&value, &iter);
+
+ dbus_message_iter_close_container(entry, &value);
+}
+
+static void emit_devices_signal(void)
+{
+ DBusMessage *signal;
+ DBusMessageIter entry;
+
+ signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
+ CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
+ if (signal == NULL)
+ return;
+
+ dbus_message_iter_init_append(signal, &entry);
+
+ append_devices(&entry);
+
+ g_dbus_send_message(connection, signal);
+}
+
+static int register_interface(struct connman_element *element)
+{
+ struct connman_device *device = element->device;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (g_dbus_register_interface(connection, element->path,
+ CONNMAN_DEVICE_INTERFACE,
+ device_methods, device_signals,
+ NULL, device, NULL) == FALSE) {
+ connman_error("Failed to register %s device", element->path);
+ return -EIO;
+ }
+
+ device->registered = TRUE;
+
+ emit_devices_signal();
+
+ return 0;
+}
+
+static void unregister_interface(struct connman_element *element)
+{
+ struct connman_device *device = element->device;
+
+ DBG("element %p name %s", element, element->name);
+
+ device->registered = FALSE;
+
+ emit_devices_signal();
+
+ g_dbus_unregister_interface(connection, element->path,
+ CONNMAN_DEVICE_INTERFACE);
+}
+
+static void device_enable(struct connman_device *device)
+{
+ DBG("device %p", device);
+
+ if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE ||
+ device->policy == CONNMAN_DEVICE_POLICY_OFF)
+ return;
+
+ if (device->powered == TRUE)
+ return;
+
+ if (device->driver->enable) {
+ device->driver->enable(device);
+ __connman_notifier_device_type_increase(device->type);
+ }
+}
+
+static void device_disable(struct connman_device *device)
+{
+ DBG("device %p", device);
+
+ if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE)
+ return;
+
+ if (device->powered == FALSE)
+ return;
+
+ g_hash_table_remove_all(device->networks);
+
+ if (device->driver->disable) {
+ device->driver->disable(device);
+ __connman_notifier_device_type_decrease(device->type);
+ }
+}
+
+static int setup_device(struct connman_device *device)
+{
+ int err;
+
+ DBG("device %p", device);
+
+ err = register_interface(&device->element);
+ if (err < 0) {
+ if (device->driver->remove)
+ device->driver->remove(device);
+ device->driver = NULL;
+ return err;
+ }
+
+ switch (device->mode) {
+ case CONNMAN_DEVICE_MODE_UNKNOWN:
+ case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
+ case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
+ break;
+ case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
+ if (device->secondary == FALSE)
+ __connman_profile_add_device(device);
+ break;
+ }
+
+ device_enable(device);
+
+ return 0;
+}
+
+static void probe_driver(struct connman_element *element, gpointer user_data)
+{
+ struct connman_device_driver *driver = user_data;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (element->device == NULL)
+ return;
+
+ if (element->device->driver != NULL)
+ return;
+
+ if (driver->type != element->device->type)
+ return;
+
+ if (driver->probe(element->device) < 0)
+ return;
+
+ element->device->driver = driver;
+
+ setup_device(element->device);
+}
+
+static void remove_device(struct connman_device *device)
+{
+ DBG("device %p", device);
+
+ device_disable(device);
+
+ switch (device->mode) {
+ case CONNMAN_DEVICE_MODE_UNKNOWN:
+ case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
+ case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
+ break;
+ case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
+ if (device->secondary == FALSE)
+ __connman_profile_remove_device(device);
+ break;
+ }
+
+ unregister_interface(&device->element);
+
+ if (device->driver->remove)
+ device->driver->remove(device);
+
+ device->driver = NULL;
+}
+
+static void remove_driver(struct connman_element *element, gpointer user_data)
+{
+ struct connman_device_driver *driver = user_data;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (element->device == NULL)
+ return;
+
+ if (element->device->driver == driver)
+ remove_device(element->device);
+}
+
+connman_bool_t __connman_device_has_driver(struct connman_device *device)
+{
+ if (device == NULL || device->driver == NULL)
+ return FALSE;
+
+ return device->registered;
+}
+
+static GSList *driver_list = NULL;
+
+static gint compare_priority(gconstpointer a, gconstpointer b)
+{
+ const struct connman_device_driver *driver1 = a;
+ const struct connman_device_driver *driver2 = b;
+
+ return driver2->priority - driver1->priority;
+}
+
+/**
+ * connman_device_driver_register:
+ * @driver: device driver definition
+ *
+ * Register a new device driver
+ *
+ * Returns: %0 on success
+ */
+int connman_device_driver_register(struct connman_device_driver *driver)
+{
+ DBG("driver %p name %s", driver, driver->name);
+
+ driver_list = g_slist_insert_sorted(driver_list, driver,
+ compare_priority);
+
+ __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
+ probe_driver, driver);
+
+ return 0;
+}
+
+/**
+ * connman_device_driver_unregister:
+ * @driver: device driver definition
+ *
+ * Remove a previously registered device driver
+ */
+void connman_device_driver_unregister(struct connman_device_driver *driver)
+{
+ DBG("driver %p name %s", driver, driver->name);
+
+ driver_list = g_slist_remove(driver_list, driver);
+
+ __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
+ remove_driver, driver);
+}
+
+static void unregister_network(gpointer data)
+{
+ struct connman_network *network = data;
+
+ DBG("network %p", network);
+
+ connman_element_unregister((struct connman_element *) network);
+
+ connman_network_unref(network);
+}
+
+static void device_destruct(struct connman_element *element)
+{
+ struct connman_device *device = element->device;
+
+ DBG("element %p name %s", element, element->name);
+
+ g_free(device->ident);
+ g_free(device->node);
+ g_free(device->name);
+ g_free(device->address);
+ g_free(device->interface);
+
+ g_free(device->last_network);
+
+ g_hash_table_destroy(device->networks);
+ device->networks = NULL;
+}
+
+/**
+ * connman_device_create:
+ * @node: device node name (for example an address)
+ * @type: device type
+ *
+ * Allocate a new device of given #type and assign the #node name to it.
+ *
+ * Returns: a newly-allocated #connman_device structure
+ */
+struct connman_device *connman_device_create(const char *node,
+ enum connman_device_type type)
+{
+ struct connman_device *device;
+ const char *str;
+
+ DBG("node %s type %d", node, type);
+
+ device = g_try_new0(struct connman_device, 1);
+ if (device == NULL)
+ return NULL;
+
+ DBG("device %p", device);
+
+ __connman_element_initialize(&device->element);
+
+ device->element.name = g_strdup(node);
+ device->element.type = CONNMAN_ELEMENT_TYPE_DEVICE;
+
+ device->element.device = device;
+ device->element.destruct = device_destruct;
+
+ str = type2string(type);
+ if (str != NULL)
+ connman_element_set_string(&device->element,
+ CONNMAN_PROPERTY_ID_TYPE, str);
+
+ device->element.ipv4.method = CONNMAN_IPV4_METHOD_DHCP;
+
+ device->type = type;
+ device->name = g_strdup(type2description(device->type));
+ device->mode = CONNMAN_DEVICE_MODE_UNKNOWN;
+ device->policy = CONNMAN_DEVICE_POLICY_AUTO;
+ device->secondary = FALSE;
+
+ switch (type) {
+ case CONNMAN_DEVICE_TYPE_UNKNOWN:
+ case CONNMAN_DEVICE_TYPE_VENDOR:
+ device->priority = 0;
+ device->scan_interval = 0;
+ break;
+ case CONNMAN_DEVICE_TYPE_ETHERNET:
+ case CONNMAN_DEVICE_TYPE_WIFI:
+ device->priority = 100;
+ device->scan_interval = 300;
+ break;
+ case CONNMAN_DEVICE_TYPE_WIMAX:
+ device->priority = 20;
+ device->scan_interval = 0;
+ break;
+ case CONNMAN_DEVICE_TYPE_BLUETOOTH:
+ device->priority = 50;
+ device->scan_interval = 0;
+ break;
+ case CONNMAN_DEVICE_TYPE_GPS:
+ device->priority = 0;
+ device->scan_interval = 0;
+ break;
+ case CONNMAN_DEVICE_TYPE_HSO:
+ case CONNMAN_DEVICE_TYPE_NOZOMI:
+ case CONNMAN_DEVICE_TYPE_HUAWEI:
+ case CONNMAN_DEVICE_TYPE_NOVATEL:
+ device->priority = 60;
+ device->scan_interval = 0;
+ break;
+ }
+
+ device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, unregister_network);
+
+ return device;
+}
+
+/**
+ * connman_device_ref:
+ * @device: device structure
+ *
+ * Increase reference counter of device
+ */
+struct connman_device *connman_device_ref(struct connman_device *device)
+{
+ if (connman_element_ref(&device->element) == NULL)
+ return NULL;
+
+ return device;
+}
+
+/**
+ * connman_device_unref:
+ * @device: device structure
+ *
+ * Decrease reference counter of device
+ */
+void connman_device_unref(struct connman_device *device)
+{
+ connman_element_unref(&device->element);
+}
+
+const char *__connman_device_get_type(struct connman_device *device)
+{
+ return type2string(device->type);
+}
+
+/**
+ * connman_device_get_type:
+ * @device: device structure
+ *
+ * Get type of device
+ */
+enum connman_device_type connman_device_get_type(struct connman_device *device)
+{
+ return device->type;
+}
+
+/**
+ * connman_device_get_name:
+ * @device: device structure
+ *
+ * Get unique name of device
+ */
+const char *connman_device_get_name(struct connman_device *device)
+{
+ return device->element.name;
+}
+
+/**
+ * connman_device_get_path:
+ * @device: device structure
+ *
+ * Get path name of device
+ */
+const char *connman_device_get_path(struct connman_device *device)
+{
+ return device->element.path;
+}
+
+/**
+ * connman_device_set_index:
+ * @device: device structure
+ * @index: index number
+ *
+ * Set index number of device
+ */
+void connman_device_set_index(struct connman_device *device, int index)
+{
+ device->element.index = index;
+}
+
+/**
+ * connman_device_get_index:
+ * @device: device structure
+ *
+ * Get index number of device
+ */
+int connman_device_get_index(struct connman_device *device)
+{
+ return device->element.index;
+}
+
+/**
+ * connman_device_set_interface:
+ * @device: device structure
+ * @interface: interface name
+ *
+ * Set interface name of device
+ */
+void connman_device_set_interface(struct connman_device *device,
+ const char *interface)
+{
+ g_free(device->element.devname);
+ device->element.devname = g_strdup(interface);
+
+ g_free(device->interface);
+ device->interface = g_strdup(interface);
+
+ if (device->name == NULL) {
+ const char *str = type2description(device->type);
+ if (str != NULL && device->interface != NULL)
+ device->name = g_strdup_printf("%s (%s)", str,
+ device->interface);
+ }
+}
+
+/**
+ * connman_device_get_interface:
+ * @device: device structure
+ *
+ * Get interface name of device
+ */
+const char *connman_device_get_interface(struct connman_device *device)
+{
+ return device->interface;
+}
+
+/**
+ * connman_device_set_ident:
+ * @device: device structure
+ * @ident: unique identifier
+ *
+ * Set unique identifier of device
+ */
+void connman_device_set_ident(struct connman_device *device,
+ const char *ident)
+{
+ g_free(device->ident);
+ device->ident = g_strdup(ident);
+}
+
+const char *__connman_device_get_ident(struct connman_device *device)
+{
+ return device->ident;
+}
+
+/**
+ * connman_device_set_policy:
+ * @device: device structure
+ * @policy: power and connection policy
+ *
+ * Change power and connection policy of device
+ */
+void connman_device_set_policy(struct connman_device *device,
+ enum connman_device_policy policy)
+{
+ device->policy = policy;
+}
+
+/**
+ * connman_device_set_mode:
+ * @device: device structure
+ * @mode: network mode
+ *
+ * Change network mode of device
+ */
+void connman_device_set_mode(struct connman_device *device,
+ enum connman_device_mode mode)
+{
+ device->mode = mode;
+}
+
+/**
+ * connman_device_get_mode:
+ * @device: device structure
+ *
+ * Get network mode of device
+ */
+enum connman_device_mode connman_device_get_mode(struct connman_device *device)
+{
+ return device->mode;
+}
+
+/**
+ * connman_device_set_secondary:
+ * @device: device structure
+ * @secondary: secondary value
+ *
+ * Change secondary value of device
+ */
+void connman_device_set_secondary(struct connman_device *device,
+ connman_bool_t secondary)
+{
+ device->secondary = secondary;
+}
+
+/**
+ * connman_device_get_secondary:
+ * @device: device structure
+ *
+ * Get secondary value of device
+ */
+connman_bool_t connman_device_get_secondary(struct connman_device *device)
+{
+ return device->secondary;
+}
+
+/**
+ * connman_device_set_powered:
+ * @device: device structure
+ * @powered: powered state
+ *
+ * Change power state of device
+ */
+int connman_device_set_powered(struct connman_device *device,
+ connman_bool_t powered)
+{
+ DBusMessage *signal;
+ DBusMessageIter entry, value;
+ const char *key = "Powered";
+
+ DBG("driver %p powered %d", device, powered);
+
+ if (device->powered == powered)
+ return -EALREADY;
+
+ device->powered = powered;
+
+ if (device->registered == FALSE)
+ return 0;
+
+ signal = dbus_message_new_signal(device->element.path,
+ CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
+ if (signal == NULL)
+ return 0;
+
+ dbus_message_iter_init_append(signal, &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_BOOLEAN_AS_STRING, &value);
+ dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &powered);
+ dbus_message_iter_close_container(&entry, &value);
+
+ g_dbus_send_message(connection, signal);
+
+ if (powered == FALSE)
+ return 0;
+
+ if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
+ return 0;
+
+ if (device->scan_timeout > 0) {
+ g_source_remove(device->scan_timeout);
+ device->scan_timeout = 0;
+ }
+
+ if (device->scan_interval > 0) {
+ guint interval = device->scan_interval;
+ device->scan_timeout = g_timeout_add_seconds(interval,
+ device_scan_trigger, device);
+ }
+
+ if (device->driver->scan)
+ device->driver->scan(device);
+
+ return 0;
+}
+
+/**
+ * connman_device_set_carrier:
+ * @device: device structure
+ * @carrier: carrier state
+ *
+ * Change carrier state of device (only for device without scanning)
+ */
+int connman_device_set_carrier(struct connman_device *device,
+ connman_bool_t carrier)
+{
+ DBG("driver %p carrier %d", device, carrier);
+
+ switch (device->mode) {
+ case CONNMAN_DEVICE_MODE_UNKNOWN:
+ case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
+ case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
+ return -EINVAL;
+ case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
+ break;
+ }
+
+ if (device->carrier == carrier)
+ return -EALREADY;
+
+ device->carrier = carrier;
+
+ return set_carrier(device, device->carrier);
+}
+
+int __connman_device_connect(struct connman_device *device)
+{
+ DBG("device %p", device);
+
+ if (device->disconnected == FALSE)
+ return -EINVAL;
+
+ return 0;
+}
+
+int __connman_device_disconnect(struct connman_device *device)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+
+ DBG("device %p", device);
+
+ connman_device_set_disconnected(device, TRUE);
+
+ g_hash_table_iter_init(&iter, device->networks);
+
+ while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+ struct connman_network *network = value;
+
+ if (connman_network_get_connected(network) == TRUE)
+ __connman_network_disconnect(network);
+ }
+
+ return 0;
+}
+
+static void connect_known_network(struct connman_device *device)
+{
+ struct connman_network *network = NULL;
+ GHashTableIter iter;
+ gpointer key, value;
+ const char *name;
+ unsigned int count = 0;
+
+ DBG("device %p", device);
+
+ g_hash_table_iter_init(&iter, device->networks);
+
+ while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+ connman_uint8_t old_strength, new_strength;
+
+ count++;
+
+ if (connman_network_get_available(value) == FALSE)
+ continue;
+
+ name = connman_network_get_string(value,
+ CONNMAN_PROPERTY_ID_NAME);
+ if (name != NULL && device->last_network != NULL) {
+ if (g_str_equal(name, device->last_network) == TRUE) {
+ network = value;
+ break;
+ }
+ }
+
+ if (network == NULL) {
+ network = value;
+ continue;
+ }
+
+ old_strength = connman_network_get_uint8(network,
+ CONNMAN_PROPERTY_ID_STRENGTH);
+ new_strength = connman_network_get_uint8(value,
+ CONNMAN_PROPERTY_ID_STRENGTH);
+
+ if (new_strength > old_strength)
+ network = value;
+ }
+
+ if (network != NULL) {
+ int err;
+
+ name = connman_network_get_string(value,
+ CONNMAN_PROPERTY_ID_NAME);
+ if (name != NULL) {
+ err = __connman_network_connect(network);
+ if (err == 0 || err == -EINPROGRESS)
+ return;
+ }
+ }
+
+ if (count > 0)
+ return;
+
+ if (device->driver && device->driver->scan)
+ device->driver->scan(device);
+}
+
+static void mark_network_unavailable(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ struct connman_network *network = value;
+
+ if (connman_network_get_connected(network) == TRUE)
+ return;
+
+ connman_network_set_available(network, FALSE);
+}
+
+static gboolean remove_unavailable_network(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ struct connman_network *network = value;
+
+ if (connman_network_get_connected(network) == TRUE)
+ return FALSE;
+
+ if (connman_network_get_available(network) == TRUE)
+ return FALSE;
+
+ return TRUE;
+}
+
+/**
+ * connman_device_set_scanning:
+ * @device: device structure
+ * @scanning: scanning state
+ *
+ * Change scanning state of device
+ */
+int connman_device_set_scanning(struct connman_device *device,
+ connman_bool_t scanning)
+{
+ DBusMessage *signal;
+ DBusMessageIter entry, value;
+ const char *key = "Scanning";
+
+ DBG("driver %p scanning %d", device, scanning);
+
+ if (!device->driver || !device->driver->scan)
+ return -EINVAL;
+
+ if (device->scanning == scanning)
+ return -EALREADY;
+
+ device->scanning = scanning;
+
+ signal = dbus_message_new_signal(device->element.path,
+ CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
+ if (signal == NULL)
+ return 0;
+
+ dbus_message_iter_init_append(signal, &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_BOOLEAN_AS_STRING, &value);
+ dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning);
+ dbus_message_iter_close_container(&entry, &value);
+
+ g_dbus_send_message(connection, signal);
+
+ if (scanning == TRUE) {
+ if (device->scan_timeout > 0) {
+ g_source_remove(device->scan_timeout);
+ device->scan_timeout = 0;
+ }
+
+ if (device->scan_interval > 0) {
+ guint interval = device->scan_interval;
+ device->scan_timeout = g_timeout_add_seconds(interval,
+ device_scan_trigger, device);
+ }
+
+ g_hash_table_foreach(device->networks,
+ mark_network_unavailable, NULL);
+ return 0;
+ }
+
+ g_hash_table_foreach_remove(device->networks,
+ remove_unavailable_network, NULL);
+
+ if (device->connections > 0)
+ return 0;
+
+ if (device->disconnected == TRUE)
+ return 0;
+
+ if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
+ return 0;
+
+ connect_known_network(device);
+
+ return 0;
+}
+
+/**
+ * connman_device_set_disconnected:
+ * @device: device structure
+ * @disconnected: disconnected state
+ *
+ * Change disconnected state of device (only for device with networks)
+ */
+int connman_device_set_disconnected(struct connman_device *device,
+ connman_bool_t disconnected)
+{
+ DBG("driver %p disconnected %d", device, disconnected);
+
+ switch (device->mode) {
+ case CONNMAN_DEVICE_MODE_UNKNOWN:
+ case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
+ return -EINVAL;
+ case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
+ case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
+ break;
+ }
+
+ if (device->disconnected == disconnected)
+ return -EALREADY;
+
+ device->disconnected = disconnected;
+
+ return 0;
+}
+
+/**
+ * connman_device_set_string:
+ * @device: device structure
+ * @key: unique identifier
+ * @value: string value
+ *
+ * Set string value for specific key
+ */
+int connman_device_set_string(struct connman_device *device,
+ const char *key, const char *value)
+{
+ DBG("device %p key %s value %s", device, key, value);
+
+ if (g_str_equal(key, "Address") == TRUE) {
+ g_free(device->address);
+ device->address = g_strdup(value);
+ } else if (g_str_equal(key, "Name") == TRUE) {
+ g_free(device->name);
+ device->name = g_strdup(value);
+ } else if (g_str_equal(key, "Node") == TRUE) {
+ g_free(device->node);
+ device->node = g_strdup(value);
+ }
+
+ return connman_element_set_string(&device->element, key, value);
+}
+
+/**
+ * connman_device_get_string:
+ * @device: device structure
+ * @key: unique identifier
+ *
+ * Get string value for specific key
+ */
+const char *connman_device_get_string(struct connman_device *device,
+ const char *key)
+{
+ DBG("device %p key %s", device, key);
+
+ if (g_str_equal(key, "Address") == TRUE)
+ return device->address;
+ else if (g_str_equal(key, "Name") == TRUE)
+ return device->name;
+ else if (g_str_equal(key, "Node") == TRUE)
+ return device->node;
+
+ return connman_element_get_string(&device->element, key);
+}
+
+static void set_offlinemode(struct connman_element *element, gpointer user_data)
+{
+ struct connman_device *device = element->device;
+ connman_bool_t offlinemode = GPOINTER_TO_UINT(user_data);
+ connman_bool_t powered;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (device == NULL)
+ return;
+
+ powered = (offlinemode == TRUE) ? FALSE : TRUE;
+
+ if (device->powered == powered)
+ return;
+
+ set_powered(device, powered);
+}
+
+int __connman_device_set_offlinemode(connman_bool_t offlinemode)
+{
+ DBG("offlinmode %d", offlinemode);
+
+ __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
+ set_offlinemode, GUINT_TO_POINTER(offlinemode));
+
+ __connman_notifier_offline_mode(offlinemode);
+
+ return 0;
+}
+
+void __connman_device_increase_connections(struct connman_device *device)
+{
+ device->connections++;
+}
+
+void __connman_device_decrease_connections(struct connman_device *device)
+{
+ device->connections--;
+}
+
+/**
+ * connman_device_add_network:
+ * @device: device structure
+ * @network: network structure
+ *
+ * Add new network to the device
+ */
+int connman_device_add_network(struct connman_device *device,
+ struct connman_network *network)
+{
+ const char *identifier = connman_network_get_identifier(network);
+ int err;
+
+ DBG("device %p network %p", device, network);
+
+ switch (device->mode) {
+ case CONNMAN_DEVICE_MODE_UNKNOWN:
+ case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
+ return -EINVAL;
+ case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
+ case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
+ break;
+ }
+
+ __connman_network_set_device(network, device);
+
+ __connman_storage_load_network(network);
+
+ err = connman_element_register((struct connman_element *) network,
+ &device->element);
+ if (err < 0) {
+ __connman_network_set_device(network, NULL);
+ return err;
+ }
+
+ g_hash_table_insert(device->networks, g_strdup(identifier),
+ network);
+
+ return 0;
+}
+
+/**
+ * connman_device_get_network:
+ * @device: device structure
+ * @identifier: network identifier
+ *
+ * Get network for given identifier
+ */
+struct connman_network *connman_device_get_network(struct connman_device *device,
+ const char *identifier)
+{
+ DBG("device %p identifier %s", device, identifier);
+
+ return g_hash_table_lookup(device->networks, identifier);
+}
+
+/**
+ * connman_device_remove_network:
+ * @device: device structure
+ * @identifier: network identifier
+ *
+ * Remove network for given identifier
+ */
+int connman_device_remove_network(struct connman_device *device,
+ const char *identifier)
+{
+ DBG("device %p identifier %s", device, identifier);
+
+ g_hash_table_remove(device->networks, identifier);
+
+ return 0;
+}
+
+void __connman_device_set_network(struct connman_device *device,
+ struct connman_network *network)
+{
+ const char *name;
+
+ if (device->network == network)
+ return;
+
+ if (device->network != NULL)
+ connman_network_unref(device->network);
+
+ if (network != NULL) {
+ name = connman_network_get_string(network,
+ CONNMAN_PROPERTY_ID_NAME);
+ g_free(device->last_network);
+ device->last_network = g_strdup(name);
+
+ device->network = connman_network_ref(network);
+ } else {
+ g_free(device->last_network);
+ device->last_network = NULL;
+
+ device->network = NULL;
+ }
+}
+
+/**
+ * connman_device_register:
+ * @device: device structure
+ *
+ * Register device with the system
+ */
+int connman_device_register(struct connman_device *device)
+{
+ __connman_storage_load_device(device);
+
+ switch (device->mode) {
+ case CONNMAN_DEVICE_MODE_UNKNOWN:
+ case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
+ break;
+ case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
+ case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
+ __connman_storage_init_network(device);
+ break;
+ }
+
+ return connman_element_register(&device->element, NULL);
+}
+
+/**
+ * connman_device_unregister:
+ * @device: device structure
+ *
+ * Unregister device with the system
+ */
+void connman_device_unregister(struct connman_device *device)
+{
+ __connman_storage_save_device(device);
+
+ connman_element_unregister(&device->element);
+}
+
+/**
+ * connman_device_get_data:
+ * @device: device structure
+ *
+ * Get private device data pointer
+ */
+void *connman_device_get_data(struct connman_device *device)
+{
+ return device->driver_data;
+}
+
+/**
+ * connman_device_set_data:
+ * @device: device structure
+ * @data: data pointer
+ *
+ * Set private device data pointer
+ */
+void connman_device_set_data(struct connman_device *device, void *data)
+{
+ device->driver_data = data;
+}
+
+static gboolean match_driver(struct connman_device *device,
+ struct connman_device_driver *driver)
+{
+ if (device->type == driver->type ||
+ driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
+ return TRUE;
+
+ return FALSE;
+}
+
+static int device_probe(struct connman_element *element)
+{
+ struct connman_device *device = element->device;
+ GSList *list;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (device == NULL)
+ return -ENODEV;
+
+ if (device->driver != NULL)
+ return -EALREADY;
+
+ for (list = driver_list; list; list = list->next) {
+ struct connman_device_driver *driver = list->data;
+
+ if (match_driver(device, driver) == FALSE)
+ continue;
+
+ DBG("driver %p name %s", driver, driver->name);
+
+ if (driver->probe(device) == 0) {
+ device->driver = driver;
+ break;
+ }
+ }
+
+ if (device->driver == NULL)
+ return -ENODEV;
+
+ return setup_device(device);
+}
+
+static void device_remove(struct connman_element *element)
+{
+ struct connman_device *device = element->device;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (device == NULL)
+ return;
+
+ if (device->driver == NULL)
+ return;
+
+ remove_device(device);
+}
+
+static struct connman_driver device_driver = {
+ .name = "device",
+ .type = CONNMAN_ELEMENT_TYPE_DEVICE,
+ .priority = CONNMAN_DRIVER_PRIORITY_LOW,
+ .probe = device_probe,
+ .remove = device_remove,
+};
+
+static int device_load(struct connman_device *device)
+{
+ GKeyFile *keyfile;
+ gchar *pathname, *identifier, *data = NULL;
+ gsize length;
+ char *str;
+ int val;
+
+ DBG("device %p", device);
+
+ pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR,
+ __connman_profile_active_ident());
+ if (pathname == NULL)
+ return -ENOMEM;
+
+ keyfile = g_key_file_new();
+
+ if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
+ g_free(pathname);
+ return -ENOENT;
+ }
+
+ g_free(pathname);
+
+ if (g_key_file_load_from_data(keyfile, data, length,
+ 0, NULL) == FALSE) {
+ g_free(data);
+ return -EILSEQ;
+ }
+
+ g_free(data);
+
+ identifier = g_strdup_printf("device_%s", device->element.name);
+ if (identifier == NULL)
+ goto done;
+
+ str = g_key_file_get_string(keyfile, identifier, "Policy", NULL);
+ if (str != NULL) {
+ device->policy = string2policy(str);
+ g_free(str);
+ }
+
+ switch (device->mode) {
+ case CONNMAN_DEVICE_MODE_UNKNOWN:
+ case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
+ break;
+ case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
+ case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
+ val = g_key_file_get_integer(keyfile, identifier,
+ "ScanInterval", NULL);
+ if (val > 0)
+ device->scan_interval = val;
+ break;
+ }
+
+done:
+ g_key_file_free(keyfile);
+
+ g_free(identifier);
+
+ return 0;
+}
+
+static int device_save(struct connman_device *device)
+{
+ GKeyFile *keyfile;
+ gchar *pathname, *identifier = NULL, *data = NULL;
+ gsize length;
+ const char *str;
+
+ DBG("device %p", device);
+
+ pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR,
+ __connman_profile_active_ident());
+ if (pathname == NULL)
+ return -ENOMEM;
+
+ keyfile = g_key_file_new();
+
+ if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
+ goto update;
+
+ if (length > 0) {
+ if (g_key_file_load_from_data(keyfile, data, length,
+ 0, NULL) == FALSE)
+ goto done;
+ }
+
+ g_free(data);
+
+update:
+ identifier = g_strdup_printf("device_%s", device->element.name);
+ if (identifier == NULL)
+ goto done;
+
+ str = policy2string(device->policy);
+ if (str != NULL)
+ g_key_file_set_string(keyfile, identifier, "Policy", str);
+
+ switch (device->mode) {
+ case CONNMAN_DEVICE_MODE_UNKNOWN:
+ case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
+ break;
+ case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
+ case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
+ if (device->scan_interval > 0)
+ g_key_file_set_integer(keyfile, identifier,
+ "ScanInterval", device->scan_interval);
+ break;
+ }
+
+ data = g_key_file_to_data(keyfile, &length, NULL);
+
+ if (g_file_set_contents(pathname, data, length, NULL) == FALSE)
+ connman_error("Failed to store device information");
+
+done:
+ g_free(data);
+
+ g_key_file_free(keyfile);
+
+ g_free(identifier);
+ g_free(pathname);
+
+ return 0;
+}
+
+static struct connman_storage device_storage = {
+ .name = "device",
+ .priority = CONNMAN_STORAGE_PRIORITY_LOW,
+ .device_load = device_load,
+ .device_save = device_save,
+};
+
+int __connman_device_init(void)
+{
+ DBG("");
+
+ connection = connman_dbus_get_connection();
+
+ if (connman_storage_register(&device_storage) < 0)
+ connman_error("Failed to register device storage");
+
+ return connman_driver_register(&device_driver);
+}
+
+void __connman_device_cleanup(void)
+{
+ DBG("");
+
+ connman_driver_unregister(&device_driver);
+
+ connman_storage_unregister(&device_storage);
+
+ dbus_connection_unref(connection);
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "connman.h"
+
+static DBusConnection *connection;
+
+static GNode *element_root = NULL;
+static GSList *driver_list = NULL;
+static gchar *device_filter = NULL;
+
+static gboolean started = FALSE;
+
+static const char *type2string(enum connman_element_type type)
+{
+ switch (type) {
+ case CONNMAN_ELEMENT_TYPE_UNKNOWN:
+ return "unknown";
+ case CONNMAN_ELEMENT_TYPE_ROOT:
+ return "root";
+ case CONNMAN_ELEMENT_TYPE_PROFILE:
+ return "profile";
+ case CONNMAN_ELEMENT_TYPE_DEVICE:
+ return "device";
+ case CONNMAN_ELEMENT_TYPE_NETWORK:
+ return "network";
+ case CONNMAN_ELEMENT_TYPE_SERVICE:
+ return "service";
+ case CONNMAN_ELEMENT_TYPE_PPP:
+ return "ppp";
+ case CONNMAN_ELEMENT_TYPE_IPV4:
+ return "ipv4";
+ case CONNMAN_ELEMENT_TYPE_IPV6:
+ return "ipv6";
+ case CONNMAN_ELEMENT_TYPE_DHCP:
+ return "dhcp";
+ case CONNMAN_ELEMENT_TYPE_BOOTP:
+ return "bootp";
+ case CONNMAN_ELEMENT_TYPE_ZEROCONF:
+ return "zeroconf";
+ case CONNMAN_ELEMENT_TYPE_CONNECTION:
+ return "connection";
+ case CONNMAN_ELEMENT_TYPE_VENDOR:
+ return "vendor";
+ }
+
+ return NULL;
+}
+
+const char *__connman_ipv4_method2string(enum connman_ipv4_method method)
+{
+ switch (method) {
+ case CONNMAN_IPV4_METHOD_UNKNOWN:
+ return "unknown";
+ case CONNMAN_IPV4_METHOD_OFF:
+ return "off";
+ case CONNMAN_IPV4_METHOD_STATIC:
+ return "static";
+ case CONNMAN_IPV4_METHOD_DHCP:
+ return "dhcp";
+ }
+
+ return "unknown";
+}
+
+enum connman_ipv4_method __connman_ipv4_string2method(const char *method)
+{
+ if (strcasecmp(method, "off") == 0)
+ return CONNMAN_IPV4_METHOD_OFF;
+ else if (strcasecmp(method, "static") == 0)
+ return CONNMAN_IPV4_METHOD_STATIC;
+ else if (strcasecmp(method, "dhcp") == 0)
+ return CONNMAN_IPV4_METHOD_DHCP;
+ else
+ return CONNMAN_IPV4_METHOD_UNKNOWN;
+}
+
+static void emit_element_signal(DBusConnection *conn, const char *member,
+ struct connman_element *element)
+{
+ DBusMessage *signal;
+
+ if (__connman_debug_enabled() == FALSE)
+ return;
+
+ DBG("conn %p member %s", conn, member);
+
+ if (element == NULL)
+ return;
+
+ signal = dbus_message_new_signal(element->path,
+ CONNMAN_DEBUG_INTERFACE, member);
+ if (signal == NULL)
+ return;
+
+ g_dbus_send_message(conn, signal);
+}
+
+struct foreach_data {
+ enum connman_element_type type;
+ element_cb_t callback;
+ gpointer user_data;
+};
+
+static gboolean foreach_callback(GNode *node, gpointer user_data)
+{
+ struct connman_element *element = node->data;
+ struct foreach_data *data = user_data;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
+ return FALSE;
+
+ if (data->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
+ data->type != element->type)
+ return FALSE;
+
+ if (data->callback)
+ data->callback(element, data->user_data);
+
+ return FALSE;
+}
+
+void __connman_element_foreach(struct connman_element *element,
+ enum connman_element_type type,
+ element_cb_t callback, gpointer user_data)
+{
+ struct foreach_data data = { type, callback, user_data };
+ GNode *node;
+
+ DBG("");
+
+ if (element != NULL) {
+ node = g_node_find(element_root, G_PRE_ORDER,
+ G_TRAVERSE_ALL, element);
+ if (node == NULL)
+ return;
+ } else
+ node = element_root;
+
+ g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
+ foreach_callback, &data);
+}
+
+struct append_filter {
+ enum connman_element_type type;
+ DBusMessageIter *iter;
+};
+
+static gboolean append_path(GNode *node, gpointer user_data)
+{
+ struct connman_element *element = node->data;
+ struct append_filter *filter = user_data;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
+ return FALSE;
+
+ if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
+ filter->type != element->type)
+ return FALSE;
+
+ if (filter->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
+ __connman_device_has_driver(element->device) == FALSE)
+ return FALSE;
+
+ if (filter->type == CONNMAN_ELEMENT_TYPE_NETWORK &&
+ __connman_network_has_driver(element->network) == FALSE)
+ return FALSE;
+
+ dbus_message_iter_append_basic(filter->iter,
+ DBUS_TYPE_OBJECT_PATH, &element->path);
+
+ return FALSE;
+}
+
+void __connman_element_list(struct connman_element *element,
+ enum connman_element_type type,
+ DBusMessageIter *iter)
+{
+ struct append_filter filter = { type, iter };
+ GNode *node;
+
+ DBG("");
+
+ if (element != NULL) {
+ node = g_node_find(element_root, G_PRE_ORDER,
+ G_TRAVERSE_ALL, element);
+ if (node == NULL)
+ return;
+ } else
+ node = element_root;
+
+ g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
+ append_path, &filter);
+}
+
+struct count_data {
+ enum connman_element_type type;
+ int count;
+};
+
+static gboolean count_element(GNode *node, gpointer user_data)
+{
+ struct connman_element *element = node->data;
+ struct count_data *data = user_data;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
+ return FALSE;
+
+ if (data->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
+ data->type != element->type)
+ return FALSE;
+
+ data->count++;
+
+ return FALSE;
+}
+
+int __connman_element_count(struct connman_element *element,
+ enum connman_element_type type)
+{
+ struct count_data data = { type, 0 };
+ GNode *node;
+
+ DBG("");
+
+ if (element != NULL) {
+ node = g_node_find(element_root, G_PRE_ORDER,
+ G_TRAVERSE_ALL, element);
+ if (node == NULL)
+ return 0;
+ } else
+ node = element_root;
+
+ g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
+ count_element, &data);
+
+ return data.count;
+}
+
+static struct connman_network *__connman_element_get_network(struct connman_element *element)
+{
+ if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK &&
+ element->network != NULL)
+ return element->network;
+
+ if (element->parent == NULL)
+ return NULL;
+
+ return __connman_element_get_network(element->parent);
+}
+
+struct connman_service *__connman_element_get_service(struct connman_element *element)
+{
+ struct connman_service *service = NULL;
+ struct connman_network *network;
+ struct connman_device *device;
+ enum connman_device_type type;
+
+ device = __connman_element_get_device(element);
+ if (device == NULL)
+ return NULL;
+
+ type = connman_device_get_type(device);
+
+ switch (type) {
+ case CONNMAN_DEVICE_TYPE_UNKNOWN:
+ case CONNMAN_DEVICE_TYPE_VENDOR:
+ case CONNMAN_DEVICE_TYPE_BLUETOOTH:
+ case CONNMAN_DEVICE_TYPE_GPS:
+ case CONNMAN_DEVICE_TYPE_HSO:
+ case CONNMAN_DEVICE_TYPE_NOZOMI:
+ case CONNMAN_DEVICE_TYPE_HUAWEI:
+ case CONNMAN_DEVICE_TYPE_NOVATEL:
+ break;
+ case CONNMAN_DEVICE_TYPE_ETHERNET:
+ service = __connman_service_lookup_from_device(device);
+ break;
+ case CONNMAN_DEVICE_TYPE_WIFI:
+ case CONNMAN_DEVICE_TYPE_WIMAX:
+ network = __connman_element_get_network(element);
+ if (network == NULL)
+ return NULL;
+ service = __connman_service_lookup_from_network(network);
+ break;
+ }
+
+ return service;
+}
+
+struct connman_device *__connman_element_get_device(struct connman_element *element)
+{
+ if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
+ element->device != NULL)
+ return element->device;
+
+ if (element->parent == NULL)
+ return NULL;
+
+ return __connman_element_get_device(element->parent);
+}
+
+const char *__connman_element_get_device_path(struct connman_element *element)
+{
+ struct connman_device *device;
+
+ device = __connman_element_get_device(element);
+ if (device == NULL)
+ return NULL;
+
+ return connman_device_get_path(device);
+}
+
+const char *__connman_element_get_network_path(struct connman_element *element)
+{
+ if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK &&
+ element->network != NULL)
+ return element->path;
+
+ if (element->parent == NULL)
+ return NULL;
+
+ return __connman_element_get_network_path(element->parent);
+}
+
+static gint compare_priority(gconstpointer a, gconstpointer b)
+{
+ const struct connman_driver *driver1 = a;
+ const struct connman_driver *driver2 = b;
+
+ return driver2->priority - driver1->priority;
+}
+
+static gboolean match_driver(struct connman_element *element,
+ struct connman_driver *driver)
+{
+ if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
+ return FALSE;
+
+ if (element->type == driver->type ||
+ driver->type == CONNMAN_ELEMENT_TYPE_UNKNOWN)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean probe_driver(GNode *node, gpointer data)
+{
+ struct connman_element *element = node->data;
+ struct connman_driver *driver = data;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (!element->driver && match_driver(element, driver) == TRUE) {
+ if (driver->probe(element) < 0)
+ return FALSE;
+
+ __connman_element_lock(element);
+ element->driver = driver;
+ __connman_element_unlock(element);
+ }
+
+ return FALSE;
+}
+
+void __connman_driver_rescan(struct connman_driver *driver)
+{
+ DBG("driver %p name %s", driver, driver->name);
+
+ if (!driver->probe)
+ return;
+
+ if (element_root != NULL)
+ g_node_traverse(element_root, G_PRE_ORDER,
+ G_TRAVERSE_ALL, -1, probe_driver, driver);
+}
+
+/**
+ * connman_driver_register:
+ * @driver: driver definition
+ *
+ * Register a new driver
+ *
+ * Returns: %0 on success
+ */
+int connman_driver_register(struct connman_driver *driver)
+{
+ DBG("driver %p name %s", driver, driver->name);
+
+ if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
+ return -EINVAL;
+
+ if (!driver->probe)
+ return -EINVAL;
+
+ driver_list = g_slist_insert_sorted(driver_list, driver,
+ compare_priority);
+
+ if (started == FALSE)
+ return 0;
+
+ if (element_root != NULL)
+ g_node_traverse(element_root, G_PRE_ORDER,
+ G_TRAVERSE_ALL, -1, probe_driver, driver);
+
+ return 0;
+}
+
+static gboolean remove_driver(GNode *node, gpointer data)
+{
+ struct connman_element *element = node->data;
+ struct connman_driver *driver = data;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (element->driver == driver) {
+ if (driver->remove)
+ driver->remove(element);
+
+ __connman_element_lock(element);
+ element->driver = NULL;
+ __connman_element_unlock(element);
+ }
+
+ return FALSE;
+}
+
+/**
+ * connman_driver_unregister:
+ * @driver: driver definition
+ *
+ * Remove a previously registered driver
+ */
+void connman_driver_unregister(struct connman_driver *driver)
+{
+ DBG("driver %p name %s", driver, driver->name);
+
+ driver_list = g_slist_remove(driver_list, driver);
+
+ if (element_root != NULL)
+ g_node_traverse(element_root, G_POST_ORDER,
+ G_TRAVERSE_ALL, -1, remove_driver, driver);
+}
+
+static void unregister_property(gpointer data)
+{
+ struct connman_property *property = data;
+
+ DBG("property %p", property);
+
+ g_free(property->value);
+ g_free(property);
+}
+
+void __connman_element_initialize(struct connman_element *element)
+{
+ DBG("element %p", element);
+
+ element->refcount = 1;
+
+ element->name = NULL;
+ element->type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
+ element->state = CONNMAN_ELEMENT_STATE_UNKNOWN;
+ element->error = CONNMAN_ELEMENT_ERROR_UNKNOWN;
+ element->index = -1;
+ element->enabled = FALSE;
+
+ element->configuring = FALSE;
+
+ element->properties = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, unregister_property);
+}
+
+/**
+ * connman_element_create:
+ * @name: element name
+ *
+ * Allocate a new element and assign the given #name to it. If the name
+ * is #NULL, it will be later on created based on the element type.
+ *
+ * Returns: a newly-allocated #connman_element structure
+ */
+struct connman_element *connman_element_create(const char *name)
+{
+ struct connman_element *element;
+
+ element = g_try_new0(struct connman_element, 1);
+ if (element == NULL)
+ return NULL;
+
+ DBG("element %p", element);
+
+ __connman_element_initialize(element);
+
+ return element;
+}
+
+struct connman_element *connman_element_ref(struct connman_element *element)
+{
+ DBG("element %p name %s refcount %d", element, element->name,
+ g_atomic_int_get(&element->refcount) + 1);
+
+ g_atomic_int_inc(&element->refcount);
+
+ return element;
+}
+
+static void free_properties(struct connman_element *element)
+{
+ DBG("element %p name %s", element, element->name);
+
+ __connman_element_lock(element);
+
+ g_hash_table_destroy(element->properties);
+ element->properties = NULL;
+
+ __connman_element_unlock(element);
+}
+
+void connman_element_unref(struct connman_element *element)
+{
+ DBG("element %p name %s refcount %d", element, element->name,
+ g_atomic_int_get(&element->refcount) - 1);
+
+ if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
+ if (element->destruct)
+ element->destruct(element);
+ free_properties(element);
+ g_free(element->ipv4.address);
+ g_free(element->ipv4.netmask);
+ g_free(element->ipv4.gateway);
+ g_free(element->ipv4.network);
+ g_free(element->ipv4.broadcast);
+ g_free(element->ipv4.nameserver);
+ g_free(element->devname);
+ g_free(element->path);
+ g_free(element->name);
+ g_free(element);
+ }
+}
+
+static int set_static_property(struct connman_element *element,
+ const char *name, int type, const void *value)
+{
+ struct connman_property *property;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
+ return -EINVAL;
+
+ property = g_try_new0(struct connman_property, 1);
+ if (property == NULL)
+ return -ENOMEM;
+
+ property->id = CONNMAN_PROPERTY_ID_INVALID;
+ property->type = type;
+
+ DBG("name %s type %d value %p", name, type, value);
+
+ switch (type) {
+ case DBUS_TYPE_STRING:
+ property->value = g_strdup(*((const char **) value));
+ break;
+ case DBUS_TYPE_BYTE:
+ property->value = g_try_malloc(1);
+ if (property->value != NULL)
+ memcpy(property->value, value, 1);
+ break;
+ }
+
+ __connman_element_lock(element);
+
+ g_hash_table_replace(element->properties, g_strdup(name), property);
+
+ __connman_element_unlock(element);
+
+ return 0;
+}
+
+static int set_static_array_property(struct connman_element *element,
+ const char *name, int type, const void *value, int len)
+{
+ struct connman_property *property;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (type != DBUS_TYPE_BYTE)
+ return -EINVAL;
+
+ property = g_try_new0(struct connman_property, 1);
+ if (property == NULL)
+ return -ENOMEM;
+
+ property->id = CONNMAN_PROPERTY_ID_INVALID;
+ property->type = DBUS_TYPE_ARRAY;
+ property->subtype = type;
+
+ DBG("name %s type %d value %p", name, type, value);
+
+ switch (type) {
+ case DBUS_TYPE_BYTE:
+ property->value = g_try_malloc(len);
+ if (property->value != NULL) {
+ memcpy(property->value,
+ *((const unsigned char **) value), len);
+ property->size = len;
+ }
+ break;
+ }
+
+ __connman_element_lock(element);
+
+ g_hash_table_replace(element->properties, g_strdup(name), property);
+
+ __connman_element_unlock(element);
+
+ return 0;
+}
+
+#if 0
+static int set_property(struct connman_element *element,
+ enum connman_property_id id, const void *value)
+{
+ switch (id) {
+ case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
+ __connman_element_lock(element);
+ g_free(element->ipv4.address);
+ element->ipv4.address = g_strdup(*((const char **) value));
+ __connman_element_unlock(element);
+ break;
+ case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
+ __connman_element_lock(element);
+ g_free(element->ipv4.netmask);
+ element->ipv4.netmask = g_strdup(*((const char **) value));
+ __connman_element_unlock(element);
+ break;
+ case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
+ __connman_element_lock(element);
+ g_free(element->ipv4.gateway);
+ element->ipv4.gateway = g_strdup(*((const char **) value));
+ __connman_element_unlock(element);
+ break;
+ case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
+ __connman_element_lock(element);
+ g_free(element->ipv4.broadcast);
+ element->ipv4.broadcast = g_strdup(*((const char **) value));
+ __connman_element_unlock(element);
+ break;
+ case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
+ __connman_element_lock(element);
+ g_free(element->ipv4.nameserver);
+ element->ipv4.nameserver = g_strdup(*((const char **) value));
+ __connman_element_unlock(element);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+#endif
+
+int connman_element_get_value(struct connman_element *element,
+ enum connman_property_id id, void *value)
+{
+ if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
+ return -EINVAL;
+
+ switch (id) {
+ case CONNMAN_PROPERTY_ID_IPV4_METHOD:
+ if (element->ipv4.method == CONNMAN_IPV4_METHOD_UNKNOWN)
+ return connman_element_get_value(element->parent,
+ id, value);
+ __connman_element_lock(element);
+ *((const char **) value) = __connman_ipv4_method2string(element->ipv4.method);
+ __connman_element_unlock(element);
+ break;
+ case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
+ if (element->ipv4.address == NULL)
+ return connman_element_get_value(element->parent,
+ id, value);
+ __connman_element_lock(element);
+ *((char **) value) = element->ipv4.address;
+ __connman_element_unlock(element);
+ break;
+ case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
+ if (element->ipv4.netmask == NULL)
+ return connman_element_get_value(element->parent,
+ id, value);
+ __connman_element_lock(element);
+ *((char **) value) = element->ipv4.netmask;
+ __connman_element_unlock(element);
+ break;
+ case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
+ if (element->ipv4.gateway == NULL)
+ return connman_element_get_value(element->parent,
+ id, value);
+ __connman_element_lock(element);
+ *((char **) value) = element->ipv4.gateway;
+ __connman_element_unlock(element);
+ break;
+ case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
+ if (element->ipv4.broadcast == NULL)
+ return connman_element_get_value(element->parent,
+ id, value);
+ __connman_element_lock(element);
+ *((char **) value) = element->ipv4.broadcast;
+ __connman_element_unlock(element);
+ break;
+ case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
+ if (element->ipv4.nameserver == NULL)
+ return connman_element_get_value(element->parent,
+ id, value);
+ __connman_element_lock(element);
+ *((char **) value) = element->ipv4.nameserver;
+ __connman_element_unlock(element);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static gboolean get_static_property(struct connman_element *element,
+ const char *name, void *value)
+{
+ struct connman_property *property;
+ gboolean found = FALSE;
+
+ DBG("element %p name %s", element, element->name);
+
+ __connman_element_lock(element);
+
+ property = g_hash_table_lookup(element->properties, name);
+ if (property != NULL) {
+ switch (property->type) {
+ case DBUS_TYPE_STRING:
+ *((char **) value) = property->value;
+ found = TRUE;
+ break;
+ case DBUS_TYPE_BYTE:
+ memcpy(value, property->value, 1);
+ found = TRUE;
+ break;
+ }
+ }
+
+ __connman_element_unlock(element);
+
+ if (found == FALSE && element->parent != NULL)
+ return get_static_property(element->parent, name, value);
+
+ return found;
+}
+
+static gboolean get_static_array_property(struct connman_element *element,
+ const char *name, void *value, unsigned int *len)
+{
+ struct connman_property *property;
+ gboolean found = FALSE;
+
+ DBG("element %p name %s", element, element->name);
+
+ __connman_element_lock(element);
+
+ property = g_hash_table_lookup(element->properties, name);
+ if (property != NULL) {
+ *((char **) value) = property->value;
+ *len = property->size;
+ found = TRUE;
+ }
+
+ __connman_element_unlock(element);
+
+ return found;
+}
+
+#if 0
+static gboolean match_static_property(struct connman_element *element,
+ const char *name, const void *value)
+{
+ struct connman_property *property;
+ gboolean result = FALSE;
+
+ DBG("element %p name %s", element, element->name);
+
+ __connman_element_lock(element);
+
+ property = g_hash_table_lookup(element->properties, name);
+ if (property != NULL) {
+ if (property->type == DBUS_TYPE_STRING)
+ result = g_str_equal(property->value,
+ *((const char **) value));
+ }
+
+ __connman_element_unlock(element);
+
+ return result;
+}
+#endif
+
+/**
+ * connman_element_set_string:
+ * @element: element structure
+ * @key: unique identifier
+ * @value: string value
+ *
+ * Set string value for specific key
+ */
+int connman_element_set_string(struct connman_element *element,
+ const char *key, const char *value)
+{
+ return set_static_property(element, key, DBUS_TYPE_STRING, &value);
+}
+
+/**
+ * connman_element_get_string:
+ * @element: element structure
+ * @key: unique identifier
+ *
+ * Get string value for specific key
+ */
+const char *connman_element_get_string(struct connman_element *element,
+ const char *key)
+{
+ const char *value;
+
+ if (get_static_property(element, key, &value) == FALSE)
+ return NULL;
+
+ return value;
+}
+
+/**
+ * connman_element_set_uint8:
+ * @element: element structure
+ * @key: unique identifier
+ * @value: integer value
+ *
+ * Set integer value for specific key
+ */
+int connman_element_set_uint8(struct connman_element *element,
+ const char *key, connman_uint8_t value)
+{
+ return set_static_property(element, key, DBUS_TYPE_BYTE, &value);
+}
+
+/**
+ * connman_element_get_uint8:
+ * @element: element structure
+ * @key: unique identifier
+ *
+ * Get integer value for specific key
+ */
+connman_uint8_t connman_element_get_uint8(struct connman_element *element,
+ const char *key)
+{
+ connman_uint8_t value;
+
+ if (get_static_property(element, key, &value) == FALSE)
+ return 0;
+
+ return value;
+}
+
+/**
+ * connman_element_set_blob:
+ * @element: element structure
+ * @key: unique identifier
+ * @data: blob data
+ * @size: blob size
+ *
+ * Set binary blob value for specific key
+ */
+int connman_element_set_blob(struct connman_element *element,
+ const char *key, const void *data, unsigned int size)
+{
+ return set_static_array_property(element, key,
+ DBUS_TYPE_BYTE, &data, size);
+}
+
+/**
+ * connman_element_get_blob:
+ * @element: element structure
+ * @key: unique identifier
+ * @size: pointer to blob size
+ *
+ * Get binary blob value for specific key
+ */
+const void *connman_element_get_blob(struct connman_element *element,
+ const char *key, unsigned int *size)
+{
+ void *value;
+
+ if (get_static_array_property(element, key, &value, size) == FALSE)
+ return NULL;
+
+ return value;
+}
+
+int __connman_element_append_ipv4(struct connman_element *element,
+ DBusMessageIter *dict)
+{
+ const char *method = NULL;
+ const char *address = NULL, *netmask = NULL, *gateway = NULL;
+
+ connman_element_get_value(element,
+ CONNMAN_PROPERTY_ID_IPV4_METHOD, &method);
+
+ connman_element_get_value(element,
+ CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &address);
+ connman_element_get_value(element,
+ CONNMAN_PROPERTY_ID_IPV4_NETMASK, &netmask);
+ connman_element_get_value(element,
+ CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
+
+ if (method != NULL)
+ connman_dbus_dict_append_variant(dict, "IPv4.Method",
+ DBUS_TYPE_STRING, &method);
+
+ if (address != NULL)
+ connman_dbus_dict_append_variant(dict, "IPv4.Address",
+ DBUS_TYPE_STRING, &address);
+
+ if (netmask != NULL)
+ connman_dbus_dict_append_variant(dict, "IPv4.Netmask",
+ DBUS_TYPE_STRING, &netmask);
+
+ if (gateway != NULL)
+ connman_dbus_dict_append_variant(dict, "IPv4.Gateway",
+ DBUS_TYPE_STRING, &gateway);
+
+ return 0;
+}
+
+int __connman_element_set_ipv4(struct connman_element *element,
+ const char *name, DBusMessageIter *value)
+{
+ int type;
+
+ type = dbus_message_iter_get_arg_type(value);
+
+ if (g_str_equal(name, "IPv4.Method") == TRUE) {
+ enum connman_ipv4_method method;
+ const char *str;
+
+ if (type != DBUS_TYPE_STRING)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(value, &str);
+ method = __connman_ipv4_string2method(str);
+ if (method == CONNMAN_IPV4_METHOD_UNKNOWN)
+ return -EINVAL;
+
+ if (method == element->ipv4.method)
+ return -EALREADY;
+
+ element->ipv4.method = method;
+
+ connman_element_update(element);
+ } else if (g_str_equal(name, "IPv4.Address") == TRUE) {
+ const char *address;
+
+ if (type != DBUS_TYPE_STRING)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(value, &address);
+
+ g_free(element->ipv4.address);
+ element->ipv4.address = g_strdup(address);
+
+ connman_element_update(element);
+ } else if (g_str_equal(name, "IPv4.Netmask") == TRUE) {
+ const char *netmask;
+
+ if (type != DBUS_TYPE_STRING)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(value, &netmask);
+
+ g_free(element->ipv4.netmask);
+ element->ipv4.netmask = g_strdup(netmask);
+
+ connman_element_update(element);
+ } else if (g_str_equal(name, "IPv4.Gateway") == TRUE) {
+ const char *gateway;
+
+ if (type != DBUS_TYPE_STRING)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(value, &gateway);
+
+ g_free(element->ipv4.gateway);
+ element->ipv4.gateway = g_strdup(gateway);
+
+ connman_element_update(element);
+ }
+
+ return 0;
+}
+
+static void append_state(DBusMessageIter *entry, const char *state)
+{
+ DBusMessageIter value;
+ const char *key = "State";
+
+ 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, &state);
+ dbus_message_iter_close_container(entry, &value);
+}
+
+static void emit_state_change(DBusConnection *conn, const char *state)
+{
+ DBusMessage *signal;
+ DBusMessageIter entry;
+
+ DBG("conn %p", conn);
+
+ signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
+ CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
+ if (signal == NULL)
+ return;
+
+ dbus_message_iter_init_append(signal, &entry);
+
+ append_state(&entry, state);
+
+ g_dbus_send_message(conn, signal);
+
+ signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
+ CONNMAN_MANAGER_INTERFACE, "StateChanged");
+ if (signal == NULL)
+ return;
+
+ dbus_message_iter_init_append(signal, &entry);
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &state);
+
+ g_dbus_send_message(conn, signal);
+}
+
+static void probe_element(struct connman_element *element)
+{
+ GSList *list;
+
+ DBG("element %p name %s", element, element->name);
+
+ for (list = driver_list; list; list = list->next) {
+ struct connman_driver *driver = list->data;
+
+ if (match_driver(element, driver) == FALSE)
+ continue;
+
+ DBG("driver %p name %s", driver, driver->name);
+
+ if (driver->probe(element) == 0) {
+ __connman_element_lock(element);
+ element->driver = driver;
+ __connman_element_unlock(element);
+ break;
+ }
+ }
+}
+
+static void register_element(gpointer data, gpointer user_data)
+{
+ struct connman_element *element = data;
+ const gchar *basepath;
+ GNode *node;
+
+ __connman_element_lock(element);
+
+ if (element->parent) {
+ node = g_node_find(element_root, G_PRE_ORDER,
+ G_TRAVERSE_ALL, element->parent);
+ basepath = element->parent->path;
+ } else {
+ element->parent = element_root->data;
+
+ node = element_root;
+ basepath = "/device";
+ }
+
+ element->path = g_strdup_printf("%s/%s", basepath, element->name);
+
+ __connman_element_unlock(element);
+
+ if (node == NULL) {
+ connman_error("Element registration for %s failed",
+ element->path);
+ return;
+ }
+
+ DBG("element %p path %s", element, element->path);
+
+ g_node_append_data(node, element);
+
+ if (element->type == CONNMAN_ELEMENT_TYPE_DHCP) {
+ element->parent->configuring = TRUE;
+
+ if (__connman_element_count(NULL,
+ CONNMAN_ELEMENT_TYPE_CONNECTION) == 0)
+ emit_state_change(connection, "connecting");
+ }
+
+ if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
+ struct connman_element *parent = element->parent;
+
+ while (parent) {
+ parent->configuring = FALSE;
+ parent = parent->parent;
+ }
+
+ if (__connman_element_count(NULL,
+ CONNMAN_ELEMENT_TYPE_CONNECTION) == 1)
+ emit_state_change(connection, "online");
+ }
+
+ emit_element_signal(connection, "ElementAdded", element);
+
+ if (started == FALSE)
+ return;
+
+ probe_element(element);
+}
+
+/**
+ * connman_element_register:
+ * @element: the element to register
+ * @parent: the parent to register the element with
+ *
+ * Register an element with the core. It will be register under the given
+ * parent of if %NULL is provided under the root element.
+ *
+ * Returns: %0 on success
+ */
+int connman_element_register(struct connman_element *element,
+ struct connman_element *parent)
+{
+ DBG("element %p name %s parent %p", element, element->name, parent);
+
+ if (element->devname == NULL)
+ element->devname = g_strdup(element->name);
+
+ if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE) {
+ if (g_pattern_match_simple(device_filter,
+ element->devname) == FALSE) {
+ DBG("ignoring %s [%s] device", element->name,
+ element->devname);
+ return -EPERM;
+ }
+ }
+
+ if (connman_element_ref(element) == NULL)
+ return -EINVAL;
+
+ __connman_element_lock(element);
+
+ if (element->name == NULL) {
+ element->name = g_strdup(type2string(element->type));
+ if (element->name == NULL) {
+ __connman_element_unlock(element);
+ return -EINVAL;
+ }
+ }
+
+ if (element->type == CONNMAN_ELEMENT_TYPE_DHCP)
+ element->ipv4.method = CONNMAN_IPV4_METHOD_DHCP;
+
+ element->parent = parent;
+
+ __connman_element_unlock(element);
+
+ register_element(element, NULL);
+
+ return 0;
+}
+
+static gboolean remove_element(GNode *node, gpointer user_data)
+{
+ struct connman_element *element = node->data;
+ struct connman_element *root = user_data;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (element == root)
+ return FALSE;
+
+ if (node != NULL)
+ g_node_unlink(node);
+
+ if (element->driver) {
+ if (element->driver->remove)
+ element->driver->remove(element);
+
+ __connman_element_lock(element);
+ element->driver = NULL;
+ __connman_element_unlock(element);
+ }
+
+ if (node != NULL)
+ g_node_destroy(node);
+
+ if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
+ if (__connman_element_count(NULL,
+ CONNMAN_ELEMENT_TYPE_CONNECTION) == 0)
+ emit_state_change(connection, "offline");
+ }
+
+ emit_element_signal(connection, "ElementRemoved", element);
+
+ connman_element_unref(element);
+
+ return FALSE;
+}
+
+void connman_element_unregister(struct connman_element *element)
+{
+ GNode *node;
+
+ DBG("element %p name %s", element, element->name);
+
+ node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
+
+ if (node != NULL)
+ g_node_traverse(node, G_POST_ORDER,
+ G_TRAVERSE_ALL, -1, remove_element, NULL);
+}
+
+void connman_element_unregister_children(struct connman_element *element)
+{
+ GNode *node;
+
+ DBG("element %p name %s", element, element->name);
+
+ node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
+
+ if (node != NULL)
+ g_node_traverse(node, G_POST_ORDER,
+ G_TRAVERSE_ALL, -1, remove_element, element);
+}
+
+static gboolean update_element(GNode *node, gpointer user_data)
+{
+ struct connman_element *element = node->data;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (element->driver && element->driver->update)
+ element->driver->update(element);
+
+ emit_element_signal(connection, "ElementUpdated", element);
+
+ return FALSE;
+}
+
+void connman_element_update(struct connman_element *element)
+{
+ GNode *node;
+
+ DBG("element %p name %s", element, element->name);
+
+ node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
+
+ if (node != NULL)
+ g_node_traverse(node, G_PRE_ORDER,
+ G_TRAVERSE_ALL, -1, update_element, element);
+}
+
+int connman_element_set_enabled(struct connman_element *element,
+ gboolean enabled)
+{
+ if (element->enabled == enabled)
+ return 0;
+
+ element->enabled = enabled;
+
+ connman_element_update(element);
+
+ return 0;
+}
+
+/**
+ * connman_element_set_error:
+ * @element: element structure
+ * @error: error identifier
+ *
+ * Set error state and specific error identifier
+ */
+void connman_element_set_error(struct connman_element *element,
+ enum connman_element_error error)
+{
+ struct connman_service *service;
+
+ DBG("element %p error %d", element, error);
+
+ if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
+ return;
+
+ element->state = CONNMAN_ELEMENT_STATE_ERROR;
+ element->error = error;
+
+ if (element->driver && element->driver->change)
+ element->driver->change(element);
+
+ service = __connman_element_get_service(element);
+ __connman_service_indicate_state(service,
+ CONNMAN_SERVICE_STATE_FAILURE);
+}
+
+int __connman_element_init(DBusConnection *conn, const char *device,
+ const char *nodevice)
+{
+ struct connman_element *element;
+
+ DBG("conn %p", conn);
+
+ connection = dbus_connection_ref(conn);
+ if (connection == NULL)
+ return -EIO;
+
+ device_filter = g_strdup(device);
+
+ element = connman_element_create("root");
+
+ element->path = g_strdup("/");
+ element->type = CONNMAN_ELEMENT_TYPE_ROOT;
+
+ element_root = g_node_new(element);
+
+ __connman_notifier_init();
+ __connman_service_init();
+ __connman_network_init();
+ __connman_device_init();
+
+ return 0;
+}
+
+static gboolean probe_node(GNode *node, gpointer data)
+{
+ struct connman_element *element = node->data;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
+ return FALSE;
+
+ if (element->driver)
+ return FALSE;
+
+ probe_element(element);
+
+ return FALSE;
+}
+
+void __connman_element_start(void)
+{
+ DBG("");
+
+ g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
+ probe_node, NULL);
+
+ started = TRUE;
+
+ __connman_storage_init_device();
+
+ __connman_connection_init();
+ __connman_ipv4_init();
+ __connman_detect_init();
+ __connman_rfkill_init();
+}
+
+void __connman_element_stop(void)
+{
+ DBG("");
+
+ __connman_rfkill_cleanup();
+ __connman_detect_cleanup();
+ __connman_ipv4_cleanup();
+ __connman_connection_cleanup();
+}
+
+static gboolean free_driver(GNode *node, gpointer data)
+{
+ struct connman_element *element = node->data;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (element->driver) {
+ if (element->driver->remove)
+ element->driver->remove(element);
+
+ __connman_element_lock(element);
+ element->driver = NULL;
+ __connman_element_unlock(element);
+ }
+
+ return FALSE;
+}
+
+static gboolean free_node(GNode *node, gpointer data)
+{
+ struct connman_element *element = node->data;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (g_node_depth(node) > 1)
+ connman_element_unregister(element);
+
+ return FALSE;
+}
+
+void __connman_element_cleanup(void)
+{
+ DBG("");
+
+ __connman_device_cleanup();
+ __connman_network_cleanup();
+ __connman_service_cleanup();
+ __connman_notifier_cleanup();
+
+ g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
+ free_driver, NULL);
+
+ g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
+ free_node, NULL);
+
+ g_node_destroy(element_root);
+ element_root = NULL;
+
+ g_free(device_filter);
+
+ dbus_connection_unref(connection);
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <string.h>
+
+#include <gdbus.h>
+
+#include "connman.h"
+
+DBusMessage *__connman_error_failed(DBusMessage *msg, int errnum)
+{
+ const char *str = strerror(errnum);
+
+ return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
+ ".Failed", str);
+}
+
+DBusMessage *__connman_error_invalid_arguments(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
+ ".InvalidArguments", "Invalid arguments");
+}
+
+DBusMessage *__connman_error_permission_denied(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
+ ".PermissionDenied", "Permission denied");
+}
+
+DBusMessage *__connman_error_not_supported(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
+ ".NotSupported", "Not supported");
+}
+
+DBusMessage *__connman_error_not_implemented(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
+ ".NotImplemented", "Not implemented");
+}
+
+DBusMessage *__connman_error_no_carrier(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
+ ".NoCarrier", "No carrier");
+}
+
+DBusMessage *__connman_error_in_progress(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
+ ".InProgress", "In progress");
+}
+
+DBusMessage *__connman_error_already_connected(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
+ ".AlreadyConnected", "Already connected");
+
+}
+
+DBusMessage *__connman_error_operation_aborted(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
+ "OperationAborted", "Operation aborted");
+}
+
+DBusMessage *__connman_error_operation_timeout(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
+ "OperationTimeout", "Operation timeout");
+}
+
+DBusMessage *__connman_error_invalid_service(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
+ "InvalidService", "Invalid service");
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/ethernet.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+
+#include "connman.h"
+
+int connman_inet_ifindex(const char *name)
+{
+ struct ifreq ifr;
+ int sk, err;
+
+ if (name == NULL)
+ return -1;
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ err = ioctl(sk, SIOCGIFINDEX, &ifr);
+
+ close(sk);
+
+ if (err < 0)
+ return -1;
+
+ return ifr.ifr_ifindex;
+}
+
+char *connman_inet_ifname(int index)
+{
+ struct ifreq ifr;
+ int sk, err;
+
+ if (index < 0)
+ return NULL;
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return NULL;
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = index;
+
+ err = ioctl(sk, SIOCGIFNAME, &ifr);
+
+ close(sk);
+
+ if (err < 0)
+ return NULL;
+
+ return strdup(ifr.ifr_name);
+}
+
+int connman_inet_ifup(int index)
+{
+ struct ifreq ifr;
+ int sk, err;
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return -errno;
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = index;
+
+ if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
+ err = -errno;
+ goto done;
+ }
+
+ if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0) {
+ err = -errno;
+ goto done;
+ }
+
+ if (ifr.ifr_flags & IFF_UP) {
+ err = -EALREADY;
+ goto done;
+ }
+
+ ifr.ifr_flags |= IFF_UP;
+
+ if (ioctl(sk, SIOCSIFFLAGS, &ifr) < 0) {
+ err = -errno;
+ goto done;
+ }
+
+ err = 0;
+
+done:
+ close(sk);
+
+ return err;
+}
+
+int connman_inet_ifdown(int index)
+{
+ struct ifreq ifr;
+ int sk, err;
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return -errno;
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = index;
+
+ if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
+ err = -errno;
+ goto done;
+ }
+
+ if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0) {
+ err = -errno;
+ goto done;
+ }
+
+ if (!(ifr.ifr_flags & IFF_UP)) {
+ err = -EALREADY;
+ goto done;
+ }
+
+ ifr.ifr_flags &= ~IFF_UP;
+
+ if (ioctl(sk, SIOCSIFFLAGS, &ifr) < 0)
+ err = -errno;
+ else
+ err = 0;
+
+done:
+ close(sk);
+
+ return err;
+}
+
+static unsigned short index2type(int index)
+{
+ struct ifreq ifr;
+ int sk, err;
+
+ if (index < 0)
+ return ARPHRD_VOID;
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return ARPHRD_VOID;
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = index;
+
+ err = ioctl(sk, SIOCGIFNAME, &ifr);
+
+ if (err == 0)
+ err = ioctl(sk, SIOCGIFHWADDR, &ifr);
+
+ close(sk);
+
+ if (err < 0)
+ return ARPHRD_VOID;
+
+ return ifr.ifr_hwaddr.sa_family;
+}
+
+static char *index2addr(int index)
+{
+ struct ifreq ifr;
+ struct ether_addr *eth;
+ char *str;
+ int sk, err;
+
+ if (index < 0)
+ return NULL;
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return NULL;
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = index;
+
+ err = ioctl(sk, SIOCGIFNAME, &ifr);
+
+ if (err == 0)
+ err = ioctl(sk, SIOCGIFHWADDR, &ifr);
+
+ close(sk);
+
+ if (err < 0)
+ return NULL;
+
+ str = malloc(18);
+ if (!str)
+ return NULL;
+
+ eth = (void *) &ifr.ifr_hwaddr.sa_data;
+ snprintf(str, 18, "%02X:%02X:%02X:%02X:%02X:%02X",
+ eth->ether_addr_octet[0],
+ eth->ether_addr_octet[1],
+ eth->ether_addr_octet[2],
+ eth->ether_addr_octet[3],
+ eth->ether_addr_octet[4],
+ eth->ether_addr_octet[5]);
+
+ return str;
+}
+
+static char *index2ident(int index, const char *prefix)
+{
+ struct ifreq ifr;
+ struct ether_addr *eth;
+ char *str;
+ int sk, err, len;
+
+ if (index < 0)
+ return NULL;
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return NULL;
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = index;
+
+ err = ioctl(sk, SIOCGIFNAME, &ifr);
+
+ if (err == 0)
+ err = ioctl(sk, SIOCGIFHWADDR, &ifr);
+
+ close(sk);
+
+ if (err < 0)
+ return NULL;
+
+ len = prefix ? strlen(prefix) + 18 : 18;
+
+ str = malloc(len);
+ if (!str)
+ return NULL;
+
+ eth = (void *) &ifr.ifr_hwaddr.sa_data;
+ snprintf(str, len, "%s%02x%02x%02x%02x%02x%02x",
+ prefix ? prefix : "",
+ eth->ether_addr_octet[0],
+ eth->ether_addr_octet[1],
+ eth->ether_addr_octet[2],
+ eth->ether_addr_octet[3],
+ eth->ether_addr_octet[4],
+ eth->ether_addr_octet[5]);
+
+ return str;
+}
+
+struct connman_device *connman_inet_create_device(int index)
+{
+ enum connman_device_type devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
+ enum connman_device_mode mode = CONNMAN_DEVICE_MODE_UNKNOWN;
+ struct connman_device *device;
+ unsigned short type = index2type(index);
+ char *addr, *name, *devname, *ident = NULL;
+
+ if (index < 0)
+ return NULL;
+
+ devname = connman_inet_ifname(index);
+ if (devname == NULL)
+ return NULL;
+
+ if (type == ARPHRD_ETHER) {
+ char bridge_path[PATH_MAX], wimax_path[PATH_MAX];
+ struct stat st;
+ struct iwreq iwr;
+ int sk;
+
+ snprintf(bridge_path, PATH_MAX,
+ "/sys/class/net/%s/bridge", devname);
+ snprintf(wimax_path, PATH_MAX,
+ "/sys/class/net/%s/wimax", devname);
+
+ memset(&iwr, 0, sizeof(iwr));
+ strncpy(iwr.ifr_ifrn.ifrn_name, devname, IFNAMSIZ);
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+
+ if (g_str_has_prefix(devname, "vmnet") == TRUE ||
+ g_str_has_prefix(devname, "vboxnet") == TRUE) {
+ connman_info("Ignoring network interface %s", devname);
+ devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
+ } else if (g_str_has_prefix(devname, "bnep") == TRUE)
+ devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
+ else if (g_str_has_prefix(devname, "wmx") == TRUE)
+ devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
+ else if (stat(wimax_path, &st) == 0 && (st.st_mode & S_IFDIR))
+ devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
+ else if (stat(bridge_path, &st) == 0 && (st.st_mode & S_IFDIR))
+ devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
+ else if (ioctl(sk, SIOCGIWNAME, &iwr) == 0)
+ devtype = CONNMAN_DEVICE_TYPE_WIFI;
+ else
+ devtype = CONNMAN_DEVICE_TYPE_ETHERNET;
+
+ close(sk);
+ } else if (type == ARPHRD_NONE) {
+ if (g_str_has_prefix(devname, "hso") == TRUE)
+ devtype = CONNMAN_DEVICE_TYPE_HSO;
+ }
+
+ switch (devtype) {
+ case CONNMAN_DEVICE_TYPE_UNKNOWN:
+ g_free(devname);
+ return NULL;
+ case CONNMAN_DEVICE_TYPE_ETHERNET:
+ case CONNMAN_DEVICE_TYPE_WIFI:
+ case CONNMAN_DEVICE_TYPE_WIMAX:
+ name = index2ident(index, "");
+ addr = index2addr(index);
+ break;
+ case CONNMAN_DEVICE_TYPE_BLUETOOTH:
+ case CONNMAN_DEVICE_TYPE_GPS:
+ case CONNMAN_DEVICE_TYPE_HSO:
+ case CONNMAN_DEVICE_TYPE_NOZOMI:
+ case CONNMAN_DEVICE_TYPE_HUAWEI:
+ case CONNMAN_DEVICE_TYPE_NOVATEL:
+ case CONNMAN_DEVICE_TYPE_VENDOR:
+ name = strdup(devname);
+ addr = NULL;
+ break;
+ }
+
+ device = connman_device_create(name, devtype);
+ if (device == NULL) {
+ g_free(devname);
+ g_free(name);
+ g_free(addr);
+ return NULL;
+ }
+
+ switch (devtype) {
+ case CONNMAN_DEVICE_TYPE_UNKNOWN:
+ case CONNMAN_DEVICE_TYPE_VENDOR:
+ case CONNMAN_DEVICE_TYPE_NOZOMI:
+ case CONNMAN_DEVICE_TYPE_HUAWEI:
+ case CONNMAN_DEVICE_TYPE_NOVATEL:
+ case CONNMAN_DEVICE_TYPE_GPS:
+ mode = CONNMAN_DEVICE_MODE_UNKNOWN;
+ break;
+ case CONNMAN_DEVICE_TYPE_ETHERNET:
+ mode = CONNMAN_DEVICE_MODE_TRANSPORT_IP;
+ ident = index2ident(index, NULL);
+ break;
+ case CONNMAN_DEVICE_TYPE_WIFI:
+ case CONNMAN_DEVICE_TYPE_WIMAX:
+ mode = CONNMAN_DEVICE_MODE_NETWORK_SINGLE;
+ ident = index2ident(index, NULL);
+ break;
+ case CONNMAN_DEVICE_TYPE_BLUETOOTH:
+ mode = CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE;
+ break;
+ case CONNMAN_DEVICE_TYPE_HSO:
+ mode = CONNMAN_DEVICE_MODE_NETWORK_SINGLE;
+ connman_device_set_policy(device, CONNMAN_DEVICE_POLICY_MANUAL);
+ break;
+ }
+
+ connman_device_set_mode(device, mode);
+
+ connman_device_set_index(device, index);
+ connman_device_set_interface(device, devname);
+
+ if (ident != NULL) {
+ connman_device_set_ident(device, ident);
+ g_free(ident);
+ }
+
+ connman_device_set_string(device, "Address", addr);
+
+ g_free(devname);
+ g_free(name);
+ g_free(addr);
+
+ return device;
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 "connman.h"
+
+static GSList *ipconfig_list = NULL;
+
+static gint compare_priority(gconstpointer a, gconstpointer b)
+{
+ const struct connman_ipconfig *ipconfig1 = a;
+ const struct connman_ipconfig *ipconfig2 = b;
+
+ return ipconfig2->priority - ipconfig1->priority;
+}
+
+/**
+ * connman_ipconfig_register:
+ * @ipconfig: IP configuration module
+ *
+ * Register a new IP configuration module
+ *
+ * Returns: %0 on success
+ */
+int connman_ipconfig_register(struct connman_ipconfig *ipconfig)
+{
+ DBG("ipconfig %p name %s", ipconfig, ipconfig->name);
+
+ ipconfig_list = g_slist_insert_sorted(ipconfig_list, ipconfig,
+ compare_priority);
+
+ return 0;
+}
+
+/**
+ * connman_ipconfig_unregister:
+ * @ipconfig: IP configuration module
+ *
+ * Remove a previously registered IP configuration module.
+ */
+void connman_ipconfig_unregister(struct connman_ipconfig *ipconfig)
+{
+ DBG("ipconfig %p name %s", ipconfig, ipconfig->name);
+
+ ipconfig_list = g_slist_remove(ipconfig_list, ipconfig);
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <unistd.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+
+#include "connman.h"
+
+struct connman_ipv4 {
+ enum connman_ipv4_method method;
+ struct in_addr address;
+ struct in_addr netmask;
+ struct in_addr broadcast;
+};
+
+static int set_ipv4(struct connman_element *element,
+ struct connman_ipv4 *ipv4, const char *nameserver)
+{
+ struct ifreq ifr;
+ struct sockaddr_in *addr;
+ int sk, err;
+
+ DBG("element %p ipv4 %p", element, ipv4);
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = element->index;
+
+ if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
+ close(sk);
+ return -1;
+ }
+
+ DBG("ifname %s", ifr.ifr_name);
+
+ addr = (struct sockaddr_in *) &ifr.ifr_addr;
+ addr->sin_family = AF_INET;
+ addr->sin_addr = ipv4->address;
+
+ err = ioctl(sk, SIOCSIFADDR, &ifr);
+
+ if (err < 0)
+ DBG("address setting failed (%s)", strerror(errno));
+
+ addr = (struct sockaddr_in *) &ifr.ifr_netmask;
+ addr->sin_family = AF_INET;
+ addr->sin_addr = ipv4->netmask;
+
+ err = ioctl(sk, SIOCSIFNETMASK, &ifr);
+
+ if (err < 0)
+ DBG("netmask setting failed (%s)", strerror(errno));
+
+ addr = (struct sockaddr_in *) &ifr.ifr_broadaddr;
+ addr->sin_family = AF_INET;
+ addr->sin_addr = ipv4->broadcast;
+
+ err = ioctl(sk, SIOCSIFBRDADDR, &ifr);
+
+ if (err < 0)
+ DBG("broadcast setting failed (%s)", strerror(errno));
+
+ close(sk);
+
+ if (nameserver == NULL)
+ connman_error("No nameserver for %s defined", ifr.ifr_name);
+
+ connman_resolver_append(ifr.ifr_name, NULL, nameserver);
+
+ return 0;
+}
+
+static int clear_ipv4(struct connman_element *element)
+{
+ struct ifreq ifr;
+ struct sockaddr_in *addr;
+ int sk, err;
+
+ DBG("element %p", element);
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = element->index;
+
+ if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
+ close(sk);
+ return -1;
+ }
+
+ DBG("ifname %s", ifr.ifr_name);
+
+ connman_resolver_remove_all(ifr.ifr_name);
+
+ addr = (struct sockaddr_in *) &ifr.ifr_addr;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = INADDR_ANY;
+
+ //err = ioctl(sk, SIOCDIFADDR, &ifr);
+ err = ioctl(sk, SIOCSIFADDR, &ifr);
+
+ close(sk);
+
+ if (err < 0 && errno != EADDRNOTAVAIL) {
+ DBG("address removal failed (%s)", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static char *index2name(int index)
+{
+ struct ifreq ifr;
+ int sk, err;
+
+ if (index < 0)
+ return NULL;
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return NULL;
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = index;
+
+ err = ioctl(sk, SIOCGIFNAME, &ifr);
+
+ close(sk);
+
+ if (err < 0)
+ return NULL;
+
+ return strdup(ifr.ifr_name);
+}
+
+static int ipv4_probe(struct connman_element *element)
+{
+ struct connman_element *connection;
+ struct connman_ipv4 ipv4;
+ const char *address = NULL, *netmask = NULL, *broadcast = NULL;
+ const char *nameserver = NULL;
+
+ DBG("element %p name %s", element, element->name);
+
+ connman_element_get_value(element,
+ CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &address);
+ connman_element_get_value(element,
+ CONNMAN_PROPERTY_ID_IPV4_NETMASK, &netmask);
+ connman_element_get_value(element,
+ CONNMAN_PROPERTY_ID_IPV4_BROADCAST, &broadcast);
+
+ connman_element_get_value(element,
+ CONNMAN_PROPERTY_ID_IPV4_NAMESERVER, &nameserver);
+
+ DBG("address %s", address);
+ DBG("netmask %s", netmask);
+ DBG("broadcast %s", broadcast);
+
+ if (address == NULL || netmask == NULL)
+ return -EINVAL;
+
+ memset(&ipv4, 0, sizeof(ipv4));
+ ipv4.address.s_addr = inet_addr(address);
+ ipv4.netmask.s_addr = inet_addr(netmask);
+ ipv4.broadcast.s_addr = inet_addr(broadcast);
+
+ set_ipv4(element, &ipv4, nameserver);
+
+ connection = connman_element_create(NULL);
+
+ connection->type = CONNMAN_ELEMENT_TYPE_CONNECTION;
+ connection->index = element->index;
+ connection->devname = index2name(element->index);
+
+ if (connman_element_register(connection, element) < 0)
+ connman_element_unref(connection);
+
+ return 0;
+}
+
+static void ipv4_remove(struct connman_element *element)
+{
+ DBG("element %p name %s", element, element->name);
+
+ clear_ipv4(element);
+}
+
+static struct connman_driver ipv4_driver = {
+ .name = "ipv4",
+ .type = CONNMAN_ELEMENT_TYPE_IPV4,
+ .priority = CONNMAN_DRIVER_PRIORITY_LOW,
+ .probe = ipv4_probe,
+ .remove = ipv4_remove,
+};
+
+int __connman_ipv4_init(void)
+{
+ return connman_driver_register(&ipv4_driver);
+}
+
+void __connman_ipv4_cleanup(void)
+{
+ connman_driver_unregister(&ipv4_driver);
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <stdarg.h>
+#include <syslog.h>
+
+#include "connman.h"
+
+static volatile gboolean debug_enabled = FALSE;
+
+/**
+ * connman_info:
+ * @format: format string
+ * @Varargs: list of arguments
+ *
+ * Output general information
+ */
+void connman_info(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+
+ vsyslog(LOG_INFO, format, ap);
+
+ va_end(ap);
+}
+
+/**
+ * connman_error:
+ * @format: format string
+ * @varargs: list of arguments
+ *
+ * Output error messages
+ */
+void connman_error(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+
+ vsyslog(LOG_ERR, format, ap);
+
+ va_end(ap);
+}
+
+/**
+ * connman_debug:
+ * @format: format string
+ * @varargs: list of arguments
+ *
+ * Output debug message
+ *
+ * The actual output of the debug message is controlled via a command line
+ * switch. If not enabled, these messages will be ignored.
+ */
+void connman_debug(const char *format, ...)
+{
+ va_list ap;
+
+ if (debug_enabled == FALSE)
+ return;
+
+ va_start(ap, format);
+
+ vsyslog(LOG_DEBUG, format, ap);
+
+ va_end(ap);
+}
+
+void __connman_toggle_debug(void)
+{
+ if (debug_enabled == TRUE)
+ debug_enabled = FALSE;
+ else
+ debug_enabled = TRUE;
+}
+
+int __connman_log_init(gboolean detach, gboolean debug)
+{
+ int option = LOG_NDELAY | LOG_PID;
+
+ if (detach == FALSE)
+ option |= LOG_PERROR;
+
+ openlog("connmand", option, LOG_DAEMON);
+
+ syslog(LOG_INFO, "Connection Manager version %s", VERSION);
+
+ debug_enabled = debug;
+
+ return 0;
+}
+
+void __connman_log_cleanup(void)
+{
+ syslog(LOG_INFO, "Exit");
+
+ closelog();
+}
+
+gboolean __connman_debug_enabled(void)
+{
+ return debug_enabled;
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <string.h>
+#include <signal.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <net/if.h>
+
+#include <gdbus.h>
+
+#include "connman.h"
+
+static GMainLoop *main_loop = NULL;
+
+static void sig_term(int sig)
+{
+ g_main_loop_quit(main_loop);
+}
+
+static void sig_debug(int sig)
+{
+ __connman_toggle_debug();
+}
+
+static void disconnect_callback(DBusConnection *conn, void *user_data)
+{
+ DBG("D-Bus disconnect");
+
+ g_main_loop_quit(main_loop);
+}
+
+static gchar *option_device = NULL;
+static gchar *option_plugin = NULL;
+static gchar *option_nodevice = NULL;
+static gchar *option_noplugin = NULL;
+static gchar *option_wifi = NULL;
+static gboolean option_detach = TRUE;
+static gboolean option_compat = FALSE;
+static gboolean option_debug = FALSE;
+static gboolean option_selftest = FALSE;
+static gboolean option_version = FALSE;
+
+static GOptionEntry options[] = {
+ { "device", 'i', 0, G_OPTION_ARG_STRING, &option_device,
+ "Specify networking device or interface", "DEV" },
+ { "nodevice", 'I', 0, G_OPTION_ARG_STRING, &option_nodevice,
+ "Specify networking interface to ignore", "DEV" },
+ { "plugin", 'p', 0, G_OPTION_ARG_STRING, &option_plugin,
+ "Specify plugins to load", "NAME" },
+ { "noplugin", 'P', 0, G_OPTION_ARG_STRING, &option_noplugin,
+ "Specify plugins not to load", "NAME" },
+ { "wifi", 'W', 0, G_OPTION_ARG_STRING, &option_wifi,
+ "Specify driver for WiFi/Supplicant", "NAME" },
+ { "nodaemon", 'n', G_OPTION_FLAG_REVERSE,
+ G_OPTION_ARG_NONE, &option_detach,
+ "Don't fork daemon to background" },
+ { "compat", 'c', 0, G_OPTION_ARG_NONE, &option_compat,
+ "Enable Network Manager compatibility" },
+ { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug,
+ "Enable debug information output" },
+ { "selftest", 't', 0, G_OPTION_ARG_NONE, &option_selftest,
+ "Run self testing routines" },
+ { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
+ "Show version information and exit" },
+ { NULL },
+};
+
+const char *connman_option_get_string(const char *key)
+{
+ if (g_strcmp0(key, "wifi") == 0) {
+ if (option_wifi == NULL)
+ return "wext,nl80211";
+ else
+ return option_wifi;
+ }
+
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ GOptionContext *context;
+ GError *error = NULL;
+ DBusConnection *conn;
+ DBusError err;
+ struct sigaction sa;
+
+#ifdef NEED_THREADS
+ if (g_thread_supported() == FALSE)
+ g_thread_init(NULL);
+#endif
+
+ context = g_option_context_new(NULL);
+ g_option_context_add_main_entries(context, options, NULL);
+
+ if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
+ if (error != NULL) {
+ g_printerr("%s\n", error->message);
+ g_error_free(error);
+ } else
+ g_printerr("An unknown error occurred\n");
+ exit(1);
+ }
+
+ g_option_context_free(context);
+
+ if (option_version == TRUE) {
+ printf("%s\n", VERSION);
+ exit(0);
+ }
+
+ if (option_detach == TRUE) {
+ if (daemon(0, 0)) {
+ perror("Can't start daemon");
+ exit(1);
+ }
+ }
+
+ if (mkdir(STATEDIR, S_IRUSR | S_IWUSR | S_IXUSR |
+ S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) {
+ if (errno != EEXIST)
+ perror("Failed to create state directory");
+ }
+
+ if (mkdir(STORAGEDIR, S_IRUSR | S_IWUSR | S_IXUSR |
+ S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) {
+ if (errno != EEXIST)
+ perror("Failed to create storage directory");
+ }
+
+ main_loop = g_main_loop_new(NULL, FALSE);
+
+#ifdef NEED_THREADS
+ if (dbus_threads_init_default() == FALSE) {
+ fprintf(stderr, "Can't init usage of threads\n");
+ exit(1);
+ }
+#endif
+
+ dbus_error_init(&err);
+
+ conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, CONNMAN_SERVICE, &err);
+ if (conn == NULL) {
+ if (dbus_error_is_set(&err) == TRUE) {
+ fprintf(stderr, "%s\n", err.message);
+ dbus_error_free(&err);
+ } else
+ fprintf(stderr, "Can't register with system bus\n");
+ exit(1);
+ }
+
+ g_dbus_set_disconnect_function(conn, disconnect_callback, NULL, NULL);
+
+ if (option_compat == TRUE) {
+ if (g_dbus_request_name(conn, NM_SERVICE, NULL) == FALSE) {
+ fprintf(stderr, "Can't register compat service\n");
+ option_compat = FALSE;
+ }
+ }
+
+ __connman_log_init(option_detach, option_debug);
+
+ if (option_selftest == TRUE) {
+ if (__connman_selftest() < 0) {
+ connman_error("Self testing routines failed");
+ goto selftest;
+ }
+ }
+
+ __connman_dbus_init(conn);
+
+ __connman_storage_init();
+ __connman_element_init(conn, option_device, option_nodevice);
+
+ __connman_agent_init(conn);
+ __connman_manager_init(conn, option_compat);
+ __connman_profile_init(conn);
+
+ __connman_resolver_init();
+ __connman_rtnl_init();
+ __connman_udev_init();
+
+ __connman_plugin_init(option_plugin, option_noplugin);
+
+ __connman_element_start();
+
+ g_free(option_device);
+ g_free(option_plugin);
+ g_free(option_nodevice);
+ g_free(option_noplugin);
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = sig_term;
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+
+ sa.sa_handler = sig_debug;
+ sigaction(SIGUSR2, &sa, NULL);
+
+ g_main_loop_run(main_loop);
+
+ __connman_element_stop();
+
+ __connman_plugin_cleanup();
+
+ __connman_udev_cleanup();
+ __connman_rtnl_cleanup();
+ __connman_resolver_cleanup();
+
+ __connman_profile_cleanup();
+ __connman_manager_cleanup();
+ __connman_agent_cleanup();
+
+ __connman_element_cleanup();
+ __connman_storage_cleanup();
+
+ __connman_dbus_cleanup();
+
+selftest:
+ __connman_log_cleanup();
+
+ dbus_connection_unref(conn);
+
+ g_main_loop_unref(main_loop);
+
+ rmdir(STORAGEDIR);
+
+ rmdir(STATEDIR);
+
+ return 0;
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <gdbus.h>
+
+#include "connman.h"
+
+enum connman_policy {
+ CONNMAN_POLICY_UNKNOWN = 0,
+ CONNMAN_POLICY_SINGLE = 1,
+ CONNMAN_POLICY_MULTIPLE = 2,
+ CONNMAN_POLICY_ASK = 3,
+};
+
+static enum connman_policy global_policy = CONNMAN_POLICY_SINGLE;
+static connman_bool_t global_offlinemode = FALSE;
+
+static const char *policy2string(enum connman_policy policy)
+{
+ switch (policy) {
+ case CONNMAN_POLICY_UNKNOWN:
+ break;
+ case CONNMAN_POLICY_SINGLE:
+ return "single";
+ case CONNMAN_POLICY_MULTIPLE:
+ return "multiple";
+ case CONNMAN_POLICY_ASK:
+ return "ask";
+ }
+
+ return NULL;
+}
+
+static enum connman_policy string2policy(const char *policy)
+{
+ if (g_str_equal(policy, "single") == TRUE)
+ return CONNMAN_POLICY_SINGLE;
+ else if (g_str_equal(policy, "multiple") == TRUE)
+ return CONNMAN_POLICY_MULTIPLE;
+ else if (g_str_equal(policy, "ask") == TRUE)
+ return CONNMAN_POLICY_ASK;
+ else
+ return CONNMAN_POLICY_UNKNOWN;
+}
+
+static void append_profiles(DBusMessageIter *dict)
+{
+ DBusMessageIter entry, value, iter;
+ const char *key = "Profiles";
+
+ 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_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
+ &value);
+
+ dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
+ __connman_profile_list(&iter);
+ dbus_message_iter_close_container(&value, &iter);
+
+ dbus_message_iter_close_container(&entry, &value);
+
+ dbus_message_iter_close_container(dict, &entry);
+}
+
+static void append_services(DBusMessageIter *dict)
+{
+ DBusMessageIter entry, value, iter;
+ const char *key = "Services";
+
+ 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_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
+ &value);
+
+ dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
+ __connman_service_list(&iter);
+ dbus_message_iter_close_container(&value, &iter);
+
+ dbus_message_iter_close_container(&entry, &value);
+
+ dbus_message_iter_close_container(dict, &entry);
+}
+
+static void append_devices(DBusMessageIter *dict)
+{
+ DBusMessageIter entry, value, iter;
+ const char *key = "Devices";
+
+ 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_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
+ &value);
+
+ dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
+ __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
+ dbus_message_iter_close_container(&value, &iter);
+
+ dbus_message_iter_close_container(&entry, &value);
+
+ dbus_message_iter_close_container(dict, &entry);
+}
+
+static void append_connections(DBusMessageIter *dict)
+{
+ DBusMessageIter entry, value, iter;
+ const char *key = "Connections";
+
+ 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_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
+ &value);
+
+ dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
+ __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
+ dbus_message_iter_close_container(&value, &iter);
+
+ dbus_message_iter_close_container(&entry, &value);
+
+ dbus_message_iter_close_container(dict, &entry);
+}
+
+static DBusMessage *get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ DBusMessageIter array, dict;
+ const char *str;
+
+ DBG("conn %p", conn);
+
+ if (__connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
+ return __connman_error_permission_denied(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &array);
+
+ dbus_message_iter_open_container(&array, 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);
+
+ str = __connman_profile_active_path();
+ if (str != NULL)
+ connman_dbus_dict_append_variant(&dict, "ActiveProfile",
+ DBUS_TYPE_OBJECT_PATH, &str);
+
+ append_profiles(&dict);
+ append_services(&dict);
+
+ append_devices(&dict);
+ append_connections(&dict);
+
+ if (__connman_element_count(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION) > 0)
+ str = "online";
+ else
+ str = "offline";
+
+ connman_dbus_dict_append_variant(&dict, "State",
+ DBUS_TYPE_STRING, &str);
+
+ str = policy2string(global_policy);
+ if (str != NULL)
+ connman_dbus_dict_append_variant(&dict, "Policy",
+ DBUS_TYPE_STRING, &str);
+
+ connman_dbus_dict_append_variant(&dict, "OfflineMode",
+ DBUS_TYPE_BOOLEAN, &global_offlinemode);
+
+ dbus_message_iter_close_container(&array, &dict);
+
+ return reply;
+}
+
+static DBusMessage *set_property(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessageIter iter, value;
+ const char *name;
+
+ DBG("conn %p", conn);
+
+ if (dbus_message_iter_init(msg, &iter) == FALSE)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&iter, &name);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &value);
+
+ if (__connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
+ return __connman_error_permission_denied(msg);
+
+ if (g_str_equal(name, "Policy") == TRUE) {
+ enum connman_policy policy;
+ const char *str;
+
+ dbus_message_iter_get_basic(&value, &str);
+ policy = string2policy(str);
+ if (policy == CONNMAN_POLICY_UNKNOWN)
+ return __connman_error_invalid_arguments(msg);
+
+ global_policy = policy;
+ } else if (g_str_equal(name, "OfflineMode") == TRUE) {
+ connman_bool_t offlinemode;
+
+ dbus_message_iter_get_basic(&value, &offlinemode);
+
+ if (global_offlinemode == offlinemode)
+ return __connman_error_invalid_arguments(msg);
+
+ global_offlinemode = offlinemode;
+
+ __connman_device_set_offlinemode(offlinemode);
+ } else if (g_str_equal(name, "ActiveProfile") == TRUE) {
+ const char *str;
+
+ dbus_message_iter_get_basic(&value, &str);
+
+ return __connman_error_not_supported(msg);
+ }
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *add_profile(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *name;
+
+ DBG("conn %p", conn);
+
+ dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID);
+
+ return __connman_error_not_supported(msg);
+}
+
+static DBusMessage *remove_profile(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *path;
+
+ DBG("conn %p", conn);
+
+ dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+
+ return __connman_error_not_supported(msg);
+}
+
+static DBusMessage *connect_service(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessageIter iter, array;
+
+ DBG("conn %p", conn);
+
+ if (__connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
+ return __connman_error_permission_denied(msg);
+
+ dbus_message_iter_init(msg, &iter);
+ dbus_message_iter_recurse(&iter, &array);
+
+ while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+ const char *key;
+
+ dbus_message_iter_recurse(&array, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
+
+ switch (dbus_message_iter_get_arg_type(&value)) {
+ }
+
+ dbus_message_iter_next(&array);
+ }
+
+ return __connman_error_not_implemented(msg);
+}
+
+static DBusMessage *register_agent(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ const char *sender, *path;
+
+ DBG("conn %p", conn);
+
+ sender = dbus_message_get_sender(msg);
+
+ dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_INVALID);
+
+ __connman_agent_register(sender, path);
+
+ return reply;
+}
+
+static DBusMessage *unregister_agent(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ const char *sender, *path;
+
+ DBG("conn %p", conn);
+
+ sender = dbus_message_get_sender(msg);
+
+ dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_INVALID);
+
+ __connman_agent_unregister(sender, path);
+
+ return reply;
+}
+
+static GDBusMethodTable manager_methods[] = {
+ { "GetProperties", "", "a{sv}", get_properties },
+ { "SetProperty", "sv", "", set_property },
+ { "AddProfile", "s", "o", add_profile },
+ { "RemoveProfile", "o", "", remove_profile },
+ { "ConnectService", "a{sv}", "o", connect_service },
+ { "RegisterAgent", "o", "", register_agent },
+ { "UnregisterAgent", "o", "", unregister_agent },
+ { },
+};
+
+static GDBusSignalTable manager_signals[] = {
+ { "PropertyChanged", "sv" },
+ { "StateChanged", "s" },
+ { },
+};
+
+static DBusMessage *nm_sleep(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+
+ DBG("conn %p", conn);
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *nm_wake(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+
+ DBG("conn %p", conn);
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+enum {
+ NM_STATE_UNKNOWN = 0,
+ NM_STATE_ASLEEP,
+ NM_STATE_CONNECTING,
+ NM_STATE_CONNECTED,
+ NM_STATE_DISCONNECTED
+};
+
+static DBusMessage *nm_state(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ dbus_uint32_t state;
+
+ DBG("conn %p", conn);
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ state = NM_STATE_DISCONNECTED;
+
+ dbus_message_append_args(reply, DBUS_TYPE_UINT32, &state,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static GDBusMethodTable nm_methods[] = {
+ { "sleep", "", "", nm_sleep },
+ { "wake", "", "", nm_wake },
+ { "state", "", "u", nm_state },
+ { },
+};
+
+static DBusConnection *connection = NULL;
+static gboolean nm_compat = FALSE;
+
+int __connman_manager_init(DBusConnection *conn, gboolean compat)
+{
+ DBG("conn %p", conn);
+
+ connection = dbus_connection_ref(conn);
+ if (connection == NULL)
+ return -1;
+
+ g_dbus_register_interface(connection, CONNMAN_MANAGER_PATH,
+ CONNMAN_MANAGER_INTERFACE,
+ manager_methods,
+ manager_signals, NULL, NULL, NULL);
+
+ if (compat == TRUE) {
+ g_dbus_register_interface(connection, NM_PATH, NM_INTERFACE,
+ nm_methods, NULL, NULL, NULL, NULL);
+
+ nm_compat = TRUE;
+ }
+
+ return 0;
+}
+
+void __connman_manager_cleanup(void)
+{
+ DBG("conn %p", connection);
+
+ if (nm_compat == TRUE) {
+ g_dbus_unregister_interface(connection, NM_PATH, NM_INTERFACE);
+ }
+
+ g_dbus_unregister_interface(connection, CONNMAN_MANAGER_PATH,
+ CONNMAN_MANAGER_INTERFACE);
+
+ dbus_connection_unref(connection);
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <string.h>
+
+#include <gdbus.h>
+
+#include "connman.h"
+
+struct connman_network {
+ struct connman_element element;
+ enum connman_network_type type;
+ enum connman_network_protocol protocol;
+ connman_bool_t associating;
+ connman_bool_t secondary;
+ connman_bool_t available;
+ connman_bool_t connected;
+ connman_uint8_t strength;
+ connman_uint16_t frequency;
+ char *identifier;
+ char *address;
+ char *name;
+ char *node;
+ char *group;
+
+ struct connman_network_driver *driver;
+ void *driver_data;
+
+ connman_bool_t registered;
+
+ struct connman_device *device;
+
+ struct {
+ void *ssid;
+ int ssid_len;
+ char *mode;
+ unsigned short channel;
+ char *security;
+ char *passphrase;
+ } wifi;
+};
+
+static const char *type2string(enum connman_network_type type)
+{
+ switch (type) {
+ case CONNMAN_NETWORK_TYPE_UNKNOWN:
+ case CONNMAN_NETWORK_TYPE_VENDOR:
+ break;
+ case CONNMAN_NETWORK_TYPE_WIFI:
+ return "wifi";
+ case CONNMAN_NETWORK_TYPE_WIMAX:
+ return "wimax";
+ case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
+ case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
+ return "bluetooth";
+ case CONNMAN_NETWORK_TYPE_HSO:
+ return "cellular";
+ }
+
+ return NULL;
+}
+
+static DBusMessage *get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_network *network = data;
+ DBusMessage *reply;
+ DBusMessageIter array, dict;
+
+ DBG("conn %p", conn);
+
+ if (__connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
+ return __connman_error_permission_denied(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &array);
+
+ dbus_message_iter_open_container(&array, 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);
+
+ if (network->device) {
+ const char *path = connman_device_get_path(network->device);
+ if (path != NULL)
+ connman_dbus_dict_append_variant(&dict, "Device",
+ DBUS_TYPE_OBJECT_PATH, &path);
+ }
+
+ if (network->address != NULL)
+ connman_dbus_dict_append_variant(&dict, "Address",
+ DBUS_TYPE_STRING, &network->address);
+
+ if (network->name != NULL)
+ connman_dbus_dict_append_variant(&dict, "Name",
+ DBUS_TYPE_STRING, &network->name);
+
+ connman_dbus_dict_append_variant(&dict, "Connected",
+ DBUS_TYPE_BOOLEAN, &network->connected);
+
+ if (network->strength > 0)
+ connman_dbus_dict_append_variant(&dict, "Strength",
+ DBUS_TYPE_BYTE, &network->strength);
+
+ if (network->frequency > 0)
+ connman_dbus_dict_append_variant(&dict, "Frequency",
+ DBUS_TYPE_UINT16, &network->frequency);
+
+ if (network->wifi.ssid != NULL && network->wifi.ssid_len > 0)
+ connman_dbus_dict_append_array(&dict, "WiFi.SSID",
+ DBUS_TYPE_BYTE, &network->wifi.ssid,
+ network->wifi.ssid_len);
+
+ if (network->wifi.mode != NULL)
+ connman_dbus_dict_append_variant(&dict, "WiFi.Mode",
+ DBUS_TYPE_STRING, &network->wifi.mode);
+
+ if (network->wifi.channel > 0)
+ connman_dbus_dict_append_variant(&dict, "WiFi.Channel",
+ DBUS_TYPE_UINT16, &network->wifi.channel);
+
+ if (network->wifi.security != NULL)
+ connman_dbus_dict_append_variant(&dict, "WiFi.Security",
+ DBUS_TYPE_STRING, &network->wifi.security);
+
+ if (network->wifi.passphrase != NULL &&
+ __connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_SECRET) == 0)
+ connman_dbus_dict_append_variant(&dict, "WiFi.Passphrase",
+ DBUS_TYPE_STRING, &network->wifi.passphrase);
+
+ dbus_message_iter_close_container(&array, &dict);
+
+ return reply;
+}
+
+static DBusMessage *set_property(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_network *network = data;
+ DBusMessageIter iter, value;
+ const char *name;
+ int type;
+
+ DBG("conn %p", conn);
+
+ if (dbus_message_iter_init(msg, &iter) == FALSE)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&iter, &name);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &value);
+
+ if (__connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
+ return __connman_error_permission_denied(msg);
+
+ type = dbus_message_iter_get_arg_type(&value);
+
+ if (g_str_equal(name, "WiFi.Passphrase") == TRUE) {
+ const char *passphrase;
+
+ if (type != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
+ if (__connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_SECRET) < 0)
+ return __connman_error_permission_denied(msg);
+
+ dbus_message_iter_get_basic(&value, &passphrase);
+
+ g_free(network->wifi.passphrase);
+ network->wifi.passphrase = g_strdup(passphrase);
+ }
+
+ __connman_storage_save_network(network);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *do_connect(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_network *network = data;
+ int err;
+
+ DBG("conn %p", conn);
+
+ if (__connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
+ return __connman_error_permission_denied(msg);
+
+ if (network->connected == TRUE)
+ return __connman_error_failed(msg, EALREADY);
+
+ if (network->driver && network->driver->connect) {
+ enum connman_device_mode mode;
+
+ mode = connman_device_get_mode(network->device);
+ if (mode == CONNMAN_DEVICE_MODE_NETWORK_SINGLE)
+ __connman_device_disconnect(network->device);
+
+ err = network->driver->connect(network);
+ if (err < 0 && err != -EINPROGRESS)
+ return __connman_error_failed(msg, -err);
+ } else
+ network->connected = TRUE;
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *do_disconnect(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_network *network = data;
+ int err;
+
+ DBG("conn %p", conn);
+
+ if (__connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
+ return __connman_error_permission_denied(msg);
+
+ if (network->connected == FALSE)
+ return __connman_error_failed(msg, EINVAL);
+
+ connman_element_unregister_children(&network->element);
+
+ connman_device_set_disconnected(network->device, TRUE);
+
+ if (network->driver && network->driver->disconnect) {
+ err = network->driver->disconnect(network);
+ if (err < 0 && err != -EINPROGRESS)
+ return __connman_error_failed(msg, -err);
+ } else
+ network->connected = FALSE;
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static GDBusMethodTable network_methods[] = {
+ { "GetProperties", "", "a{sv}", get_properties },
+ { "SetProperty", "sv", "", set_property },
+ { "Connect", "", "", do_connect },
+ { "Disconnect", "", "", do_disconnect },
+ { },
+};
+
+static GDBusSignalTable network_signals[] = {
+ { "PropertyChanged", "sv" },
+ { },
+};
+
+static DBusConnection *connection;
+
+static void append_networks(struct connman_device *device,
+ DBusMessageIter *entry)
+{
+ DBusMessageIter value, iter;
+ const char *key = "Networks";
+
+ dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
+
+ dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
+ &value);
+
+ dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
+ __connman_element_list((struct connman_element *) device,
+ CONNMAN_ELEMENT_TYPE_NETWORK, &iter);
+ dbus_message_iter_close_container(&value, &iter);
+
+ dbus_message_iter_close_container(entry, &value);
+}
+
+static void emit_networks_signal(struct connman_device *device)
+{
+ const char *path = connman_device_get_path(device);
+ DBusMessage *signal;
+ DBusMessageIter entry;
+
+ signal = dbus_message_new_signal(path,
+ CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
+ if (signal == NULL)
+ return;
+
+ dbus_message_iter_init_append(signal, &entry);
+
+ append_networks(device, &entry);
+
+ g_dbus_send_message(connection, signal);
+}
+
+static int register_interface(struct connman_element *element)
+{
+ struct connman_network *network = element->network;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (g_dbus_register_interface(connection, element->path,
+ CONNMAN_NETWORK_INTERFACE,
+ network_methods, network_signals,
+ NULL, network, NULL) == FALSE) {
+ connman_error("Failed to register %s network", element->path);
+ return -EIO;
+ }
+
+ network->registered = TRUE;
+
+ emit_networks_signal(network->device);
+
+ return 0;
+}
+
+static void unregister_interface(struct connman_element *element)
+{
+ struct connman_network * network = element->network;
+
+ DBG("element %p name %s", element, element->name);
+
+ network->registered = FALSE;
+
+ emit_networks_signal(network->device);
+
+ g_dbus_unregister_interface(connection, element->path,
+ CONNMAN_NETWORK_INTERFACE);
+}
+
+connman_bool_t __connman_network_has_driver(struct connman_network *network)
+{
+ if (network == NULL || network->driver == NULL)
+ return FALSE;
+
+ return network->registered;
+}
+
+static GSList *driver_list = NULL;
+
+static gint compare_priority(gconstpointer a, gconstpointer b)
+{
+ const struct connman_network_driver *driver1 = a;
+ const struct connman_network_driver *driver2 = b;
+
+ return driver2->priority - driver1->priority;
+}
+
+/**
+ * connman_network_driver_register:
+ * @driver: network driver definition
+ *
+ * Register a new network driver
+ *
+ * Returns: %0 on success
+ */
+int connman_network_driver_register(struct connman_network_driver *driver)
+{
+ DBG("driver %p name %s", driver, driver->name);
+
+ driver_list = g_slist_insert_sorted(driver_list, driver,
+ compare_priority);
+
+ return 0;
+}
+
+/**
+ * connman_network_driver_unregister:
+ * @driver: network driver definition
+ *
+ * Remove a previously registered network driver
+ */
+void connman_network_driver_unregister(struct connman_network_driver *driver)
+{
+ DBG("driver %p name %s", driver, driver->name);
+
+ driver_list = g_slist_remove(driver_list, driver);
+}
+
+static void network_destruct(struct connman_element *element)
+{
+ struct connman_network *network = element->network;
+
+ DBG("element %p name %s", element, element->name);
+
+ g_free(network->wifi.ssid);
+ g_free(network->wifi.mode);
+ g_free(network->wifi.security);
+ g_free(network->wifi.passphrase);
+
+ g_free(network->group);
+ g_free(network->node);
+ g_free(network->name);
+ g_free(network->address);
+ g_free(network->identifier);
+}
+
+/**
+ * connman_network_create:
+ * @identifier: network identifier (for example an unqiue name)
+ *
+ * Allocate a new network and assign the #identifier to it.
+ *
+ * Returns: a newly-allocated #connman_network structure
+ */
+struct connman_network *connman_network_create(const char *identifier,
+ enum connman_network_type type)
+{
+ struct connman_network *network;
+ connman_uint8_t strength = 0;
+ const char *str;
+ char *temp;
+
+ DBG("identifier %s type %d", identifier, type);
+
+ network = g_try_new0(struct connman_network, 1);
+ if (network == NULL)
+ return NULL;
+
+ DBG("network %p", network);
+
+ __connman_element_initialize(&network->element);
+
+ //temp = connman_dbus_encode_string(identifier);
+ temp = g_strdup(identifier);
+ if (temp == NULL) {
+ g_free(network);
+ return NULL;
+ }
+
+ network->element.name = temp;
+ network->element.type = CONNMAN_ELEMENT_TYPE_NETWORK;
+
+ network->element.network = network;
+ network->element.destruct = network_destruct;
+
+ str = type2string(type);
+ if (str != NULL)
+ connman_element_set_string(&network->element, "Type", str);
+
+ connman_element_set_uint8(&network->element, "Strength", strength);
+
+ network->type = type;
+ network->secondary = FALSE;
+ network->identifier = g_strdup(identifier);
+
+ return network;
+}
+
+/**
+ * connman_network_ref:
+ * @network: network structure
+ *
+ * Increase reference counter of network
+ */
+struct connman_network *connman_network_ref(struct connman_network *network)
+{
+ if (connman_element_ref(&network->element) == NULL)
+ return NULL;
+
+ return network;
+}
+
+/**
+ * connman_network_unref:
+ * @network: network structure
+ *
+ * Decrease reference counter of network
+ */
+void connman_network_unref(struct connman_network *network)
+{
+ connman_element_unref(&network->element);
+}
+
+const char *__connman_network_get_type(struct connman_network *network)
+{
+ return type2string(network->type);
+}
+
+/**
+ * connman_network_get_type:
+ * @network: network structure
+ *
+ * Get type of network
+ */
+enum connman_network_type connman_network_get_type(struct connman_network *network)
+{
+ return network->type;
+}
+
+/**
+ * connman_network_get_identifier:
+ * @network: network structure
+ *
+ * Get identifier of network
+ */
+const char *connman_network_get_identifier(struct connman_network *network)
+{
+ return network->identifier;
+}
+
+/**
+ * connman_network_get_path:
+ * @network: network structure
+ *
+ * Get path name of network
+ */
+const char *connman_network_get_path(struct connman_network *network)
+{
+ return network->element.path;
+}
+
+/**
+ * connman_network_set_index:
+ * @network: network structure
+ * @index: index number
+ *
+ * Set index number of network
+ */
+void connman_network_set_index(struct connman_network *network, int index)
+{
+ network->element.index = index;
+}
+
+/**
+ * connman_network_get_index:
+ * @network: network structure
+ *
+ * Get index number of network
+ */
+int connman_network_get_index(struct connman_network *network)
+{
+ return network->element.index;
+}
+
+/**
+ * connman_network_set_protocol:
+ * @network: network structure
+ * @protocol: network protocol
+ *
+ * Change protocol of network
+ */
+void connman_network_set_protocol(struct connman_network *network,
+ enum connman_network_protocol protocol)
+{
+ network->protocol = protocol;
+}
+
+/**
+ * connman_network_set_group:
+ * @network: network structure
+ * @group: group name
+ *
+ * Set group name for automatic clustering
+ */
+void connman_network_set_group(struct connman_network *network,
+ const char *group)
+{
+ if (network->secondary == TRUE)
+ return;
+
+ if (g_strcmp0(network->group, group) == 0)
+ return;
+
+ switch (network->type) {
+ case CONNMAN_NETWORK_TYPE_UNKNOWN:
+ case CONNMAN_NETWORK_TYPE_VENDOR:
+ case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
+ case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
+ case CONNMAN_NETWORK_TYPE_HSO:
+ return;
+ case CONNMAN_NETWORK_TYPE_WIFI:
+ case CONNMAN_NETWORK_TYPE_WIMAX:
+ break;
+ }
+
+ if (network->group != NULL) {
+ __connman_profile_remove_network(network);
+
+ g_free(network->group);
+ }
+
+ network->group = g_strdup(group);
+
+ if (network->group != NULL)
+ __connman_profile_add_network(network);
+}
+
+const char *__connman_network_get_group(struct connman_network *network)
+{
+ return network->group;
+}
+
+const char *__connman_network_get_ident(struct connman_network *network)
+{
+ if (network->device == NULL)
+ return NULL;
+
+ return __connman_device_get_ident(network->device);
+}
+
+/**
+ * connman_network_set_available:
+ * @network: network structure
+ * @available: availability state
+ *
+ * Change availability state of network (in range)
+ */
+int connman_network_set_available(struct connman_network *network,
+ connman_bool_t available)
+{
+ DBG("network %p available %d", network, available);
+
+ if (network->available == available)
+ return -EALREADY;
+
+ network->available = available;
+
+ return 0;
+}
+
+/**
+ * connman_network_get_available:
+ * @network: network structure
+ *
+ * Get network available setting
+ */
+connman_bool_t connman_network_get_available(struct connman_network *network)
+{
+ return network->available;
+}
+
+/**
+ * connman_network_set_associating:
+ * @network: network structure
+ * @associating: associating state
+ *
+ * Change associating state of network
+ */
+int connman_network_set_associating(struct connman_network *network,
+ connman_bool_t associating)
+{
+ DBG("network %p associating %d", network, associating);
+
+ if (network->associating == associating)
+ return -EALREADY;
+
+ network->associating = associating;
+
+ if (associating == TRUE) {
+ struct connman_service *service;
+
+ service = __connman_service_lookup_from_network(network);
+ __connman_service_indicate_state(service,
+ CONNMAN_SERVICE_STATE_ASSOCIATION);
+ }
+
+ return 0;
+}
+
+static gboolean set_connected(gpointer user_data)
+{
+ struct connman_network *network = user_data;
+ struct connman_service *service;
+
+ service = __connman_service_lookup_from_network(network);
+
+ if (network->connected == TRUE) {
+ struct connman_element *element;
+ enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
+
+ switch (network->protocol) {
+ case CONNMAN_NETWORK_PROTOCOL_UNKNOWN:
+ return 0;
+ case CONNMAN_NETWORK_PROTOCOL_IP:
+ type = CONNMAN_ELEMENT_TYPE_DHCP;
+ break;
+ case CONNMAN_NETWORK_PROTOCOL_PPP:
+ type = CONNMAN_ELEMENT_TYPE_PPP;
+ break;
+ }
+
+ __connman_device_increase_connections(network->device);
+
+ __connman_device_set_network(network->device, network);
+
+ connman_device_set_disconnected(network->device, FALSE);
+
+ element = connman_element_create(NULL);
+ if (element != NULL) {
+ element->type = type;
+ element->index = network->element.index;
+
+ if (connman_element_register(element,
+ &network->element) < 0)
+ connman_element_unref(element);
+
+ __connman_service_indicate_state(service,
+ CONNMAN_SERVICE_STATE_CONFIGURATION);
+ }
+ } else {
+ __connman_service_indicate_state(service,
+ CONNMAN_SERVICE_STATE_IDLE);
+
+ connman_element_unregister_children(&network->element);
+
+ __connman_device_set_network(network->device, NULL);
+
+ __connman_device_decrease_connections(network->device);
+ }
+
+ return FALSE;
+}
+
+/**
+ * connman_network_set_connected:
+ * @network: network structure
+ * @connected: connected state
+ *
+ * Change connected state of network
+ */
+int connman_network_set_connected(struct connman_network *network,
+ connman_bool_t connected)
+{
+ DBusMessage *signal;
+ DBusMessageIter entry, value;
+ const char *key = "Connected";
+
+ DBG("network %p connected %d", network, connected);
+
+ if (network->connected == connected)
+ return -EALREADY;
+
+ network->connected = connected;
+
+ if (connected == TRUE)
+ network->associating = FALSE;
+
+ if (network->registered == FALSE) {
+ g_idle_add(set_connected, network);
+ return 0;
+ }
+
+ signal = dbus_message_new_signal(network->element.path,
+ CONNMAN_NETWORK_INTERFACE, "PropertyChanged");
+ if (signal == NULL)
+ return 0;
+
+ dbus_message_iter_init_append(signal, &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_BOOLEAN_AS_STRING, &value);
+ dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &connected);
+ dbus_message_iter_close_container(&entry, &value);
+
+ g_dbus_send_message(connection, signal);
+
+ set_connected(network);
+
+ return 0;
+}
+
+/**
+ * connman_network_get_connected:
+ * @network: network structure
+ *
+ * Get network connection status
+ */
+connman_bool_t connman_network_get_connected(struct connman_network *network)
+{
+ return network->connected;
+}
+
+/**
+ * __connman_network_connect:
+ * @network: network structure
+ *
+ * Connect network
+ */
+int __connman_network_connect(struct connman_network *network)
+{
+ int err;
+
+ DBG("network %p", network);
+
+ if (network->connected == TRUE)
+ return -EALREADY;
+
+ if (network->driver == NULL)
+ return -EUNATCH;
+
+ if (network->driver->connect == NULL)
+ return -ENOSYS;
+
+ __connman_device_disconnect(network->device);
+
+ err = network->driver->connect(network);
+ if (err == 0) {
+ network->connected = TRUE;
+ set_connected(network);
+ }
+
+ return err;
+}
+
+/**
+ * __connman_network_disconnect:
+ * @network: network structure
+ *
+ * Disconnect network
+ */
+int __connman_network_disconnect(struct connman_network *network)
+{
+ int err;
+
+ DBG("network %p", network);
+
+ if (network->connected == FALSE)
+ return -ENOTCONN;
+
+ if (network->driver == NULL)
+ return -EUNATCH;
+
+ if (network->driver->disconnect == NULL)
+ return -ENOSYS;
+
+ err = network->driver->disconnect(network);
+ if (err == 0) {
+ network->connected = FALSE;
+ set_connected(network);
+ }
+
+ return err;
+}
+
+/**
+ * connman_network_set_address:
+ * @network: network structure
+ * @address: binary address value
+ * @size: binary address length
+ *
+ * Set unique address value for network
+ */
+int connman_network_set_address(struct connman_network *network,
+ const void *address, unsigned int size)
+{
+ const unsigned char *addr_octet = address;
+ char *str;
+
+ DBG("network %p size %d", network, size);
+
+ if (size != 6)
+ return -EINVAL;
+
+ str = g_strdup_printf("%02X:%02X:%02X:%02X:%02X:%02X",
+ addr_octet[0], addr_octet[1], addr_octet[2],
+ addr_octet[3], addr_octet[4], addr_octet[5]);
+ if (str == NULL)
+ return -ENOMEM;
+
+ g_free(network->address);
+ network->address = str;
+
+ return connman_element_set_string(&network->element,
+ "Address", network->address);
+}
+
+/**
+ * connman_network_set_name:
+ * @network: network structure
+ * @name: name value
+ *
+ * Set display name value for network
+ */
+int connman_network_set_name(struct connman_network *network,
+ const char *name)
+{
+ DBG("network %p name %s", network, name);
+
+ g_free(network->name);
+ network->name = g_strdup(name);
+
+ return connman_element_set_string(&network->element, "Name", name);
+}
+
+/**
+ * connman_network_set_strength:
+ * @network: network structure
+ * @strength: strength value
+ *
+ * Set signal strength value for network
+ */
+int connman_network_set_strength(struct connman_network *network,
+ connman_uint8_t strength)
+{
+ DBG("network %p strengh %d", network, strength);
+
+ network->strength = strength;
+
+ return connman_element_set_uint8(&network->element,
+ "Strength", strength);
+}
+
+/**
+ * connman_network_set_string:
+ * @network: network structure
+ * @key: unique identifier
+ * @value: string value
+ *
+ * Set string value for specific key
+ */
+int connman_network_set_string(struct connman_network *network,
+ const char *key, const char *value)
+{
+ DBG("network %p key %s value %s", network, key, value);
+
+ if (g_strcmp0(key, "Name") == 0)
+ return connman_network_set_name(network, value);
+
+ if (g_str_equal(key, "Address") == TRUE) {
+ g_free(network->address);
+ network->address = g_strdup(value);
+ } else if (g_str_equal(key, "Node") == TRUE) {
+ g_free(network->node);
+ network->node = g_strdup(value);
+ } else if (g_str_equal(key, "WiFi.Mode") == TRUE) {
+ g_free(network->wifi.mode);
+ network->wifi.mode = g_strdup(value);
+ } else if (g_str_equal(key, "WiFi.Security") == TRUE) {
+ g_free(network->wifi.security);
+ network->wifi.security = g_strdup(value);
+ } else if (g_str_equal(key, "WiFi.Passphrase") == TRUE) {
+ g_free(network->wifi.passphrase);
+ network->wifi.passphrase = g_strdup(value);
+ }
+
+ return connman_element_set_string(&network->element, key, value);
+}
+
+/**
+ * connman_network_get_string:
+ * @network: network structure
+ * @key: unique identifier
+ *
+ * Get string value for specific key
+ */
+const char *connman_network_get_string(struct connman_network *network,
+ const char *key)
+{
+ DBG("network %p key %s", network, key);
+
+ if (g_str_equal(key, "Address") == TRUE)
+ return network->address;
+ else if (g_str_equal(key, "Name") == TRUE)
+ return network->name;
+ else if (g_str_equal(key, "Node") == TRUE)
+ return network->node;
+ else if (g_str_equal(key, "WiFi.Mode") == TRUE)
+ return network->wifi.mode;
+ else if (g_str_equal(key, "WiFi.Security") == TRUE)
+ return network->wifi.security;
+ else if (g_str_equal(key, "WiFi.Passphrase") == TRUE)
+ return network->wifi.passphrase;
+
+ return connman_element_get_string(&network->element, key);
+}
+
+/**
+ * connman_network_set_uint8:
+ * @network: network structure
+ * @key: unique identifier
+ * @value: integer value
+ *
+ * Set integer value for specific key
+ */
+int connman_network_set_uint8(struct connman_network *network,
+ const char *key, connman_uint8_t value)
+{
+ DBG("network %p key %s value %d", network, key, value);
+
+ if (g_strcmp0(key, "Strength") == 0)
+ return connman_network_set_strength(network, value);
+
+ return connman_element_set_uint8(&network->element, key, value);
+}
+
+/**
+ * connman_network_get_uint8:
+ * @network: network structure
+ * @key: unique identifier
+ *
+ * Get integer value for specific key
+ */
+connman_uint8_t connman_network_get_uint8(struct connman_network *network,
+ const char *key)
+{
+ DBG("network %p key %s", network, key);
+
+ if (g_str_equal(key, "Strength") == TRUE)
+ return network->strength;
+
+ return connman_element_get_uint8(&network->element, key);
+}
+
+/**
+ * connman_network_set_uint16:
+ * @network: network structure
+ * @key: unique identifier
+ * @value: integer value
+ *
+ * Set integer value for specific key
+ */
+int connman_network_set_uint16(struct connman_network *network,
+ const char *key, connman_uint16_t value)
+{
+ DBG("network %p key %s value %d", network, key, value);
+
+ if (g_str_equal(key, "Frequency") == TRUE)
+ network->frequency = value;
+ else if (g_str_equal(key, "WiFi.Channel") == TRUE)
+ network->wifi.channel = value;
+
+ return -EINVAL;
+}
+
+/**
+ * connman_network_get_uint16:
+ * @network: network structure
+ * @key: unique identifier
+ *
+ * Get integer value for specific key
+ */
+connman_uint16_t connman_network_get_uint16(struct connman_network *network,
+ const char *key)
+{
+ DBG("network %p key %s", network, key);
+
+ if (g_str_equal(key, "Frequency") == TRUE)
+ return network->frequency;
+ else if (g_str_equal(key, "WiFi.Channel") == TRUE)
+ return network->wifi.channel;
+
+ return 0;
+}
+
+/**
+ * connman_network_set_blob:
+ * @network: network structure
+ * @key: unique identifier
+ * @data: blob data
+ * @size: blob size
+ *
+ * Set binary blob value for specific key
+ */
+int connman_network_set_blob(struct connman_network *network,
+ const char *key, const void *data, unsigned int size)
+{
+ DBG("network %p key %s size %d", network, key, size);
+
+ if (g_strcmp0(key, "Address") == 0)
+ return connman_network_set_address(network, data, size);
+
+ if (g_str_equal(key, "WiFi.SSID") == TRUE) {
+ g_free(network->wifi.ssid);
+ network->wifi.ssid = g_try_malloc(size);
+ if (network->wifi.ssid != NULL) {
+ memcpy(network->wifi.ssid, data, size);
+ network->wifi.ssid_len = size;
+ } else
+ network->wifi.ssid_len = 0;
+ }
+
+ return connman_element_set_blob(&network->element, key, data, size);
+}
+
+/**
+ * connman_network_get_blob:
+ * @network: network structure
+ * @key: unique identifier
+ * @size: pointer to blob size
+ *
+ * Get binary blob value for specific key
+ */
+const void *connman_network_get_blob(struct connman_network *network,
+ const char *key, unsigned int *size)
+{
+ DBG("network %p key %s", network, key);
+
+ if (g_str_equal(key, "WiFi.SSID") == TRUE) {
+ if (size != NULL)
+ *size = network->wifi.ssid_len;
+ return network->wifi.ssid;
+ }
+
+ return connman_element_get_blob(&network->element, key, size);
+}
+
+void __connman_network_set_device(struct connman_network *network,
+ struct connman_device *device)
+{
+ network->device = device;
+}
+
+/**
+ * connman_network_get_device:
+ * @network: network structure
+ *
+ * Get parent device of network
+ */
+struct connman_device *connman_network_get_device(struct connman_network *network)
+{
+ return network->device;
+}
+
+/**
+ * connman_network_get_data:
+ * @network: network structure
+ *
+ * Get private network data pointer
+ */
+void *connman_network_get_data(struct connman_network *network)
+{
+ return network->driver_data;
+}
+
+/**
+ * connman_network_set_data:
+ * @network: network structure
+ * @data: data pointer
+ *
+ * Set private network data pointer
+ */
+void connman_network_set_data(struct connman_network *network, void *data)
+{
+ network->driver_data = data;
+}
+
+static gboolean match_driver(struct connman_network *network,
+ struct connman_network_driver *driver)
+{
+ if (network->type == driver->type ||
+ driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN)
+ return TRUE;
+
+ return FALSE;
+}
+
+static int network_probe(struct connman_element *element)
+{
+ struct connman_network *network = element->network;
+ GSList *list;
+ int err;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (network == NULL)
+ return -ENODEV;
+
+ for (list = driver_list; list; list = list->next) {
+ struct connman_network_driver *driver = list->data;
+
+ if (match_driver(network, driver) == FALSE)
+ continue;
+
+ DBG("driver %p name %s", driver, driver->name);
+
+ if (driver->probe(network) == 0) {
+ network->driver = driver;
+ break;
+ }
+ }
+
+ if (network->driver == NULL)
+ return -ENODEV;
+
+ err = register_interface(element);
+ if (err < 0) {
+ if (network->driver->remove)
+ network->driver->remove(network);
+ return err;
+ }
+
+ network->secondary = connman_device_get_secondary(network->device);
+
+ switch (network->type) {
+ case CONNMAN_NETWORK_TYPE_UNKNOWN:
+ case CONNMAN_NETWORK_TYPE_VENDOR:
+ case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
+ case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
+ case CONNMAN_NETWORK_TYPE_HSO:
+ break;
+ case CONNMAN_NETWORK_TYPE_WIFI:
+ case CONNMAN_NETWORK_TYPE_WIMAX:
+ if (network->group != NULL && network->secondary == FALSE)
+ __connman_profile_add_network(network);
+ break;
+ }
+
+ return 0;
+}
+
+static void network_remove(struct connman_element *element)
+{
+ struct connman_network *network = element->network;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (network == NULL)
+ return;
+
+ if (network->driver == NULL)
+ return;
+
+ switch (network->type) {
+ case CONNMAN_NETWORK_TYPE_UNKNOWN:
+ case CONNMAN_NETWORK_TYPE_VENDOR:
+ case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
+ case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
+ case CONNMAN_NETWORK_TYPE_HSO:
+ break;
+ case CONNMAN_NETWORK_TYPE_WIFI:
+ case CONNMAN_NETWORK_TYPE_WIMAX:
+ if (network->group != NULL && network->secondary == FALSE) {
+ __connman_profile_remove_network(network);
+
+ g_free(network->group);
+ network->group = NULL;
+ }
+ break;
+ }
+
+ unregister_interface(element);
+
+ if (network->driver->remove)
+ network->driver->remove(network);
+}
+
+static void network_change(struct connman_element *element)
+{
+ struct connman_network *network = element->network;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (element->state != CONNMAN_ELEMENT_STATE_ERROR)
+ return;
+
+ if (element->error != CONNMAN_ELEMENT_ERROR_DHCP_FAILED)
+ return;
+
+ if (network->connected == FALSE)
+ return;
+
+ connman_element_unregister_children(element);
+
+ connman_device_set_disconnected(network->device, TRUE);
+
+ if (network->driver && network->driver->disconnect) {
+ network->driver->disconnect(network);
+ return;
+ }
+
+ network->connected = FALSE;
+}
+
+static struct connman_driver network_driver = {
+ .name = "network",
+ .type = CONNMAN_ELEMENT_TYPE_NETWORK,
+ .priority = CONNMAN_DRIVER_PRIORITY_LOW,
+ .probe = network_probe,
+ .remove = network_remove,
+ .change = network_change,
+};
+
+int __connman_network_init(void)
+{
+ DBG("");
+
+ connection = connman_dbus_get_connection();
+
+ return connman_driver_register(&network_driver);
+}
+
+void __connman_network_cleanup(void)
+{
+ DBG("");
+
+ connman_driver_unregister(&network_driver);
+
+ dbus_connection_unref(connection);
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 "connman.h"
+
+static GSList *notifier_list = NULL;
+
+static gint compare_priority(gconstpointer a, gconstpointer b)
+{
+ const struct connman_notifier *notifier1 = a;
+ const struct connman_notifier *notifier2 = b;
+
+ return notifier2->priority - notifier1->priority;
+}
+
+/**
+ * connman_notifier_register:
+ * @notifier: notifier module
+ *
+ * Register a new notifier module
+ *
+ * Returns: %0 on success
+ */
+int connman_notifier_register(struct connman_notifier *notifier)
+{
+ DBG("notifier %p name %s", notifier, notifier->name);
+
+ notifier_list = g_slist_insert_sorted(notifier_list, notifier,
+ compare_priority);
+
+ return 0;
+}
+
+/**
+ * connman_notifier_unregister:
+ * @notifier: notifier module
+ *
+ * Remove a previously registered notifier module
+ */
+void connman_notifier_unregister(struct connman_notifier *notifier)
+{
+ DBG("notifier %p name %s", notifier, notifier->name);
+
+ notifier_list = g_slist_remove(notifier_list, notifier);
+}
+
+static void device_enabled(enum connman_device_type type,
+ connman_bool_t enabled)
+{
+ GSList *list;
+
+ for (list = notifier_list; list; list = list->next) {
+ struct connman_notifier *notifier = list->data;
+
+ if (notifier->device_enabled)
+ notifier->device_enabled(type, enabled);
+ }
+
+}
+
+static volatile gint enabled[10];
+
+void __connman_notifier_device_type_increase(enum connman_device_type type)
+{
+ DBG("type %d", type);
+
+ switch (type) {
+ case CONNMAN_DEVICE_TYPE_UNKNOWN:
+ case CONNMAN_DEVICE_TYPE_HSO:
+ case CONNMAN_DEVICE_TYPE_NOZOMI:
+ case CONNMAN_DEVICE_TYPE_HUAWEI:
+ case CONNMAN_DEVICE_TYPE_NOVATEL:
+ case CONNMAN_DEVICE_TYPE_VENDOR:
+ return;
+ case CONNMAN_DEVICE_TYPE_ETHERNET:
+ case CONNMAN_DEVICE_TYPE_WIFI:
+ case CONNMAN_DEVICE_TYPE_WIMAX:
+ case CONNMAN_DEVICE_TYPE_BLUETOOTH:
+ case CONNMAN_DEVICE_TYPE_GPS:
+ if (g_atomic_int_exchange_and_add(&enabled[type], 1) == 0)
+ device_enabled(type, TRUE);
+ break;
+ }
+}
+
+void __connman_notifier_device_type_decrease(enum connman_device_type type)
+{
+ DBG("type %d", type);
+
+ switch (type) {
+ case CONNMAN_DEVICE_TYPE_UNKNOWN:
+ case CONNMAN_DEVICE_TYPE_HSO:
+ case CONNMAN_DEVICE_TYPE_NOZOMI:
+ case CONNMAN_DEVICE_TYPE_HUAWEI:
+ case CONNMAN_DEVICE_TYPE_NOVATEL:
+ case CONNMAN_DEVICE_TYPE_VENDOR:
+ return;
+ case CONNMAN_DEVICE_TYPE_ETHERNET:
+ case CONNMAN_DEVICE_TYPE_WIFI:
+ case CONNMAN_DEVICE_TYPE_WIMAX:
+ case CONNMAN_DEVICE_TYPE_BLUETOOTH:
+ case CONNMAN_DEVICE_TYPE_GPS:
+ if (g_atomic_int_dec_and_test(&enabled[type]) == TRUE)
+ device_enabled(type, FALSE);
+ break;
+ }
+}
+
+void __connman_notifier_offline_mode(connman_bool_t enabled)
+{
+ GSList *list;
+
+ DBG("enabled %d", enabled);
+
+ for (list = notifier_list; list; list = list->next) {
+ struct connman_notifier *notifier = list->data;
+
+ if (notifier->offline_mode)
+ notifier->offline_mode(enabled);
+ }
+}
+
+int __connman_notifier_init(void)
+{
+ DBG("");
+
+ return 0;
+}
+
+void __connman_notifier_cleanup(void)
+{
+ DBG("");
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <dlfcn.h>
+
+#include <glib.h>
+
+#ifdef CONNMAN_PLUGIN_BUILTIN
+#undef CONNMAN_PLUGIN_BUILTIN
+#endif
+
+#include "connman.h"
+
+/*
+ * Plugins that are using libraries with threads and their own mainloop
+ * will crash on exit. This is a bug inside these libraries, but there is
+ * nothing much that can be done about it.
+ */
+#ifdef NEED_THREADS
+#define PLUGINFLAG (RTLD_NOW | RTLD_NODELETE)
+#else
+#define PLUGINFLAG (RTLD_NOW)
+#endif
+
+static GSList *plugins = NULL;
+
+struct connman_plugin {
+ void *handle;
+ gboolean active;
+ struct connman_plugin_desc *desc;
+};
+
+static gint compare_priority(gconstpointer a, gconstpointer b)
+{
+ const struct connman_plugin *plugin1 = a;
+ const struct connman_plugin *plugin2 = b;
+
+ return plugin2->desc->priority - plugin1->desc->priority;
+}
+
+static gboolean add_plugin(void *handle, struct connman_plugin_desc *desc)
+{
+ struct connman_plugin *plugin;
+
+ if (desc->init == NULL)
+ return FALSE;
+
+ if (g_str_equal(desc->version, CONNMAN_VERSION) == FALSE) {
+ connman_error("Version mismatch for %s", desc->description);
+ return FALSE;
+ }
+
+ plugin = g_try_new0(struct connman_plugin, 1);
+ if (plugin == NULL)
+ return FALSE;
+
+ plugin->handle = handle;
+ plugin->active = FALSE;
+ plugin->desc = desc;
+
+ plugins = g_slist_insert_sorted(plugins, plugin, compare_priority);
+
+ return TRUE;
+}
+
+static gboolean check_plugin(struct connman_plugin_desc *desc,
+ const char *pattern, const char *exclude)
+{
+ if (exclude != NULL &&
+ g_pattern_match_simple(exclude, desc->name) == TRUE) {
+ connman_info("Excluding %s", desc->description);
+ return FALSE;
+ }
+
+ if (pattern != NULL &&
+ g_pattern_match_simple(pattern, desc->name) == FALSE) {
+ connman_info("Ignoring %s", desc->description);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#include "builtin.h"
+
+int __connman_plugin_init(const char *pattern, const char *exclude)
+{
+ GSList *list;
+ GDir *dir;
+ const gchar *file;
+ gchar *filename;
+ unsigned int i;
+
+ DBG("");
+
+ for (i = 0; __connman_builtin[i]; i++) {
+ if (check_plugin(__connman_builtin[i],
+ pattern, exclude) == FALSE)
+ continue;
+
+ add_plugin(NULL, __connman_builtin[i]);
+ }
+
+ dir = g_dir_open(PLUGINDIR, 0, NULL);
+ if (dir != NULL) {
+ while ((file = g_dir_read_name(dir)) != NULL) {
+ void *handle;
+ struct connman_plugin_desc *desc;
+
+ if (g_str_has_prefix(file, "lib") == TRUE ||
+ g_str_has_suffix(file, ".so") == FALSE)
+ continue;
+
+ filename = g_build_filename(PLUGINDIR, file, NULL);
+
+ handle = dlopen(filename, PLUGINFLAG);
+ if (handle == NULL) {
+ connman_error("Can't load %s: %s",
+ filename, dlerror());
+ g_free(filename);
+ continue;
+ }
+
+ g_free(filename);
+
+ desc = dlsym(handle, "connman_plugin_desc");
+ if (desc == NULL) {
+ connman_error("Can't load symbol: %s",
+ dlerror());
+ dlclose(handle);
+ continue;
+ }
+
+ if (check_plugin(desc, pattern, exclude) == FALSE) {
+ dlclose(handle);
+ continue;
+ }
+
+ if (add_plugin(handle, desc) == FALSE)
+ dlclose(handle);
+ }
+
+ g_dir_close(dir);
+ }
+
+ for (list = plugins; list; list = list->next) {
+ struct connman_plugin *plugin = list->data;
+
+ if (plugin->desc->init() < 0)
+ continue;
+
+ plugin->active = TRUE;
+ }
+
+ return 0;
+}
+
+void __connman_plugin_cleanup(void)
+{
+ GSList *list;
+
+ DBG("");
+
+ for (list = plugins; list; list = list->next) {
+ struct connman_plugin *plugin = list->data;
+
+ if (plugin->active == TRUE && plugin->desc->exit)
+ plugin->desc->exit();
+
+ if (plugin->handle != NULL)
+ dlclose(plugin->handle);
+
+ g_free(plugin);
+ }
+
+ g_slist_free(plugins);
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <glib.h>
+#include <gdbus.h>
+
+#include "connman.h"
+
+#define PROFILE_DEFAULT_IDENT "default"
+
+static DBusConnection *connection = NULL;
+
+const char *__connman_profile_active_ident(void)
+{
+ DBG("");
+
+ return PROFILE_DEFAULT_IDENT;
+}
+
+const char *__connman_profile_active_path(void)
+{
+ DBG("");
+
+ return "/profile/" PROFILE_DEFAULT_IDENT;
+}
+
+static void append_services(DBusMessageIter *entry)
+{
+ DBusMessageIter value, iter;
+ const char *key = "Services";
+
+ dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
+
+ dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
+ &value);
+
+ dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
+ __connman_service_list(&iter);
+ dbus_message_iter_close_container(&value, &iter);
+
+ dbus_message_iter_close_container(entry, &value);
+}
+
+void __connman_profile_changed(void)
+{
+ const char *path = __connman_profile_active_path();
+ DBusMessage *signal;
+ DBusMessageIter entry;
+
+ signal = dbus_message_new_signal(path,
+ CONNMAN_PROFILE_INTERFACE, "PropertyChanged");
+ if (signal == NULL)
+ return;
+
+ dbus_message_iter_init_append(signal, &entry);
+ append_services(&entry);
+ g_dbus_send_message(connection, signal);
+
+ signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
+ CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
+ if (signal == NULL)
+ return;
+
+ dbus_message_iter_init_append(signal, &entry);
+ append_services(&entry);
+ g_dbus_send_message(connection, signal);
+}
+
+int __connman_profile_add_device(struct connman_device *device)
+{
+ struct connman_service *service;
+
+ DBG("device %p", device);
+
+ service = __connman_service_create_from_device(device);
+ if (service == NULL)
+ return -EINVAL;
+
+ return 0;
+}
+
+int __connman_profile_remove_device(struct connman_device *device)
+{
+ struct connman_service *service;
+
+ DBG("device %p", device);
+
+ service = __connman_service_lookup_from_device(device);
+ if (service == NULL)
+ return -EINVAL;
+
+ __connman_service_put(service);
+
+ return 0;
+}
+
+int __connman_profile_add_network(struct connman_network *network)
+{
+ struct connman_service *service;
+
+ DBG("network %p", network);
+
+ service = __connman_service_create_from_network(network);
+ if (service == NULL)
+ return -EINVAL;
+
+ return 0;
+}
+
+int __connman_profile_remove_network(struct connman_network *network)
+{
+ struct connman_service *service;
+
+ DBG("network %p", network);
+
+ service = __connman_service_lookup_from_network(network);
+ if (service == NULL)
+ return -EINVAL;
+
+ __connman_service_put(service);
+
+ return 0;
+}
+
+void __connman_profile_list(DBusMessageIter *iter)
+{
+ const char *path = __connman_profile_active_path();
+
+ DBG("");
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+}
+
+static DBusMessage *get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *name = "Default";
+ DBusMessage *reply;
+ DBusMessageIter array, dict, entry;
+
+ DBG("conn %p", conn);
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &array);
+
+ dbus_message_iter_open_container(&array, 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);
+
+ connman_dbus_dict_append_variant(&dict, "Name",
+ DBUS_TYPE_STRING, &name);
+
+ dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+ append_services(&entry);
+ dbus_message_iter_close_container(&dict, &entry);
+
+ dbus_message_iter_close_container(&array, &dict);
+
+ return reply;
+}
+
+static GDBusMethodTable profile_methods[] = {
+ { "GetProperties", "", "a{sv}", get_properties },
+ { },
+};
+
+static GDBusSignalTable profile_signals[] = {
+ { "PropertyChanged", "sv" },
+ { },
+};
+
+int __connman_profile_init(DBusConnection *conn)
+{
+ const char *path = __connman_profile_active_path();
+
+ DBG("conn %p", conn);
+
+ connection = dbus_connection_ref(conn);
+ if (connection == NULL)
+ return -1;
+
+ g_dbus_register_interface(connection, path,
+ CONNMAN_PROFILE_INTERFACE,
+ profile_methods, profile_signals,
+ NULL, NULL, NULL);
+
+ return 0;
+}
+
+void __connman_profile_cleanup(void)
+{
+ const char *path = __connman_profile_active_path();
+
+ DBG("conn %p", connection);
+
+ g_dbus_unregister_interface(connection, path,
+ CONNMAN_PROFILE_INTERFACE);
+
+ if (connection == NULL)
+ return;
+
+ dbus_connection_unref(connection);
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "connman.h"
+
+struct entry_data {
+ struct connman_resolver *resolver;
+ char *interface;
+ char *domain;
+ char *server;
+};
+
+static GSList *entry_list = NULL;
+static GSList *resolver_list = NULL;
+
+static void remove_entries(GSList *entries)
+{
+ GSList *list;
+
+ for (list = entries; list; list = list->next) {
+ struct entry_data *entry = list->data;
+ struct connman_resolver *resolver = entry->resolver;
+
+ entry_list = g_slist_remove(entry_list, entry);
+
+ if (resolver->remove)
+ resolver->remove(entry->interface, entry->domain,
+ entry->server);
+
+ g_free(entry->server);
+ g_free(entry->domain);
+ g_free(entry->interface);
+ g_free(entry);
+ }
+
+ g_slist_free(entries);
+}
+
+static gint compare_priority(gconstpointer a, gconstpointer b)
+{
+ const struct connman_resolver *resolver1 = a;
+ const struct connman_resolver *resolver2 = b;
+
+ return resolver2->priority - resolver1->priority;
+}
+
+/**
+ * connman_resolver_register:
+ * @resolver: resolver module
+ *
+ * Register a new resolver module
+ *
+ * Returns: %0 on success
+ */
+int connman_resolver_register(struct connman_resolver *resolver)
+{
+ GSList *list;
+
+ DBG("resolver %p name %s", resolver, resolver->name);
+
+ resolver_list = g_slist_insert_sorted(resolver_list, resolver,
+ compare_priority);
+
+ if (resolver->append == NULL)
+ return 0;
+
+ for (list = entry_list; list; list = list->next) {
+ struct entry_data *entry = list->data;
+
+ if (entry->resolver)
+ continue;
+
+ if (resolver->append(entry->interface, entry->domain,
+ entry->server) == 0)
+ entry->resolver = resolver;
+ }
+
+ return 0;
+}
+
+/**
+ * connman_resolver_unregister:
+ * @resolver: resolver module
+ *
+ * Remove a previously registered resolver module
+ */
+void connman_resolver_unregister(struct connman_resolver *resolver)
+{
+ GSList *list, *matches = NULL;
+
+ DBG("resolver %p name %s", resolver, resolver->name);
+
+ resolver_list = g_slist_remove(resolver_list, resolver);
+
+ for (list = entry_list; list; list = list->next) {
+ struct entry_data *entry = list->data;
+
+ if (entry->resolver != resolver)
+ continue;
+
+ matches = g_slist_append(matches, entry);
+ }
+
+ remove_entries(matches);
+}
+
+/**
+ * connman_resolver_append:
+ * @interface: network interface
+ * @domain: domain limitation
+ * @server: server address
+ *
+ * Append resolver server address to current list
+ */
+int connman_resolver_append(const char *interface, const char *domain,
+ const char *server)
+{
+ struct entry_data *entry;
+ GSList *list;
+
+ DBG("interface %s domain %s server %s", interface, domain, server);
+
+ if (server == NULL)
+ return -EINVAL;
+
+ entry = g_try_new0(struct entry_data, 1);
+ if (entry == NULL)
+ return -ENOMEM;
+
+ entry->interface = g_strdup(interface);
+ entry->domain = g_strdup(domain);
+ entry->server = g_strdup(server);
+
+ entry_list = g_slist_append(entry_list, entry);
+
+ for (list = resolver_list; list; list = list->next) {
+ struct connman_resolver *resolver = list->data;
+
+ if (resolver->append == NULL)
+ continue;
+
+ if (resolver->append(interface, domain, server) == 0) {
+ entry->resolver = resolver;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * connman_resolver_remove_all:
+ * @interface: network interface
+ *
+ * Remove all resolver server address for the specified interface
+ */
+int connman_resolver_remove_all(const char *interface)
+{
+ GSList *list, *matches = NULL;
+
+ DBG("interface %s", interface);
+
+ for (list = entry_list; list; list = list->next) {
+ struct entry_data *entry = list->data;
+
+ if (g_str_equal(entry->interface, interface) == FALSE)
+ continue;
+
+ matches = g_slist_append(matches, entry);
+ }
+
+ remove_entries(matches);
+
+ return 0;
+}
+
+static int selftest_append(const char *interface, const char *domain,
+ const char *server)
+{
+ DBG("server %s", server);
+
+ return 0;
+}
+
+static int selftest_remove(const char *interface, const char *domain,
+ const char *server)
+{
+ DBG("server %s", server);
+
+ return 0;
+}
+
+static struct connman_resolver selftest_resolver = {
+ .name = "selftest",
+ .priority = CONNMAN_RESOLVER_PRIORITY_HIGH + 42,
+ .append = selftest_append,
+ .remove = selftest_remove,
+};
+
+int __connman_resolver_selftest(void)
+{
+ connman_resolver_append("wlan0", "lwn.net", "192.168.0.1");
+
+ connman_resolver_register(&selftest_resolver);
+
+ connman_resolver_append("eth0", "moblin.org", "192.168.42.1");
+ connman_resolver_append("wlan0", "lwn.net", "192.168.0.2");
+
+ connman_resolver_remove_all("wlan0");
+
+ connman_resolver_unregister(&selftest_resolver);
+
+ return 0;
+}
+
+static int resolvfile_append(const char *interface, const char *domain,
+ const char *server)
+{
+ char *cmd;
+ int fd, len, err;
+
+ DBG("interface %s server %s", interface, server);
+
+ fd = open("/etc/resolv.conf", O_RDWR | O_CREAT,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd < 0)
+ return -errno;
+
+ err = ftruncate(fd, 0);
+
+ cmd = g_strdup_printf("# Generated by Connection Manager\n"
+ "nameserver %s\n", server);
+
+ len = write(fd, cmd, strlen(cmd));
+
+ g_free(cmd);
+
+ close(fd);
+
+ return 0;
+}
+
+static int resolvfile_remove(const char *interface, const char *domain,
+ const char *server)
+{
+ DBG("interface %s server %s", interface, server);
+
+ return 0;
+}
+
+static struct connman_resolver resolvfile_resolver = {
+ .name = "resolvfile",
+ .priority = CONNMAN_RESOLVER_PRIORITY_LOW,
+ .append = resolvfile_append,
+ .remove = resolvfile_remove,
+};
+
+int __connman_resolver_init(void)
+{
+ DBG("");
+
+ return connman_resolver_register(&resolvfile_resolver);
+}
+
+void __connman_resolver_cleanup(void)
+{
+ DBG("");
+
+ connman_resolver_unregister(&resolvfile_resolver);
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "connman.h"
+
+enum rfkill_type {
+ RFKILL_TYPE_ALL = 0,
+ RFKILL_TYPE_WLAN,
+ RFKILL_TYPE_BLUETOOTH,
+ RFKILL_TYPE_UWB,
+ RFKILL_TYPE_WIMAX,
+ RFKILL_TYPE_WWAN,
+};
+
+enum rfkill_operation {
+ RFKILL_OP_ADD = 0,
+ RFKILL_OP_DEL,
+ RFKILL_OP_CHANGE,
+ RFKILL_OP_CHANGE_ALL,
+};
+
+struct rfkill_event {
+ uint32_t idx;
+ uint8_t type;
+ uint8_t op;
+ uint8_t soft;
+ uint8_t hard;
+};
+
+static gboolean rfkill_event(GIOChannel *chan,
+ GIOCondition cond, gpointer data)
+{
+ unsigned char buf[32];
+ struct rfkill_event *event = (void *) buf;
+ gsize len;
+ GIOError err;
+
+ if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
+ return FALSE;
+
+ memset(buf, 0, sizeof(buf));
+
+ err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len);
+ if (err) {
+ if (err == G_IO_ERROR_AGAIN)
+ return TRUE;
+ return FALSE;
+ }
+
+ if (len != sizeof(struct rfkill_event))
+ return TRUE;
+
+ connman_info("RFKILL event: idx %u type %u op %u soft %u hard %u",
+ event->idx, event->type, event->op,
+ event->soft, event->hard);
+
+ return TRUE;
+}
+
+static GIOChannel *channel = NULL;
+
+int __connman_rfkill_init(void)
+{
+ int fd;
+
+ DBG("");
+
+ fd = open("/dev/rfkill", O_RDWR);
+ if (fd < 0) {
+ connman_error("Failed to open RFKILL control device");
+ return -EIO;
+ }
+
+ channel = g_io_channel_unix_new(fd);
+ g_io_channel_set_close_on_unref(channel, TRUE);
+
+ g_io_add_watch(channel, G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
+ rfkill_event, NULL);
+
+ return 0;
+}
+
+void __connman_rfkill_cleanup(void)
+{
+ DBG("");
+
+ if (channel == NULL)
+ return;
+
+ g_io_channel_shutdown(channel, TRUE, NULL);
+ g_io_channel_unref(channel);
+
+ channel = NULL;
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <linux/if.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <glib.h>
+
+#include "connman.h"
+
+struct watch_data {
+ unsigned int id;
+ int index;
+ connman_rtnl_link_cb_t newlink;
+ void *user_data;
+};
+
+static GSList *watch_list = NULL;
+static unsigned int watch_id = 0;
+
+/**
+ * connman_rtnl_add_newlink_watch:
+ * @index: network device index
+ * @callback: callback function
+ * @user_data: callback data;
+ *
+ * Add a new RTNL watch for newlink events
+ *
+ * Returns: %0 on failure and a unique id on success
+ */
+unsigned int connman_rtnl_add_newlink_watch(int index,
+ connman_rtnl_link_cb_t callback, void *user_data)
+{
+ struct watch_data *watch;
+
+ watch = g_try_new0(struct watch_data, 1);
+ if (watch == NULL)
+ return 0;
+
+ watch->id = ++watch_id;
+ watch->index = index;
+
+ watch->newlink = callback;
+ watch->user_data = user_data;
+
+ watch_list = g_slist_prepend(watch_list, watch);
+
+ DBG("id %d", watch->id);
+
+ return watch->id;
+}
+
+/**
+ * connman_rtnl_remove_watch:
+ * @id: watch identifier
+ *
+ * Remove the RTNL watch for the identifier
+ */
+void connman_rtnl_remove_watch(unsigned int id)
+{
+ GSList *list;
+
+ DBG("id %d", id);
+
+ if (id == 0)
+ return;
+
+ for (list = watch_list; list; list = list->next) {
+ struct watch_data *watch = list->data;
+
+ if (watch->id == id) {
+ watch_list = g_slist_remove(watch_list, watch);
+ g_free(watch);
+ break;
+ }
+ }
+}
+
+static GSList *rtnl_list = NULL;
+
+static gint compare_priority(gconstpointer a, gconstpointer b)
+{
+ const struct connman_rtnl *rtnl1 = a;
+ const struct connman_rtnl *rtnl2 = b;
+
+ return rtnl2->priority - rtnl1->priority;
+}
+
+/**
+ * connman_rtnl_register:
+ * @rtnl: RTNL module
+ *
+ * Register a new RTNL module
+ *
+ * Returns: %0 on success
+ */
+int connman_rtnl_register(struct connman_rtnl *rtnl)
+{
+ DBG("rtnl %p name %s", rtnl, rtnl->name);
+
+ rtnl_list = g_slist_insert_sorted(rtnl_list, rtnl,
+ compare_priority);
+
+ return 0;
+}
+
+/**
+ * connman_rtnl_unregister:
+ * @rtnl: RTNL module
+ *
+ * Remove a previously registered RTNL module
+ */
+void connman_rtnl_unregister(struct connman_rtnl *rtnl)
+{
+ DBG("rtnl %p name %s", rtnl, rtnl->name);
+
+ rtnl_list = g_slist_remove(rtnl_list, rtnl);
+}
+
+static void process_newlink(unsigned short type, int index,
+ unsigned flags, unsigned change)
+{
+ GSList *list;
+
+ for (list = rtnl_list; list; list = list->next) {
+ struct connman_rtnl *rtnl = list->data;
+
+ if (rtnl->newlink)
+ rtnl->newlink(type, index, flags, change);
+ }
+
+ for (list = watch_list; list; list = list->next) {
+ struct watch_data *watch = list->data;
+
+ if (watch->index != index)
+ continue;
+
+ if (watch->newlink)
+ watch->newlink(flags, change, watch->user_data);
+ }
+}
+
+static void process_dellink(unsigned short type, int index,
+ unsigned flags, unsigned change)
+{
+ GSList *list;
+
+ for (list = rtnl_list; list; list = list->next) {
+ struct connman_rtnl *rtnl = list->data;
+
+ if (rtnl->dellink)
+ rtnl->dellink(type, index, flags, change);
+ }
+}
+
+static char *extract_gateway(struct rtmsg *msg, int bytes, int *index)
+{
+ char *gateway = NULL;
+ struct in_addr addr;
+ struct rtattr *attr;
+
+ for (attr = RTM_RTA(msg); RTA_OK(attr, bytes);
+ attr = RTA_NEXT(attr, bytes)) {
+ switch (attr->rta_type) {
+ case RTA_GATEWAY:
+ addr = *((struct in_addr *) RTA_DATA(attr));
+ g_free(gateway);
+ gateway = g_strdup(inet_ntoa(addr));
+ break;
+ case RTA_OIF:
+ *index = *((int *) RTA_DATA(attr));
+ break;
+ }
+ }
+
+ return gateway;
+}
+
+static void process_newgateway(struct rtmsg *msg, int bytes)
+{
+ int index = -1;
+ char *gateway;
+ GSList *list;
+
+ gateway = extract_gateway(msg, bytes, &index);
+ if (gateway == NULL || index < 0)
+ return;
+
+ for (list = rtnl_list; list; list = list->next) {
+ struct connman_rtnl *rtnl = list->data;
+
+ if (rtnl->newgateway)
+ rtnl->newgateway(index, gateway);
+ }
+
+ g_free(gateway);
+}
+
+static void process_delgateway(struct rtmsg *msg, int bytes)
+{
+ int index = -1;
+ char *gateway;
+ GSList *list;
+
+ gateway = extract_gateway(msg, bytes, &index);
+ if (gateway == NULL || index < 0)
+ return;
+
+ for (list = rtnl_list; list; list = list->next) {
+ struct connman_rtnl *rtnl = list->data;
+
+ if (rtnl->delgateway)
+ rtnl->delgateway(index, gateway);
+ }
+
+ g_free(gateway);
+}
+
+static inline void print_inet(struct rtattr *attr, const char *name, int family)
+{
+ if (family == AF_INET) {
+ struct in_addr addr;
+ addr = *((struct in_addr *) RTA_DATA(attr));
+ DBG(" attr %s (len %d) %s\n", name,
+ (int) RTA_PAYLOAD(attr), inet_ntoa(addr));
+ } else
+ DBG(" attr %s (len %d)\n", name, (int) RTA_PAYLOAD(attr));
+}
+
+static inline void print_char(struct rtattr *attr, const char *name)
+{
+ DBG(" attr %s (len %d) %s\n", name, (int) RTA_PAYLOAD(attr),
+ (char *) RTA_DATA(attr));
+}
+
+static inline void print_byte(struct rtattr *attr, const char *name)
+{
+ DBG(" attr %s (len %d) 0x%02x\n", name, (int) RTA_PAYLOAD(attr),
+ *((unsigned char *) RTA_DATA(attr)));
+}
+
+static inline void print_attr(struct rtattr *attr, const char *name)
+{
+ if (name)
+ DBG(" attr %s (len %d)\n", name, (int) RTA_PAYLOAD(attr));
+ else
+ DBG(" attr %d (len %d)\n",
+ attr->rta_type, (int) RTA_PAYLOAD(attr));
+}
+
+static void rtnl_link(struct nlmsghdr *hdr)
+{
+#if 0
+ struct ifinfomsg *msg;
+ struct rtattr *attr;
+ int bytes;
+
+ msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
+ bytes = IFLA_PAYLOAD(hdr);
+
+ DBG("ifi_index %d ifi_flags 0x%04x", msg->ifi_index, msg->ifi_flags);
+
+ for (attr = IFLA_RTA(msg); RTA_OK(attr, bytes);
+ attr = RTA_NEXT(attr, bytes)) {
+ switch (attr->rta_type) {
+ case IFLA_ADDRESS:
+ print_attr(attr, "address");
+ break;
+ case IFLA_BROADCAST:
+ print_attr(attr, "broadcast");
+ break;
+ case IFLA_IFNAME:
+ print_char(attr, "ifname");
+ break;
+ case IFLA_MTU:
+ print_attr(attr, "mtu");
+ break;
+ case IFLA_LINK:
+ print_attr(attr, "link");
+ break;
+ case IFLA_QDISC:
+ print_attr(attr, "qdisc");
+ break;
+ case IFLA_STATS:
+ print_attr(attr, "stats");
+ break;
+ case IFLA_COST:
+ print_attr(attr, "cost");
+ break;
+ case IFLA_PRIORITY:
+ print_attr(attr, "priority");
+ break;
+ case IFLA_MASTER:
+ print_attr(attr, "master");
+ break;
+ case IFLA_WIRELESS:
+ print_attr(attr, "wireless");
+ break;
+ case IFLA_PROTINFO:
+ print_attr(attr, "protinfo");
+ break;
+ case IFLA_TXQLEN:
+ print_attr(attr, "txqlen");
+ break;
+ case IFLA_MAP:
+ print_attr(attr, "map");
+ break;
+ case IFLA_WEIGHT:
+ print_attr(attr, "weight");
+ break;
+ case IFLA_OPERSTATE:
+ print_byte(attr, "operstate");
+ break;
+ case IFLA_LINKMODE:
+ print_byte(attr, "linkmode");
+ break;
+ default:
+ print_attr(attr, NULL);
+ break;
+ }
+ }
+#endif
+}
+
+static void rtnl_newlink(struct nlmsghdr *hdr)
+{
+ struct ifinfomsg *msg;
+
+ msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
+
+ DBG("ifi_type %d ifi_index %d ifi_flags 0x%04x ifi_change 0x%04x",
+ msg->ifi_type, msg->ifi_index,
+ msg->ifi_flags, msg->ifi_change);
+
+ process_newlink(msg->ifi_type, msg->ifi_index,
+ msg->ifi_flags, msg->ifi_change);
+
+ rtnl_link(hdr);
+}
+
+static void rtnl_dellink(struct nlmsghdr *hdr)
+{
+ struct ifinfomsg *msg;
+
+ msg = (struct ifinfomsg *) NLMSG_DATA(hdr);
+
+ DBG("ifi_type %d ifi_index %d ifi_flags 0x%04x ifi_change 0x%04x",
+ msg->ifi_type, msg->ifi_index,
+ msg->ifi_flags, msg->ifi_change);
+
+ process_dellink(msg->ifi_type, msg->ifi_index,
+ msg->ifi_flags, msg->ifi_change);
+
+ rtnl_link(hdr);
+}
+
+static void rtnl_addr(struct nlmsghdr *hdr)
+{
+ struct ifaddrmsg *msg;
+ struct rtattr *attr;
+ int bytes;
+
+ msg = (struct ifaddrmsg *) NLMSG_DATA(hdr);
+ bytes = IFA_PAYLOAD(hdr);
+
+ DBG("ifa_family %d ifa_index %d", msg->ifa_family, msg->ifa_index);
+
+ for (attr = IFA_RTA(msg); RTA_OK(attr, bytes);
+ attr = RTA_NEXT(attr, bytes)) {
+ switch (attr->rta_type) {
+ case IFA_ADDRESS:
+ print_inet(attr, "address", msg->ifa_family);
+ break;
+ case IFA_LOCAL:
+ print_inet(attr, "local", msg->ifa_family);
+ break;
+ case IFA_LABEL:
+ print_char(attr, "label");
+ break;
+ case IFA_BROADCAST:
+ print_inet(attr, "broadcast", msg->ifa_family);
+ break;
+ case IFA_ANYCAST:
+ print_attr(attr, "anycast");
+ break;
+ case IFA_CACHEINFO:
+ print_attr(attr, "cacheinfo");
+ break;
+ case IFA_MULTICAST:
+ print_attr(attr, "multicast");
+ break;
+ default:
+ print_attr(attr, NULL);
+ break;
+ }
+ }
+}
+
+static void rtnl_route(struct nlmsghdr *hdr)
+{
+#if 0
+ struct rtmsg *msg;
+ struct rtattr *attr;
+ int bytes;
+
+ msg = (struct rtmsg *) NLMSG_DATA(hdr);
+ bytes = RTM_PAYLOAD(hdr);
+
+ DBG("rtm_family %d rtm_flags 0x%04x", msg->rtm_family, msg->rtm_flags);
+
+ for (attr = RTM_RTA(msg); RTA_OK(attr, bytes);
+ attr = RTA_NEXT(attr, bytes)) {
+ switch (attr->rta_type) {
+ case RTA_DST:
+ print_inet(attr, "dst", msg->rtm_family);
+ break;
+ case RTA_SRC:
+ print_inet(attr, "src", msg->rtm_family);
+ break;
+ case RTA_IIF:
+ print_char(attr, "iif");
+ break;
+ case RTA_OIF:
+ print_attr(attr, "oif");
+ break;
+ case RTA_GATEWAY:
+ print_inet(attr, "gateway", msg->rtm_family);
+ break;
+ case RTA_PRIORITY:
+ print_attr(attr, "priority");
+ break;
+ case RTA_PREFSRC:
+ print_inet(attr, "prefsrc", msg->rtm_family);
+ break;
+ case RTA_METRICS:
+ print_attr(attr, "metrics");
+ break;
+ case RTA_TABLE:
+ print_attr(attr, "table");
+ break;
+ default:
+ print_attr(attr, NULL);
+ break;
+ }
+ }
+#endif
+}
+
+static void rtnl_newroute(struct nlmsghdr *hdr)
+{
+ struct rtmsg *msg;
+
+ msg = (struct rtmsg *) NLMSG_DATA(hdr);
+
+ if (msg->rtm_type == RTN_UNICAST && msg->rtm_table == RT_TABLE_MAIN &&
+ msg->rtm_scope == RT_SCOPE_UNIVERSE) {
+ DBG("rtm_table %d rtm_scope %d rtm_type %d rtm_flags 0x%04x",
+ msg->rtm_table, msg->rtm_scope,
+ msg->rtm_type, msg->rtm_flags);
+ process_newgateway(msg, RTM_PAYLOAD(hdr));
+ }
+
+ rtnl_route(hdr);
+}
+
+static void rtnl_delroute(struct nlmsghdr *hdr)
+{
+ struct rtmsg *msg;
+
+ msg = (struct rtmsg *) NLMSG_DATA(hdr);
+
+ if (msg->rtm_type == RTN_UNICAST && msg->rtm_table == RT_TABLE_MAIN &&
+ msg->rtm_scope == RT_SCOPE_UNIVERSE) {
+ DBG("rtm_table %d rtm_scope %d rtm_type %d rtm_flags 0x%04x",
+ msg->rtm_table, msg->rtm_scope,
+ msg->rtm_type, msg->rtm_flags);
+ process_delgateway(msg, RTM_PAYLOAD(hdr));
+ }
+
+ rtnl_route(hdr);
+}
+
+static const char *type2string(uint16_t type)
+{
+ switch (type) {
+ case NLMSG_NOOP:
+ return "NOOP";
+ case NLMSG_ERROR:
+ return "ERROR";
+ case NLMSG_DONE:
+ return "DONE";
+ case NLMSG_OVERRUN:
+ return "OVERRUN";
+ case RTM_GETLINK:
+ return "GETLINK";
+ case RTM_NEWLINK:
+ return "NEWLINK";
+ case RTM_DELLINK:
+ return "DELLINK";
+ case RTM_NEWADDR:
+ return "NEWADDR";
+ case RTM_DELADDR:
+ return "DELADDR";
+ case RTM_GETROUTE:
+ return "GETROUTE";
+ case RTM_NEWROUTE:
+ return "NEWROUTE";
+ case RTM_DELROUTE:
+ return "DELROUTE";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static GIOChannel *channel = NULL;
+
+struct rtnl_request {
+ struct nlmsghdr hdr;
+ struct rtgenmsg msg;
+};
+#define RTNL_REQUEST_SIZE (sizeof(struct nlmsghdr) + sizeof(struct rtgenmsg))
+
+static GSList *request_list = NULL;
+static guint32 request_seq = 0;
+
+static struct rtnl_request *find_request(guint32 seq)
+{
+ GSList *list;
+
+ for (list = request_list; list; list = list->next) {
+ struct rtnl_request *req = list->data;
+
+ if (req->hdr.nlmsg_seq == seq)
+ return req;
+ }
+
+ return NULL;
+}
+
+static int send_request(struct rtnl_request *req)
+{
+ struct sockaddr_nl addr;
+ int sk;
+
+ DBG("%s len %d type %d flags 0x%04x seq %d",
+ type2string(req->hdr.nlmsg_type),
+ req->hdr.nlmsg_len, req->hdr.nlmsg_type,
+ req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
+
+ sk = g_io_channel_unix_get_fd(channel);
+
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+
+ return sendto(sk, req, req->hdr.nlmsg_len, 0,
+ (struct sockaddr *) &addr, sizeof(addr));
+}
+
+static int queue_request(struct rtnl_request *req)
+{
+ request_list = g_slist_append(request_list, req);
+
+ if (g_slist_length(request_list) > 1)
+ return 0;
+
+ return send_request(req);
+}
+
+static int process_response(guint32 seq)
+{
+ struct rtnl_request *req;
+
+ DBG("seq %d", seq);
+
+ req = find_request(seq);
+ if (req != NULL) {
+ request_list = g_slist_remove(request_list, req);
+ g_free(req);
+ }
+
+ req = g_slist_nth_data(request_list, 0);
+ if (req == NULL)
+ return 0;
+
+ return send_request(req);
+}
+
+static void rtnl_message(void *buf, size_t len)
+{
+ DBG("buf %p len %zd", buf, len);
+
+ while (len > 0) {
+ struct nlmsghdr *hdr = buf;
+ struct nlmsgerr *err;
+
+ if (!NLMSG_OK(hdr, len))
+ break;
+
+ DBG("%s len %d type %d flags 0x%04x seq %d",
+ type2string(hdr->nlmsg_type),
+ hdr->nlmsg_len, hdr->nlmsg_type,
+ hdr->nlmsg_flags, hdr->nlmsg_seq);
+
+ switch (hdr->nlmsg_type) {
+ case NLMSG_NOOP:
+ case NLMSG_OVERRUN:
+ return;
+ case NLMSG_DONE:
+ process_response(hdr->nlmsg_seq);
+ return;
+ case NLMSG_ERROR:
+ err = NLMSG_DATA(hdr);
+ DBG("error %d (%s)", -err->error,
+ strerror(-err->error));
+ return;
+ case RTM_NEWLINK:
+ rtnl_newlink(hdr);
+ break;
+ case RTM_DELLINK:
+ rtnl_dellink(hdr);
+ break;
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ rtnl_addr(hdr);
+ break;
+ case RTM_NEWROUTE:
+ rtnl_newroute(hdr);
+ break;
+ case RTM_DELROUTE:
+ rtnl_delroute(hdr);
+ break;
+ }
+
+ len -= hdr->nlmsg_len;
+ buf += hdr->nlmsg_len;
+ }
+}
+
+static gboolean netlink_event(GIOChannel *chan,
+ GIOCondition cond, gpointer data)
+{
+ unsigned char buf[4096];
+ gsize len;
+ GIOError err;
+
+ if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
+ return FALSE;
+
+ memset(buf, 0, sizeof(buf));
+
+ err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len);
+ if (err) {
+ if (err == G_IO_ERROR_AGAIN)
+ return TRUE;
+ return FALSE;
+ }
+
+ rtnl_message(buf, len);
+
+ return TRUE;
+}
+
+int connman_rtnl_send_getlink(void)
+{
+ struct rtnl_request *req;
+
+ DBG("");
+
+ req = g_try_malloc0(RTNL_REQUEST_SIZE);
+ if (req == NULL)
+ return -ENOMEM;
+
+ req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
+ req->hdr.nlmsg_type = RTM_GETLINK;
+ req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ req->hdr.nlmsg_pid = 0;
+ req->hdr.nlmsg_seq = request_seq++;
+ req->msg.rtgen_family = AF_INET;
+
+ return queue_request(req);
+}
+
+int connman_rtnl_send_getroute(void)
+{
+ struct rtnl_request *req;
+
+ DBG("");
+
+ req = g_try_malloc0(RTNL_REQUEST_SIZE);
+ if (req == NULL)
+ return -ENOMEM;
+
+ req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
+ req->hdr.nlmsg_type = RTM_GETROUTE;
+ req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ req->hdr.nlmsg_pid = 0;
+ req->hdr.nlmsg_seq = request_seq++;
+ req->msg.rtgen_family = AF_INET;
+
+ return queue_request(req);
+}
+
+int __connman_rtnl_init(void)
+{
+ struct sockaddr_nl addr;
+ int sk;
+
+ DBG("");
+
+ sk = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (sk < 0)
+ return -1;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE;
+ //addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
+ //addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ close(sk);
+ return -1;
+ }
+
+ channel = g_io_channel_unix_new(sk);
+ g_io_channel_set_close_on_unref(channel, TRUE);
+
+ g_io_add_watch(channel, G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
+ netlink_event, NULL);
+
+ return 0;
+}
+
+void __connman_rtnl_cleanup(void)
+{
+ GSList *list;
+
+ DBG("");
+
+ for (list = watch_list; list; list = list->next) {
+ struct watch_data *watch = list->data;
+
+ DBG("removing watch %d", watch->id);
+
+ g_free(watch);
+ list->data = NULL;
+ }
+
+ g_slist_free(watch_list);
+ watch_list = NULL;
+
+ for (list = request_list; list; list = list->next) {
+ struct rtnl_request *req = list->data;
+
+ DBG("%s len %d type %d flags 0x%04x seq %d",
+ type2string(req->hdr.nlmsg_type),
+ req->hdr.nlmsg_len, req->hdr.nlmsg_type,
+ req->hdr.nlmsg_flags, req->hdr.nlmsg_seq);
+
+ g_free(req);
+ list->data = NULL;
+ }
+
+ g_slist_free(request_list);
+ request_list = NULL;
+
+ g_io_channel_shutdown(channel, TRUE, NULL);
+ g_io_channel_unref(channel);
+
+ channel = NULL;
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 "connman.h"
+
+static GSList *security_list = NULL;
+
+static gint compare_priority(gconstpointer a, gconstpointer b)
+{
+ const struct connman_security *security1 = a;
+ const struct connman_security *security2 = b;
+
+ return security2->priority - security1->priority;
+}
+
+/**
+ * connman_security_register:
+ * @security: security module
+ *
+ * Register a new security module
+ *
+ * Returns: %0 on success
+ */
+int connman_security_register(struct connman_security *security)
+{
+ DBG("security %p name %s", security, security->name);
+
+ security_list = g_slist_insert_sorted(security_list, security,
+ compare_priority);
+
+ return 0;
+}
+
+/**
+ * connman_security_unregister:
+ * @security: security module
+ *
+ * Remove a previously registered security module
+ */
+void connman_security_unregister(struct connman_security *security)
+{
+ DBG("security %p name %s", security, security->name);
+
+ security_list = g_slist_remove(security_list, security);
+}
+
+int __connman_security_check_privilege(DBusMessage *message,
+ enum connman_security_privilege privilege)
+{
+ GSList *list;
+ const char *sender;
+ int err = 0;
+
+ DBG("message %p", message);
+
+ sender = dbus_message_get_sender(message);
+
+ for (list = security_list; list; list = list->next) {
+ struct connman_security *security = list->data;
+
+ DBG("%s", security->name);
+
+ if (security->authorize_sender) {
+ err = security->authorize_sender(sender, privilege);
+ break;
+ }
+ }
+
+ return err;
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 "connman.h"
+
+int __connman_selftest(void)
+{
+ int err;
+
+ connman_info("Start self testing");
+
+ connman_info("Testing resolver unit");
+ err = __connman_resolver_selftest();
+ if (err < 0)
+ goto done;
+
+done:
+ connman_info("Finished self testing");
+
+ return err;
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <gdbus.h>
+
+#include "connman.h"
+
+static DBusConnection *connection = NULL;
+
+static GSequence *service_list = NULL;
+static GHashTable *service_hash = NULL;
+
+struct connman_service {
+ gint refcount;
+ char *identifier;
+ char *path;
+ enum connman_service_type type;
+ enum connman_service_mode mode;
+ enum connman_service_security security;
+ enum connman_service_state state;
+ connman_uint8_t strength;
+ connman_bool_t favorite;
+ connman_bool_t hidden;
+ GTimeVal modified;
+ unsigned int order;
+ char *name;
+ char *passphrase;
+ char *profile;
+ struct connman_device *device;
+ struct connman_network *network;
+ DBusMessage *pending;
+ guint timeout;
+};
+
+static void append_path(gpointer value, gpointer user_data)
+{
+ struct connman_service *service = value;
+ DBusMessageIter *iter = user_data;
+
+ if (service->path == NULL)
+ return;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
+ &service->path);
+}
+
+void __connman_service_list(DBusMessageIter *iter)
+{
+ DBG("");
+
+ g_sequence_foreach(service_list, append_path, iter);
+}
+
+struct find_data {
+ const char *path;
+ struct connman_service *service;
+};
+
+static void compare_path(gpointer value, gpointer user_data)
+{
+ struct connman_service *service = value;
+ struct find_data *data = user_data;
+
+ if (data->service != NULL)
+ return;
+
+ if (g_strcmp0(service->path, data->path) == 0)
+ data->service = service;
+}
+
+static struct connman_service *find_service(const char *path)
+{
+ struct find_data data = { .path = path, .service = NULL };
+
+ DBG("path %s", path);
+
+ g_sequence_foreach(service_list, compare_path, &data);
+
+ return data.service;
+}
+
+static const char *type2string(enum connman_service_type type)
+{
+ switch (type) {
+ case CONNMAN_SERVICE_TYPE_UNKNOWN:
+ break;
+ case CONNMAN_SERVICE_TYPE_ETHERNET:
+ return "ethernet";
+ case CONNMAN_SERVICE_TYPE_WIFI:
+ return "wifi";
+ case CONNMAN_SERVICE_TYPE_WIMAX:
+ return "wimax";
+ }
+
+ return NULL;
+}
+
+static const char *mode2string(enum connman_service_mode mode)
+{
+ switch (mode) {
+ case CONNMAN_SERVICE_MODE_UNKNOWN:
+ break;
+ case CONNMAN_SERVICE_MODE_MANAGED:
+ return "managed";
+ case CONNMAN_SERVICE_MODE_ADHOC:
+ return "adhoc";
+ }
+
+ return NULL;
+}
+
+static const char *security2string(enum connman_service_security security)
+{
+ switch (security) {
+ case CONNMAN_SERVICE_SECURITY_UNKNOWN:
+ break;
+ case CONNMAN_SERVICE_SECURITY_NONE:
+ return "none";
+ case CONNMAN_SERVICE_SECURITY_WEP:
+ return "wep";
+ case CONNMAN_SERVICE_SECURITY_WPA:
+ return "wpa";
+ case CONNMAN_SERVICE_SECURITY_RSN:
+ return "rsn";
+ }
+
+ return NULL;
+}
+
+static const char *state2string(enum connman_service_state state)
+{
+ switch (state) {
+ case CONNMAN_SERVICE_STATE_UNKNOWN:
+ break;
+ case CONNMAN_SERVICE_STATE_IDLE:
+ return "idle";
+ case CONNMAN_SERVICE_STATE_CARRIER:
+ return "carrier";
+ case CONNMAN_SERVICE_STATE_ASSOCIATION:
+ return "association";
+ case CONNMAN_SERVICE_STATE_CONFIGURATION:
+ return "configuration";
+ case CONNMAN_SERVICE_STATE_READY:
+ return "ready";
+ case CONNMAN_SERVICE_STATE_DISCONNECT:
+ return "disconnect";
+ case CONNMAN_SERVICE_STATE_FAILURE:
+ return "failure";
+ }
+
+ return NULL;
+}
+
+static void state_changed(struct connman_service *service)
+{
+ DBusMessage *signal;
+ DBusMessageIter entry, value;
+ const char *str, *key = "State";
+
+ if (service->path == NULL)
+ return;
+
+ str = state2string(service->state);
+ if (str == NULL)
+ return;
+
+ signal = dbus_message_new_signal(service->path,
+ CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
+ if (signal == NULL)
+ return;
+
+ dbus_message_iter_init_append(signal, &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);
+
+ g_dbus_send_message(connection, signal);
+}
+
+static void strength_changed(struct connman_service *service)
+{
+ DBusMessage *signal;
+ DBusMessageIter entry, value;
+ const char *key = "Strength";
+
+ if (service->path == NULL)
+ return;
+
+ if (service->strength == 0)
+ return;
+
+ signal = dbus_message_new_signal(service->path,
+ CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
+ if (signal == NULL)
+ return;
+
+ dbus_message_iter_init_append(signal, &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_BYTE_AS_STRING, &value);
+ dbus_message_iter_append_basic(&value, DBUS_TYPE_BYTE,
+ &service->strength);
+ dbus_message_iter_close_container(&entry, &value);
+
+ g_dbus_send_message(connection, signal);
+}
+
+static DBusMessage *get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct connman_service *service = user_data;
+ DBusMessage *reply;
+ DBusMessageIter array, dict;
+ const char *str;
+
+ DBG("service %p", service);
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &array);
+
+ dbus_message_iter_open_container(&array, 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);
+
+ str = type2string(service->type);
+ if (str != NULL)
+ connman_dbus_dict_append_variant(&dict, "Type",
+ DBUS_TYPE_STRING, &str);
+
+ str = mode2string(service->mode);
+ if (str != NULL)
+ connman_dbus_dict_append_variant(&dict, "Mode",
+ DBUS_TYPE_STRING, &str);
+
+ str = security2string(service->security);
+ if (str != NULL)
+ connman_dbus_dict_append_variant(&dict, "Security",
+ DBUS_TYPE_STRING, &str);
+
+ str = state2string(service->state);
+ if (str != NULL)
+ connman_dbus_dict_append_variant(&dict, "State",
+ DBUS_TYPE_STRING, &str);
+
+ if (service->strength > 0)
+ connman_dbus_dict_append_variant(&dict, "Strength",
+ DBUS_TYPE_BYTE, &service->strength);
+
+ connman_dbus_dict_append_variant(&dict, "Favorite",
+ DBUS_TYPE_BOOLEAN, &service->favorite);
+
+ if (service->name != NULL)
+ connman_dbus_dict_append_variant(&dict, "Name",
+ DBUS_TYPE_STRING, &service->name);
+
+ if (service->passphrase != NULL &&
+ __connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_SECRET) == 0)
+ connman_dbus_dict_append_variant(&dict, "Passphrase",
+ DBUS_TYPE_STRING, &service->passphrase);
+
+ dbus_message_iter_close_container(&array, &dict);
+
+ return reply;
+}
+
+static DBusMessage *set_property(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct connman_service *service = user_data;
+ DBusMessageIter iter, value;
+ const char *name;
+ int type;
+
+ DBG("service %p", service);
+
+ if (dbus_message_iter_init(msg, &iter) == FALSE)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&iter, &name);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &value);
+
+ if (__connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
+ return __connman_error_permission_denied(msg);
+
+ type = dbus_message_iter_get_arg_type(&value);
+
+ if (g_str_equal(name, "Passphrase") == TRUE) {
+ const char *passphrase;
+
+ if (type != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
+ if (__connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_SECRET) < 0)
+ return __connman_error_permission_denied(msg);
+
+ dbus_message_iter_get_basic(&value, &passphrase);
+
+ g_free(service->passphrase);
+ service->passphrase = g_strdup(passphrase);
+
+ if (service->network != NULL)
+ connman_network_set_string(service->network,
+ "WiFi.Passphrase", service->passphrase);
+
+ __connman_storage_save_service(service);
+ }
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static gboolean connect_timeout(gpointer user_data)
+{
+ struct connman_service *service = user_data;
+
+ DBG("service %p", service);
+
+ service->timeout = 0;
+
+ if (service->network != NULL)
+ __connman_network_disconnect(service->network);
+
+ if (service->pending != NULL) {
+ DBusMessage *reply;
+
+ reply = __connman_error_operation_timeout(service->pending);
+ if (reply != NULL)
+ g_dbus_send_message(connection, reply);
+
+ dbus_message_unref(service->pending);
+ service->pending = NULL;
+
+ __connman_service_indicate_state(service,
+ CONNMAN_SERVICE_STATE_FAILURE);
+ }
+
+ return FALSE;
+}
+
+static DBusMessage *connect_service(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct connman_service *service = user_data;
+
+ DBG("service %p", service);
+
+ if (service->pending != NULL)
+ return __connman_error_in_progress(msg);
+
+ if (service->state == CONNMAN_SERVICE_STATE_READY)
+ return __connman_error_already_connected(msg);
+
+ if (service->network != NULL) {
+ int err;
+
+ if (service->hidden == TRUE)
+ return __connman_error_invalid_service(msg);
+
+ connman_network_set_string(service->network,
+ "WiFi.Passphrase", service->passphrase);
+
+ err = __connman_network_connect(service->network);
+ if (err < 0 && err != -EINPROGRESS)
+ return __connman_error_failed(msg, -err);
+
+ service->pending = dbus_message_ref(msg);
+
+ service->timeout = g_timeout_add_seconds(45,
+ connect_timeout, service);
+
+ return NULL;
+ } else if (service->device != NULL) {
+ if (service->favorite == FALSE)
+ return __connman_error_no_carrier(msg);
+
+ if (__connman_device_connect(service->device) < 0)
+ return __connman_error_failed(msg, EINVAL);
+
+ service->pending = dbus_message_ref(msg);
+ service->timeout = g_timeout_add_seconds(15,
+ connect_timeout, service);
+
+ return NULL;
+ }
+
+ return __connman_error_not_supported(msg);
+}
+
+static DBusMessage *disconnect_service(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct connman_service *service = user_data;
+
+ DBG("service %p", service);
+
+ if (service->pending != NULL) {
+ DBusMessage *reply;
+
+ reply = __connman_error_operation_aborted(service->pending);
+ if (reply != NULL)
+ g_dbus_send_message(conn, reply);
+
+ dbus_message_unref(service->pending);
+ service->pending = NULL;
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ }
+
+ if (service->network != NULL) {
+ int err;
+
+ err = __connman_network_disconnect(service->network);
+ if (err < 0 && err != -EINPROGRESS)
+ return __connman_error_failed(msg, -err);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ } else if (service->device != NULL) {
+ int err;
+
+ if (service->favorite == FALSE)
+ return __connman_error_no_carrier(msg);
+
+ err = __connman_device_disconnect(service->device);
+ if (err < 0)
+ return __connman_error_failed(msg, -err);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ }
+
+ return __connman_error_not_supported(msg);
+}
+
+static DBusMessage *remove_service(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct connman_service *service = user_data;
+
+ DBG("service %p", service);
+
+ if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
+ return __connman_error_not_supported(msg);
+
+ if (service->favorite == FALSE)
+ return __connman_error_not_supported(msg);
+
+ if (service->network != NULL)
+ __connman_network_disconnect(service->network);
+
+ connman_service_set_favorite(service, FALSE);
+ __connman_storage_save_service(service);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *move_before(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct connman_service *service = user_data;
+ struct connman_service *target;
+ const char *path;
+ GSequenceIter *src, *dst;
+
+ DBG("service %p", service);
+
+ dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+
+ if (service->favorite == FALSE)
+ return __connman_error_not_supported(msg);
+
+ target = find_service(path);
+ if (target == NULL || target->favorite == FALSE || target == service)
+ return __connman_error_invalid_service(msg);
+
+ DBG("target %s", target->identifier);
+
+ g_get_current_time(&service->modified);
+ __connman_storage_save_service(service);
+
+ src = g_hash_table_lookup(service_hash, service->identifier);
+ dst = g_hash_table_lookup(service_hash, target->identifier);
+
+#if 0
+ g_sequence_move(src, dst);
+
+ __connman_profile_changed();
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+#endif
+ return __connman_error_not_implemented(msg);
+}
+
+static DBusMessage *move_after(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct connman_service *service = user_data;
+ struct connman_service *target;
+ const char *path;
+
+ DBG("service %p", service);
+
+ dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+
+ if (service->favorite == FALSE)
+ return __connman_error_not_supported(msg);
+
+ target = find_service(path);
+ if (target == NULL || target->favorite == FALSE || target == service)
+ return __connman_error_invalid_service(msg);
+
+ DBG("target %s", target->identifier);
+
+ g_get_current_time(&service->modified);
+ __connman_storage_save_service(service);
+
+ return __connman_error_not_implemented(msg);
+}
+
+static GDBusMethodTable service_methods[] = {
+ { "GetProperties", "", "a{sv}", get_properties },
+ { "SetProperty", "sv", "", set_property },
+ { "Connect", "", "", connect_service,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "Disconnect", "", "", disconnect_service },
+ { "Remove", "", "", remove_service },
+ { "MoveBefore", "o", "", move_before },
+ { "MoveAfter", "o", "", move_after },
+ { },
+};
+
+static GDBusSignalTable service_signals[] = {
+ { "PropertyChanged", "sv" },
+ { },
+};
+
+static void service_free(gpointer user_data)
+{
+ struct connman_service *service = user_data;
+ char *path = service->path;
+
+ DBG("service %p", service);
+
+ g_hash_table_remove(service_hash, service->identifier);
+
+ if (service->timeout > 0)
+ g_source_remove(service->timeout);
+
+ if (service->pending != NULL) {
+ dbus_message_unref(service->pending);
+ service->pending = NULL;
+ }
+
+ service->path = NULL;
+
+ if (path != NULL) {
+ __connman_profile_changed();
+
+ g_dbus_unregister_interface(connection, path,
+ CONNMAN_SERVICE_INTERFACE);
+ g_free(path);
+ }
+
+ if (service->network != NULL)
+ connman_network_unref(service->network);
+
+ g_free(service->profile);
+ g_free(service->name);
+ g_free(service->passphrase);
+ g_free(service->identifier);
+ g_free(service);
+}
+
+/**
+ * __connman_service_put:
+ * @service: service structure
+ *
+ * Release service if no longer needed
+ */
+void __connman_service_put(struct connman_service *service)
+{
+ DBG("service %p", service);
+
+ if (g_atomic_int_dec_and_test(&service->refcount) == TRUE) {
+ GSequenceIter *iter;
+
+ iter = g_hash_table_lookup(service_hash, service->identifier);
+ if (iter != NULL)
+ g_sequence_remove(iter);
+ else
+ service_free(service);
+ }
+}
+
+static void __connman_service_initialize(struct connman_service *service)
+{
+ DBG("service %p", service);
+
+ service->refcount = 1;
+
+ service->type = CONNMAN_SERVICE_TYPE_UNKNOWN;
+ service->mode = CONNMAN_SERVICE_MODE_UNKNOWN;
+ service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
+ service->state = CONNMAN_SERVICE_STATE_UNKNOWN;
+
+ service->favorite = FALSE;
+ service->hidden = FALSE;
+
+ service->order = 0;
+}
+
+/**
+ * connman_service_create:
+ *
+ * Allocate a new service.
+ *
+ * Returns: a newly-allocated #connman_service structure
+ */
+struct connman_service *connman_service_create(void)
+{
+ struct connman_service *service;
+
+ service = g_try_new0(struct connman_service, 1);
+ if (service == NULL)
+ return NULL;
+
+ DBG("service %p", service);
+
+ __connman_service_initialize(service);
+
+ return service;
+}
+
+/**
+ * connman_service_ref:
+ * @service: service structure
+ *
+ * Increase reference counter of service
+ */
+struct connman_service *connman_service_ref(struct connman_service *service)
+{
+ g_atomic_int_inc(&service->refcount);
+
+ return service;
+}
+
+/**
+ * connman_service_unref:
+ * @service: service structure
+ *
+ * Decrease reference counter of service
+ */
+void connman_service_unref(struct connman_service *service)
+{
+ __connman_service_put(service);
+}
+
+static gint service_compare(gconstpointer a, gconstpointer b,
+ gpointer user_data)
+{
+ struct connman_service *service_a = (void *) a;
+ struct connman_service *service_b = (void *) b;
+
+ if (service_a->state != service_b->state) {
+ if (service_a->state == CONNMAN_SERVICE_STATE_READY)
+ return -1;
+ if (service_b->state == CONNMAN_SERVICE_STATE_READY)
+ return 1;
+ }
+
+ if (service_a->order > service_b->order)
+ return -1;
+
+ if (service_a->order < service_b->order)
+ return 1;
+
+ if (service_a->favorite == TRUE && service_b->favorite == FALSE)
+ return -1;
+
+ if (service_a->favorite == FALSE && service_b->favorite == TRUE)
+ return 1;
+
+ return (gint) service_b->strength - (gint) service_a->strength;
+}
+
+/**
+ * connman_service_set_favorite:
+ * @service: service structure
+ * @favorite: favorite value
+ *
+ * Change the favorite setting of service
+ */
+int connman_service_set_favorite(struct connman_service *service,
+ connman_bool_t favorite)
+{
+ GSequenceIter *iter;
+
+ iter = g_hash_table_lookup(service_hash, service->identifier);
+ if (iter == NULL)
+ return -ENOENT;
+
+ if (service->favorite == favorite)
+ return -EALREADY;
+
+ service->favorite = favorite;
+
+ g_sequence_sort_changed(iter, service_compare, NULL);
+
+ __connman_profile_changed();
+
+ return 0;
+}
+
+int __connman_service_set_carrier(struct connman_service *service,
+ connman_bool_t carrier)
+{
+ DBG("service %p carrier %d", service, carrier);
+
+ if (service == NULL)
+ return -EINVAL;
+
+ switch (service->type) {
+ case CONNMAN_SERVICE_TYPE_UNKNOWN:
+ case CONNMAN_SERVICE_TYPE_WIFI:
+ case CONNMAN_SERVICE_TYPE_WIMAX:
+ return -EINVAL;
+ case CONNMAN_SERVICE_TYPE_ETHERNET:
+ break;
+ }
+
+ if (carrier == FALSE) {
+ service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
+ state_changed(service);
+
+ service->state = CONNMAN_SERVICE_STATE_IDLE;
+ state_changed(service);
+ } else {
+ service->state = CONNMAN_SERVICE_STATE_CARRIER;
+ state_changed(service);
+ }
+
+ return connman_service_set_favorite(service, carrier);
+}
+
+int __connman_service_indicate_state(struct connman_service *service,
+ enum connman_service_state state)
+{
+ GSequenceIter *iter;
+
+ DBG("service %p state %d", service, state);
+
+ if (service == NULL)
+ return -EINVAL;
+
+ if (state == CONNMAN_SERVICE_STATE_CARRIER)
+ return __connman_service_set_carrier(service, TRUE);
+
+ if (service->state == state)
+ return -EALREADY;
+
+ if (service->state == CONNMAN_SERVICE_STATE_IDLE &&
+ state == CONNMAN_SERVICE_STATE_DISCONNECT)
+ return -EINVAL;
+
+ if (state == CONNMAN_SERVICE_STATE_IDLE &&
+ service->state != CONNMAN_SERVICE_STATE_DISCONNECT) {
+ service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
+ state_changed(service);
+ }
+
+ service->state = state;
+ state_changed(service);
+
+ if (state == CONNMAN_SERVICE_STATE_READY) {
+ connman_service_set_favorite(service, TRUE);
+ __connman_storage_save_service(service);
+
+ if (service->timeout > 0)
+ g_source_remove(service->timeout);
+
+ if (service->pending != NULL) {
+ g_dbus_send_reply(connection, service->pending,
+ DBUS_TYPE_INVALID);
+
+ dbus_message_unref(service->pending);
+ service->pending = NULL;
+ }
+
+ g_get_current_time(&service->modified);
+ __connman_storage_save_service(service);
+ }
+
+ if (state == CONNMAN_SERVICE_STATE_FAILURE) {
+ if (service->timeout > 0)
+ g_source_remove(service->timeout);
+
+ if (service->pending != NULL) {
+ DBusMessage *reply;
+
+ reply = __connman_error_failed(service->pending, EIO);
+ if (reply != NULL)
+ g_dbus_send_message(connection, reply);
+
+ dbus_message_unref(service->pending);
+ service->pending = NULL;
+ }
+
+ service->state = CONNMAN_SERVICE_STATE_IDLE;
+ state_changed(service);
+ }
+
+ iter = g_hash_table_lookup(service_hash, service->identifier);
+ if (iter != NULL)
+ g_sequence_sort_changed(iter, service_compare, NULL);
+
+ __connman_profile_changed();
+
+ return 0;
+}
+
+int __connman_service_indicate_default(struct connman_service *service)
+{
+ DBG("service %p", service);
+
+ return 0;
+}
+
+/**
+ * __connman_service_lookup:
+ * @identifier: service identifier
+ *
+ * Look up a service by identifier (reference count will not be increased)
+ */
+static struct connman_service *__connman_service_lookup(const char *identifier)
+{
+ GSequenceIter *iter;
+
+ iter = g_hash_table_lookup(service_hash, identifier);
+ if (iter != NULL)
+ return g_sequence_get(iter);
+
+ return NULL;
+}
+
+/**
+ * __connman_service_get:
+ * @identifier: service identifier
+ *
+ * Look up a service by identifier or create a new one if not found
+ */
+static struct connman_service *__connman_service_get(const char *identifier)
+{
+ struct connman_service *service;
+ GSequenceIter *iter;
+
+ iter = g_hash_table_lookup(service_hash, identifier);
+ if (iter != NULL) {
+ service = g_sequence_get(iter);
+ if (service != NULL)
+ g_atomic_int_inc(&service->refcount);
+ return service;
+ }
+
+ service = g_try_new0(struct connman_service, 1);
+ if (service == NULL)
+ return NULL;
+
+ DBG("service %p", service);
+
+ __connman_service_initialize(service);
+
+ service->identifier = g_strdup(identifier);
+
+ service->profile = g_strdup(__connman_profile_active_ident());
+
+ __connman_storage_load_service(service);
+
+ iter = g_sequence_insert_sorted(service_list, service,
+ service_compare, NULL);
+
+ g_hash_table_insert(service_hash, service->identifier, iter);
+
+ return service;
+}
+
+static int service_register(struct connman_service *service)
+{
+ const char *path = __connman_profile_active_path();
+ GSequenceIter *iter;
+
+ DBG("service %p", service);
+
+ if (service->path != NULL)
+ return -EALREADY;
+
+ service->path = g_strdup_printf("%s/%s", path, service->identifier);
+
+ DBG("path %s", service->path);
+
+ g_dbus_register_interface(connection, service->path,
+ CONNMAN_SERVICE_INTERFACE,
+ service_methods, service_signals,
+ NULL, service, NULL);
+
+ __connman_storage_load_service(service);
+
+ iter = g_hash_table_lookup(service_hash, service->identifier);
+ if (iter != NULL)
+ g_sequence_sort_changed(iter, service_compare, NULL);
+
+ __connman_profile_changed();
+
+ return 0;
+}
+
+/**
+ * connman_service_lookup_from_device:
+ * @device: device structure
+ *
+ * Look up a service by device (reference count will not be increased)
+ */
+struct connman_service *__connman_service_lookup_from_device(struct connman_device *device)
+{
+ struct connman_service *service;
+ const char *ident;
+ char *name;
+
+ ident = __connman_device_get_ident(device);
+ if (ident == NULL)
+ return NULL;
+
+ name = g_strdup_printf("%s_%s",
+ __connman_device_get_type(device), ident);
+
+ service = __connman_service_lookup(name);
+
+ g_free(name);
+
+ return service;
+}
+
+static enum connman_service_type convert_device_type(struct connman_device *device)
+{
+ enum connman_device_type type = connman_device_get_type(device);
+
+ switch (type) {
+ case CONNMAN_DEVICE_TYPE_UNKNOWN:
+ case CONNMAN_DEVICE_TYPE_VENDOR:
+ case CONNMAN_DEVICE_TYPE_WIFI:
+ case CONNMAN_DEVICE_TYPE_WIMAX:
+ case CONNMAN_DEVICE_TYPE_BLUETOOTH:
+ case CONNMAN_DEVICE_TYPE_GPS:
+ case CONNMAN_DEVICE_TYPE_HSO:
+ case CONNMAN_DEVICE_TYPE_NOZOMI:
+ case CONNMAN_DEVICE_TYPE_HUAWEI:
+ case CONNMAN_DEVICE_TYPE_NOVATEL:
+ break;
+ case CONNMAN_DEVICE_TYPE_ETHERNET:
+ return CONNMAN_SERVICE_TYPE_ETHERNET;
+ }
+
+ return CONNMAN_SERVICE_TYPE_UNKNOWN;
+}
+
+/**
+ * connman_service_create_from_device:
+ * @device: device structure
+ *
+ * Look up service by device and if not found, create one
+ */
+struct connman_service *__connman_service_create_from_device(struct connman_device *device)
+{
+ struct connman_service *service;
+ const char *ident;
+ char *name;
+
+ ident = __connman_device_get_ident(device);
+ if (ident == NULL)
+ return NULL;
+
+ name = g_strdup_printf("%s_%s",
+ __connman_device_get_type(device), ident);
+
+ service = __connman_service_get(name);
+ if (service == NULL)
+ goto done;
+
+ if (service->path != NULL) {
+ __connman_service_put(service);
+ service = NULL;
+ goto done;
+ }
+
+ service->type = convert_device_type(device);
+
+ service->device = device;
+
+ service_register(service);
+
+done:
+ g_free(name);
+
+ return service;
+}
+
+/**
+ * connman_service_lookup_from_network:
+ * @network: network structure
+ *
+ * Look up a service by network (reference count will not be increased)
+ */
+struct connman_service *__connman_service_lookup_from_network(struct connman_network *network)
+{
+ struct connman_service *service;
+ const char *ident, *group;
+ char *name;
+
+ ident = __connman_network_get_ident(network);
+ if (ident == NULL)
+ return NULL;
+
+ group = __connman_network_get_group(network);
+ if (group == NULL)
+ return NULL;
+
+ name = g_strdup_printf("%s_%s_%s",
+ __connman_network_get_type(network), ident, group);
+
+ service = __connman_service_lookup(name);
+
+ g_free(name);
+
+ return service;
+}
+
+static enum connman_service_type convert_network_type(struct connman_network *network)
+{
+ enum connman_network_type type = connman_network_get_type(network);
+
+ switch (type) {
+ case CONNMAN_NETWORK_TYPE_UNKNOWN:
+ case CONNMAN_NETWORK_TYPE_VENDOR:
+ case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
+ case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
+ case CONNMAN_NETWORK_TYPE_HSO:
+ break;
+ case CONNMAN_NETWORK_TYPE_WIFI:
+ return CONNMAN_SERVICE_TYPE_WIFI;
+ case CONNMAN_NETWORK_TYPE_WIMAX:
+ return CONNMAN_SERVICE_TYPE_WIMAX;
+ }
+
+ return CONNMAN_SERVICE_TYPE_UNKNOWN;
+}
+
+static enum connman_service_mode convert_wifi_mode(const char *mode)
+{
+ if (mode == NULL)
+ return CONNMAN_SERVICE_MODE_UNKNOWN;
+ else if (g_str_equal(mode, "managed") == TRUE)
+ return CONNMAN_SERVICE_MODE_MANAGED;
+ else if (g_str_equal(mode, "adhoc") == TRUE)
+ return CONNMAN_SERVICE_MODE_ADHOC;
+ else
+ return CONNMAN_SERVICE_MODE_UNKNOWN;
+}
+
+static enum connman_service_mode convert_wifi_security(const char *security)
+{
+ if (security == NULL)
+ return CONNMAN_SERVICE_SECURITY_UNKNOWN;
+ else if (g_str_equal(security, "none") == TRUE)
+ return CONNMAN_SERVICE_SECURITY_NONE;
+ else if (g_str_equal(security, "wep") == TRUE)
+ return CONNMAN_SERVICE_SECURITY_WEP;
+ else if (g_str_equal(security, "wpa") == TRUE)
+ return CONNMAN_SERVICE_SECURITY_WPA;
+ else if (g_str_equal(security, "rsn") == TRUE)
+ return CONNMAN_SERVICE_SECURITY_RSN;
+ else
+ return CONNMAN_SERVICE_SECURITY_UNKNOWN;
+}
+
+static void update_from_network(struct connman_service *service,
+ struct connman_network *network)
+{
+ connman_uint8_t strength = service->strength;
+ GSequenceIter *iter;
+ const char *str;
+
+ str = connman_network_get_string(network, "Name");
+ if (str != NULL) {
+ g_free(service->name);
+ service->name = g_strdup(str);
+ service->hidden = FALSE;
+ } else {
+ g_free(service->name);
+ service->name = NULL;
+ service->hidden = TRUE;
+ }
+
+ service->strength = connman_network_get_uint8(network, "Strength");
+
+ str = connman_network_get_string(network, "WiFi.Mode");
+ service->mode = convert_wifi_mode(str);
+
+ str = connman_network_get_string(network, "WiFi.Security");
+ service->security = convert_wifi_security(str);
+
+ if (service->strength > strength && service->network != NULL) {
+ connman_network_unref(service->network);
+ service->network = NULL;
+
+ strength_changed(service);
+ }
+
+ if (service->network == NULL) {
+ service->network = connman_network_ref(network);
+
+ str = connman_network_get_string(network, "WiFi.Passphrase");
+ if (str != NULL) {
+ g_free(service->passphrase);
+ service->passphrase = g_strdup(str);
+ }
+ }
+
+ iter = g_hash_table_lookup(service_hash, service->identifier);
+ if (iter != NULL)
+ g_sequence_sort_changed(iter, service_compare, NULL);
+}
+
+/**
+ * connman_service_create_from_network:
+ * @network: network structure
+ *
+ * Look up service by network and if not found, create one
+ */
+struct connman_service *__connman_service_create_from_network(struct connman_network *network)
+{
+ struct connman_service *service;
+ const char *ident, *group;
+ char *name;
+
+ ident = __connman_network_get_ident(network);
+ if (ident == NULL)
+ return NULL;
+
+ group = __connman_network_get_group(network);
+ if (group == NULL)
+ return NULL;
+
+ name = g_strdup_printf("%s_%s_%s",
+ __connman_network_get_type(network), ident, group);
+
+ service = __connman_service_get(name);
+ if (service == NULL)
+ goto done;
+
+ if (service->path != NULL) {
+ update_from_network(service, network);
+
+ __connman_profile_changed();
+
+ __connman_service_put(service);
+ service = NULL;
+ goto done;
+ }
+
+ service->type = convert_network_type(network);
+
+ service->state = CONNMAN_SERVICE_STATE_IDLE;
+
+ update_from_network(service, network);
+
+ service_register(service);
+
+done:
+ g_free(name);
+
+ return service;
+}
+
+static int service_load(struct connman_service *service)
+{
+ GKeyFile *keyfile;
+ gchar *pathname, *data = NULL;
+ gsize length;
+ gchar *str;
+
+ DBG("service %p", service);
+
+ if (service->profile == NULL)
+ return -EINVAL;
+
+ pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, service->profile);
+ if (pathname == NULL)
+ return -ENOMEM;
+
+ keyfile = g_key_file_new();
+
+ if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
+ g_free(pathname);
+ return -ENOENT;
+ }
+
+ g_free(pathname);
+
+ if (g_key_file_load_from_data(keyfile, data, length,
+ 0, NULL) == FALSE) {
+ g_free(data);
+ return -EILSEQ;
+ }
+
+ g_free(data);
+
+ switch (service->type) {
+ case CONNMAN_SERVICE_TYPE_UNKNOWN:
+ case CONNMAN_SERVICE_TYPE_ETHERNET:
+ break;
+ case CONNMAN_SERVICE_TYPE_WIFI:
+ case CONNMAN_SERVICE_TYPE_WIMAX:
+ service->favorite = g_key_file_get_boolean(keyfile,
+ service->identifier, "Favorite", NULL);
+ break;
+ }
+
+ str = g_key_file_get_string(keyfile,
+ service->identifier, "Modified", NULL);
+ if (str != NULL) {
+ g_time_val_from_iso8601(str, &service->modified);
+ g_free(str);
+ }
+
+ str = g_key_file_get_string(keyfile,
+ service->identifier, "Passphrase", NULL);
+ if (str != NULL) {
+ g_free(service->passphrase);
+ service->passphrase = str;
+ }
+
+ g_key_file_free(keyfile);
+
+ return 0;
+}
+
+static int service_save(struct connman_service *service)
+{
+ GKeyFile *keyfile;
+ gchar *pathname, *data = NULL;
+ gsize length;
+ gchar *str;
+
+ DBG("service %p", service);
+
+ if (service->profile == NULL)
+ return -EINVAL;
+
+ pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, service->profile);
+ if (pathname == NULL)
+ return -ENOMEM;
+
+ keyfile = g_key_file_new();
+
+ if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
+ goto update;
+
+ if (length > 0) {
+ if (g_key_file_load_from_data(keyfile, data, length,
+ 0, NULL) == FALSE)
+ goto done;
+ }
+
+ g_free(data);
+
+update:
+ if (service->name != NULL)
+ g_key_file_set_string(keyfile, service->identifier,
+ "Name", service->name);
+
+ switch (service->type) {
+ case CONNMAN_SERVICE_TYPE_UNKNOWN:
+ case CONNMAN_SERVICE_TYPE_ETHERNET:
+ break;
+ case CONNMAN_SERVICE_TYPE_WIFI:
+ case CONNMAN_SERVICE_TYPE_WIMAX:
+ g_key_file_set_boolean(keyfile, service->identifier,
+ "Favorite", service->favorite);
+ break;
+ }
+
+ str = g_time_val_to_iso8601(&service->modified);
+ if (str != NULL) {
+ g_key_file_set_string(keyfile, service->identifier,
+ "Modified", str);
+ g_free(str);
+ }
+
+ if (service->passphrase != NULL)
+ g_key_file_set_string(keyfile, service->identifier,
+ "Passphrase", service->passphrase);
+
+ data = g_key_file_to_data(keyfile, &length, NULL);
+
+ if (g_file_set_contents(pathname, data, length, NULL) == FALSE)
+ connman_error("Failed to store service information");
+
+done:
+ g_free(data);
+
+ g_key_file_free(keyfile);
+
+ g_free(pathname);
+
+ return 0;
+}
+
+static struct connman_storage service_storage = {
+ .name = "service",
+ .priority = CONNMAN_STORAGE_PRIORITY_LOW,
+ .service_load = service_load,
+ .service_save = service_save,
+};
+
+int __connman_service_init(void)
+{
+ DBG("");
+
+ connection = connman_dbus_get_connection();
+
+ if (connman_storage_register(&service_storage) < 0)
+ connman_error("Failed to register service storage");
+
+ service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, NULL);
+
+ service_list = g_sequence_new(service_free);
+
+ return 0;
+}
+
+void __connman_service_cleanup(void)
+{
+ DBG("");
+
+ g_sequence_free(service_list);
+ service_list = NULL;
+
+ g_hash_table_destroy(service_hash);
+ service_hash = NULL;
+
+ connman_storage_unregister(&service_storage);
+
+ dbus_connection_unref(connection);
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 "connman.h"
+
+static GSList *storage_list = NULL;
+
+static gint compare_priority(gconstpointer a, gconstpointer b)
+{
+ const struct connman_storage *storage1 = a;
+ const struct connman_storage *storage2 = b;
+
+ return storage2->priority - storage1->priority;
+}
+
+/**
+ * connman_storage_register:
+ * @storage: storage module
+ *
+ * Register a new storage module
+ *
+ * Returns: %0 on success
+ */
+int connman_storage_register(struct connman_storage *storage)
+{
+ DBG("storage %p name %s", storage, storage->name);
+
+ storage_list = g_slist_insert_sorted(storage_list, storage,
+ compare_priority);
+
+ return 0;
+}
+
+/**
+ * connman_storage_unregister:
+ * @storage: storage module
+ *
+ * Remove a previously registered storage module
+ */
+void connman_storage_unregister(struct connman_storage *storage)
+{
+ DBG("storage %p name %s", storage, storage->name);
+
+ storage_list = g_slist_remove(storage_list, storage);
+}
+
+int __connman_storage_init_device(void)
+{
+ GSList *list;
+
+ DBG("");
+
+ for (list = storage_list; list; list = list->next) {
+ struct connman_storage *storage = list->data;
+
+ if (storage->device_init) {
+ if (storage->device_init() == 0)
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+int __connman_storage_load_device(struct connman_device *device)
+{
+ GSList *list;
+
+ DBG("device %p", device);
+
+ for (list = storage_list; list; list = list->next) {
+ struct connman_storage *storage = list->data;
+
+ if (storage->device_load) {
+ if (storage->device_load(device) == 0)
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+int __connman_storage_save_device(struct connman_device *device)
+{
+ GSList *list;
+
+ DBG("device %p", device);
+
+ for (list = storage_list; list; list = list->next) {
+ struct connman_storage *storage = list->data;
+
+ if (storage->device_save) {
+ if (storage->device_save(device) == 0)
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+int __connman_storage_init_network(struct connman_device *device)
+{
+ GSList *list;
+
+ DBG("device %p", device);
+
+ for (list = storage_list; list; list = list->next) {
+ struct connman_storage *storage = list->data;
+
+ if (storage->network_init) {
+ if (storage->network_init(device) == 0)
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+int __connman_storage_load_network(struct connman_network *network)
+{
+ GSList *list;
+
+ DBG("network %p", network);
+
+ for (list = storage_list; list; list = list->next) {
+ struct connman_storage *storage = list->data;
+
+ if (storage->network_load) {
+ if (storage->network_load(network) == 0)
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+int __connman_storage_save_network(struct connman_network *network)
+{
+ GSList *list;
+
+ DBG("network %p", network);
+
+ for (list = storage_list; list; list = list->next) {
+ struct connman_storage *storage = list->data;
+
+ if (storage->network_save) {
+ if (storage->network_save(network) == 0)
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+int __connman_storage_init_service(void)
+{
+ DBG("");
+
+ return -ENOENT;
+}
+
+int __connman_storage_load_service(struct connman_service *service)
+{
+ GSList *list;
+
+ DBG("service %p", service);
+
+ for (list = storage_list; list; list = list->next) {
+ struct connman_storage *storage = list->data;
+
+ if (storage->service_load) {
+ if (storage->service_load(service) == 0)
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+int __connman_storage_save_service(struct connman_service *service)
+{
+ GSList *list;
+
+ DBG("service %p", service);
+
+ for (list = storage_list; list; list = list->next) {
+ struct connman_storage *storage = list->data;
+
+ if (storage->service_save) {
+ if (storage->service_save(service) == 0)
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+int __connman_storage_init(void)
+{
+ DBG("");
+
+ return 0;
+}
+
+void __connman_storage_cleanup(void)
+{
+ DBG("");
+}
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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 <sys/types.h>
+
+#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
+#include <libudev.h>
+
+#include <glib.h>
+
+#include "connman.h"
+
+#ifdef NEED_UDEV_ENUMERATE_ADD_MATCH_PROPERTY
+static int udev_enumerate_add_match_property(struct udev_enumerate *enumerate,
+ const char *property, const char *value)
+{
+ return -EINVAL;
+}
+#endif
+
+#ifdef NEED_UDEV_DEVICE_GET_PARENT_WITH_SUBSYSTEM_DEVTYPE
+static struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *device,
+ const char *subsystem, const char *devtype)
+{
+ return NULL;
+}
+#endif
+
+static GSList *device_list = NULL;
+
+static struct connman_device *find_device(const char *interface)
+{
+ GSList *list;
+
+ if (interface == NULL)
+ return NULL;
+
+ for (list = device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+ const char *device_interface;
+
+ device_interface = connman_device_get_interface(device);
+ if (device_interface == NULL)
+ continue;
+
+ if (g_str_equal(device_interface, interface) == TRUE)
+ return device;
+ }
+
+ return NULL;
+}
+
+static void add_device(struct udev_device *udev_device)
+{
+ enum connman_device_type devtype = CONNMAN_DEVICE_TYPE_UNKNOWN;
+ struct connman_device *device;
+ struct udev_list_entry *entry;
+ const char *type = NULL, *interface = NULL;
+
+ DBG("");
+
+ entry = udev_device_get_properties_list_entry(udev_device);
+ while (entry) {
+ const char *name = udev_list_entry_get_name(entry);
+
+ if (g_str_has_prefix(name, "CONNMAN_TYPE") == TRUE)
+ type = udev_list_entry_get_value(entry);
+ else if (g_str_has_prefix(name, "CONNMAN_INTERFACE") == TRUE)
+ interface = udev_list_entry_get_value(entry);
+
+ entry = udev_list_entry_get_next(entry);
+ }
+
+ device = find_device(interface);
+ if (device != NULL)
+ return;
+
+ if (type == NULL || interface == NULL)
+ return;
+
+ if (g_str_equal(interface, "ttyUSB0") == FALSE &&
+ g_str_equal(interface, "noz0") == FALSE)
+ return;
+
+ if (g_str_equal(type, "nozomi") == TRUE)
+ devtype = CONNMAN_DEVICE_TYPE_NOZOMI;
+ else if (g_str_equal(type, "huawei") == TRUE)
+ devtype = CONNMAN_DEVICE_TYPE_HUAWEI;
+ else if (g_str_equal(type, "novatel") == TRUE)
+ devtype = CONNMAN_DEVICE_TYPE_NOVATEL;
+ else
+ return;
+
+ device = connman_device_create(interface, devtype);
+ if (device == NULL)
+ return;
+
+ connman_device_set_mode(device, CONNMAN_DEVICE_MODE_NETWORK_SINGLE);
+ connman_device_set_policy(device, CONNMAN_DEVICE_POLICY_MANUAL);
+
+ connman_device_set_interface(device, interface);
+
+ if (connman_device_register(device) < 0) {
+ connman_device_unref(device);
+ return;
+ }
+
+ device_list = g_slist_append(device_list, device);
+}
+
+static void remove_device(struct udev_device *udev_device)
+{
+ struct connman_device *device;
+ struct udev_list_entry *entry;
+ const char *interface = NULL;
+
+ DBG("");
+
+ entry = udev_device_get_properties_list_entry(udev_device);
+ while (entry) {
+ const char *name = udev_list_entry_get_name(entry);
+
+ if (g_str_has_prefix(name, "CONNMAN_INTERFACE") == TRUE)
+ interface = udev_list_entry_get_value(entry);
+
+ entry = udev_list_entry_get_next(entry);
+ }
+
+ device = find_device(interface);
+ if (device == NULL)
+ return;
+
+ device_list = g_slist_remove(device_list, device);
+
+ connman_device_unregister(device);
+ connman_device_unref(device);
+}
+
+static void print_properties(struct udev_device *device, const char *prefix)
+{
+ struct udev_list_entry *entry;
+
+ entry = udev_device_get_properties_list_entry(device);
+ while (entry) {
+ const char *name = udev_list_entry_get_name(entry);
+ const char *value = udev_list_entry_get_value(entry);
+
+ if (g_str_has_prefix(name, "CONNMAN") == TRUE ||
+ g_str_has_prefix(name, "RFKILL") == TRUE ||
+ g_str_has_prefix(name, "ID_MODEM") == TRUE ||
+ g_str_equal(name, "ID_VENDOR") == TRUE ||
+ g_str_equal(name, "ID_MODEL") == TRUE ||
+ g_str_equal(name, "INTERFACE") == TRUE ||
+ g_str_equal(name, "IFINDEX") == TRUE ||
+ g_str_equal(name, "DEVNAME") == TRUE ||
+ g_str_equal(name, "DEVPATH") == TRUE)
+ connman_debug("%s%s = %s", prefix, name, value);
+
+ entry = udev_list_entry_get_next(entry);
+ }
+}
+
+static void print_device(struct udev_device *device, const char *action)
+{
+ const char *subsystem, *devtype = NULL;
+ struct udev_device *parent;
+
+ connman_debug("=== %s ===", action);
+ print_properties(device, "");
+
+ parent = udev_device_get_parent(device);
+ if (parent == NULL)
+ return;
+
+ subsystem = udev_device_get_subsystem(parent);
+
+ if (subsystem != NULL &&
+ g_str_equal(subsystem, "usb-serial") == TRUE) {
+ subsystem = "usb";
+ devtype = "usb_device";
+ }
+
+ parent = udev_device_get_parent_with_subsystem_devtype(device,
+ subsystem, devtype);
+ print_properties(parent, " ");
+}
+
+static void enumerate_devices(struct udev *context)
+{
+ struct udev_enumerate *enumerate;
+ struct udev_list_entry *entry;
+
+ enumerate = udev_enumerate_new(context);
+ if (enumerate == NULL)
+ return;
+
+ udev_enumerate_add_match_property(enumerate, "CONNMAN_TYPE", "?*");
+
+ udev_enumerate_scan_devices(enumerate);
+
+ entry = udev_enumerate_get_list_entry(enumerate);
+ while (entry) {
+ const char *syspath = udev_list_entry_get_name(entry);
+ struct udev_device *device;
+
+ device = udev_device_new_from_syspath(context, syspath);
+
+ print_device(device, "coldplug");
+
+ add_device(device);
+
+ udev_device_unref(device);
+
+ entry = udev_list_entry_get_next(entry);
+ }
+
+ udev_enumerate_unref(enumerate);
+}
+
+static gboolean udev_event(GIOChannel *channel,
+ GIOCondition condition, gpointer user_data)
+{
+ struct udev_monitor *monitor = user_data;
+ struct udev_device *device;
+ const char *action;
+
+ device = udev_monitor_receive_device(monitor);
+ if (device == NULL)
+ return TRUE;
+
+ action = udev_device_get_action(device);
+ if (action == NULL)
+ goto done;
+
+ print_device(device, action);
+
+ if (g_str_equal(action, "add") == TRUE)
+ add_device(device);
+ else if (g_str_equal(action, "remove") == TRUE)
+ remove_device(device);
+
+done:
+ udev_device_unref(device);
+
+ return TRUE;
+}
+
+static struct udev *udev_ctx;
+static struct udev_monitor *udev_mon;
+static guint udev_watch = 0;
+
+int __connman_udev_init(void)
+{
+ GIOChannel *channel;
+ int fd;
+
+ DBG("");
+
+ udev_ctx = udev_new();
+ if (udev_ctx == NULL) {
+ connman_error("Failed to create udev context");
+ return -1;
+ }
+
+ udev_mon = udev_monitor_new_from_socket(udev_ctx,
+ "@/org/moblin/connman/udev");
+ if (udev_mon == NULL) {
+ connman_error("Failed to create udev monitor");
+ udev_unref(udev_ctx);
+ udev_ctx = NULL;
+ return -1;
+ }
+
+ if (udev_monitor_enable_receiving(udev_mon) < 0) {
+ connman_error("Failed to enable udev monitor");
+ udev_unref(udev_ctx);
+ udev_ctx = NULL;
+ udev_monitor_unref(udev_mon);
+ return -1;
+ }
+
+ enumerate_devices(udev_ctx);
+
+ fd = udev_monitor_get_fd(udev_mon);
+
+ channel = g_io_channel_unix_new(fd);
+ if (channel == NULL)
+ return 0;
+
+ udev_watch = g_io_add_watch(channel, G_IO_IN, udev_event, udev_mon);
+
+ g_io_channel_unref(channel);
+
+ return 0;
+}
+
+void __connman_udev_cleanup(void)
+{
+ GSList *list;
+
+ DBG("");
+
+ if (udev_watch > 0)
+ g_source_remove(udev_watch);
+
+ for (list = device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+
+ connman_device_unregister(device);
+ connman_device_unref(device);
+ }
+
+ g_slist_free(device_list);
+ device_list = NULL;
+
+ if (udev_ctx == NULL)
+ return;
+
+ udev_monitor_unref(udev_mon);
+ udev_unref(udev_ctx);
+}
--- /dev/null
+
+EXTRA_DIST = get-state list-profiles list-services \
+ list-connections select-connection \
+ list-devices enable-device disable-device start-scanning \
+ list-networks select-network disable-network create-network \
+ set-passphrase set-address set-policy set-priority \
+ connect-network disconnect-network join-network \
+ simple-agent show-introspection test-compat test-manager \
+ test-connman monitor-connman monitor-services debug-connman
+
+MAINTAINERCLEANFILES = Makefile.in
--- /dev/null
+#!/usr/bin/python
+
+import sys
+import dbus
+
+if (len(sys.argv) < 2):
+ print "Usage: %s <network>" % (sys.argv[0])
+ sys.exit(1)
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"),
+ "org.moblin.connman.Manager")
+
+properties = manager.GetProperties()
+
+for path in properties["Devices"]:
+ device = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Device")
+
+ properties = device.GetProperties()
+
+ if properties["Type"] not in ["wifi", "wimax",
+ "bluetooth", "cellular"]:
+ continue
+
+ for path in properties["Networks"]:
+ network = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Network")
+
+ properties = network.GetProperties()
+
+ dev = path[path.rfind("/") + 1:]
+
+ if "Name" not in properties.keys():
+ continue
+
+ if dev == sys.argv[1] or properties["Name"] == sys.argv[1]:
+ print "Connecting %s" % (path)
+ network.Connect()
--- /dev/null
+#!/usr/bin/python
+
+import sys
+import dbus
+
+if (len(sys.argv) < 2):
+ print "Usage: %s <network>" % (sys.argv[0])
+ sys.exit(1)
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"),
+ "org.moblin.connman.Manager")
+
+properties = manager.GetProperties()
+
+for path in properties["Devices"]:
+ device = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Device")
+
+ properties = device.GetProperties()
+
+ if (properties["Type"] != "wifi" and properties["Type"] != "wimax"):
+ continue;
+
+ path = device.CreateNetwork({ "WiFi.SSID": sys.argv[1] });
--- /dev/null
+#!/usr/bin/python
+
+import gobject
+
+import dbus
+import dbus.mainloop.glib
+
+def element_signal(path, member):
+ if member == "ElementAdded":
+ action = "Add "
+ elif member == "ElementRemoved":
+ action = "Remove"
+ elif member == "ElementUpdated":
+ action = "Update"
+ else:
+ return
+ print "%s [ %s ]" % (action, path)
+
+if __name__ == '__main__':
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+
+ bus.add_signal_receiver(element_signal,
+ bus_name="org.moblin.connman",
+ signal_name = "ElementAdded",
+ path_keyword="path",
+ member_keyword="member")
+ bus.add_signal_receiver(element_signal,
+ bus_name="org.moblin.connman",
+ signal_name = "ElementRemoved",
+ path_keyword="path",
+ member_keyword="member")
+ bus.add_signal_receiver(element_signal,
+ bus_name="org.moblin.connman",
+ signal_name = "ElementUpdated",
+ path_keyword="path",
+ member_keyword="member")
+
+ mainloop = gobject.MainLoop()
+ mainloop.run()
--- /dev/null
+#!/usr/bin/python
+
+import sys
+import dbus
+
+if (len(sys.argv) < 2):
+ print "Usage: %s <device>" % (sys.argv[0])
+ sys.exit(1)
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object('org.moblin.connman', "/"),
+ 'org.moblin.connman.Manager')
+
+properties = manager.GetProperties()
+
+for path in properties["Devices"]:
+ device = dbus.Interface(bus.get_object('org.moblin.connman', path),
+ 'org.moblin.connman.Device')
+
+ properties = device.GetProperties()
+
+ if properties["Interface"] != sys.argv[1]:
+ continue;
+
+ print "Disabling device %s" % (path)
+
+ device.SetProperty("Powered", dbus.Boolean(0));
--- /dev/null
+#!/usr/bin/python
+
+import dbus
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"),
+ "org.moblin.connman.Manager")
+
+properties = manager.GetProperties()
+
+for path in properties["Devices"]:
+ device = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Device")
+
+ properties = device.GetProperties()
+
+ if (properties["Type"] != "wifi" and properties["Type"] != "wimax"):
+ continue;
+
+ print "[ %s ]" % (path)
+
+ for path in properties["Networks"]:
+ network = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Network")
+
+ properties = network.GetProperties()
+
+ if (properties["Connected"] == dbus.Boolean(1)):
+ print "Disconnecting %s" % (path)
+ network.Disconnect()
--- /dev/null
+#!/usr/bin/python
+
+import sys
+import dbus
+
+if (len(sys.argv) < 2):
+ print "Usage: %s <network>" % (sys.argv[0])
+ sys.exit(1)
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"),
+ "org.moblin.connman.Manager")
+
+properties = manager.GetProperties()
+
+for path in properties["Devices"]:
+ device = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Device")
+
+ properties = device.GetProperties()
+
+ if properties["Type"] not in ["wifi", "wimax",
+ "bluetooth", "cellular"]:
+ continue
+
+ for path in properties["Networks"]:
+ network = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Network")
+
+ properties = network.GetProperties()
+
+ dev = path[path.rfind("/") + 1:]
+
+ if "Name" not in properties.keys():
+ continue
+
+ if dev == sys.argv[1] or properties["Name"] == sys.argv[1]:
+ print "Disconnecting %s" % (path)
+ network.Disconnect()
--- /dev/null
+#!/usr/bin/python
+
+import sys
+import dbus
+
+if (len(sys.argv) < 2):
+ print "Usage: %s <device>" % (sys.argv[0])
+ sys.exit(1)
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object('org.moblin.connman', "/"),
+ 'org.moblin.connman.Manager')
+
+properties = manager.GetProperties()
+
+for path in properties["Devices"]:
+ device = dbus.Interface(bus.get_object('org.moblin.connman', path),
+ 'org.moblin.connman.Device')
+
+ properties = device.GetProperties()
+
+ if properties["Interface"] != sys.argv[1]:
+ continue;
+
+ print "Enabling device %s" % (path)
+
+ device.SetProperty("Powered", dbus.Boolean(1));
--- /dev/null
+#!/usr/bin/python
+
+import dbus
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object('org.moblin.connman', "/"),
+ 'org.moblin.connman.Manager')
+
+properties = manager.GetProperties()
+
+print "System is %s" % (properties["State"])
--- /dev/null
+#!/usr/bin/python
+
+import sys
+import dbus
+
+if (len(sys.argv) < 2):
+ print "Usage: %s <ssid> [passphrase] [security]" % (sys.argv[0])
+ sys.exit(1)
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"),
+ "org.moblin.connman.Manager")
+
+properties = manager.GetProperties()
+
+for path in properties["Devices"]:
+ device = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Device")
+
+ properties = device.GetProperties()
+
+ if (properties["Type"] != "wifi"):
+ continue;
+
+ print "[ %s ]" % (path)
+ print "Attempting to join %s" % (sys.argv[1])
+
+ if len(sys.argv) > 2:
+ if len(sys.argv) > 3:
+ security = sys.argv[3]
+ else:
+ security = "rsn"
+ passphrase = sys.argv[2]
+ else:
+ security = "none"
+ passphrase = ""
+
+ device.JoinNetwork({ "WiFi.Mode": "managed",
+ "WiFi.SSID": sys.argv[1],
+ "WiFi.Security": security,
+ "WiFi.Passphrase": passphrase })
--- /dev/null
+#!/usr/bin/python
+
+import dbus
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"),
+ "org.moblin.connman.Manager")
+
+properties = manager.GetProperties()
+
+for path in properties["Connections"]:
+ connection = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Connection")
+
+ properties = connection.GetProperties()
+
+ print "[ %s ]" % (path)
+
+ for key in properties.keys():
+ if key in ["Strength", "Priority"]:
+ val = int(properties[key])
+ else:
+ val = str(properties[key])
+ print " %s = %s" % (key, val)
+
+ print
--- /dev/null
+#!/usr/bin/python
+
+import dbus
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"),
+ "org.moblin.connman.Manager")
+
+properties = manager.GetProperties()
+
+for path in properties["Devices"]:
+ device = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Device")
+
+ properties = device.GetProperties()
+
+ print "[ %s ]" % (path)
+
+ for key in properties.keys():
+ print " %s = %s" % (key, properties[key])
+
+ print
--- /dev/null
+#!/usr/bin/python
+
+import dbus
+import string
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"),
+ "org.moblin.connman.Manager")
+
+properties = manager.GetProperties()
+
+def convert_ssid(ssid_list):
+ ssid = ""
+ for byte in ssid_list:
+ if (str(byte) in string.printable):
+ ssid = ssid + str(byte)
+ else:
+ ssid = ssid + "."
+ return ssid
+
+for path in properties["Devices"]:
+ device = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Device")
+
+ properties = device.GetProperties()
+
+ try:
+ if properties["Type"] not in ["wifi", "wimax",
+ "bluetooth", "cellular"]:
+ continue
+ except:
+ continue
+
+ print "[ %s ]" % (path)
+
+ for path in properties["Networks"]:
+ network = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Network")
+
+ properties = network.GetProperties()
+
+ print " [ %s ]" % (path)
+
+ for key in properties.keys():
+ if key == "WiFi.SSID":
+ ssid = convert_ssid(properties[key])
+ print " %s = [ %s ]" % (key, ssid)
+ elif key in ["Strength", "Priority"]:
+ print " %s = %d" % (key, properties[key])
+ else:
+ print " %s = %s" % (key, properties[key])
+
+ print
--- /dev/null
+#!/usr/bin/python
+
+import dbus
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"),
+ "org.moblin.connman.Manager")
+
+properties = manager.GetProperties()
+
+active = properties["ActiveProfile"]
+
+for path in properties["Profiles"]:
+ if (active == path):
+ print "[ %s ] <== active" % (path)
+ else:
+ print "[ %s ]" % (path)
+
+ profile = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Profile")
+
+ properties = profile.GetProperties()
+ for key in properties.keys():
+ if key in ["Services"]:
+ list = ""
+ for path in properties["Services"]:
+ val = str(path)
+ list = list + val[val.rfind("/") + 1:] + " "
+ print " Services = [ %s]" % (list)
+ else:
+ print " %s = %s" % (key, properties[key])
+
+ print
--- /dev/null
+#!/usr/bin/python
+
+import dbus
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"),
+ "org.moblin.connman.Manager")
+
+properties = manager.GetProperties()
+
+for path in properties["Services"]:
+ service = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Service")
+
+ properties = service.GetProperties()
+
+ print "[ %s ]" % (path)
+
+ for key in properties.keys():
+ if key in ["Strength"]:
+ val = int(properties[key])
+ else:
+ val = str(properties[key])
+ print " %s = %s" % (key, val)
+
+ print
--- /dev/null
+#!/usr/bin/python
+
+import gobject
+
+import dbus
+import dbus.mainloop.glib
+
+def property_changed(name, value, path, interface):
+ iface = interface[interface.rfind(".") + 1:]
+ if name in ["Strength", "Priority"]:
+ val = int(value)
+ else:
+ val = str(value)
+ print "{%s} [%s] %s = %s" % (iface, path, name, val)
+
+if __name__ == '__main__':
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+
+ bus.add_signal_receiver(property_changed,
+ bus_name="org.moblin.connman",
+ signal_name = "PropertyChanged",
+ path_keyword="path",
+ interface_keyword="interface")
+
+ mainloop = gobject.MainLoop()
+ mainloop.run()
--- /dev/null
+#!/usr/bin/python
+
+import gobject
+
+import dbus
+import dbus.mainloop.glib
+
+def property_changed(name, value, path, interface):
+ iface = interface[interface.rfind(".") + 1:]
+ ipath = path[path.rfind("/") + 1:]
+ if iface not in ["Service"]:
+ return
+ if name in ["Profiles", "Services",
+ "Devices", "Networks", "Connections"]:
+ val = "["
+ for i in value:
+ val = val + " " + i[i.rfind("/") + 1:]
+ val = val + " ]"
+ elif name in ["Strength", "Priority"]:
+ val = int(value)
+ else:
+ val = str(value)
+ print "{%s} [%s] %s = %s" % (iface, ipath, name, val)
+
+if __name__ == '__main__':
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+
+ bus.add_signal_receiver(property_changed,
+ bus_name="org.moblin.connman",
+ signal_name = "PropertyChanged",
+ path_keyword="path",
+ interface_keyword="interface")
+
+ mainloop = gobject.MainLoop()
+ mainloop.run()
--- /dev/null
+#!/usr/bin/python
+
+import dbus
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"),
+ "org.moblin.connman.Manager")
+
+properties = manager.GetProperties()
+
+for path in properties["Connections"]:
+ connection = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Connection")
+
+ properties = connection.GetProperties()
+
+ if (properties["Default"] == dbus.Boolean(1)):
+ continue
+
+ print "[ %s ]" % (path)
+
+ connection.SetProperty("Default", dbus.Boolean(1))
--- /dev/null
+#!/usr/bin/python
+
+import sys
+import dbus
+
+if (len(sys.argv) < 2):
+ print "Usage: %s <network>" % (sys.argv[0])
+ sys.exit(1)
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"),
+ "org.moblin.connman.Manager")
+
+properties = manager.GetProperties()
+
+for path in properties["Devices"]:
+ device = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Device")
+
+ properties = device.GetProperties()
+
+ if (properties["Type"] != "wifi" and properties["Type"] != "wimax"):
+ continue
+
+ print "[ %s ]" % (path)
+
+ for path in properties["Networks"]:
+ network = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Network")
+
+ properties = network.GetProperties()
+
+ if "Name" not in properties.keys():
+ continue
+
+ if (properties["Connected"] == dbus.Boolean(1)):
+ continue
+
+ if (properties["Name"] == sys.argv[1]):
+ print "Connecting %s" % (path)
+ network.Connect()
--- /dev/null
+#!/usr/bin/python
+
+import sys
+import dbus
+
+if (len(sys.argv) < 2):
+ print "Usage: %s <address>" % (sys.argv[0])
+ sys.exit(1)
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object('org.moblin.connman', "/"),
+ 'org.moblin.connman.Manager')
+
+properties = manager.GetProperties()
+
+for path in properties["Devices"]:
+ device = dbus.Interface(bus.get_object('org.moblin.connman', path),
+ 'org.moblin.connman.Device')
+
+ print "Setting static address %s for %s" % (sys.argv[1], path)
+
+ device.SetProperty("IPv4.Method", "static")
+ device.SetProperty("IPv4.Address", sys.argv[1])
+
+ print
--- /dev/null
+#!/usr/bin/python
+
+import sys
+import dbus
+
+if (len(sys.argv) < 3):
+ print "Usage: %s <network> <passphrase>" % (sys.argv[0])
+ sys.exit(1)
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"),
+ "org.moblin.connman.Manager")
+
+properties = manager.GetProperties()
+
+for path in properties["Devices"]:
+ device = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Device")
+
+ properties = device.GetProperties()
+
+ if (properties["Type"] != "wifi" and properties["Type"] != "wimax"):
+ continue;
+
+ for path in properties["Networks"]:
+ network = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Network")
+
+ properties = network.GetProperties()
+
+ if (properties["Name"] == sys.argv[1]):
+ print "Setting passphrase for %s" % (path)
+ network.SetProperty("WiFi.Passphrase", sys.argv[2])
--- /dev/null
+#!/usr/bin/python
+
+import sys
+import dbus
+
+if (len(sys.argv) < 3):
+ print "Usage: %s <device> <policy>" % (sys.argv[0])
+ sys.exit(1)
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"),
+ "org.moblin.connman.Manager")
+
+properties = manager.GetProperties()
+
+for path in properties["Devices"]:
+ device = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Device")
+
+ properties = device.GetProperties()
+
+ if properties["Interface"] != sys.argv[1]:
+ continue;
+
+ print "Setting policy \"%s\" for %s" % (sys.argv[2], path)
+
+ device.SetProperty("Policy", sys.argv[2])
--- /dev/null
+#!/usr/bin/python
+
+import sys
+import dbus
+
+if (len(sys.argv) < 3):
+ print "Usage: %s <device> <priority>" % (sys.argv[0])
+ sys.exit(1)
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object('org.moblin.connman', "/"),
+ 'org.moblin.connman.Manager')
+
+properties = manager.GetProperties()
+
+for path in properties["Devices"]:
+ device = dbus.Interface(bus.get_object('org.moblin.connman', path),
+ 'org.moblin.connman.Device')
+
+ properties = device.GetProperties()
+
+ if properties["Interface"] != sys.argv[1]:
+ continue;
+
+ print "Setting priority %d for device %s" % (int(sys.argv[2]), path)
+
+ device.SetProperty("Priority", dbus.Byte(int(sys.argv[2])));
--- /dev/null
+#!/usr/bin/python
+
+import dbus
+
+bus = dbus.SystemBus()
+
+object = dbus.Interface(bus.get_object("org.moblin.connman", '/'),
+ "org.freedesktop.DBus.Introspectable")
+
+print object.Introspect()
+
+manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"),
+ "org.moblin.connman.Manager")
+
+properties = manager.GetProperties()
+
+for path in properties["Devices"]:
+ object = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.freedesktop.DBus.Introspectable")
+
+ print object.Introspect()
--- /dev/null
+#!/usr/bin/python
+
+import gobject
+
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+
+class Agent(dbus.service.Object):
+ @dbus.service.method("org.moblin.connman.Agent",
+ in_signature='', out_signature='')
+ def Release(self):
+ print("Release")
+ mainloop.quit()
+
+if __name__ == '__main__':
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+ manager = dbus.Interface(bus.get_object('org.moblin.connman', "/"),
+ 'org.moblin.connman.Manager')
+
+ path = "/test/agent"
+ object = Agent(bus, path)
+
+ manager.RegisterAgent(path)
+
+ mainloop = gobject.MainLoop()
+ mainloop.run()
+
+ #manager.UnregisterAgent(path)
--- /dev/null
+#!/usr/bin/python
+
+import dbus
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object('org.moblin.connman', "/"),
+ 'org.moblin.connman.Manager')
+
+properties = manager.GetProperties()
+
+for path in properties["Devices"]:
+ device = dbus.Interface(bus.get_object('org.moblin.connman', path),
+ 'org.moblin.connman.Device')
+
+ properties = device.GetProperties()
+
+ print "[ %s ]" % (path)
+
+ if properties["Type"] in ["wifi", "wimax"]:
+ print " Started scanning"
+ device.ProposeScan()
+ else:
+ print " No scanning"
+
+ print
--- /dev/null
+#!/usr/bin/python
+
+import dbus
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object('org.freedesktop.NetworkManager',
+ '/org/freedesktop/NetworkManager'),
+ 'org.freedesktop.NetworkManager')
+
+states = [ "unknown", "asleep", "connecting", "connected", "disconnected" ]
+
+state = manager.state()
+
+print "System is %s" % (states[state])
--- /dev/null
+#!/usr/bin/python
+
+import sys
+import dbus
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"),
+ "org.moblin.connman.Manager")
+
+if len(sys.argv) < 2:
+ print "Usage: %s <command>" % (sys.argv[0])
+ print ""
+ print " state"
+ print " services"
+ print " passphrase <service> [passphrase]"
+ print " connect <service>"
+ print " disconnect <service>"
+ print " remove <service>"
+ print ""
+ print " scan [ <interface> ]"
+ print " dev <interface>"
+ print " dev <interface> scan"
+ print " dev <interface> networks"
+ print " dev <interface> connect <network>"
+ print " dev <interface> remember <network>"
+ print " dev <interface> disconnect [network]"
+ print " dev <interface> policy [ignore|off|auto|manual]"
+ print " dev <interface> powered [on|off]"
+ print " dev <interface> priority [0-255]"
+ sys.exit(1)
+
+def print_properties(path, properties):
+ print "[ %s ]" % (path)
+ for key in properties.keys():
+ if key == "Networks":
+ continue
+
+ if key in ["Powered", "Scanning", "Connected",
+ "Available", "Remember", "Default"]:
+ if properties[key] == dbus.Boolean(1):
+ val = "true"
+ else:
+ val = "false"
+ elif key in ["Strength", "Priority"]:
+ val = int(properties[key])
+ else:
+ val = str(properties[key])
+
+ print " %s = %s" % (key, val)
+
+ if "Networks" in properties.keys():
+ list = ""
+ for path in properties["Networks"]:
+ val = str(path)
+ list = list + val[val.rfind("/") + 1:] + " "
+ print " Networks = [ %s]" % (list)
+
+def print_networks(networks):
+ for path in networks:
+ network = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Network")
+
+ properties = network.GetProperties()
+
+ if properties["Connected"] == dbus.Boolean(1):
+ connected = "*"
+ else:
+ connected = " "
+
+ if "Name" in properties.keys():
+ name = properties["Name"]
+ else:
+ name = ""
+
+ strength = int(properties["Strength"])
+
+ details = ""
+ try:
+ details += "{" + properties["WiFi.Mode"] + "} "
+ except:
+ pass
+ try:
+ details += "{" + properties["WiFi.Security"] + "} "
+ except:
+ pass
+ if "WiFi.Passphrase" in properties.keys():
+ if properties["WiFi.Passphrase"] != "":
+ details += "{passphrase present}"
+
+ print "%s %-26s %3d%% %s" % (connected,
+ name, strength, details)
+
+def select_network(networks, name):
+ for path in networks:
+ network = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Network")
+
+ properties = network.GetProperties()
+
+ if properties["Name"] != name:
+ continue
+
+ if properties["Connected"] == dbus.Boolean(1):
+ print "Already connected to network %s" % (name)
+ break
+
+ print "Selecting network %s" % (name)
+
+ network.Connect()
+
+def remember_network(networks, name):
+ for path in networks:
+ network = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Network")
+
+ properties = network.GetProperties()
+
+ if properties["Name"] != name:
+ continue
+
+ if properties["Remember"] == dbus.Boolean(1):
+ print "Already a known network %s" % (name)
+ break
+
+ print "Remembering network %s" % (name)
+
+ network.SetProperty("Remember", dbus.Boolean(1))
+
+def disconnect_network(networks, name):
+ for path in networks:
+ network = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Network")
+
+ properties = network.GetProperties()
+
+ if name != "" and properties["Name"] != name:
+ continue
+
+ if properties["Connected"] == dbus.Boolean(1):
+ name = properties["Name"]
+ print "Disconnecting from network %s" % (name)
+ network.Disconnect()
+
+def print_services(services):
+ for path in services:
+ service = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Service")
+
+ properties = service.GetProperties()
+
+ identifier = path[path.rfind("/") + 1:]
+
+ if properties["Favorite"] == dbus.Boolean(1):
+ favorite = "*"
+ else:
+ favorite = " "
+
+ if "Name" in properties.keys():
+ name = properties["Name"]
+ else:
+ name = "{" + properties["Type"] + "}"
+
+ print "%s %-26s { %s }" % (favorite, name, identifier)
+
+if sys.argv[1] == "state":
+ properties = manager.GetProperties()
+
+ print "System is %s" % (properties["State"])
+
+elif sys.argv[1] in ["services", "list", "show"]:
+ properties = manager.GetProperties()
+
+ print_services(properties["Services"])
+
+elif sys.argv[1] in ["passphrase", "pass"]:
+ if (len(sys.argv) < 3):
+ print "Need at least service parameter"
+ sys.exit(1)
+
+ path = "/profile/default/" + sys.argv[2]
+
+ service = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Service")
+
+ if (len(sys.argv) > 3):
+ passphrase = sys.argv[3]
+
+ service.SetProperty("Passphrase", passphrase);
+
+ print "Passphrase %s set for %s" % (passphrase, sys.argv[2])
+ else:
+ properties = service.GetProperties()
+
+ if "Name" in properties.keys():
+ name = properties["Name"]
+ else:
+ name = "{" + properties["Type"] + "}"
+
+ if "Passphrase" in properties.keys():
+ passphrase = properties["Passphrase"]
+ else:
+ passphrase = "not set"
+
+ print "Passphrase for %s is %s" % (name, passphrase)
+
+elif sys.argv[1] in ["connect", "conn"]:
+ if (len(sys.argv) < 3):
+ print "Need at least service parameter"
+ sys.exit(1)
+
+ path = "/profile/default/" + sys.argv[2]
+
+ service = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Service")
+
+ try:
+ service.Connect(timeout=60000)
+ except dbus.DBusException, error:
+ print "%s: %s" % (error._dbus_error_name, error.message)
+
+elif sys.argv[1] in ["disconnect", "disc"]:
+ if (len(sys.argv) < 3):
+ print "Need at least service parameter"
+ sys.exit(1)
+
+ path = "/profile/default/" + sys.argv[2]
+
+ service = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Service")
+
+ try:
+ service.Disconnect()
+ except dbus.DBusException, error:
+ print "%s: %s" % (error._dbus_error_name, error.message)
+
+elif sys.argv[1] in ["remove"]:
+ if (len(sys.argv) < 3):
+ print "Need at least service parameter"
+ sys.exit(1)
+
+ path = "/profile/default/" + sys.argv[2]
+
+ service = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Service")
+
+ properties = service.GetProperties()
+
+ if properties["Favorite"] == dbus.Boolean(0):
+ print "Only favorite services can be removed"
+ sys.exit(1)
+
+ try:
+ service.Remove()
+ except dbus.DBusException, error:
+ print "%s: %s" % (error._dbus_error_name, error.message)
+
+elif sys.argv[1] == "scan":
+ properties = manager.GetProperties()
+
+ interface = ""
+ found = 0
+
+ if len(sys.argv) > 2:
+ interface = sys.argv[2]
+
+ for path in properties["Devices"]:
+ device = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Device")
+
+ properties = device.GetProperties()
+
+ if interface != "" and properties["Interface"] != interface:
+ continue
+
+ if properties["Type"] in ["wifi", "wimax"]:
+ interface = properties["Interface"]
+ print "Propose scanning for device %s" % (interface)
+ device.ProposeScan()
+ found = 1
+ elif interface != "":
+ print "No scanning support for device %s" % (interface)
+ found = 1
+
+ if found == 0:
+ print "No such device"
+
+elif sys.argv[1] == "dev":
+ properties = manager.GetProperties()
+
+ interface = ""
+ command = ""
+ value = ""
+ found = 0
+
+ if len(sys.argv) > 2:
+ interface = sys.argv[2]
+ if len(sys.argv) > 3:
+ command = sys.argv[3]
+ if len(sys.argv) > 4:
+ value = sys.argv[4]
+
+ for path in properties["Devices"]:
+ device = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Device")
+
+ properties = device.GetProperties()
+
+ if interface != "" and properties["Interface"] != interface:
+ continue
+
+ if command == "scan":
+ if properties["Type"] in ["wifi", "wimax"]:
+ interface = properties["Interface"]
+ print "Scan for device %s" % (interface)
+ device.ProposeScan()
+ else:
+ print "No scanning for device %s" % (interface)
+ elif command in ["networks", "net"]:
+ if "Networks" in properties.keys():
+ print_networks(properties["Networks"])
+ else:
+ print "Device has no networks"
+ elif command in ["connect", "conn"] and value != "":
+ if "Networks" in properties.keys():
+ select_network(properties["Networks"], value)
+ else:
+ print "Device can't connect networks"
+ elif command in ["connect", "conn"]:
+ print "Need to specify network"
+ elif command in ["remember", "known"] and value != "":
+ if "Networks" in properties.keys():
+ remember_network(properties["Networks"], value)
+ else:
+ print "Device has no networks"
+ elif command in ["remember", "known"]:
+ print "Need to specify network"
+ elif command in ["disconnect", "disc"] and value != "":
+ if "Networks" in properties.keys():
+ disconnect_network(properties["Networks"], value)
+ else:
+ print "Device has no networks"
+ elif command in ["discconnect", "disc"]:
+ if "Networks" in properties.keys():
+ disconnect_network(properties["Networks"], "")
+ else:
+ print "Device has no networks"
+ elif command == "policy" and value != "":
+ policy = value
+ device.SetProperty("Policy", policy)
+ elif command == "policy":
+ interface = properties["Interface"]
+ policy = properties["Policy"]
+ print "Policy of device %s is %s" % (interface, policy)
+ elif command == "powered" and value != "":
+ if value == "on":
+ powered = dbus.Boolean(1)
+ elif value == "off":
+ powered = dbus.Boolean(0)
+ else:
+ powered = dbus.Boolean(value)
+ device.SetProperty("Powered", powered)
+ elif command == "powered":
+ interface = properties["Interface"]
+ if properties["Powered"] == dbus.Boolean(1):
+ powered = "on"
+ else:
+ powered = "off"
+ print "Device %s is powered %s" % (interface, powered)
+ elif command == "priority" and value != "":
+ priority = int(value)
+ device.SetProperty("Priority", priority)
+ elif command == "priority":
+ interface = properties["Interface"]
+ priority = properties["Priority"]
+ print "Device %s has priority of %d" % (interface, priority)
+ elif command == "list" or command == "":
+ print_properties(path, properties)
+ else:
+ print "Unknown command"
+
+else:
+ print "Unknown command"
--- /dev/null
+#!/usr/bin/python
+
+import dbus
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"),
+ "org.moblin.connman.Manager")
+
+properties = manager.GetProperties()
+
+def print_properties(key, value):
+ if key == "Profiles":
+ interface = "org.moblin.connman.Profile"
+ elif key == "Devices":
+ interface = "org.moblin.connman.Device"
+ elif key == "Connections":
+ interface = "org.moblin.connman.Connection"
+ elif key == "Services":
+ interface = "org.moblin.connman.Service"
+ else:
+ return
+
+ print "%s" % (key)
+ for path in value:
+ print " %s" % (path)
+ obj = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ interface)
+
+ properties = obj.GetProperties()
+
+ for key in properties.keys():
+ if key in ["Networks", "Services"]:
+ continue
+
+ if key in ["Powered", "Scanning", "Connected",
+ "Available", "Remember", "Default"]:
+ if properties[key] == dbus.Boolean(1):
+ val = "true"
+ else:
+ val = "false"
+ elif key in ["Strength", "Priority"]:
+ val = int(properties[key])
+ else:
+ val = str(properties[key])
+
+ print " %s = %s" % (key, val)
+
+ if "Networks" in properties.keys():
+ list = ""
+ for path in properties["Networks"]:
+ val = str(path)
+ list = list + val[val.rfind("/") + 1:] + " "
+ print " Networks = [ %s]" % (list)
+ if "Services" in properties.keys():
+ list = ""
+ for path in properties["Services"]:
+ val = str(path)
+ list = list + val[val.rfind("/") + 1:] + " "
+ print " Services = [ %s]" % (list)
+
+for key in properties.keys():
+ if key in ["Profiles", "Devices", "Connections", "Services"]:
+ print_properties(key, properties[key])
+ elif key in ["OfflineMode"]:
+ print "%s" % (key)
+ if properties[key] == dbus.Boolean(1):
+ print " true"
+ else:
+ print " false"
+ else:
+ print "%s" % (key)
+ print " %s" % (properties[key])
--- /dev/null
+#!/usr/bin/python
+
+import dbus
+import time
+
+WPA_NAME='fi.epitest.hostap.WPASupplicant'
+WPA_INTF='fi.epitest.hostap.WPASupplicant'
+WPA_PATH='/fi/epitest/hostap/WPASupplicant'
+
+bus = dbus.SystemBus()
+
+dummy = dbus.Interface(bus.get_object(WPA_NAME, WPA_PATH),
+ 'org.freedesktop.DBus.Introspectable')
+
+#print dummy.Introspect()
+
+manager = dbus.Interface(bus.get_object(WPA_NAME, WPA_PATH), WPA_INTF)
+
+try:
+ path = manager.getInterface("wlan0")
+except:
+ path = manager.addInterface("wlan0")
+
+interface = dbus.Interface(bus.get_object(WPA_NAME, path),
+ WPA_INTF + ".Interface")
+
+print interface.state()
+
+print interface.scan()
+
+print "[ %s ]" % (path)
+
+capabilities = interface.capabilities()
+
+for key in capabilities.keys():
+ list = ""
+ for value in capabilities[key]:
+ list += " " + value
+ print " %s =%s" % (key, list)
+
+time.sleep(2)
+
+print interface.state()
+
+results = interface.scanResults()
+
+print results
+
+path = results[0]
+
+print "[ %s ]" % (path)
+
+bssid = dbus.Interface(bus.get_object(WPA_NAME, path),
+ WPA_INTF + ".BSSID")
+
+properties = bssid.properties()
+
+for key in properties.keys():
+ print " %s = %s" % (key, properties[key])
--- /dev/null
+
+if TOOLS
+noinst_PROGRAMS = wifi-scan
+
+wifi_scan_LDADD = @GLIB_LIBS@ @NETLINK_LIBS@
+endif
+
+AM_CFLAGS = @NETLINK_CFLAGS@ @GLIB_CFLAGS@
+
+MAINTAINERCLEANFILES = Makefile.in
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 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
+
+int main(int argc, char *argv[])
+{
+ return 0;
+}