Merge remote-tracking branch 'cros/upstream' into 'cros/master'
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0fa0bd3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,76 @@
+*~
+*.o
+*.lo
+*.la
+*.bz2
+
+ChangeLog
+INSTALL
+Makefile
+Makefile.in
+README
+aclocal.m4
+autom4te.cache
+compile
+config.cache
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+install-sh
+libtool
+ltmain.sh
+m4
+missing
+stamp-h1
+depcomp
+gtk-doc.make
+test-driver
+
+build-aux/mbim-codegen/*.pyc
+
+data/pkg-config/mbim-glib.pc
+
+docs/reference/libmbim-glib/version.xml
+docs/reference/libmbim-glib/libmbim-glib.args
+docs/reference/libmbim-glib/libmbim-glib.hierarchy
+docs/reference/libmbim-glib/libmbim-glib.interfaces
+docs/reference/libmbim-glib/libmbim-glib.prerequisites
+docs/reference/libmbim-glib/libmbim-glib.signals
+docs/reference/libmbim-glib/libmbim-glib.types
+docs/reference/libmbim-glib/*.mstamp
+docs/reference/libmbim-glib/*.stamp
+docs/reference/libmbim-glib/*.txt
+docs/reference/libmbim-glib/*.bak
+docs/reference/libmbim-glib/html
+docs/reference/libmbim-glib/tmpl
+docs/reference/libmbim-glib/xml
+docs/reference/libmbim-glib/.libs
+
+libmbim-glib/.deps
+libmbim-glib/.libs
+libmbim-glib/mbim-version.h
+
+libmbim-glib/test/.deps
+libmbim-glib/test/.libs
+libmbim-glib/test/test-uuid
+libmbim-glib/test/test-cid
+libmbim-glib/test/test-message
+libmbim-glib/test/test-fragment
+libmbim-glib/test/test-message-parser
+libmbim-glib/test/test-message-builder
+libmbim-glib/test/*.log
+libmbim-glib/test/*.trs
+
+libmbim-glib/generated/.deps
+libmbim-glib/generated/.libs
+libmbim-glib/generated/*.c
+libmbim-glib/generated/*.h
+libmbim-glib/generated/*.sections
+
+cli/.deps
+cli/.libs
+cli/mbimcli
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..8f0552f
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Aleksander Morgado <aleksander@gnu.org>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..bf50f20
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,482 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, 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 library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, 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 companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the 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.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..b9cce85
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,8 @@
+
+SUBDIRS = . build-aux data libmbim-glib cli utils docs
+
+ACLOCAL_AMFLAGS = -I m4
+
+DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc
+
+EXTRA_DIST = gtester.make
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..046c152
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,88 @@
+
+Overview of changes in libmbim 1.4
+----------------------------------------
+
+ * Added support for additional MBIM messages:
+ MBIM_SMS_CONFIGURATION
+ MBIM_SMS_READ
+ MBIM_SMS_SEND
+ MBIM_SMS_DELETE
+ MBIM_SMS_MESSAGE_STORE_STATUS
+ MBIM_USSD
+ MBIM_PHONEBOOK_CONFIGURATION
+ MBIM_PHONEBOOK_READ
+ MBIM_PHONEBOOK_DELETE
+ MBIM_PHONEBOOK_WRITE
+ MBIM_STK_PAC
+ MBIM_STK_TERMINAL_RESPONSE
+ MBIM_STK_ENVELOPE
+ MBIM_DEVICE_SERVICE_SUBSCRIBER_LIST
+ MBIM_AUTH_AKA
+ MBIM_AUTH_AKAP
+ MBIM_AUTH_SIM
+ MBIM_PACKET_STATISTICS
+ MBIM_NETWORK_IDLE_HINT
+ MBIM_EMERGENCY_MODE
+ MBIM_IP_PACKET_FILTERS
+ MBIM_DSS_CONNECT
+ MBIM_MULTICARRIER_PROVIDERS
+
+ * Updated mbimcli with new commands:
+ --query-packet-statistics
+
+ * Use gtester to run unit tests.
+
+Overview of changes in libmbim 1.2
+----------------------------------------
+
+ * Added support for additional MBIM messages:
+ MBIM_VISIBLE_PROVIDERS
+ MBIM_PREFERRED_PROVIDERS
+ MBIM_HOME_PROVIDER
+ MBIM_SERVICE_ACTIVATION
+
+ * Updated mbimcli with new commands:
+ --query-visible-providers
+ --query-preferred-providers
+ --query-home-provider
+ --query-signal-state
+ --no-open
+ --noop
+
+ * Updated mbim-network with session support, keeping TRID sequence between
+ commands.
+
+ * New symbols to check library version.
+
+
+Overview of changes in libmbim 1.0
+----------------------------------------
+
+ * Updated mbimcli with new commands:
+ --enter-pin
+ --change-pin
+ --enable-pin
+ --disable-pin
+ --enter-puk
+ --query-registration-state
+ --register-automatic
+ --query-packet-service-state
+ --attach-packet-service
+ --detach-packet-service
+ --query-connection-state
+ --connect
+ --disconnect
+ --no-close
+
+ * Removed the 'basic-connect' prefix from mbimcli commands.
+
+ * New 'mbim-network' script to help launch a connection through the
+ shell.
+
+ * Added gtk-doc documentation
+
+
+Overview of changes in libmbim 0.0.1
+----------------------------------------
+
+Initial release.
\ No newline at end of file
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..a1fecad
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+REQUIRED_AUTOMAKE_VERSION=1.9
+PKG_NAME=libmbim
+
+(test -f $srcdir/configure.ac \
+ && test -f $srcdir/libmbim-glib/libmbim-glib.h) || {
+ echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
+ echo " top-level $PKG_NAME directory"
+ exit 1
+}
+
+(cd $srcdir;
+ gtkdocize || exit 1
+ mkdir -p m4
+ touch README NEWS ChangeLog
+ autoreconf --force --install --verbose
+ if test -z "$NOCONFIGURE"; then
+ ./configure --enable-maintainer-mode "$@"
+ fi
+)
diff --git a/build-aux/Makefile.am b/build-aux/Makefile.am
new file mode 100644
index 0000000..987cbaa
--- /dev/null
+++ b/build-aux/Makefile.am
@@ -0,0 +1,2 @@
+
+SUBDIRS = templates mbim-codegen
diff --git a/build-aux/mbim-codegen/Makefile.am b/build-aux/mbim-codegen/Makefile.am
new file mode 100644
index 0000000..9dc56aa
--- /dev/null
+++ b/build-aux/mbim-codegen/Makefile.am
@@ -0,0 +1,9 @@
+
+EXTRA_DIST = \
+ utils.py \
+ Struct.py \
+ Message.py \
+ ObjectList.py \
+ mbim-codegen
+
+CLEANFILES = *.pyc
diff --git a/build-aux/mbim-codegen/Message.py b/build-aux/mbim-codegen/Message.py
new file mode 100644
index 0000000..cbeb239
--- /dev/null
+++ b/build-aux/mbim-codegen/Message.py
@@ -0,0 +1,875 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+#
+
+import string
+import utils
+
+
+"""
+Flag the values which always need to be read
+"""
+def flag_always_read_field(fields, field_name):
+ for field in fields:
+ if field['name'] == field_name:
+ if field['format'] != 'guint32':
+ raise ValueError('Fields to always read \'%s\' must be a guint32' % field_name)
+ field['always-read'] = True
+ return
+ raise ValueError('Couldn\'t find field to always read \'%s\'' % field_name)
+
+
+"""
+Validate fields in the dictionary
+"""
+def validate_fields(fields):
+ for field in fields:
+ # Look for condition fields, which need to be always read
+ if 'available-if' in field:
+ condition = field['available-if']
+ flag_always_read_field(fields, condition['field'])
+
+ # Look for array size fields, which need to be always read
+ if field['format'] == 'byte-array':
+ pass
+ elif field['format'] == 'ref-byte-array':
+ pass
+ elif field['format'] == 'ref-byte-array-no-offset':
+ pass
+ elif field['format'] == 'unsized-byte-array':
+ pass
+ elif field['format'] == 'uuid':
+ pass
+ elif field['format'] == 'guint32':
+ pass
+ elif field['format'] == 'guint32-array':
+ flag_always_read_field(fields, field['array-size-field'])
+ elif field['format'] == 'guint64':
+ pass
+ elif field['format'] == 'guint64-array':
+ flag_always_read_field(fields, field['array-size-field'])
+ elif field['format'] == 'string':
+ pass
+ elif field['format'] == 'string-array':
+ flag_always_read_field(fields, field['array-size-field'])
+ elif field['format'] == 'struct':
+ if 'struct-type' not in field:
+ raise ValueError('Field type \'struct\' requires \'struct-type\' field')
+ elif field['format'] == 'struct-array':
+ flag_always_read_field(fields, field['array-size-field'])
+ if 'struct-type' not in field:
+ raise ValueError('Field type \'struct\' requires \'struct-type\' field')
+ elif field['format'] == 'ref-struct-array':
+ flag_always_read_field(fields, field['array-size-field'])
+ if 'struct-type' not in field:
+ raise ValueError('Field type \'struct\' requires \'struct-type\' field')
+ elif field['format'] == 'ipv4':
+ pass
+ elif field['format'] == 'ref-ipv4':
+ pass
+ elif field['format'] == 'ipv4-array':
+ flag_always_read_field(fields, field['array-size-field'])
+ elif field['format'] == 'ipv6':
+ pass
+ elif field['format'] == 'ref-ipv6':
+ pass
+ elif field['format'] == 'ipv6-array':
+ flag_always_read_field(fields, field['array-size-field'])
+ else:
+ raise ValueError('Cannot handle field type \'%s\'' % field['format'])
+
+
+"""
+The Message class takes care of all message handling
+"""
+class Message:
+
+ """
+ Constructor
+ """
+ def __init__(self, dictionary):
+ # The message service, e.g. "Basic Connect"
+ self.service = dictionary['service']
+
+ # The name of the specific message, e.g. "Something"
+ self.name = dictionary['name']
+
+ # Query
+ if 'query' in dictionary:
+ self.has_query = True
+ self.query = dictionary['query']
+ validate_fields(self.query)
+ else:
+ self.has_query = False
+ self.query = []
+
+ # Set
+ if 'set' in dictionary:
+ self.has_set = True
+ self.set = dictionary['set']
+ validate_fields(self.set)
+ else:
+ self.has_set = False
+ self.set = []
+
+
+ # Response
+ if 'response' in dictionary:
+ self.has_response = True
+ self.response = dictionary['response']
+ validate_fields(self.response)
+ else:
+ self.has_response = False
+ self.response = []
+
+ # Notification
+ if 'notification' in dictionary:
+ self.has_notification = True
+ self.notification = dictionary['notification']
+ validate_fields(self.notification)
+ else:
+ self.has_notification = False
+ self.notification = []
+
+ # Build Fullname
+ if self.service == 'Basic Connect':
+ self.fullname = 'MBIM Message ' + self.name
+ elif self.name == "":
+ self.fullname = 'MBIM Message ' + self.service
+ else:
+ self.fullname = 'MBIM Message ' + self.service + ' ' + self.name
+
+ # Build CID enum
+ self.cid_enum_name = 'MBIM CID ' + self.service
+ if self.name != "":
+ self.cid_enum_name += (' ' + self.name)
+ self.cid_enum_name = utils.build_underscore_name(self.cid_enum_name).upper()
+
+
+ """
+ Emit the message handling implementation
+ """
+ def emit(self, hfile, cfile):
+ if self.has_query:
+ utils.add_separator(hfile, 'Message (Query)', self.fullname);
+ utils.add_separator(cfile, 'Message (Query)', self.fullname);
+ self._emit_message_creator(hfile, cfile, 'query', self.query)
+
+ if self.has_set:
+ utils.add_separator(hfile, 'Message (Set)', self.fullname);
+ utils.add_separator(cfile, 'Message (Set)', self.fullname);
+ self._emit_message_creator(hfile, cfile, 'set', self.set)
+
+ if self.has_response:
+ utils.add_separator(hfile, 'Message (Response)', self.fullname);
+ utils.add_separator(cfile, 'Message (Response)', self.fullname);
+ self._emit_message_parser(hfile, cfile, 'response', self.response)
+
+ if self.has_notification:
+ utils.add_separator(hfile, 'Message (Notification)', self.fullname);
+ utils.add_separator(cfile, 'Message (Notification)', self.fullname);
+ self._emit_message_parser(hfile, cfile, 'notification', self.notification)
+
+
+ """
+ Emit message creator
+ """
+ def _emit_message_creator(self, hfile, cfile, message_type, fields):
+ translations = { 'message' : self.name,
+ 'service' : self.service,
+ 'underscore' : utils.build_underscore_name (self.fullname),
+ 'message_type' : message_type,
+ 'message_type_upper' : message_type.upper(),
+ 'service_underscore_upper' : utils.build_underscore_name (self.service).upper(),
+ 'cid_enum_name' : self.cid_enum_name }
+ template = (
+ '\n'
+ 'MbimMessage *${underscore}_${message_type}_new (\n')
+
+ for field in fields:
+ translations['field'] = utils.build_underscore_name_from_camelcase (field['name'])
+ translations['struct'] = field['struct-type'] if 'struct-type' in field else ''
+ translations['public'] = field['public-format'] if 'public-format' in field else field['format']
+
+ if field['format'] == 'byte-array':
+ inner_template = (' const guint8 *${field},\n')
+ elif field['format'] == 'unsized-byte-array' or \
+ field['format'] == 'ref-byte-array' or \
+ field['format'] == 'ref-byte-array-no-offset':
+ inner_template = (' const guint32 ${field}_size,\n'
+ ' const guint8 *${field},\n')
+ elif field['format'] == 'uuid':
+ inner_template = (' const MbimUuid *${field},\n')
+ elif field['format'] == 'guint32':
+ inner_template = (' ${public} ${field},\n')
+ elif field['format'] == 'guint32-array':
+ inner_template = (' const ${public} *${field},\n')
+ elif field['format'] == 'guint64':
+ inner_template = (' ${public} ${field},\n')
+ elif field['format'] == 'guint64-array':
+ inner_template = (' const ${public} *${field},\n')
+ elif field['format'] == 'string':
+ inner_template = (' const gchar *${field},\n')
+ elif field['format'] == 'string-array':
+ inner_template = (' const gchar *const *${field},\n')
+ elif field['format'] == 'struct':
+ inner_template = (' const ${struct} *${field},\n')
+ elif field['format'] == 'struct-array':
+ inner_template = (' const ${struct} *const *${field},\n')
+ elif field['format'] == 'ref-struct-array':
+ inner_template = (' const ${struct} *const *${field},\n')
+ elif field['format'] == 'ipv4':
+ inner_template = (' const MbimIPv4 *${field},\n')
+ elif field['format'] == 'ref-ipv4':
+ inner_template = (' const MbimIPv4 *${field},\n')
+ elif field['format'] == 'ipv4-array':
+ inner_template = (' const MbimIPv4 *${field},\n')
+ elif field['format'] == 'ipv6':
+ inner_template = (' const MbimIPv6 *${field},\n')
+ elif field['format'] == 'ref-ipv6':
+ inner_template = (' const MbimIPv6 *${field},\n')
+ elif field['format'] == 'ipv6-array':
+ inner_template = (' const MbimIPv6 *${field},\n')
+
+ template += (string.Template(inner_template).substitute(translations))
+
+ template += (
+ ' GError **error);\n')
+ hfile.write(string.Template(template).substitute(translations))
+
+ template = (
+ '\n'
+ '/**\n'
+ ' * ${underscore}_${message_type}_new:\n')
+
+ for field in fields:
+ translations['name'] = field['name']
+ translations['field'] = utils.build_underscore_name_from_camelcase (field['name'])
+ translations['struct'] = field['struct-type'] if 'struct-type' in field else ''
+ translations['public'] = field['public-format'] if 'public-format' in field else field['format']
+ translations['array_size'] = field['array-size'] if 'array-size' in field else ''
+
+ if field['format'] == 'byte-array':
+ inner_template = (' * @${field}: the \'${name}\' field, given as an array of ${array_size} #guint8 values.\n')
+ elif field['format'] == 'unsized-byte-array' or \
+ field['format'] == 'ref-byte-array' or \
+ field['format'] == 'ref-byte-array-no-offset':
+ inner_template = (' * @${field}_size: size of the ${field} array.\n'
+ ' * @${field}: the \'${name}\' field, given as an array of #guint8 values.\n')
+ elif field['format'] == 'uuid':
+ inner_template = (' * @${field}: the \'${name}\' field, given as a #MbimUuid.\n')
+ elif field['format'] == 'guint32':
+ inner_template = (' * @${field}: the \'${name}\' field, given as a #${public}.\n')
+ elif field['format'] == 'guint32-array':
+ inner_template = (' * @${field}: the \'${name}\' field, given as an array of #${public}.\n')
+ elif field['format'] == 'guint64':
+ inner_template = (' * @${field}: the \'${name}\' field, given as a #${public}.\n')
+ elif field['format'] == 'guint64-array':
+ inner_template = (' * @${field}: the \'${name}\' field, given as an array of #${public}.\n')
+ elif field['format'] == 'string':
+ inner_template = (' * @${field}: the \'${name}\' field, given as a string.\n')
+ elif field['format'] == 'string-array':
+ inner_template = (' * @${field}: the \'${name}\' field, given as an array of strings.\n')
+ elif field['format'] == 'struct':
+ inner_template = (' * @${field}: the \'${name}\' field, given as a #${struct}.\n')
+ elif field['format'] == 'struct-array':
+ inner_template = (' * @${field}: the \'${name}\' field, given as an array of #${struct}s.\n')
+ elif field['format'] == 'ref-struct-array':
+ inner_template = (' * @${field}: the \'${name}\' field, given as an array of #${struct}s.\n')
+ elif field['format'] == 'ipv4':
+ inner_template = (' * @${field}: the \'${name}\' field, given as a #MbimIPv4.\n')
+ elif field['format'] == 'ref-ipv4':
+ inner_template = (' * @${field}: the \'${name}\' field, given as a #MbimIPv4.\n')
+ elif field['format'] == 'ipv4-array':
+ inner_template = (' * @${field}: the \'${name}\' field, given as an array of #MbimIPv4.\n')
+ elif field['format'] == 'ipv6':
+ inner_template = (' * @${field}: the \'${name}\' field, given as a #MbimIPv6.\n')
+ elif field['format'] == 'ref-ipv6':
+ inner_template = (' * @${field}: the \'${name}\' field, given as a #MbimIPv6.\n')
+ elif field['format'] == 'ipv6-array':
+ inner_template = (' * @${field}: the \'${name}\' field, given as an array of #MbimIPv6.\n')
+
+ template += (string.Template(inner_template).substitute(translations))
+
+ template += (
+ ' * @error: return location for error or %NULL.\n'
+ ' *\n'
+ ' * Create a new request for the \'${message}\' ${message_type} command in the \'${service}\' service.\n'
+ ' *\n'
+ ' * Returns: a newly allocated #MbimMessage, which should be freed with mbim_message_unref().\n'
+ ' */\n'
+ 'MbimMessage *\n'
+ '${underscore}_${message_type}_new (\n')
+
+ for field in fields:
+ translations['field'] = utils.build_underscore_name_from_camelcase (field['name'])
+ translations['struct'] = field['struct-type'] if 'struct-type' in field else ''
+ translations['public'] = field['public-format'] if 'public-format' in field else field['format']
+ translations['array_size'] = field['array-size'] if 'array-size' in field else ''
+
+ if field['format'] == 'byte-array':
+ inner_template = (' const guint8 *${field},\n')
+ elif field['format'] == 'unsized-byte-array' or \
+ field['format'] == 'ref-byte-array' or \
+ field['format'] == 'ref-byte-array-no-offset':
+ inner_template = (' const guint32 ${field}_size,\n'
+ ' const guint8 *${field},\n')
+ elif field['format'] == 'uuid':
+ inner_template = (' const MbimUuid *${field},\n')
+ elif field['format'] == 'guint32':
+ inner_template = (' ${public} ${field},\n')
+ elif field['format'] == 'guint32-array':
+ inner_template = (' const ${public} *${field},\n')
+ elif field['format'] == 'guint64':
+ inner_template = (' ${public} ${field},\n')
+ elif field['format'] == 'guint64-array':
+ inner_template = (' const ${public} *${field},\n')
+ elif field['format'] == 'string':
+ inner_template = (' const gchar *${field},\n')
+ elif field['format'] == 'string-array':
+ inner_template = (' const gchar *const *${field},\n')
+ elif field['format'] == 'struct':
+ inner_template = (' const ${struct} *${field},\n')
+ elif field['format'] == 'struct-array':
+ inner_template = (' const ${struct} *const *${field},\n')
+ elif field['format'] == 'ref-struct-array':
+ inner_template = (' const ${struct} *const *${field},\n')
+ elif field['format'] == 'ipv4':
+ inner_template = (' const MbimIPv4 *${field},\n')
+ elif field['format'] == 'ref-ipv4':
+ inner_template = (' const MbimIPv4 *${field},\n')
+ elif field['format'] == 'ipv4-array':
+ inner_template = (' const MbimIPv4 *${field},\n')
+ elif field['format'] == 'ipv6':
+ inner_template = (' const MbimIPv6 *${field},\n')
+ elif field['format'] == 'ref-ipv6':
+ inner_template = (' const MbimIPv6 *${field},\n')
+ elif field['format'] == 'ipv6-array':
+ inner_template = (' const MbimIPv6 *${field},\n')
+
+ template += (string.Template(inner_template).substitute(translations))
+
+ template += (
+ ' GError **error)\n'
+ '{\n'
+ ' MbimMessageCommandBuilder *builder;\n'
+ '\n'
+ ' builder = _mbim_message_command_builder_new (0,\n'
+ ' MBIM_SERVICE_${service_underscore_upper},\n'
+ ' ${cid_enum_name},\n'
+ ' MBIM_MESSAGE_COMMAND_TYPE_${message_type_upper});\n')
+
+ for field in fields:
+ translations['field'] = utils.build_underscore_name_from_camelcase(field['name'])
+ translations['array_size_field'] = utils.build_underscore_name_from_camelcase(field['array-size-field']) if 'array-size-field' in field else ''
+ translations['struct'] = field['struct-type'] if 'struct-type' in field else ''
+ translations['struct_underscore'] = utils.build_underscore_name_from_camelcase (translations['struct'])
+ translations['array_size'] = field['array-size'] if 'array-size' in field else ''
+
+ inner_template = ''
+ if 'available-if' in field:
+ condition = field['available-if']
+ translations['condition_field'] = utils.build_underscore_name_from_camelcase(condition['field'])
+ translations['condition_operation'] = condition['operation']
+ translations['condition_value'] = condition['value']
+ inner_template += (
+ ' if (${condition_field} ${condition_operation} ${condition_value}) {\n')
+ else:
+ inner_template += (' {\n')
+
+ if field['format'] == 'byte-array':
+ inner_template += (' _mbim_message_command_builder_append_byte_array (builder, FALSE, FALSE, ${field}, ${array_size});\n')
+ elif field['format'] == 'unsized-byte-array':
+ inner_template += (' _mbim_message_command_builder_append_byte_array (builder, FALSE, FALSE, ${field}, ${field}_size);\n')
+ elif field['format'] == 'ref-byte-array':
+ inner_template += (' _mbim_message_command_builder_append_byte_array (builder, TRUE, TRUE, ${field}, ${field}_size);\n')
+ elif field['format'] == 'ref-byte-array-no-offset':
+ inner_template += (' _mbim_message_command_builder_append_byte_array (builder, FALSE, TRUE, ${field}, ${field}_size);\n')
+ elif field['format'] == 'uuid':
+ inner_template += (' _mbim_message_command_builder_append_uuid (builder, ${field});\n')
+ elif field['format'] == 'guint32':
+ inner_template += (' _mbim_message_command_builder_append_guint32 (builder, ${field});\n')
+ elif field['format'] == 'guint32-array':
+ inner_template += (' _mbim_message_command_builder_append_guint32_array (builder, ${field}, ${array_size_field});\n')
+ elif field['format'] == 'guint64':
+ inner_template += (' _mbim_message_command_builder_append_guint64 (builder, ${field});\n')
+ elif field['format'] == 'string':
+ inner_template += (' _mbim_message_command_builder_append_string (builder, ${field});\n')
+ elif field['format'] == 'string-array':
+ inner_template += (' _mbim_message_command_builder_append_string_array (builder, ${field}, ${array_size_field});\n')
+ elif field['format'] == 'struct':
+ inner_template += (' _mbim_message_command_builder_append_${struct_underscore}_struct (builder, ${field});\n')
+ elif field['format'] == 'struct-array':
+ inner_template += (' _mbim_message_command_builder_append_${struct_underscore}_struct_array (builder, ${field}, ${array_size_field}, FALSE);\n')
+ elif field['format'] == 'ref-struct-array':
+ inner_template += (' _mbim_message_command_builder_append_${struct_underscore}_struct_array (builder, ${field}, ${array_size_field}, TRUE);\n')
+ elif field['format'] == 'ipv4':
+ inner_template += (' _mbim_message_command_builder_append_ipv4 (builder, ${field}, FALSE);\n')
+ elif field['format'] == 'ref-ipv4':
+ inner_template += (' _mbim_message_command_builder_append_ipv4 (builder, ${field}, TRUE);\n')
+ elif field['format'] == 'ipv4-array':
+ inner_template += (' _mbim_message_command_builder_append_ipv4_array (builder, ${field}, ${array_size_field});\n')
+ elif field['format'] == 'ipv6':
+ inner_template += (' _mbim_message_command_builder_append_ipv6 (builder, ${field}, FALSE);\n')
+ elif field['format'] == 'ref-ipv6':
+ inner_template += (' _mbim_message_command_builder_append_ipv6 (builder, ${field}, TRUE);\n')
+ elif field['format'] == 'ipv6-array':
+ inner_template += (' _mbim_message_command_builder_append_ipv6_array (builder, ${field}, ${array_size_field});\n')
+ else:
+ raise ValueError('Cannot handle field type \'%s\'' % field['format'])
+
+ inner_template += (' }\n')
+
+ template += (string.Template(inner_template).substitute(translations))
+
+ template += (
+ '\n'
+ ' return _mbim_message_command_builder_complete (builder);\n'
+ '}\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+
+ """
+ Emit message parser
+ """
+ def _emit_message_parser(self, hfile, cfile, message_type, fields):
+ translations = { 'name' : self.name,
+ 'service' : self.service,
+ 'underscore' : utils.build_underscore_name (self.fullname),
+ 'message_type' : message_type,
+ 'message_type_upper' : message_type.upper(),
+ 'service_underscore_upper' : utils.build_underscore_name (self.service).upper() }
+ template = (
+ '\n'
+ 'gboolean ${underscore}_${message_type}_parse (\n'
+ ' const MbimMessage *message,\n')
+
+ for field in fields:
+ translations['field'] = utils.build_underscore_name_from_camelcase(field['name'])
+ translations['public'] = field['public-format'] if 'public-format' in field else field['format']
+ translations['struct'] = field['struct-type'] if 'struct-type' in field else ''
+
+ if field['format'] == 'byte-array':
+ inner_template = (' const guint8 **${field},\n')
+ elif field['format'] == 'unsized-byte-array' or field['format'] == 'ref-byte-array':
+ inner_template = (' guint32 *${field}_size,\n'
+ ' const guint8 **${field},\n')
+ elif field['format'] == 'uuid':
+ inner_template = (' const MbimUuid **${field},\n')
+ elif field['format'] == 'guint32':
+ inner_template = (' ${public} *${field},\n')
+ elif field['format'] == 'guint32-array':
+ inner_template = (' ${public} **${field},\n')
+ elif field['format'] == 'guint64':
+ inner_template = (' ${public} *${field},\n')
+ elif field['format'] == 'guint64-array':
+ inner_template = (' ${public} **${field},\n')
+ elif field['format'] == 'string':
+ inner_template = (' gchar **${field},\n')
+ elif field['format'] == 'string-array':
+ inner_template = (' gchar ***${field},\n')
+ elif field['format'] == 'struct':
+ inner_template = (' ${struct} **${field},\n')
+ elif field['format'] == 'struct-array':
+ inner_template = (' ${struct} ***${field},\n')
+ elif field['format'] == 'ref-struct-array':
+ inner_template = (' ${struct} ***${field},\n')
+ elif field['format'] == 'ipv4':
+ inner_template = (' const MbimIPv4 **${field},\n')
+ elif field['format'] == 'ref-ipv4':
+ inner_template = (' const MbimIPv4 **${field},\n')
+ elif field['format'] == 'ipv4-array':
+ inner_template = (' MbimIPv4 **${field},\n')
+ elif field['format'] == 'ipv6':
+ inner_template = (' const MbimIPv6 **${field},\n')
+ elif field['format'] == 'ref-ipv6':
+ inner_template = (' const MbimIPv6 **${field},\n')
+ elif field['format'] == 'ipv6-array':
+ inner_template = (' MbimIPv6 **${field},\n')
+ else:
+ raise ValueError('Cannot handle field type \'%s\'' % field['format'])
+
+ template += (string.Template(inner_template).substitute(translations))
+
+ template += (
+ ' GError **error);\n')
+ hfile.write(string.Template(template).substitute(translations))
+
+ template = (
+ '\n'
+ '/**\n'
+ ' * ${underscore}_${message_type}_parse:\n'
+ ' * @message: the #MbimMessage.\n')
+
+ for field in fields:
+ translations['field'] = utils.build_underscore_name_from_camelcase(field['name'])
+ translations['name'] = field['name']
+ translations['public'] = field['public-format'] if 'public-format' in field else field['format']
+ translations['struct'] = field['struct-type'] if 'struct-type' in field else ''
+ translations['struct_underscore'] = utils.build_underscore_name_from_camelcase (translations['struct'])
+ translations['array_size'] = field['array-size'] if 'array-size' in field else ''
+
+ if field['format'] == 'byte-array':
+ inner_template = (' * @${field}: return location for an array of ${array_size} #guint8 values. Do not free the returned value, it is owned by @message.\n')
+ elif field['format'] == 'unsized-byte-array' or field['format'] == 'ref-byte-array':
+ inner_template = (' * @${field}_size: return location for the size of the ${field} array.\n'
+ ' * @${field}: return location for an array of #guint8 values. Do not free the returned value, it is owned by @message.\n')
+ elif field['format'] == 'uuid':
+ inner_template = (' * @${field}: return location for a #MbimUuid, or %NULL if the \'${name}\' field is not needed. Do not free the returned value, it is owned by @message.\n')
+ elif field['format'] == 'guint32':
+ inner_template = (' * @${field}: return location for a #${public}, or %NULL if the \'${name}\' field is not needed.\n')
+ elif field['format'] == 'guint32-array':
+ inner_template = (' * @${field}: return location for a newly allocated array of #${public}s, or %NULL if the \'${name}\' field is not needed. Free the returned value with g_free().\n')
+ elif field['format'] == 'guint64':
+ inner_template = (' * @${field}: return location for a #guint64, or %NULL if the \'${name}\' field is not needed.\n')
+ elif field['format'] == 'guint64-array':
+ inner_template = (' * @${field}: return location for a newly allocated array of #guint64s, or %NULL if the \'${name}\' field is not needed. Free the returned value with g_free().\n')
+ elif field['format'] == 'string':
+ inner_template = (' * @${field}: return location for a newly allocated string, or %NULL if the \'${name}\' field is not needed. Free the returned value with g_free().\n')
+ elif field['format'] == 'string-array':
+ inner_template = (' * @${field}: return location for a newly allocated array of strings, or %NULL if the \'${name}\' field is not needed. Free the returned value with g_strfreev().\n')
+ elif field['format'] == 'struct':
+ inner_template = (' * @${field}: return location for a newly allocated #${struct}, or %NULL if the \'${name}\' field is not needed. Free the returned value with ${struct_underscore}_free().\n')
+ elif field['format'] == 'struct-array':
+ inner_template = (' * @${field}: return location for a newly allocated array of #${struct}s, or %NULL if the \'${name}\' field is not needed. Free the returned value with ${struct_underscore}_array_free().\n')
+ elif field['format'] == 'ref-struct-array':
+ inner_template = (' * @${field}: return location for a newly allocated array of #${struct}s, or %NULL if the \'${name}\' field is not needed. Free the returned value with ${struct_underscore}_array_free().\n')
+ elif field['format'] == 'ipv4':
+ inner_template = (' * @${field}: return location for a #MbimIPv4, or %NULL if the \'${name}\' field is not needed. Do not free the returned value, it is owned by @message.\n')
+ elif field['format'] == 'ref-ipv4':
+ inner_template = (' * @${field}: return location for a #MbimIPv4, or %NULL if the \'${name}\' field is not needed. Do not free the returned value, it is owned by @message.\n')
+ elif field['format'] == 'ipv4-array':
+ inner_template = (' * @${field}: return location for a newly allocated array of #MbimIPv4s, or %NULL if the \'${name}\' field is not needed. Free the returned value with g_free().\n')
+ elif field['format'] == 'ipv6':
+ inner_template = (' * @${field}: return location for a #MbimIPv6, or %NULL if the \'${name}\' field is not needed. Do not free the returned value, it is owned by @message.\n')
+ elif field['format'] == 'ref-ipv6':
+ inner_template = (' * @${field}: return location for a #MbimIPv6, or %NULL if the \'${name}\' field is not needed. Do not free the returned value, it is owned by @message.\n')
+ elif field['format'] == 'ipv6-array':
+ inner_template = (' * @${field}: return location for a newly allocated array of #MbimIPv6s, or %NULL if the \'${name}\' field is not needed. Free the returned value with g_free().\n')
+
+ template += (string.Template(inner_template).substitute(translations))
+
+ template += (
+ ' * @error: return location for error or %NULL.\n'
+ ' *\n'
+ ' * Create a new request for the \'${name}\' ${message_type} command in the \'${service}\' service.\n'
+ ' *\n'
+ ' * Returns: %TRUE if the message was correctly parsed, %FALSE if @error is set.\n'
+ ' */\n'
+ 'gboolean\n'
+ '${underscore}_${message_type}_parse (\n'
+ ' const MbimMessage *message,\n')
+
+ for field in fields:
+ translations['field'] = utils.build_underscore_name_from_camelcase(field['name'])
+ translations['public'] = field['public-format'] if 'public-format' in field else field['format']
+ translations['struct'] = field['struct-type'] if 'struct-type' in field else ''
+
+ if field['format'] == 'byte-array':
+ inner_template = (' const guint8 **${field},\n')
+ elif field['format'] == 'unsized-byte-array' or field['format'] == 'ref-byte-array':
+ inner_template = (' guint32 *${field}_size,\n'
+ ' const guint8 **${field},\n')
+ elif field['format'] == 'uuid':
+ inner_template = (' const MbimUuid **${field},\n')
+ elif field['format'] == 'guint32':
+ inner_template = (' ${public} *${field},\n')
+ elif field['format'] == 'guint32-array':
+ inner_template = (' ${public} **${field},\n')
+ elif field['format'] == 'guint64':
+ inner_template = (' ${public} *${field},\n')
+ elif field['format'] == 'guint64-array':
+ inner_template = (' ${public} **${field},\n')
+ elif field['format'] == 'string':
+ inner_template = (' gchar **${field},\n')
+ elif field['format'] == 'string-array':
+ inner_template = (' gchar ***${field},\n')
+ elif field['format'] == 'struct':
+ inner_template = (' ${struct} **${field},\n')
+ elif field['format'] == 'struct-array':
+ inner_template = (' ${struct} ***${field},\n')
+ elif field['format'] == 'ref-struct-array':
+ inner_template = (' ${struct} ***${field},\n')
+ elif field['format'] == 'ipv4':
+ inner_template = (' const MbimIPv4 **${field},\n')
+ elif field['format'] == 'ref-ipv4':
+ inner_template = (' const MbimIPv4 **${field},\n')
+ elif field['format'] == 'ipv4-array':
+ inner_template = (' MbimIPv4 **${field},\n')
+ elif field['format'] == 'ipv6':
+ inner_template = (' const MbimIPv6 **${field},\n')
+ elif field['format'] == 'ref-ipv6':
+ inner_template = (' const MbimIPv6 **${field},\n')
+ elif field['format'] == 'ipv6-array':
+ inner_template = (' MbimIPv6 **${field},\n')
+
+ template += (string.Template(inner_template).substitute(translations))
+
+ template += (
+ ' GError **error)\n'
+ '{\n')
+
+ if fields != []:
+ template += (
+ ' guint32 offset = 0;\n')
+
+ for field in fields:
+ if 'always-read' in field:
+ translations['field'] = utils.build_underscore_name_from_camelcase(field['name'])
+ inner_template = (' guint32 _${field};\n')
+ template += (string.Template(inner_template).substitute(translations))
+
+ if message_type == 'response':
+ template += (
+ '\n'
+ ' if (mbim_message_get_message_type (message) != MBIM_MESSAGE_TYPE_COMMAND_DONE) {\n'
+ ' g_set_error (error,\n'
+ ' MBIM_CORE_ERROR,\n'
+ ' MBIM_CORE_ERROR_INVALID_MESSAGE,\n'
+ ' \"Message is not a response\");\n'
+ ' return FALSE;\n'
+ ' }\n')
+ elif message_type == 'notification':
+ template += (
+ '\n'
+ ' if (mbim_message_get_message_type (message) != MBIM_MESSAGE_TYPE_INDICATE_STATUS) {\n'
+ ' g_set_error (error,\n'
+ ' MBIM_CORE_ERROR,\n'
+ ' MBIM_CORE_ERROR_INVALID_MESSAGE,\n'
+ ' \"Message is not a notification\");\n'
+ ' return FALSE;\n'
+ ' }\n')
+ else:
+ raise ValueError('Unexpected message type \'%s\'' % message_type)
+
+ for field in fields:
+ translations['field'] = utils.build_underscore_name_from_camelcase(field['name'])
+ translations['field_format_underscore'] = utils.build_underscore_name_from_camelcase(field['format'])
+ translations['field_name'] = field['name']
+ translations['array_size_field'] = utils.build_underscore_name_from_camelcase(field['array-size-field']) if 'array-size-field' in field else ''
+ translations['struct_name'] = utils.build_underscore_name_from_camelcase(field['struct-type']) if 'struct-type' in field else ''
+ translations['struct_type'] = field['struct-type'] if 'struct-type' in field else ''
+ translations['array_size'] = field['array-size'] if 'array-size' in field else ''
+
+ inner_template = (
+ '\n'
+ ' /* Read the \'${field_name}\' variable */\n')
+ if 'available-if' in field:
+ condition = field['available-if']
+ translations['condition_field'] = utils.build_underscore_name_from_camelcase(condition['field'])
+ translations['condition_operation'] = condition['operation']
+ translations['condition_value'] = condition['value']
+ inner_template += (
+ ' if (!(_${condition_field} ${condition_operation} ${condition_value})) {\n')
+ if field['format'] == 'byte-array':
+ inner_template += (
+ ' if (${field})\n'
+ ' *${field} = NULL;\n')
+ elif field['format'] == 'unsized-byte-array' or \
+ field['format'] == 'ref-byte-array':
+ inner_template += (
+ ' if (${field}_size)\n'
+ ' *${field}_size = 0;\n'
+ ' if (${field})\n'
+ ' *${field} = NULL;\n')
+ elif field['format'] == 'guint32-array' or \
+ field['format'] == 'string' or \
+ field['format'] == 'string-array' or \
+ field['format'] == 'struct' or \
+ field['format'] == 'struct-array' or \
+ field['format'] == 'ref-struct-array' or \
+ field['format'] == 'ipv4' or \
+ field['format'] == 'ref-ipv4' or \
+ field['format'] == 'ipv4-array' or \
+ field['format'] == 'ipv6' or \
+ field['format'] == 'ref-ipv6' or \
+ field['format'] == 'ipv6-array':
+ inner_template += (
+ ' if (${field} != NULL)\n'
+ ' *${field} = NULL;\n')
+ else:
+ raise ValueError('Field format \'%s\' unsupported as optional field' % field['format'])
+
+ inner_template += (
+ ' } else {\n')
+ else:
+ inner_template += (
+ ' {\n')
+
+ if 'always-read' in field:
+ inner_template += (
+ ' _${field} = _mbim_message_read_guint32 (message, offset);\n'
+ ' if (${field} != NULL)\n'
+ ' *${field} = _${field};\n'
+ ' offset += 4;\n')
+ elif field['format'] == 'byte-array':
+ inner_template += (
+ ' const guint8 *tmp;\n'
+ '\n'
+ ' tmp = _mbim_message_read_byte_array (message, 0, offset, FALSE, FALSE, NULL);\n'
+ ' if (${field} != NULL)\n'
+ ' *${field} = tmp;\n'
+ ' offset += ${array_size};\n')
+ elif field['format'] == 'unsized-byte-array':
+ inner_template += (
+ ' const guint8 *tmp;\n'
+ ' guint32 tmpsize;\n'
+ '\n'
+ ' tmp = _mbim_message_read_byte_array (message, 0, offset, FALSE, FALSE, &tmpsize);\n'
+ ' if (${field} != NULL)\n'
+ ' *${field} = tmp;\n'
+ ' if (${field}_size != NULL)\n'
+ ' *${field}_size = tmpsize;\n'
+ ' offset += tmpsize;\n')
+ elif field['format'] == 'ref-byte-array':
+ inner_template += (
+ ' const guint8 *tmp;\n'
+ ' guint32 tmpsize;\n'
+ '\n'
+ ' tmp = _mbim_message_read_byte_array (message, 0, offset, TRUE, TRUE, &tmpsize);\n'
+ ' if (${field} != NULL)\n'
+ ' *${field} = tmp;\n'
+ ' if (${field}_size != NULL)\n'
+ ' *${field}_size = tmpsize;\n'
+ ' offset += 8;\n')
+ elif field['format'] == 'uuid':
+ inner_template += (
+ ' if (${field} != NULL)\n'
+ ' *${field} = _mbim_message_read_uuid (message, offset);\n'
+ ' offset += 16;\n')
+ elif field['format'] == 'guint32':
+ inner_template += (
+ ' if (${field} != NULL)\n'
+ ' *${field} = _mbim_message_read_guint32 (message, offset);\n'
+ ' offset += 4;\n')
+ elif field['format'] == 'guint32-array':
+ inner_template += (
+ ' if (${field} != NULL)\n'
+ ' *${field} = _mbim_message_read_guint32_array (message, _{array_size_field}, offset);\n'
+ ' offset += (4 * _${array_size_field});\n')
+ elif field['format'] == 'guint64':
+ inner_template += (
+ ' if (${field} != NULL)\n'
+ ' *${field} = _mbim_message_read_guint64 (message, offset);\n'
+ ' offset += 8;\n')
+ elif field['format'] == 'string':
+ inner_template += (
+ ' if (${field} != NULL)\n'
+ ' *${field} = _mbim_message_read_string (message, 0, offset);\n'
+ ' offset += 8;\n')
+ elif field['format'] == 'string-array':
+ inner_template += (
+ ' if (${field} != NULL)\n'
+ ' *${field} = _mbim_message_read_string_array (message, _${array_size_field}, 0, offset);\n'
+ ' offset += (8 * _${array_size_field});\n')
+ elif field['format'] == 'struct':
+ inner_template += (
+ ' ${struct_type} *tmp;\n'
+ ' guint32 bytes_read = 0;\n'
+ '\n'
+ ' tmp = _mbim_message_read_${struct_name}_struct (message, offset, &bytes_read);\n'
+ ' if (${field} != NULL)\n'
+ ' *${field} = tmp;\n'
+ ' else\n'
+ ' _${struct_name}_free (tmp);\n'
+ ' offset += bytes_read;\n')
+ elif field['format'] == 'struct-array':
+ inner_template += (
+ ' if (${field} != NULL)\n'
+ ' *${field} = _mbim_message_read_${struct_name}_struct_array (message, _${array_size_field}, offset, FALSE);\n'
+ ' offset += 4;\n')
+ elif field['format'] == 'ref-struct-array':
+ inner_template += (
+ ' if (${field} != NULL)\n'
+ ' *${field} = _mbim_message_read_${struct_name}_struct_array (message, _${array_size_field}, offset, TRUE);\n'
+ ' offset += (8 * _${array_size_field});\n')
+ elif field['format'] == 'ipv4':
+ inner_template += (
+ ' if (${field} != NULL)\n'
+ ' *${field} = _mbim_message_read_ipv4 (message, offset, FALSE);\n'
+ ' offset += 4;\n')
+ elif field['format'] == 'ref-ipv4':
+ inner_template += (
+ ' if (${field} != NULL)\n'
+ ' *${field} = _mbim_message_read_ipv4 (message, offset, TRUE);\n'
+ ' offset += 4;\n')
+ elif field['format'] == 'ipv4-array':
+ inner_template += (
+ ' if (${field} != NULL)\n'
+ ' *${field} = _mbim_message_read_ipv4_array (message, _${array_size_field}, offset);\n'
+ ' offset += 4;\n')
+ elif field['format'] == 'ipv6':
+ inner_template += (
+ ' if (${field} != NULL)\n'
+ ' *${field} = _mbim_message_read_ipv6 (message, offset, FALSE);\n'
+ ' offset += 4;\n')
+ elif field['format'] == 'ref-ipv6':
+ inner_template += (
+ ' if (${field} != NULL)\n'
+ ' *${field} = _mbim_message_read_ipv6 (message, offset, TRUE);\n'
+ ' offset += 4;\n')
+ elif field['format'] == 'ipv6-array':
+ inner_template += (
+ ' if (${field} != NULL)\n'
+ ' *${field} = _mbim_message_read_ipv6_array (message, _${array_size_field}, offset);\n'
+ ' offset += 4;\n')
+
+ inner_template += (
+ ' }\n')
+
+ template += (string.Template(inner_template).substitute(translations))
+
+ template += (
+ '\n'
+ ' return TRUE;\n'
+ '}\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+
+ """
+ Emit the section content
+ """
+ def emit_section_content(self, sfile):
+ translations = { 'name_dashed' : utils.build_dashed_name(self.name),
+ 'underscore' : utils.build_underscore_name(self.fullname) }
+
+ template = (
+ '\n'
+ '<SUBSECTION ${name_dashed}>\n')
+ sfile.write(string.Template(template).substitute(translations))
+
+ if self.has_query:
+ template = (
+ '${underscore}_query_new\n')
+ sfile.write(string.Template(template).substitute(translations))
+
+ if self.has_set:
+ template = (
+ '${underscore}_set_new\n')
+ sfile.write(string.Template(template).substitute(translations))
+
+ if self.has_response:
+ template = (
+ '${underscore}_response_parse\n')
+ sfile.write(string.Template(template).substitute(translations))
+
+ if self.has_notification:
+ template = (
+ '${underscore}_notification_parse\n')
+ sfile.write(string.Template(template).substitute(translations))
diff --git a/build-aux/mbim-codegen/ObjectList.py b/build-aux/mbim-codegen/ObjectList.py
new file mode 100644
index 0000000..ddb5a68
--- /dev/null
+++ b/build-aux/mbim-codegen/ObjectList.py
@@ -0,0 +1,115 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+#
+
+import string
+
+from Message import Message
+from Struct import Struct
+import utils
+
+"""
+Check field to see if it holds a struct
+"""
+def set_struct_usage(struct, fields):
+ for field in fields:
+ if field['format'] == 'struct' and field['struct-type'] == struct.name:
+ struct.single_member = True
+ break
+ if field['format'] == 'ref-struct-array' and field['struct-type'] == struct.name:
+ struct.array_member = True
+ break
+ if field['format'] == 'struct-array' and field['struct-type'] == struct.name:
+ struct.array_member = True
+ break
+
+
+"""
+The ObjectList class handles the generation of all commands and types for a given
+specific service
+"""
+class ObjectList:
+
+ """
+ Constructor
+ """
+ def __init__(self, objects_dictionary):
+ self.command_list = []
+ self.struct_list = []
+ self.service = ''
+
+ # Loop items in the list, creating Message objects for the messages
+ for object_dictionary in objects_dictionary:
+ if object_dictionary['type'] == 'Command':
+ self.command_list.append(Message(object_dictionary))
+ elif object_dictionary['type'] == 'Struct':
+ self.struct_list.append(Struct(object_dictionary))
+ elif object_dictionary['type'] == 'Service':
+ self.service = object_dictionary['name']
+ else:
+ raise ValueError('Cannot handle object type \'%s\'' % object_dictionary['type'])
+
+ if self.service == '':
+ raise ValueError('Service name not specified')
+
+ # Populate struct usages
+ for struct in self.struct_list:
+ for command in self.command_list:
+ set_struct_usage(struct, command.query)
+ set_struct_usage(struct, command.set)
+ set_struct_usage(struct, command.response)
+ set_struct_usage(struct, command.notification)
+
+ """
+ Emit the structs and commands handling implementation
+ """
+ def emit(self, hfile, cfile):
+ # Emit all structs
+ for item in self.struct_list:
+ item.emit(hfile, cfile)
+ # Emit all commands
+ for item in self.command_list:
+ item.emit(hfile, cfile)
+
+
+ """
+ Emit the sections
+ """
+ def emit_sections(self, sfile):
+ translations = { 'service_dashed' : utils.build_dashed_name(self.service),
+ 'service' : self.service }
+
+ # Emit section header
+ template = (
+ '\n'
+ '<SECTION>\n'
+ '<FILE>mbim-${service_dashed}</FILE>\n'
+ '<TITLE>${service}</TITLE>\n')
+ sfile.write(string.Template(template).substitute(translations))
+
+ # Emit subsection per type
+ for struct in self.struct_list:
+ struct.emit_section_content(sfile)
+
+ # Emit subsection per command
+ for command in self.command_list:
+ command.emit_section_content(sfile)
+
+ sfile.write(
+ '</SECTION>\n')
diff --git a/build-aux/mbim-codegen/Struct.py b/build-aux/mbim-codegen/Struct.py
new file mode 100644
index 0000000..afe2ba5
--- /dev/null
+++ b/build-aux/mbim-codegen/Struct.py
@@ -0,0 +1,688 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil -*-
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+#
+
+import string
+
+import utils
+
+"""
+The Struct class takes care of emitting the struct type
+"""
+class Struct:
+
+ """
+ Constructor
+ """
+ def __init__(self, dictionary):
+ self.name = dictionary['name']
+ self.contents = dictionary['contents']
+
+ # Whether the struct is used as a single field, or as an array of
+ # fields. Will be updated after having created the object.
+ self.single_member = False
+ self.array_member = False
+
+ # Check whether the struct is composed of fixed-sized fields
+ self.size = 0
+ for field in self.contents:
+ if field['format'] == 'guint32':
+ self.size += 4
+ elif field['format'] == 'guint64':
+ self.size += 8
+ elif field['format'] == 'uuid':
+ self.size += 16
+ elif field['format'] == 'ipv4':
+ self.size += 4
+ elif field['format'] == 'ipv6':
+ self.size += 16
+ else:
+ self.size = 0
+ break
+
+
+ """
+ Emit the new struct type
+ """
+ def _emit_type(self, hfile):
+ translations = { 'name' : self.name }
+ template = (
+ '\n'
+ '/**\n'
+ ' * ${name}:\n')
+ for field in self.contents:
+ translations['field_name_underscore'] = utils.build_underscore_name_from_camelcase(field['name'])
+ if field['format'] == 'uuid':
+ inner_template = (
+ ' * @${field_name_underscore}: a #MbimUuid.\n')
+ elif field['format'] =='byte-array':
+ inner_template = (' * @${field_name_underscore}: an array of #guint8 values.\n')
+ elif field['format'] =='unsized-byte-array' or field['format'] == 'ref-byte-array':
+ inner_template = ''
+ if 'array-size-field' not in field:
+ inner_template += (' * @${field_name_underscore}_size: size of the ${field_name_underscore} array.\n')
+ inner_template += (' * @${field_name_underscore}: an array of #guint8 values.\n')
+ elif field['format'] == 'guint32':
+ inner_template = (
+ ' * @${field_name_underscore}: a #guint32.\n')
+ elif field['format'] == 'guint32-array':
+ inner_template = (
+ ' * @${field_name_underscore}: an array of #guint32 values.\n')
+ elif field['format'] == 'guint64':
+ inner_template = (
+ ' * @${field_name_underscore}: a #guint64.\n')
+ elif field['format'] == 'string':
+ inner_template = (
+ ' * @${field_name_underscore}: a string.\n')
+ elif field['format'] == 'string-array':
+ inner_template = (
+ ' * @${field_name_underscore}: an array of strings.\n')
+ elif field['format'] == 'ipv4':
+ inner_template = (
+ ' * @${field_name_underscore}: a #MbimIPv4.\n')
+ elif field['format'] == 'ref-ipv4':
+ inner_template = (
+ ' * @${field_name_underscore}: a #MbimIPv4.\n')
+ elif field['format'] == 'ipv4-array':
+ inner_template = (
+ ' * @${field_name_underscore}: an array of #MbimIPv4 values.\n')
+ elif field['format'] == 'ipv6':
+ inner_template = (
+ ' * @${field_name_underscore}: a #MbimIPv6\n')
+ elif field['format'] == 'ref-ipv6':
+ inner_template = (
+ ' * @${field_name_underscore}: a #MbimIPv6\n')
+ elif field['format'] == 'ipv6-array':
+ inner_template = (
+ ' * @${field_name_underscore}: an array of #MbimIPv6 values.\n')
+ else:
+ raise ValueError('Cannot handle format \'%s\' in struct' % field['format'])
+ template += string.Template(inner_template).substitute(translations)
+
+ template += (
+ ' */\n'
+ 'typedef struct {\n')
+ for field in self.contents:
+ translations['field_name_underscore'] = utils.build_underscore_name_from_camelcase(field['name'])
+ if field['format'] == 'uuid':
+ inner_template = (
+ ' MbimUuid ${field_name_underscore};\n')
+ elif field['format'] == 'byte-array':
+ translations['array_size'] = field['array-size']
+ inner_template = (
+ ' guint8 ${field_name_underscore}[${array_size}];\n')
+ elif field['format'] == 'unsized-byte-array' or field['format'] == 'ref-byte-array':
+ inner_template = ''
+ if 'array-size-field' not in field:
+ inner_template += (
+ ' guint32 ${field_name_underscore}_size;\n')
+ inner_template += (
+ ' guint8 *${field_name_underscore};\n')
+ elif field['format'] == 'guint32':
+ inner_template = (
+ ' guint32 ${field_name_underscore};\n')
+ elif field['format'] == 'guint32-array':
+ inner_template = (
+ ' guint32 *${field_name_underscore};\n')
+ elif field['format'] == 'guint64':
+ inner_template = (
+ ' guint64 ${field_name_underscore};\n')
+ elif field['format'] == 'string':
+ inner_template = (
+ ' gchar *${field_name_underscore};\n')
+ elif field['format'] == 'string-array':
+ inner_template = (
+ ' gchar **${field_name_underscore};\n')
+ elif field['format'] == 'ipv4':
+ inner_template = (
+ ' MbimIPv4 ${field_name_underscore};\n')
+ elif field['format'] == 'ref-ipv4':
+ inner_template = (
+ ' MbimIPv4 ${field_name_underscore};\n')
+ elif field['format'] == 'ipv4-array':
+ inner_template = (
+ ' MbimIPv4 *${field_name_underscore};\n')
+ elif field['format'] == 'ipv6':
+ inner_template = (
+ ' MbimIPv6 ${field_name_underscore};\n')
+ elif field['format'] == 'ref-ipv6':
+ inner_template = (
+ ' MbimIPv6 ${field_name_underscore};\n')
+ elif field['format'] == 'ipv6-array':
+ inner_template = (
+ ' MbimIPv6 *${field_name_underscore};\n')
+ else:
+ raise ValueError('Cannot handle format \'%s\' in struct' % field['format'])
+ template += string.Template(inner_template).substitute(translations)
+ template += (
+ '} ${name};\n')
+ hfile.write(string.Template(template).substitute(translations))
+
+
+ """
+ Emit the type's free methods
+ """
+ def _emit_free(self, hfile, cfile):
+ translations = { 'name' : self.name,
+ 'name_underscore' : utils.build_underscore_name_from_camelcase(self.name) }
+ template = ''
+
+ if self.single_member == True:
+ template = (
+ '\n'
+ 'void ${name_underscore}_free (${name} *var);\n')
+ hfile.write(string.Template(template).substitute(translations))
+
+
+ template = (
+ '\n'
+ 'static void\n'
+ '_${name_underscore}_free (${name} *var)\n'
+ '{\n'
+ ' if (!var)\n'
+ ' return;\n'
+ '\n')
+
+ for field in self.contents:
+ translations['field_name_underscore'] = utils.build_underscore_name_from_camelcase(field['name'])
+ inner_template = ''
+ if field['format'] == 'uuid':
+ pass
+ elif field['format'] == 'unsized-byte-array' or field['format'] == 'ref-byte-array':
+ inner_template += (
+ ' g_free (var->${field_name_underscore});\n')
+ elif field['format'] == 'guint32':
+ pass
+ elif field['format'] == 'guint32-array':
+ inner_template += (
+ ' g_free (var->${field_name_underscore});\n')
+ elif field['format'] == 'guint64':
+ pass
+ elif field['format'] == 'string':
+ inner_template += (
+ ' g_free (var->${field_name_underscore});\n')
+ elif field['format'] == 'string-array':
+ inner_template += (
+ ' g_strfreev (var->${field_name_underscore});\n')
+ elif field['format'] == 'ipv4':
+ pass
+ elif field['format'] == 'ref-ipv4':
+ pass
+ elif field['format'] == 'ipv4-array':
+ inner_template += (
+ ' g_free (var->${field_name_underscore});\n')
+ elif field['format'] == 'ipv6':
+ pass
+ elif field['format'] == 'ref-ipv6':
+ pass
+ elif field['format'] == 'ipv6-array':
+ inner_template += (
+ ' g_free (var->${field_name_underscore});\n')
+ else:
+ raise ValueError('Cannot handle format \'%s\' in struct clear' % field['format'])
+ template += string.Template(inner_template).substitute(translations)
+
+ template += (
+ ' g_free (var);\n'
+ '}\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+ if self.single_member == True:
+ template = (
+ '\n'
+ '/**\n'
+ ' * ${name_underscore}_free:\n'
+ ' * @var: a #${name}.\n'
+ ' *\n'
+ ' * Frees the memory allocated for the #${name}.\n'
+ ' */\n'
+ 'void\n'
+ '${name_underscore}_free (${name} *var)\n'
+ '{\n'
+ ' _${name_underscore}_free (var);\n'
+ '}\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+ if self.array_member:
+ template = (
+ '\n'
+ 'void ${name_underscore}_array_free (${name} **array);\n')
+ hfile.write(string.Template(template).substitute(translations))
+
+ template = (
+ '\n'
+ '/**\n'
+ ' * ${name_underscore}_array_free:\n'
+ ' * @array: a #NULL terminated array of #${name} structs.\n'
+ ' *\n'
+ ' * Frees the memory allocated for the array of #${name}s.\n'
+ ' */\n'
+ 'void\n'
+ '${name_underscore}_array_free (${name} **array)\n'
+ '{\n'
+ ' guint32 i;\n'
+ '\n'
+ ' if (!array)\n'
+ ' return;\n'
+ '\n'
+ ' for (i = 0; array[i]; i++)\n'
+ ' _${name_underscore}_free (array[i]);\n'
+ ' g_free (array);\n'
+ '}\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+
+ """
+ Emit the type's read methods
+ """
+ def _emit_read(self, cfile):
+ translations = { 'name' : self.name,
+ 'name_underscore' : utils.build_underscore_name_from_camelcase(self.name),
+ 'struct_size' : self.size }
+
+ template = (
+ '\n'
+ 'static ${name} *\n'
+ '_mbim_message_read_${name_underscore}_struct (\n'
+ ' const MbimMessage *self,\n'
+ ' guint32 relative_offset,\n'
+ ' guint32 *bytes_read)\n'
+ '{\n'
+ ' ${name} *out;\n'
+ ' guint32 offset = relative_offset;\n'
+ '\n'
+ ' g_assert (self != NULL);\n'
+ '\n'
+ ' out = g_new (${name}, 1);\n')
+
+ for field in self.contents:
+ translations['field_name_underscore'] = utils.build_underscore_name_from_camelcase(field['name'])
+
+ inner_template = ''
+ if field['format'] == 'uuid':
+ inner_template += (
+ '\n'
+ ' memcpy (&(out->${field_name_underscore}), _mbim_message_read_uuid (self, offset), 16);\n'
+ ' offset += 16;\n')
+ elif field['format'] == 'ref-byte-array':
+ if 'array-size-field' in field:
+ translations['array_size_field_name_underscore'] = utils.build_underscore_name_from_camelcase(field['array-size-field'])
+ inner_template += (
+ '\n'
+ ' {\n'
+ ' const guint8 *tmp;\n'
+ '\n'
+ ' tmp = _mbim_message_read_byte_array (self, relative_offset, offset, TRUE, FALSE, NULL);\n'
+ ' out->${field_name_underscore} = g_malloc (out->${array_size_field_name_underscore});\n'
+ ' memcpy (out->${field_name_underscore}, tmp, out->${array_size_field_name_underscore});\n'
+ ' offset += 4;\n'
+ ' }\n')
+ else:
+ inner_template += (
+ '\n'
+ ' {\n'
+ ' const guint8 *tmp;\n'
+ '\n'
+ ' tmp = _mbim_message_read_byte_array (self, relative_offset, offset, TRUE, TRUE, &(out->${field_name_underscore}_size));\n'
+ ' out->${field_name_underscore} = g_malloc (out->${field_name_underscore}_size);\n'
+ ' memcpy (out->${field_name_underscore}, tmp, out->${field_name_underscore}_size);\n'
+ ' offset += 8;\n'
+ ' }\n')
+ elif field['format'] == 'unsized-byte-array':
+ inner_template += (
+ '\n'
+ ' {\n'
+ ' const guint8 *tmp;\n'
+ '\n'
+ ' tmp = _mbim_message_read_byte_array (self, relative_offset, offset, FALSE, FALSE, &(out->${field_name_underscore}_size));\n'
+ ' out->${field_name_underscore} = g_malloc (out->${field_name_underscore}_size);\n'
+ ' memcpy (out->${field_name_underscore}, tmp, out->${field_name_underscore}_size);\n'
+ ' /* no offset update expected, this should be the last field */\n'
+ ' }\n')
+ elif field['format'] == 'byte-array':
+ translations['array_size'] = field['array-size']
+ inner_template += (
+ '\n'
+ ' {\n'
+ ' const guint8 *tmp;\n'
+ '\n'
+ ' tmp = _mbim_message_read_byte_array (self, relative_offset, offset, FALSE, FALSE, NULL));\n'
+ ' memcpy (out->${field_name_underscore}, tmp, ${array_size});\n'
+ ' offset += ${array_size};\n'
+ ' }\n')
+ elif field['format'] == 'guint32':
+ inner_template += (
+ '\n'
+ ' out->${field_name_underscore} = _mbim_message_read_guint32 (self, offset);\n'
+ ' offset += 4;\n')
+ elif field['format'] == 'guint32-array':
+ translations['array_size_field_name_underscore'] = utils.build_underscore_name_from_camelcase(field['array-size-field'])
+ inner_template += (
+ '\n'
+ ' out->${field_name_underscore} = _mbim_message_read_guint32_array (self, out->${array_size_field_name_underscore}, offset);\n'
+ ' offset += (4 * out->${array_size_field_name_underscore});\n')
+ elif field['format'] == 'guint64':
+ inner_template += (
+ '\n'
+ ' out->${field_name_underscore} = _mbim_message_read_guint64 (self, offset);\n'
+ ' offset += 8;\n')
+ elif field['format'] == 'string':
+ inner_template += (
+ '\n'
+ ' out->${field_name_underscore} = _mbim_message_read_string (self, relative_offset, offset);\n'
+ ' offset += 8;\n')
+ elif field['format'] == 'string-array':
+ translations['array_size_field_name_underscore'] = utils.build_underscore_name_from_camelcase(field['array-size-field'])
+ inner_template += (
+ '\n'
+ ' out->${field_name_underscore} = _mbim_message_read_string_array (self, out->${array_size_field_name_underscore}, relative_offset, offset);\n'
+ ' offset += (8 * out->${array_size_field_name_underscore});\n')
+ elif field['format'] == 'ipv4':
+ inner_template += (
+ '\n'
+ ' memcpy (&(out->${field_name_underscore}), _mbim_message_read_ipv4 (self, offset, FALSE), 4);\n'
+ ' offset += 4;\n')
+ elif field['format'] == 'ref-ipv4':
+ inner_template += (
+ '\n'
+ ' memcpy (&(out->${field_name_underscore}), _mbim_message_read_ipv4 (self, offset, TRUE), 4);\n'
+ ' offset += 4;\n')
+ elif field['format'] == 'ipv4-array':
+ inner_template += (
+ '\n'
+ ' out->${field_name_underscore} =_mbim_message_read_ipv4_array (self, out->${array_size_field_name_underscore}, offset);\n'
+ ' offset += 4;\n')
+ elif field['format'] == 'ipv6':
+ inner_template += (
+ '\n'
+ ' memcpy (&(out->${field_name_underscore}), _mbim_message_read_ipv6 (self, offset, FALSE), 16);\n'
+ ' offset += 4;\n')
+ elif field['format'] == 'ref-ipv6':
+ inner_template += (
+ '\n'
+ ' memcpy (&(out->${field_name_underscore}), _mbim_message_read_ipv6 (self, offset, TRUE), 16);\n'
+ ' offset += 4;\n')
+ elif field['format'] == 'ipv6-array':
+ inner_template += (
+ '\n'
+ ' out->${field_name_underscore} =_mbim_message_read_ipv6_array (self, out->${array_size_field_name_underscore}, offset);\n'
+ ' offset += 4;\n')
+ else:
+ raise ValueError('Cannot handle format \'%s\' in struct' % field['format'])
+
+ template += string.Template(inner_template).substitute(translations)
+
+ template += (
+ '\n'
+ ' if (bytes_read)\n'
+ ' *bytes_read = (offset - relative_offset);\n'
+ '\n'
+ ' return out;\n'
+ '}\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+ template = (
+ '\n'
+ 'static ${name} **\n'
+ '_mbim_message_read_${name_underscore}_struct_array (\n'
+ ' const MbimMessage *self,\n'
+ ' guint32 array_size,\n'
+ ' guint32 relative_offset_array_start,\n'
+ ' gboolean refs)\n'
+ '{\n'
+ ' ${name} **out;\n'
+ ' guint32 i;\n'
+ ' guint32 offset;\n'
+ '\n'
+ ' if (!array_size)\n'
+ ' return NULL;\n'
+ '\n'
+ ' out = g_new (${name} *, array_size + 1);\n'
+ '\n'
+ ' if (!refs) {\n'
+ ' offset = _mbim_message_read_guint32 (self, relative_offset_array_start);\n'
+ ' for (i = 0; i < array_size; i++, offset += ${struct_size})\n'
+ ' out[i] = _mbim_message_read_${name_underscore}_struct (self, offset, NULL);\n'
+ ' } else {\n'
+ ' offset = relative_offset_array_start;\n'
+ ' for (i = 0; i < array_size; i++, offset += 8)\n'
+ ' out[i] = _mbim_message_read_${name_underscore}_struct (self, _mbim_message_read_guint32 (self, offset), NULL);\n'
+ ' }\n'
+ ' out[array_size] = NULL;\n'
+ '\n'
+ ' return out;\n'
+ '}\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+
+ """
+ Emit the type's append methods
+ """
+ def _emit_append(self, cfile):
+ translations = { 'name' : self.name,
+ 'name_underscore' : utils.build_underscore_name_from_camelcase(self.name),
+ 'struct_size' : self.size }
+
+ template = (
+ '\n'
+ 'static GByteArray *\n'
+ '_${name_underscore}_struct_new (const ${name} *value)\n'
+ '{\n'
+ ' MbimStructBuilder *builder;\n'
+ '\n'
+ ' g_assert (value != NULL);\n'
+ '\n'
+ ' builder = _mbim_struct_builder_new ();\n')
+
+ for field in self.contents:
+ translations['field'] = utils.build_underscore_name_from_camelcase(field['name'])
+ translations['array_size'] = field['array-size'] if 'array-size' in field else ''
+ translations['array_size_field'] = utils.build_underscore_name_from_camelcase(field['array-size-field']) if 'array-size-field' in field else ''
+
+ if field['format'] == 'uuid':
+ inner_template = (' _mbim_struct_builder_append_uuid (builder, &(value->${field}));\n')
+ elif field['format'] == 'byte-array':
+ inner_template = (' _mbim_struct_builder_append_byte_array (builder, FALSE, FALSE, value->${field}, ${array_size});\n')
+ elif field['format'] == 'unsized-byte-array':
+ inner_template = (' _mbim_struct_builder_append_byte_array (builder, FALSE, FALSE, value->${field}, value->${field}_size);\n')
+ elif field['format'] == 'ref-byte-array':
+ if 'array-size-field' in field:
+ inner_template = (' _mbim_struct_builder_append_byte_array (builder, TRUE, FALSE, value->${field}, value->${array_size_field});\n')
+ else:
+ inner_template = (' _mbim_struct_builder_append_byte_array (builder, TRUE, TRUE, value->${field}, value->${field}_size);\n')
+ elif field['format'] == 'guint32':
+ inner_template = (' _mbim_struct_builder_append_guint32 (builder, value->${field});\n')
+ elif field['format'] == 'guint32-array':
+ inner_template = (' _mbim_struct_builder_append_guint32_array (builder, value->${field}, value->${array_size_field});\n')
+ elif field['format'] == 'guint64':
+ inner_template = (' _mbim_struct_builder_append_guint64 (builder, value->${field});\n')
+ elif field['format'] == 'guint64-array':
+ inner_template = (' _mbim_struct_builder_append_guint64_array (builder, value->${field}, value->${array_size_field});\n')
+ elif field['format'] == 'string':
+ inner_template = (' _mbim_struct_builder_append_string (builder, value->${field});\n')
+ elif field['format'] == 'string-array':
+ inner_template = (' _mbim_struct_builder_append_string_array (builder, value->${field}, value->${array_size_field});\n')
+ elif field['format'] == 'ipv4':
+ inner_template = (' _mbim_struct_builder_append_ipv4 (builder, &value->${field}, FALSE);\n')
+ elif field['format'] == 'ref-ipv4':
+ inner_template = (' _mbim_struct_builder_append_ipv4 (builder, &value->${field}, TRUE);\n')
+ elif field['format'] == 'ipv4-array':
+ inner_template = (' _mbim_struct_builder_append_ipv4_array (builder, value->${field}, value->${array_size_field});\n')
+ elif field['format'] == 'ipv6':
+ inner_template = (' _mbim_struct_builder_append_ipv6 (builder, &value->${field}, FALSE);\n')
+ elif field['format'] == 'ref-ipv6':
+ inner_template = (' _mbim_struct_builder_append_ipv6 (builder, &value->${field}, TRUE);\n')
+ elif field['format'] == 'ipv6-array':
+ inner_template = (' _mbim_struct_builder_append_ipv6_array (builder, value->${field}, value->${array_size_field});\n')
+ else:
+ raise ValueError('Cannot handle format \'%s\' in struct' % field['format'])
+
+ template += string.Template(inner_template).substitute(translations)
+
+ template += (
+ '\n'
+ ' return _mbim_struct_builder_complete (builder);\n'
+ '}\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+ template = (
+ '\n'
+ 'static void\n'
+ '_mbim_struct_builder_append_${name_underscore}_struct (\n'
+ ' MbimStructBuilder *builder,\n'
+ ' const ${name} *value)\n'
+ '{\n'
+ ' GByteArray *raw;\n'
+ '\n'
+ ' raw = _${name_underscore}_struct_new (value);\n'
+ ' g_byte_array_append (builder->fixed_buffer, raw->data, raw->len);\n'
+ ' g_byte_array_unref (raw);\n'
+ '}\n'
+ '\n'
+ 'static void\n'
+ '_mbim_message_command_builder_append_${name_underscore}_struct (\n'
+ ' MbimMessageCommandBuilder *builder,\n'
+ ' const ${name} *value)\n'
+ '{\n'
+ ' _mbim_struct_builder_append_${name_underscore}_struct (builder->contents_builder, value);\n'
+ '}\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+ template = (
+ '\n'
+ 'static void\n'
+ '_mbim_struct_builder_append_${name_underscore}_struct_array (\n'
+ ' MbimStructBuilder *builder,\n'
+ ' const ${name} *const *values,\n'
+ ' guint32 n_values,\n'
+ ' gboolean refs)\n'
+ '{\n'
+ ' guint32 offset;\n'
+ ' guint32 i;\n'
+ ' GByteArray *raw_all = NULL;\n'
+ '\n'
+ ' if (!refs) {\n'
+ ' for (i = 0; i < n_values; i++) {\n'
+ ' GByteArray *raw;\n'
+ '\n'
+ ' raw = _${name_underscore}_struct_new (values[i]);\n'
+ ' if (!raw_all)\n'
+ ' raw_all = raw;\n'
+ ' else {\n'
+ ' g_byte_array_append (raw_all, raw->data, raw->len);\n'
+ ' g_byte_array_unref (raw);\n'
+ ' }\n'
+ ' }\n'
+ '\n'
+ ' if (!raw_all) {\n'
+ ' offset = 0;\n'
+ ' g_byte_array_append (builder->fixed_buffer, (guint8 *)&offset, sizeof (offset));\n'
+ ' } else {\n'
+ ' guint32 offset_offset;\n'
+ '\n'
+ ' /* Offset of the offset */\n'
+ ' offset_offset = builder->fixed_buffer->len;\n'
+ ' /* Length *not* in LE yet */\n'
+ ' offset = builder->variable_buffer->len;\n'
+ ' /* Add the offset value */\n'
+ ' g_byte_array_append (builder->fixed_buffer, (guint8 *)&offset, sizeof (offset));\n'
+ ' /* Configure the value to get updated */\n'
+ ' g_array_append_val (builder->offsets, offset_offset);\n'
+ ' /* Add the final array itself */\n'
+ ' g_byte_array_append (builder->variable_buffer, raw_all->data, raw_all->len);\n'
+ ' g_byte_array_unref (raw_all);\n'
+ ' }\n'
+ ' } else {\n'
+ ' for (i = 0; i < n_values; i++) {\n'
+ ' guint32 length;\n'
+ ' guint32 offset_offset;\n'
+ ' GByteArray *raw;\n'
+ '\n'
+ ' raw = _${name_underscore}_struct_new (values[i]);\n'
+ ' g_assert (raw->len > 0);\n'
+ '\n'
+ ' /* Offset of the offset */\n'
+ ' offset_offset = builder->fixed_buffer->len;\n'
+ '\n'
+ ' /* Length *not* in LE yet */\n'
+ ' offset = builder->variable_buffer->len;\n'
+ ' /* Add the offset value */\n'
+ ' g_byte_array_append (builder->fixed_buffer, (guint8 *)&offset, sizeof (offset));\n'
+ ' /* Configure the value to get updated */\n'
+ ' g_array_append_val (builder->offsets, offset_offset);\n'
+ '\n'
+ ' /* Add the length value */\n'
+ ' length = GUINT32_TO_LE (raw->len);\n'
+ ' g_byte_array_append (builder->fixed_buffer, (guint8 *)&length, sizeof (length));\n'
+ '\n'
+ ' /* And finally, the bytearray itself to the variable buffer */\n'
+ ' g_byte_array_append (builder->variable_buffer, (const guint8 *)raw->data, (guint)raw->len);\n'
+ ' g_byte_array_unref (raw);\n'
+ ' }\n'
+ ' }\n'
+ '}\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+ template = (
+ '\n'
+ 'static void\n'
+ '_mbim_message_command_builder_append_${name_underscore}_struct_array (\n'
+ ' MbimMessageCommandBuilder *builder,\n'
+ ' const ${name} *const *values,\n'
+ ' guint32 n_values,\n'
+ ' gboolean refs)\n'
+ '{\n'
+ ' _mbim_struct_builder_append_${name_underscore}_struct_array (builder->contents_builder, values, n_values, refs);\n'
+ '}\n')
+ cfile.write(string.Template(template).substitute(translations))
+
+
+ """
+ Emit the struct handling implementation
+ """
+ def emit(self, hfile, cfile):
+ utils.add_separator(hfile, 'Struct', self.name);
+ utils.add_separator(cfile, 'Struct', self.name);
+
+ # Emit type
+ self._emit_type(hfile)
+ # Emit type's free
+ self._emit_free(hfile, cfile)
+ # Emit type's read
+ self._emit_read(cfile)
+ # Emit type's append
+ self._emit_append(cfile)
+
+
+ """
+ Emit the section contents
+ """
+ def emit_section_content(self, sfile):
+ translations = { 'struct_name' : self.name,
+ 'name_underscore' : utils.build_underscore_name_from_camelcase(self.name) }
+ template = (
+ '<SUBSECTION ${struct_name}>\n'
+ '${struct_name}\n')
+ if self.single_member == True:
+ template += (
+ '${name_underscore}_free\n')
+ if self.array_member == True:
+ template += (
+ '${name_underscore}_array_free\n')
+ sfile.write(string.Template(template).substitute(translations))
diff --git a/build-aux/mbim-codegen/mbim-codegen b/build-aux/mbim-codegen/mbim-codegen
new file mode 100755
index 0000000..4d01384
--- /dev/null
+++ b/build-aux/mbim-codegen/mbim-codegen
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+#
+
+import os
+import sys
+import optparse
+import json
+
+from ObjectList import ObjectList
+import utils
+
+def codegen_main():
+ # Input arguments
+ arg_parser = optparse.OptionParser('%prog [options]')
+ arg_parser.add_option('', '--input', metavar='JSONFILE',
+ help='Input JSON-formatted database')
+ arg_parser.add_option('', '--output', metavar='OUTFILES',
+ help='Generate C code in OUTFILES.[ch]')
+ (opts, args) = arg_parser.parse_args();
+
+ if opts.input == None:
+ raise RuntimeError('Input JSON file is mandatory')
+ if opts.output == None:
+ raise RuntimeError('Output file pattern is mandatory')
+
+ # Prepare output file names
+ output_file_c = open(opts.output + ".c", 'w')
+ output_file_h = open(opts.output + ".h", 'w')
+ output_file_sections = open(opts.output + ".sections", 'w')
+
+ # Load database file contents
+ database_file_contents = utils.read_json_file(opts.input)
+
+ # Build message list
+ object_list_json = json.loads(database_file_contents)
+ object_list = ObjectList(object_list_json)
+
+ # Add common stuff to the output files
+ utils.add_copyright(output_file_c);
+ utils.add_copyright(output_file_h);
+ utils.add_header_start(output_file_h, os.path.basename(opts.output))
+ utils.add_source_start(output_file_c, os.path.basename(opts.output))
+
+ # Emit the message creation/parsing code
+ object_list.emit(output_file_h, output_file_c)
+
+ # Emit sections
+ object_list.emit_sections(output_file_sections)
+
+ utils.add_header_stop(output_file_h, os.path.basename(opts.output))
+
+ output_file_c.close()
+ output_file_h.close()
+ output_file_sections.close()
+
+ sys.exit(0)
+
+
+if __name__ == "__main__":
+ codegen_main()
diff --git a/build-aux/mbim-codegen/utils.py b/build-aux/mbim-codegen/utils.py
new file mode 100644
index 0000000..7666a1d
--- /dev/null
+++ b/build-aux/mbim-codegen/utils.py
@@ -0,0 +1,192 @@
+#!/usr/bin/env python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2012 Lanedo GmbH
+# Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+#
+# Implementation originally developed in 'libqmi'.
+#
+
+import string
+import re
+
+"""
+Add the common copyright header to the given file
+"""
+def add_copyright(f):
+ f.write(
+ "\n"
+ "/* GENERATED CODE... DO NOT EDIT */\n"
+ "\n"
+ "/*\n"
+ " * This library is free software; you can redistribute it and/or\n"
+ " * modify it under the terms of the GNU Lesser General Public\n"
+ " * License as published by the Free Software Foundation; either\n"
+ " * version 2 of the License, or (at your option) any later version.\n"
+ " *\n"
+ " * This library is distributed in the hope that it will be useful,\n"
+ " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
+ " * Lesser General Public License for more details.\n"
+ " *\n"
+ " * You should have received a copy of the GNU Lesser General Public\n"
+ " * License along with this library; if not, write to the\n"
+ " * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,\n"
+ " * Boston, MA 02110-1301 USA.\n"
+ " *\n"
+ " * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>\n"
+ " */\n"
+ "\n");
+
+
+"""
+Build a header guard string based on the given filename
+"""
+def build_header_guard(output_name):
+ return "__LIBMBIM_GLIB_" + output_name.replace('-', '_').upper() + "__"
+
+"""
+Write the common header start chunk
+"""
+def add_header_start(f, output_name):
+ translations = { 'guard' : build_header_guard(output_name) }
+ template = (
+ "\n"
+ "#include <glib.h>\n"
+ "#include <glib-object.h>\n"
+ "#include <gio/gio.h>\n"
+ "\n"
+ "#include \"mbim-message.h\"\n"
+ "#include \"mbim-device.h\"\n"
+ "#include \"mbim-enums.h\"\n"
+ "\n"
+ "#ifndef ${guard}\n"
+ "#define ${guard}\n"
+ "\n"
+ "G_BEGIN_DECLS\n")
+ f.write(string.Template(template).substitute(translations))
+
+
+"""
+Write the common header stop chunk
+"""
+def add_header_stop(f, output_name):
+ template = string.Template (
+ "\n"
+ "G_END_DECLS\n"
+ "\n"
+ "#endif /* ${guard} */\n")
+ f.write(template.substitute(guard = build_header_guard(output_name)))
+
+
+"""
+Write the common source file start chunk
+"""
+def add_source_start(f, output_name):
+ template = string.Template (
+ "\n"
+ "#include <string.h>\n"
+ "\n"
+ "#include \"${name}.h\"\n"
+ "#include \"mbim-message-private.h\"\n"
+ "#include \"mbim-enum-types.h\"\n"
+ "#include \"mbim-error-types.h\"\n"
+ "#include \"mbim-device.h\"\n"
+ "#include \"mbim-utils.h\"\n")
+ f.write(template.substitute(name = output_name))
+
+
+"""
+Write a separator comment in the file
+"""
+def add_separator(f, separator_type, separator_name):
+ template = string.Template (
+ "\n"
+ "/*****************************************************************************/\n"
+ "/* ${type}: ${name} */\n")
+ f.write(template.substitute(type = separator_type,
+ name = separator_name))
+
+
+"""
+Build an underscore name from the given full name
+e.g.: "This is a message" --> "this_is_a_message"
+"""
+def build_underscore_name(name):
+ return name.replace(' ', '_').replace('-', '_').lower()
+
+
+"""
+Build an underscore uppercase name from the given full name
+e.g.: "This is a message" --> "THIS_IS_A_MESSAGE"
+"""
+def build_underscore_uppercase_name(name):
+ return name.replace(' ', '_').replace('-', '_').upper()
+
+
+
+"""
+Build an underscore name from the given camelcase name
+e.g.: "ThisIsAMessage" --> "this_is_a_message"
+"""
+def build_underscore_name_from_camelcase(camelcase):
+ s0 = camelcase.replace('IP','Ip')
+ s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', s0)
+ return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
+
+
+
+"""
+Build a camelcase name from the given full name
+e.g.: "This is a message" --> "ThisIsAMessage"
+"""
+def build_camelcase_name(name):
+ return string.capwords(name).replace(' ', '')
+
+
+"""
+Build a dashed lowercase name from the given full name
+e.g.: "This is a message" --> "this-is-a-message"
+"""
+def build_dashed_name(name):
+ return name.lower().replace(' ', '-')
+
+
+"""
+Remove the given prefix from the string
+"""
+def remove_prefix(line, prefix):
+ return line[len(prefix):] if line.startswith(prefix) else line
+
+
+"""
+Read the contents of the JSON file, skipping lines prefixed with '//', which are
+considered comments.
+"""
+def read_json_file(path):
+ f = open(path)
+ out = ''
+ for line in f.readlines():
+ stripped = line.strip()
+ if stripped.startswith('//'):
+ # Skip this line
+ # We add an empty line instead so that errors when parsing the JSON
+ # report the proper line number
+ out += "\n"
+ else:
+ out += line
+ return out
diff --git a/build-aux/templates/Makefile.am b/build-aux/templates/Makefile.am
new file mode 100644
index 0000000..d663e1d
--- /dev/null
+++ b/build-aux/templates/Makefile.am
@@ -0,0 +1,7 @@
+
+EXTRA_DIST = \
+ mbim-error-types-template.h \
+ mbim-error-types-template.c \
+ mbim-error-quarks-template.c \
+ mbim-enum-types-template.h \
+ mbim-enum-types-template.c
diff --git a/build-aux/templates/mbim-enum-types-template.c b/build-aux/templates/mbim-enum-types-template.c
new file mode 100644
index 0000000..635147f
--- /dev/null
+++ b/build-aux/templates/mbim-enum-types-template.c
@@ -0,0 +1,118 @@
+/*** BEGIN file-header ***/
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+static const G@Type@Value @enum_name@_values[] = {
+/*** END value-header ***/
+/*** BEGIN value-production ***/
+ { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL }
+};
+
+/* Define type-specific symbols */
+
+GType
+@enum_name@_get_type (void)
+{
+ static volatile gsize g_define_type_id__volatile = 0;
+
+ if (g_once_init_enter (&g_define_type_id__volatile)) {
+ GType g_define_type_id =
+ g_@type@_register_static (g_intern_static_string ("@EnumName@"),
+ @enum_name@_values);
+ g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+ }
+
+ return g_define_type_id__volatile;
+}
+
+/* Enum-specific method to get the value as a string.
+ * We get the nick of the GEnumValue. Note that this will be
+ * valid even if the GEnumClass is not referenced anywhere. */
+#if defined __@ENUMNAME@_IS_ENUM__
+/**
+ * @enum_name@_get_string:
+ * @val: a @EnumName@.
+ *
+ * Gets the nickname string for the #@EnumName@ specified at @val.
+ *
+ * Returns: (transfer none): a string with the nickname, or %NULL if not found. Do not free the returned value.
+ */
+const gchar *
+@enum_name@_get_string (@EnumName@ val)
+{
+ guint i;
+
+ for (i = 0; @enum_name@_values[i].value_nick; i++) {
+ if (val == @enum_name@_values[i].value)
+ return @enum_name@_values[i].value_nick;
+ }
+
+ return NULL;
+}
+#endif /* __@ENUMNAME@_IS_ENUM__ */
+
+/* Flags-specific method to build a string with the given mask.
+ * We get a comma separated list of the nicks of the GFlagsValues.
+ * Note that this will be valid even if the GFlagsClass is not referenced
+ * anywhere. */
+#if defined __@ENUMNAME@_IS_FLAGS__
+/**
+ * @enum_name@_build_string_from_mask:
+ * @mask: bitmask of @EnumName@ values.
+ *
+ * Builds a string containing a comma-separated list of nicknames for
+ * each #@EnumName@ in @mask.
+ *
+ * Returns: (transfer full): a string with the list of nicknames, or %NULL if none given. The returned value should be freed with g_free().
+ */
+gchar *
+@enum_name@_build_string_from_mask (@EnumName@ mask)
+{
+ guint i;
+ gboolean first = TRUE;
+ GString *str = NULL;
+
+ for (i = 0; @enum_name@_values[i].value_nick; i++) {
+ /* We also look for exact matches */
+ if (mask == @enum_name@_values[i].value) {
+ if (str)
+ g_string_free (str, TRUE);
+ return g_strdup (@enum_name@_values[i].value_nick);
+ }
+
+ /* Build list with single-bit masks */
+ if (mask & @enum_name@_values[i].value) {
+ guint c;
+ gulong number = @enum_name@_values[i].value;
+
+ for (c = 0; number; c++)
+ number &= number - 1;
+
+ if (c == 1) {
+ if (!str)
+ str = g_string_new ("");
+ g_string_append_printf (str, "%s%s",
+ first ? "" : ", ",
+ @enum_name@_values[i].value_nick);
+ if (first)
+ first = FALSE;
+ }
+ }
+ }
+
+ return (str ? g_string_free (str, FALSE) : NULL);
+}
+#endif /* __@ENUMNAME@_IS_FLAGS__ */
+
+/*** END value-tail ***/
+
+/*** BEGIN file-tail ***/
+/*** END file-tail ***/
diff --git a/build-aux/templates/mbim-enum-types-template.h b/build-aux/templates/mbim-enum-types-template.h
new file mode 100644
index 0000000..31e0732
--- /dev/null
+++ b/build-aux/templates/mbim-enum-types-template.h
@@ -0,0 +1,33 @@
+/*** BEGIN file-header ***/
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name@_get_type (void) G_GNUC_CONST;
+#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
+
+/* Define type-specific symbols */
+#define __@ENUMNAME@_IS_@TYPE@__
+
+#if defined __@ENUMNAME@_IS_ENUM__
+const gchar *@enum_name@_get_string (@EnumName@ val);
+#endif
+
+#if defined __@ENUMNAME@_IS_FLAGS__
+gchar *@enum_name@_build_string_from_mask (@EnumName@ mask);
+#endif
+
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+/*** END file-tail ***/
diff --git a/build-aux/templates/mbim-error-quarks-template.c b/build-aux/templates/mbim-error-quarks-template.c
new file mode 100644
index 0000000..4386a60
--- /dev/null
+++ b/build-aux/templates/mbim-error-quarks-template.c
@@ -0,0 +1,42 @@
+/*** BEGIN file-header ***/
+
+#include <gio/gio.h>
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+
+#define ERROR_PREFIX @ENUMNAME@_DBUS_PREFIX
+static const GDBusErrorEntry @enum_name@_entries[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+ { @VALUENAME@, ERROR_PREFIX ".@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+};
+#undef ERROR_PREFIX
+
+GQuark
+@enum_name@_quark (void)
+{
+ static volatile gsize quark_volatile = 0;
+
+ if (!quark_volatile)
+ g_dbus_error_register_error_domain ("@enum_name@_quark",
+ &quark_volatile,
+ @enum_name@_entries,
+ G_N_ELEMENTS (@enum_name@_entries));
+
+ return (GQuark) quark_volatile;
+}
+
+/*** END value-tail ***/
+
+/*** BEGIN file-tail ***/
+/*** END file-tail ***/
diff --git a/build-aux/templates/mbim-error-types-template.c b/build-aux/templates/mbim-error-types-template.c
new file mode 100644
index 0000000..66ab892
--- /dev/null
+++ b/build-aux/templates/mbim-error-types-template.c
@@ -0,0 +1,62 @@
+/*** BEGIN file-header ***/
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+static const G@Type@Value @enum_name@_values[] = {
+/*** END value-header ***/
+/*** BEGIN value-production ***/
+ { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL }
+};
+
+/* @enum_name@_quark() implemented in mbim-errors-quarks.c */
+
+GType
+@enum_name@_get_type (void)
+{
+ static volatile gsize g_define_type_id__volatile = 0;
+
+ if (g_once_init_enter (&g_define_type_id__volatile)) {
+ GType g_define_type_id =
+ g_@type@_register_static (g_intern_static_string ("@EnumName@"),
+ @enum_name@_values);
+ g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+ }
+
+ return g_define_type_id__volatile;
+}
+
+/* Enum-specific method to get the value as a string.
+ * We get the nick of the GEnumValue. Note that this will be
+ * valid even if the GEnumClass is not referenced anywhere. */
+/**
+ * @enum_name@_get_string:
+ * @val: a @EnumName@.
+ *
+ * Gets the nickname string for the #@EnumName@ specified at @val.
+ *
+ * Returns: (transfer none): a string with the nickname, or %NULL if not found. Do not free the returned value.
+ */
+const gchar *
+@enum_name@_get_string (@EnumName@ val)
+{
+ guint i;
+
+ for (i = 0; @enum_name@_values[i].value_nick; i++) {
+ if (val == @enum_name@_values[i].value)
+ return @enum_name@_values[i].value_nick;
+ }
+
+ return NULL;
+}
+
+/*** END value-tail ***/
+
+/*** BEGIN file-tail ***/
+/*** END file-tail ***/
diff --git a/build-aux/templates/mbim-error-types-template.h b/build-aux/templates/mbim-error-types-template.h
new file mode 100644
index 0000000..217f006
--- /dev/null
+++ b/build-aux/templates/mbim-error-types-template.h
@@ -0,0 +1,24 @@
+/*** BEGIN file-header ***/
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GQuark @enum_name@_quark (void);
+GType @enum_name@_get_type (void) G_GNUC_CONST;
+#define @ENUMNAME@ (@enum_name@_quark ())
+#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
+const gchar *@enum_name@_get_string (@EnumName@ val);
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+/*** END file-tail ***/
diff --git a/cli/Makefile.am b/cli/Makefile.am
new file mode 100644
index 0000000..3685e93
--- /dev/null
+++ b/cli/Makefile.am
@@ -0,0 +1,19 @@
+
+bin_PROGRAMS = mbimcli
+
+mbimcli_CPPFLAGS = \
+ $(MBIMCLI_CFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libmbim-glib \
+ -I$(top_builddir)/libmbim-glib \
+ -I$(top_srcdir)/libmbim-glib/generated \
+ -I$(top_builddir)/libmbim-glib/generated
+
+mbimcli_SOURCES = \
+ mbimcli.h \
+ mbimcli.c \
+ mbimcli-basic-connect.c
+
+mbimcli_LDADD = \
+ $(MBIMCLI_LIBS) \
+ $(top_builddir)/libmbim-glib/libmbim-glib.la
diff --git a/cli/mbimcli-basic-connect.c b/cli/mbimcli-basic-connect.c
new file mode 100644
index 0000000..8f2db5e
--- /dev/null
+++ b/cli/mbimcli-basic-connect.c
@@ -0,0 +1,1715 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * mbimcli -- Command line interface to control MBIM devices
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <string.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <libmbim-glib.h>
+
+#include "mbimcli.h"
+
+/* Context */
+typedef struct {
+ MbimDevice *device;
+ GCancellable *cancellable;
+} Context;
+static Context *ctx;
+
+/* Options */
+static gboolean query_device_caps_flag;
+static gboolean query_subscriber_ready_status_flag;
+static gboolean query_radio_state_flag;
+static gboolean query_device_services_flag;
+static gboolean query_pin_flag;
+static gchar *set_pin_enter_str;
+static gchar *set_pin_change_str;
+static gchar *set_pin_enable_str;
+static gchar *set_pin_disable_str;
+static gchar *set_pin_enter_puk_str;
+static gboolean query_home_provider_flag;
+static gboolean query_preferred_providers_flag;
+static gboolean query_visible_providers_flag;
+static gboolean query_register_state_flag;
+static gboolean set_register_state_automatic_flag;
+static gboolean query_signal_state_flag;
+static gboolean query_packet_service_flag;
+static gboolean set_packet_service_attach_flag;
+static gboolean set_packet_service_detach_flag;
+static gboolean query_connect_flag;
+static gchar *set_connect_activate_str;
+static gboolean set_connect_deactivate_flag;
+static gboolean query_packet_statistics_flag;
+
+static GOptionEntry entries[] = {
+ { "query-device-caps", 0, 0, G_OPTION_ARG_NONE, &query_device_caps_flag,
+ "Query device capabilities",
+ NULL
+ },
+ { "query-subscriber-ready-status", 0, 0, G_OPTION_ARG_NONE, &query_subscriber_ready_status_flag,
+ "Query subscriber ready status",
+ NULL
+ },
+ { "query-radio-state", 0, 0, G_OPTION_ARG_NONE, &query_radio_state_flag,
+ "Query radio state",
+ NULL
+ },
+ { "query-device-services", 0, 0, G_OPTION_ARG_NONE, &query_device_services_flag,
+ "Query device services",
+ NULL
+ },
+ { "query-pin-state", 0, 0, G_OPTION_ARG_NONE, &query_pin_flag,
+ "Query PIN state",
+ NULL
+ },
+ { "enter-pin", 0, 0, G_OPTION_ARG_STRING, &set_pin_enter_str,
+ "Enter PIN",
+ "[(current PIN)]"
+ },
+ { "change-pin", 0, 0, G_OPTION_ARG_STRING, &set_pin_change_str,
+ "Change PIN",
+ "[(current PIN),(new PIN)]"
+ },
+ { "enable-pin", 0, 0, G_OPTION_ARG_STRING, &set_pin_enable_str,
+ "Enable PIN",
+ "[(current PIN)]"
+ },
+ { "disable-pin", 0, 0, G_OPTION_ARG_STRING, &set_pin_disable_str,
+ "Disable PIN",
+ "[(current PIN)]"
+ },
+ { "enter-puk", 0, 0, G_OPTION_ARG_STRING, &set_pin_enter_puk_str,
+ "Enter PUK",
+ "[(PUK),(new PIN)]"
+ },
+ { "query-home-provider", 0, 0, G_OPTION_ARG_NONE, &query_home_provider_flag,
+ "Query home provider",
+ NULL
+ },
+ { "query-preferred-providers", 0, 0, G_OPTION_ARG_NONE, &query_preferred_providers_flag,
+ "Query preferred providers",
+ NULL
+ },
+ { "query-visible-providers", 0, 0, G_OPTION_ARG_NONE, &query_visible_providers_flag,
+ "Query visible providers",
+ NULL
+ },
+ { "query-registration-state", 0, 0, G_OPTION_ARG_NONE, &query_register_state_flag,
+ "Query registration state",
+ NULL
+ },
+ { "register-automatic", 0, 0, G_OPTION_ARG_NONE, &set_register_state_automatic_flag,
+ "Launch automatic registration",
+ NULL
+ },
+ { "query-signal-state", 0, 0, G_OPTION_ARG_NONE, &query_signal_state_flag,
+ "Query signal state",
+ NULL
+ },
+ { "query-packet-service-state", 0, 0, G_OPTION_ARG_NONE, &query_packet_service_flag,
+ "Query packet service state",
+ NULL
+ },
+ { "attach-packet-service", 0, 0, G_OPTION_ARG_NONE, &set_packet_service_attach_flag,
+ "Attach to the packet service",
+ NULL
+ },
+ { "detach-packet-service", 0, 0, G_OPTION_ARG_NONE, &set_packet_service_detach_flag,
+ "Detach from the packet service",
+ NULL
+ },
+ { "query-connection-state", 0, 0, G_OPTION_ARG_NONE, &query_connect_flag,
+ "Query connection state",
+ NULL
+ },
+ { "connect", 0, 0, G_OPTION_ARG_STRING, &set_connect_activate_str,
+ "Connect (Authentication, Username and Password are optional)",
+ "[(APN),(PAP|CHAP|MSCHAPV2),(Username),(Password)]"
+ },
+ { "disconnect", 0, 0, G_OPTION_ARG_NONE, &set_connect_deactivate_flag,
+ "Disconnect",
+ NULL
+ },
+ { "query-packet-statistics", 0, 0, G_OPTION_ARG_NONE, &query_packet_statistics_flag,
+ "Query packet statistics",
+ NULL
+ },
+ { NULL }
+};
+
+GOptionGroup *
+mbimcli_basic_connect_get_option_group (void)
+{
+ GOptionGroup *group;
+
+ group = g_option_group_new ("basic-connect",
+ "Basic Connect options",
+ "Show Basic Connect Service options",
+ NULL,
+ NULL);
+ g_option_group_add_entries (group, entries);
+
+ return group;
+}
+
+gboolean
+mbimcli_basic_connect_options_enabled (void)
+{
+ static guint n_actions = 0;
+ static gboolean checked = FALSE;
+
+ if (checked)
+ return !!n_actions;
+
+ n_actions = (query_device_caps_flag +
+ query_subscriber_ready_status_flag +
+ query_radio_state_flag +
+ query_device_services_flag +
+ query_pin_flag +
+ !!set_pin_enter_str +
+ !!set_pin_change_str +
+ !!set_pin_enable_str +
+ !!set_pin_disable_str +
+ !!set_pin_enter_puk_str +
+ query_register_state_flag +
+ query_home_provider_flag +
+ query_preferred_providers_flag +
+ query_visible_providers_flag +
+ set_register_state_automatic_flag +
+ query_signal_state_flag +
+ query_packet_service_flag +
+ set_packet_service_attach_flag +
+ set_packet_service_detach_flag +
+ query_connect_flag +
+ !!set_connect_activate_str +
+ set_connect_deactivate_flag +
+ query_packet_statistics_flag);
+
+ if (n_actions > 1) {
+ g_printerr ("error: too many Basic Connect actions requested\n");
+ exit (EXIT_FAILURE);
+ }
+
+ checked = TRUE;
+ return !!n_actions;
+}
+
+static void
+context_free (Context *context)
+{
+ if (!context)
+ return;
+
+ if (context->cancellable)
+ g_object_unref (context->cancellable);
+ if (context->device)
+ g_object_unref (context->device);
+ g_slice_free (Context, context);
+}
+
+static void
+shutdown (gboolean operation_status)
+{
+ /* Cleanup context and finish async operation */
+ context_free (ctx);
+ mbimcli_async_operation_done (operation_status);
+}
+
+static void
+query_device_caps_ready (MbimDevice *device,
+ GAsyncResult *res)
+{
+ MbimMessage *response;
+ GError *error = NULL;
+ MbimDeviceType device_type;
+ const gchar *device_type_str;
+ MbimCellularClass cellular_class;
+ gchar *cellular_class_str;
+ MbimVoiceClass voice_class;
+ const gchar *voice_class_str;
+ MbimSimClass sim_class;
+ gchar *sim_class_str;
+ MbimDataClass data_class;
+ gchar *data_class_str;
+ MbimSmsCaps sms_caps;
+ gchar *sms_caps_str;
+ MbimCtrlCaps ctrl_caps;
+ gchar *ctrl_caps_str;
+ guint32 max_sessions;
+ gchar *custom_data_class;
+ gchar *device_id;
+ gchar *firmware_info;
+ gchar *hardware_info;
+
+ response = mbim_device_command_finish (device, res, &error);
+ if (!response) {
+ g_printerr ("error: operation failed: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ if (!mbim_message_device_caps_response_parse (
+ response,
+ &device_type,
+ &cellular_class,
+ &voice_class,
+ &sim_class,
+ &data_class,
+ &sms_caps,
+ &ctrl_caps,
+ &max_sessions,
+ &custom_data_class,
+ &device_id,
+ &firmware_info,
+ &hardware_info,
+ &error)) {
+ g_printerr ("error: couldn't parse response message: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ device_type_str = mbim_device_type_get_string (device_type);
+ cellular_class_str = mbim_cellular_class_build_string_from_mask (cellular_class);
+ voice_class_str = mbim_device_type_get_string (voice_class);
+ sim_class_str = mbim_sim_class_build_string_from_mask (sim_class);
+ data_class_str = mbim_data_class_build_string_from_mask (data_class);
+ sms_caps_str = mbim_sms_caps_build_string_from_mask (sms_caps);
+ ctrl_caps_str = mbim_ctrl_caps_build_string_from_mask (ctrl_caps);
+
+#undef VALIDATE_UNKNOWN
+#define VALIDATE_UNKNOWN(str) (str ? str : "unknown")
+
+ g_print ("[%s] Device capabilities retrieved:\n"
+ "\t Device type: '%s'\n"
+ "\t Cellular class: '%s'\n"
+ "\t Voice class: '%s'\n"
+ "\t Sim class: '%s'\n"
+ "\t Data class: '%s'\n"
+ "\t SMS caps: '%s'\n"
+ "\t Ctrl caps: '%s'\n"
+ "\t Max sessions: '%u'\n"
+ "\tCustom data class: '%s'\n"
+ "\t Device ID: '%s'\n"
+ "\t Firmware info: '%s'\n"
+ "\t Hardware info: '%s'\n",
+ mbim_device_get_path_display (device),
+ VALIDATE_UNKNOWN (device_type_str),
+ VALIDATE_UNKNOWN (cellular_class_str),
+ VALIDATE_UNKNOWN (voice_class_str),
+ VALIDATE_UNKNOWN (sim_class_str),
+ VALIDATE_UNKNOWN (data_class_str),
+ VALIDATE_UNKNOWN (sms_caps_str),
+ VALIDATE_UNKNOWN (ctrl_caps_str),
+ max_sessions,
+ VALIDATE_UNKNOWN (custom_data_class),
+ VALIDATE_UNKNOWN (device_id),
+ VALIDATE_UNKNOWN (firmware_info),
+ VALIDATE_UNKNOWN (hardware_info));
+
+ g_free (cellular_class_str);
+ g_free (sim_class_str);
+ g_free (data_class_str);
+ g_free (sms_caps_str);
+ g_free (ctrl_caps_str);
+ g_free (custom_data_class);
+ g_free (device_id);
+ g_free (firmware_info);
+ g_free (hardware_info);
+
+ mbim_message_unref (response);
+ shutdown (TRUE);
+}
+
+static void
+query_subscriber_ready_status_ready (MbimDevice *device,
+ GAsyncResult *res)
+{
+ MbimMessage *response;
+ GError *error = NULL;
+ MbimSubscriberReadyState ready_state;
+ const gchar *ready_state_str;
+ gchar *subscriber_id;
+ gchar *sim_iccid;
+ MbimReadyInfoFlag ready_info;
+ gchar *ready_info_str;
+ guint32 telephone_numbers_count;
+ gchar **telephone_numbers;
+ gchar *telephone_numbers_str;
+
+ response = mbim_device_command_finish (device, res, &error);
+ if (!response) {
+ g_printerr ("error: operation failed: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ if (!mbim_message_subscriber_ready_status_response_parse (
+ response,
+ &ready_state,
+ &subscriber_id,
+ &sim_iccid,
+ &ready_info,
+ &telephone_numbers_count,
+ &telephone_numbers,
+ &error)) {
+ g_printerr ("error: couldn't parse response message: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ telephone_numbers_str = (telephone_numbers ? g_strjoinv (", ", telephone_numbers) : NULL);
+ ready_state_str = mbim_subscriber_ready_state_get_string (ready_state);
+ ready_info_str = mbim_ready_info_flag_build_string_from_mask (ready_info);
+
+#undef VALIDATE_UNKNOWN
+#define VALIDATE_UNKNOWN(str) (str ? str : "unknown")
+
+ g_print ("[%s] Subscriber ready status retrieved:\n"
+ "\t Ready state: '%s'\n"
+ "\t Subscriber ID: '%s'\n"
+ "\t SIM ICCID: '%s'\n"
+ "\t Ready info: '%s'\n"
+ "\tTelephone numbers: (%u) '%s'\n",
+ mbim_device_get_path_display (device),
+ VALIDATE_UNKNOWN (ready_state_str),
+ VALIDATE_UNKNOWN (subscriber_id),
+ VALIDATE_UNKNOWN (sim_iccid),
+ VALIDATE_UNKNOWN (ready_info_str),
+ telephone_numbers_count, VALIDATE_UNKNOWN (telephone_numbers_str));
+
+ g_free (subscriber_id);
+ g_free (sim_iccid);
+ g_free (ready_info_str);
+ g_strfreev (telephone_numbers);
+ g_free (telephone_numbers_str);
+
+ mbim_message_unref (response);
+ shutdown (TRUE);
+}
+
+static void
+query_radio_state_ready (MbimDevice *device,
+ GAsyncResult *res)
+{
+ MbimMessage *response;
+ GError *error = NULL;
+ MbimRadioSwitchState hardware_radio_state;
+ const gchar *hardware_radio_state_str;
+ MbimRadioSwitchState software_radio_state;
+ const gchar *software_radio_state_str;
+
+ response = mbim_device_command_finish (device, res, &error);
+ if (!response) {
+ g_printerr ("error: operation failed: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ if (!mbim_message_radio_state_response_parse (
+ response,
+ &hardware_radio_state,
+ &software_radio_state,
+ &error)) {
+ g_printerr ("error: couldn't parse response message: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ hardware_radio_state_str = mbim_radio_switch_state_get_string (hardware_radio_state);
+ software_radio_state_str = mbim_radio_switch_state_get_string (software_radio_state);
+
+#undef VALIDATE_UNKNOWN
+#define VALIDATE_UNKNOWN(str) (str ? str : "unknown")
+
+ g_print ("[%s] Radio state retrieved:\n"
+ "\t Hardware Radio State: '%s'\n"
+ "\t Software Radio State: '%s'\n",
+ mbim_device_get_path_display (device),
+ VALIDATE_UNKNOWN (hardware_radio_state_str),
+ VALIDATE_UNKNOWN (software_radio_state_str));
+
+ mbim_message_unref (response);
+ shutdown (TRUE);
+}
+
+static void
+query_device_services_ready (MbimDevice *device,
+ GAsyncResult *res)
+{
+ MbimMessage *response;
+ GError *error = NULL;
+ MbimDeviceServiceElement **device_services;
+ guint32 device_services_count;
+ guint32 max_dss_sessions;
+
+ response = mbim_device_command_finish (device, res, &error);
+ if (!response) {
+ g_printerr ("error: operation failed: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ if (!mbim_message_device_services_response_parse (
+ response,
+ &device_services_count,
+ &max_dss_sessions,
+ &device_services,
+ &error)) {
+ g_printerr ("error: couldn't parse response message: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ g_print ("[%s] Device services retrieved:\n"
+ "\tMax DSS sessions: '%u'\n",
+ mbim_device_get_path_display (device),
+ max_dss_sessions);
+ if (device_services_count == 0)
+ g_print ("\t Services: None\n");
+ else {
+ guint32 i;
+
+ g_print ("\t Services: (%u)\n", device_services_count);
+ for (i = 0; i < device_services_count; i++) {
+ MbimService service;
+ gchar *uuid_str;
+ GString *cids;
+ guint32 j;
+
+ service = mbim_uuid_to_service (&device_services[i]->device_service_id);
+ uuid_str = mbim_uuid_get_printable (&device_services[i]->device_service_id);
+
+ cids = g_string_new ("");
+ for (j = 0; j < device_services[i]->cids_count; j++) {
+ if (service == MBIM_SERVICE_INVALID) {
+ g_string_append_printf (cids, "%u", device_services[i]->cids[j]);
+ if (j < device_services[i]->cids_count - 1)
+ g_string_append (cids, ", ");
+ } else {
+ g_string_append_printf (cids, "%s%s (%u)",
+ j == 0 ? "" : "\t\t ",
+ mbim_cid_get_printable (service, device_services[i]->cids[j]),
+ device_services[i]->cids[j]);
+ if (j < device_services[i]->cids_count - 1)
+ g_string_append (cids, ",\n");
+ }
+ }
+
+ g_print ("\n"
+ "\t\t Service: '%s'\n"
+ "\t\t UUID: [%s]:\n"
+ "\t\t DSS payload: %u\n"
+ "\t\tMax DSS instances: %u\n"
+ "\t\t CIDs: %s\n",
+ service == MBIM_SERVICE_INVALID ? "unknown" : mbim_service_get_string (service),
+ uuid_str,
+ device_services[i]->dss_payload,
+ device_services[i]->max_dss_instances,
+ cids->str);
+
+ g_string_free (cids, TRUE);
+ g_free (uuid_str);
+ }
+ }
+
+ mbim_device_service_element_array_free (device_services);
+
+ mbim_message_unref (response);
+ shutdown (TRUE);
+}
+
+static void
+pin_ready (MbimDevice *device,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ MbimMessage *response;
+ GError *error = NULL;
+ MbimPinType pin_type;
+ MbimPinState pin_state;
+ const gchar *pin_state_str;
+ guint32 remaining_attempts;
+
+ response = mbim_device_command_finish (device, res, &error);
+ if (!response || !mbim_message_command_done_get_result (response, &error)) {
+ g_printerr ("error: operation failed: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ if (!mbim_message_pin_response_parse (
+ response,
+ &pin_type,
+ &pin_state,
+ &remaining_attempts,
+ &error)) {
+ g_printerr ("error: couldn't parse response message: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ if (GPOINTER_TO_UINT (user_data))
+ g_print ("[%s] PIN operation successful\n\n",
+ mbim_device_get_path_display (device));
+
+#undef VALIDATE_UNKNOWN
+#define VALIDATE_UNKNOWN(str) (str ? str : "unknown")
+
+ pin_state_str = mbim_pin_state_get_string (pin_state);
+
+ g_print ("[%s] Pin Info:\n"
+ "\t Pin State: '%s'\n",
+ mbim_device_get_path_display (device),
+ VALIDATE_UNKNOWN (pin_state_str));
+ if (pin_type != MBIM_PIN_TYPE_UNKNOWN) {
+ const gchar *pin_type_str;
+
+ pin_type_str = mbim_pin_type_get_string (pin_type);
+ g_print ("\t PinType: '%s'\n"
+ "\tRemaining attempts: '%u'\n",
+ VALIDATE_UNKNOWN (pin_type_str),
+ remaining_attempts);
+ }
+
+ mbim_message_unref (response);
+ shutdown (TRUE);
+}
+
+static gboolean
+set_pin_input_parse (guint n_expected,
+ const gchar *str,
+ gchar **pin,
+ gchar **new_pin)
+{
+ gchar **split;
+
+ g_assert (n_expected == 1 || n_expected == 2);
+ g_assert (pin != NULL);
+ g_assert (new_pin != NULL);
+
+ /* Format of the string is:
+ * "[(current PIN)]"
+ * or:
+ * "[(current PIN),(new PIN)]"
+ */
+ split = g_strsplit (str, ",", -1);
+
+ if (g_strv_length (split) > n_expected) {
+ g_printerr ("error: couldn't parse input string, too many arguments\n");
+ g_strfreev (split);
+ return FALSE;
+ }
+
+ if (g_strv_length (split) < n_expected) {
+ g_printerr ("error: couldn't parse input string, missing arguments\n");
+ g_strfreev (split);
+ return FALSE;
+ }
+
+ *pin = split[0];
+ *new_pin = split[1] ? split[1] : NULL;
+
+ g_free (split);
+ return TRUE;
+}
+
+enum {
+ CONNECTION_STATUS,
+ CONNECT,
+ DISCONNECT
+};
+
+static void
+connect_ready (MbimDevice *device,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ MbimMessage *response;
+ GError *error = NULL;
+ guint32 session_id;
+ MbimActivationState activation_state;
+ MbimVoiceCallState voice_call_state;
+ MbimContextIpType ip_type;
+ const MbimUuid *context_type;
+ guint32 nw_error;
+
+ response = mbim_device_command_finish (device, res, &error);
+ if (!response || !mbim_message_command_done_get_result (response, &error)) {
+ g_printerr ("error: operation failed: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ if (!mbim_message_connect_response_parse (
+ response,
+ &session_id,
+ &activation_state,
+ &voice_call_state,
+ &ip_type,
+ &context_type,
+ &nw_error,
+ &error)) {
+ g_printerr ("error: couldn't parse response message: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ switch (GPOINTER_TO_UINT (user_data)) {
+ case CONNECT:
+ g_print ("[%s] Successfully connected\n\n",
+ mbim_device_get_path_display (device));
+ break;
+ case DISCONNECT:
+ g_print ("[%s] Successfully disconnected\n\n",
+ mbim_device_get_path_display (device));
+ break;
+ default:
+ break;
+ }
+
+#undef VALIDATE_UNKNOWN
+#define VALIDATE_UNKNOWN(str) (str ? str : "unknown")
+
+ g_print ("[%s] Connection status:\n"
+ "\t Session ID: '%u'\n"
+ "\tActivation state: '%s'\n"
+ "\tVoice call state: '%s'\n"
+ "\t IP type: '%s'\n"
+ "\t Context type: '%s'\n"
+ "\t Network error: '%s'\n",
+ mbim_device_get_path_display (device),
+ session_id,
+ VALIDATE_UNKNOWN (mbim_activation_state_get_string (activation_state)),
+ VALIDATE_UNKNOWN (mbim_voice_call_state_get_string (voice_call_state)),
+ VALIDATE_UNKNOWN (mbim_context_ip_type_get_string (ip_type)),
+ VALIDATE_UNKNOWN (mbim_context_type_get_string (mbim_uuid_to_context_type (context_type))),
+ VALIDATE_UNKNOWN (mbim_nw_error_get_string (nw_error)));
+
+ mbim_message_unref (response);
+ shutdown (TRUE);
+}
+
+static gboolean
+set_connect_activate_parse (const gchar *str,
+ gchar **apn,
+ MbimAuthProtocol *auth_protocol,
+ gchar **username,
+ gchar **password)
+{
+ gchar **split;
+
+ g_assert (apn != NULL);
+ g_assert (auth_protocol != NULL);
+ g_assert (username != NULL);
+ g_assert (password != NULL);
+
+ /* Format of the string is:
+ * "[(APN),(PAP|CHAP|MSCHAPV2),(Username),(Password)]"
+ */
+ split = g_strsplit (str, ",", -1);
+
+ if (g_strv_length (split) > 4) {
+ g_printerr ("error: couldn't parse input string, too many arguments\n");
+ g_strfreev (split);
+ return FALSE;
+ }
+
+ if (g_strv_length (split) < 1) {
+ g_printerr ("error: couldn't parse input string, missing arguments\n");
+ g_strfreev (split);
+ return FALSE;
+ }
+
+ /* APN */
+ *apn = split[0];
+
+ /* Some defaults */
+ *auth_protocol = MBIM_AUTH_PROTOCOL_NONE;
+ *username = NULL;
+ *password = NULL;
+
+ /* Use authentication method */
+ if (split[1]) {
+ if (g_ascii_strcasecmp (split[1], "PAP") == 0)
+ *auth_protocol = MBIM_AUTH_PROTOCOL_PAP;
+ else if (g_ascii_strcasecmp (split[1], "CHAP") == 0)
+ *auth_protocol = MBIM_AUTH_PROTOCOL_CHAP;
+ else if (g_ascii_strcasecmp (split[1], "MSCHAPV2") == 0)
+ *auth_protocol = MBIM_AUTH_PROTOCOL_MSCHAPV2;
+ else
+ *auth_protocol = MBIM_AUTH_PROTOCOL_NONE;
+
+ /* Username */
+ if (split[2]) {
+ *username = split[2];
+
+ /* Password */
+ if (split[3])
+ *password = split[3];
+ }
+ }
+
+ g_free (split);
+ return TRUE;
+}
+
+static void
+home_provider_ready (MbimDevice *device,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ MbimMessage *response;
+ GError *error = NULL;
+ MbimProvider *provider;
+ gchar *provider_state_str;
+ gchar *cellular_class_str;
+
+ response = mbim_device_command_finish (device, res, &error);
+ if (!response || !mbim_message_command_done_get_result (response, &error)) {
+ g_printerr ("error: operation failed: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ if (!mbim_message_home_provider_response_parse (response,
+ &provider,
+ &error)) {
+ g_printerr ("error: couldn't parse response message: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ provider_state_str = mbim_provider_state_build_string_from_mask (provider->provider_state);
+ cellular_class_str = mbim_cellular_class_build_string_from_mask (provider->cellular_class);
+
+#undef VALIDATE_UNKNOWN
+#define VALIDATE_UNKNOWN(str) (str ? str : "unknown")
+
+ g_print ("[%s] Home provider:\n"
+ "\t Provider ID: '%s'\n"
+ "\t Provider Name: '%s'\n"
+ "\t State: '%s'\n"
+ "\tCellular class: '%s'\n"
+ "\t RSSI: '%u'\n"
+ "\t Error rate: '%u'\n",
+ mbim_device_get_path_display (device),
+ VALIDATE_UNKNOWN (provider->provider_id),
+ VALIDATE_UNKNOWN (provider->provider_name),
+ VALIDATE_UNKNOWN (provider_state_str),
+ VALIDATE_UNKNOWN (cellular_class_str),
+ provider->rssi,
+ provider->error_rate);
+
+ g_free (cellular_class_str);
+ g_free (provider_state_str);
+
+ mbim_provider_free (provider);
+ mbim_message_unref (response);
+ shutdown (TRUE);
+}
+
+static void
+preferred_providers_ready (MbimDevice *device,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ MbimMessage *response;
+ GError *error = NULL;
+ MbimProvider **providers;
+ guint n_providers;
+ guint i;
+
+ response = mbim_device_command_finish (device, res, &error);
+ if (!response || !mbim_message_command_done_get_result (response, &error)) {
+ g_printerr ("error: operation failed: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ if (!mbim_message_preferred_providers_response_parse (response,
+ &n_providers,
+ &providers,
+ &error)) {
+ g_printerr ("error: couldn't parse response message: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ if (!n_providers)
+ g_print ("[%s] No preferred providers given\n",
+ mbim_device_get_path_display (device));
+ else
+ g_print ("[%s] Preferred providers (%u):\n",
+ mbim_device_get_path_display (device),
+ n_providers);
+
+ for (i = 0; i < n_providers; i++) {
+ gchar *provider_state_str;
+ gchar *cellular_class_str;
+
+ provider_state_str = mbim_provider_state_build_string_from_mask (providers[i]->provider_state);
+ cellular_class_str = mbim_cellular_class_build_string_from_mask (providers[i]->cellular_class);
+
+#undef VALIDATE_UNKNOWN
+#define VALIDATE_UNKNOWN(str) (str ? str : "unknown")
+
+ g_print ("\tProvider [%u]:\n"
+ "\t\t Provider ID: '%s'\n"
+ "\t\t Provider Name: '%s'\n"
+ "\t\t State: '%s'\n"
+ "\t\t Cellular class: '%s'\n"
+ "\t\t RSSI: '%u'\n"
+ "\t\t Error rate: '%u'\n",
+ i,
+ VALIDATE_UNKNOWN (providers[i]->provider_id),
+ VALIDATE_UNKNOWN (providers[i]->provider_name),
+ VALIDATE_UNKNOWN (provider_state_str),
+ VALIDATE_UNKNOWN (cellular_class_str),
+ providers[i]->rssi,
+ providers[i]->error_rate);
+
+ g_free (cellular_class_str);
+ g_free (provider_state_str);
+ }
+
+ mbim_provider_array_free (providers);
+ mbim_message_unref (response);
+ shutdown (TRUE);
+}
+
+static void
+visible_providers_ready (MbimDevice *device,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ MbimMessage *response;
+ GError *error = NULL;
+ MbimProvider **providers;
+ guint n_providers;
+ guint i;
+
+ response = mbim_device_command_finish (device, res, &error);
+ if (!response || !mbim_message_command_done_get_result (response, &error)) {
+ g_printerr ("error: operation failed: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ if (!mbim_message_visible_providers_response_parse (response,
+ &n_providers,
+ &providers,
+ &error)) {
+ g_printerr ("error: couldn't parse response message: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ if (!n_providers)
+ g_print ("[%s] No visible providers given\n",
+ mbim_device_get_path_display (device));
+ else
+ g_print ("[%s] Visible providers (%u):\n",
+ mbim_device_get_path_display (device),
+ n_providers);
+
+ for (i = 0; i < n_providers; i++) {
+ gchar *provider_state_str;
+ gchar *cellular_class_str;
+
+ provider_state_str = mbim_provider_state_build_string_from_mask (providers[i]->provider_state);
+ cellular_class_str = mbim_cellular_class_build_string_from_mask (providers[i]->cellular_class);
+
+#undef VALIDATE_UNKNOWN
+#define VALIDATE_UNKNOWN(str) (str ? str : "unknown")
+
+ g_print ("\tProvider [%u]:\n"
+ "\t\t Provider ID: '%s'\n"
+ "\t\t Provider Name: '%s'\n"
+ "\t\t State: '%s'\n"
+ "\t\t Cellular class: '%s'\n"
+ "\t\t RSSI: '%u'\n"
+ "\t\t Error rate: '%u'\n",
+ i,
+ VALIDATE_UNKNOWN (providers[i]->provider_id),
+ VALIDATE_UNKNOWN (providers[i]->provider_name),
+ VALIDATE_UNKNOWN (provider_state_str),
+ VALIDATE_UNKNOWN (cellular_class_str),
+ providers[i]->rssi,
+ providers[i]->error_rate);
+
+ g_free (cellular_class_str);
+ g_free (provider_state_str);
+ }
+
+ mbim_provider_array_free (providers);
+ mbim_message_unref (response);
+ shutdown (TRUE);
+}
+
+static void
+register_state_ready (MbimDevice *device,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ MbimMessage *response;
+ GError *error = NULL;
+ MbimNwError nw_error;
+ MbimRegisterState register_state;
+ MbimRegisterMode register_mode;
+ MbimDataClass available_data_classes;
+ gchar *available_data_classes_str;
+ MbimCellularClass cellular_class;
+ gchar *cellular_class_str;
+ gchar *provider_id;
+ gchar *provider_name;
+ gchar *roaming_text;
+ MbimRegistrationFlag registration_flag;
+ gchar *registration_flag_str;
+
+ response = mbim_device_command_finish (device, res, &error);
+ if (!response || !mbim_message_command_done_get_result (response, &error)) {
+ g_printerr ("error: operation failed: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ if (!mbim_message_register_state_response_parse (response,
+ &nw_error,
+ ®ister_state,
+ ®ister_mode,
+ &available_data_classes,
+ &cellular_class,
+ &provider_id,
+ &provider_name,
+ &roaming_text,
+ ®istration_flag,
+ &error)) {
+ g_printerr ("error: couldn't parse response message: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ if (GPOINTER_TO_UINT (user_data))
+ g_print ("[%s] Successfully launched automatic registration\n\n",
+ mbim_device_get_path_display (device));
+
+ available_data_classes_str = mbim_data_class_build_string_from_mask (available_data_classes);
+ cellular_class_str = mbim_cellular_class_build_string_from_mask (cellular_class);
+ registration_flag_str = mbim_registration_flag_build_string_from_mask (registration_flag);
+
+#undef VALIDATE_UNKNOWN
+#define VALIDATE_UNKNOWN(str) (str ? str : "unknown")
+
+ g_print ("[%s] Registration status:\n"
+ "\t Network error: '%s'\n"
+ "\t Register state: '%s'\n"
+ "\t Register mode: '%s'\n"
+ "\tAvailable data classes: '%s'\n"
+ "\tCurrent cellular class: '%s'\n"
+ "\t Provider ID: '%s'\n"
+ "\t Provider name: '%s'\n"
+ "\t Roaming text: '%s'\n"
+ "\t Registration flags: '%s'\n",
+ mbim_device_get_path_display (device),
+ VALIDATE_UNKNOWN (mbim_nw_error_get_string (nw_error)),
+ VALIDATE_UNKNOWN (mbim_register_state_get_string (register_state)),
+ VALIDATE_UNKNOWN (mbim_register_mode_get_string (register_mode)),
+ VALIDATE_UNKNOWN (available_data_classes_str),
+ VALIDATE_UNKNOWN (cellular_class_str),
+ VALIDATE_UNKNOWN (provider_id),
+ VALIDATE_UNKNOWN (provider_name),
+ VALIDATE_UNKNOWN (roaming_text),
+ VALIDATE_UNKNOWN (registration_flag_str));
+
+ g_free (available_data_classes_str);
+ g_free (cellular_class_str);
+ g_free (registration_flag_str);
+ g_free (provider_name);
+ g_free (provider_id);
+ g_free (roaming_text);
+
+ mbim_message_unref (response);
+ shutdown (TRUE);
+}
+
+static void
+signal_state_ready (MbimDevice *device,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ MbimMessage *response;
+ GError *error = NULL;
+ guint32 rssi;
+ guint32 error_rate;
+ guint32 signal_strength_interval;
+ guint32 rssi_threshold;
+ guint32 error_rate_threshold;
+
+ response = mbim_device_command_finish (device, res, &error);
+ if (!response || !mbim_message_command_done_get_result (response, &error)) {
+ g_printerr ("error: operation failed: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ if (!mbim_message_signal_state_response_parse (response,
+ &rssi,
+ &error_rate,
+ &signal_strength_interval,
+ &rssi_threshold,
+ &error_rate_threshold,
+ &error)) {
+ g_printerr ("error: couldn't parse response message: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ g_print ("[%s] Signal state:\n"
+ "\t RSSI [0-31,99]: '%u'\n"
+ "\t Error rate [0-7,99]: '%u'\n"
+ "\tSignal strength interval: '%u'\n"
+ "\t RSSI threshold: '%u'\n",
+ mbim_device_get_path_display (device),
+ rssi,
+ error_rate,
+ signal_strength_interval,
+ rssi_threshold);
+
+ if (error_rate_threshold == 0xFFFFFFFF)
+ g_print ("\t Error rate threshold: 'unspecified'\n");
+ else
+ g_print ("\t Error rate threshold: '%u'\n", error_rate_threshold);
+
+ mbim_message_unref (response);
+ shutdown (TRUE);
+}
+
+enum {
+ PACKET_SERVICE_STATUS,
+ PACKET_SERVICE_ATTACH,
+ PACKET_SERVICE_DETACH
+};
+
+static void
+packet_service_ready (MbimDevice *device,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ MbimMessage *response;
+ GError *error = NULL;
+ guint32 nw_error;
+ MbimPacketServiceState packet_service_state;
+ MbimDataClass highest_available_data_class;
+ gchar *highest_available_data_class_str;
+ guint64 uplink_speed;
+ guint64 downlink_speed;
+
+ response = mbim_device_command_finish (device, res, &error);
+ if (!response || !mbim_message_command_done_get_result (response, &error)) {
+ g_printerr ("error: operation failed: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ if (!mbim_message_packet_service_response_parse (response,
+ &nw_error,
+ &packet_service_state,
+ &highest_available_data_class,
+ &uplink_speed,
+ &downlink_speed,
+ &error)) {
+ g_printerr ("error: couldn't parse response message: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ switch (GPOINTER_TO_UINT (user_data)) {
+ case PACKET_SERVICE_ATTACH:
+ g_print ("[%s] Successfully attached to packet service\n\n",
+ mbim_device_get_path_display (device));
+ break;
+ case PACKET_SERVICE_DETACH:
+ g_print ("[%s] Successfully detached from packet service\n\n",
+ mbim_device_get_path_display (device));
+ break;
+ default:
+ break;
+ }
+
+#undef VALIDATE_UNKNOWN
+#define VALIDATE_UNKNOWN(str) (str ? str : "unknown")
+
+ highest_available_data_class_str = mbim_data_class_build_string_from_mask (highest_available_data_class);
+
+ g_print ("[%s] Packet service status:\n"
+ "\t Network error: '%s'\n"
+ "\t Packet service state: '%s'\n"
+ "\tAvailable data classes: '%s'\n"
+ "\t Uplink speed: '%" G_GUINT64_FORMAT " bps'\n"
+ "\t Downlink speed: '%" G_GUINT64_FORMAT " bps'\n",
+ mbim_device_get_path_display (device),
+ VALIDATE_UNKNOWN (mbim_nw_error_get_string (nw_error)),
+ VALIDATE_UNKNOWN (mbim_packet_service_state_get_string (packet_service_state)),
+ VALIDATE_UNKNOWN (highest_available_data_class_str),
+ uplink_speed,
+ downlink_speed);
+
+ g_free (highest_available_data_class_str);
+
+ mbim_message_unref (response);
+ shutdown (TRUE);
+}
+
+static void
+packet_statistics_ready (MbimDevice *device,
+ GAsyncResult *res)
+{
+ MbimMessage *response;
+ GError *error = NULL;
+ guint32 in_discards;
+ guint32 in_errors;
+ guint64 in_octets;
+ guint64 in_packets;
+ guint64 out_octets;
+ guint64 out_packets;
+ guint32 out_errors;
+ guint32 out_discards;
+
+ response = mbim_device_command_finish (device, res, &error);
+ if (!response || !mbim_message_command_done_get_result (response, &error)) {
+ g_printerr ("error: operation failed: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ if (!mbim_message_packet_statistics_response_parse (response,
+ &in_discards,
+ &in_errors,
+ &in_octets,
+ &in_packets,
+ &out_octets,
+ &out_packets,
+ &out_errors,
+ &out_discards,
+ &error)) {
+ g_printerr ("error: couldn't parse response message: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ g_print ("[%s] Packet statistics:\n"
+ "\t Octets (in): '%" G_GUINT64_FORMAT "'\n"
+ "\t Packets (in): '%" G_GUINT64_FORMAT "'\n"
+ "\t Discards (in): '%u'\n"
+ "\t Errors (in): '%u'\n"
+ "\t Octets (out): '%" G_GUINT64_FORMAT "'\n"
+ "\t Packets (out): '%" G_GUINT64_FORMAT "'\n"
+ "\tDiscards (out): '%u'\n"
+ "\t Errors (out): '%u'\n",
+ mbim_device_get_path_display (device),
+ in_octets,
+ in_packets,
+ in_discards,
+ in_errors,
+ out_octets,
+ out_packets,
+ out_discards,
+ out_errors);
+
+ mbim_message_unref (response);
+ shutdown (TRUE);
+}
+
+void
+mbimcli_basic_connect_run (MbimDevice *device,
+ GCancellable *cancellable)
+{
+ /* Initialize context */
+ ctx = g_slice_new (Context);
+ ctx->device = g_object_ref (device);
+ if (cancellable)
+ ctx->cancellable = g_object_ref (cancellable);
+
+ /* Request to get capabilities? */
+ if (query_device_caps_flag) {
+ MbimMessage *request;
+
+ g_debug ("Asynchronously querying device capabilities...");
+ request = (mbim_message_device_caps_query_new (NULL));
+ mbim_device_command (ctx->device,
+ request,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)query_device_caps_ready,
+ NULL);
+ mbim_message_unref (request);
+ return;
+ }
+
+ /* Request to get subscriber ready status? */
+ if (query_subscriber_ready_status_flag) {
+ MbimMessage *request;
+
+ g_debug ("Asynchronously querying subscriber ready status...");
+ request = (mbim_message_subscriber_ready_status_query_new (NULL));
+ mbim_device_command (ctx->device,
+ request,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)query_subscriber_ready_status_ready,
+ NULL);
+ mbim_message_unref (request);
+ return;
+ }
+
+ /* Request to get radio state? */
+ if (query_radio_state_flag) {
+ MbimMessage *request;
+
+ g_debug ("Asynchronously querying radio state...");
+ request = (mbim_message_radio_state_query_new (NULL));
+ mbim_device_command (ctx->device,
+ request,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)query_radio_state_ready,
+ NULL);
+ mbim_message_unref (request);
+ return;
+ }
+
+ /* Request to query device services? */
+ if (query_device_services_flag) {
+ MbimMessage *request;
+
+ g_debug ("Asynchronously querying device services...");
+ request = (mbim_message_device_services_query_new (NULL));
+ mbim_device_command (ctx->device,
+ request,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)query_device_services_ready,
+ NULL);
+ mbim_message_unref (request);
+ return;
+ }
+
+ /* Query PIN state? */
+ if (query_pin_flag) {
+ MbimMessage *request;
+
+ g_debug ("Asynchronously querying PIN state...");
+ request = (mbim_message_pin_query_new (NULL));
+ mbim_device_command (ctx->device,
+ request,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)pin_ready,
+ GUINT_TO_POINTER (FALSE));
+ mbim_message_unref (request);
+ return;
+ }
+
+ /* Set PIN? */
+ if (set_pin_enter_str ||
+ set_pin_change_str ||
+ set_pin_enable_str ||
+ set_pin_disable_str ||
+ set_pin_enter_puk_str) {
+ MbimMessage *request;
+ guint n_expected;
+ MbimPinType pin_type;
+ MbimPinOperation pin_operation;
+ gchar *pin;
+ gchar *new_pin;
+ const gchar *input = NULL;
+ GError *error = NULL;
+
+ if (set_pin_enter_puk_str) {
+ g_debug ("Asynchronously entering PUK...");
+ pin_type = MBIM_PIN_TYPE_PUK1;
+ input = set_pin_enter_puk_str;
+ n_expected = 2;
+ pin_operation = MBIM_PIN_OPERATION_ENTER;
+ } else {
+ pin_type = MBIM_PIN_TYPE_PIN1;
+ if (set_pin_change_str) {
+ g_debug ("Asynchronously changing PIN...");
+ input = set_pin_change_str;
+ n_expected = 2;
+ pin_operation = MBIM_PIN_OPERATION_CHANGE;
+ } else if (set_pin_enable_str) {
+ g_debug ("Asynchronously enabling PIN...");
+ input = set_pin_enable_str;
+ n_expected = 1;
+ pin_operation = MBIM_PIN_OPERATION_ENABLE;
+ } else if (set_pin_disable_str) {
+ g_debug ("Asynchronously disabling PIN...");
+ input = set_pin_disable_str;
+ n_expected = 1;
+ pin_operation = MBIM_PIN_OPERATION_DISABLE;
+ } else if (set_pin_enter_str) {
+ g_debug ("Asynchronously entering PIN...");
+ input = set_pin_enter_str;
+ n_expected = 1;
+ pin_operation = MBIM_PIN_OPERATION_ENTER;
+ } else
+ g_assert_not_reached ();
+ }
+
+ if (!set_pin_input_parse (n_expected, input, &pin, &new_pin)) {
+ shutdown (FALSE);
+ return;
+ }
+
+ request = (mbim_message_pin_set_new (pin_type,
+ pin_operation,
+ pin,
+ new_pin,
+ &error));
+ g_free (pin);
+ g_free (new_pin);
+
+ if (!request) {
+ g_printerr ("error: couldn't create request: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ mbim_device_command (ctx->device,
+ request,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)pin_ready,
+ GUINT_TO_POINTER (TRUE));
+ mbim_message_unref (request);
+ return;
+ }
+
+ /* Query home provider? */
+ if (query_home_provider_flag) {
+ MbimMessage *request;
+
+ request = mbim_message_home_provider_query_new (NULL);
+ mbim_device_command (ctx->device,
+ request,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)home_provider_ready,
+ NULL);
+ mbim_message_unref (request);
+ return;
+ }
+
+ /* Query preferred providers? */
+ if (query_preferred_providers_flag) {
+ MbimMessage *request;
+
+ request = mbim_message_preferred_providers_query_new (NULL);
+ mbim_device_command (ctx->device,
+ request,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)preferred_providers_ready,
+ NULL);
+ mbim_message_unref (request);
+ return;
+ }
+
+ /* Query visible providers? */
+ if (query_visible_providers_flag) {
+ MbimMessage *request;
+
+ request = mbim_message_visible_providers_query_new (MBIM_VISIBLE_PROVIDERS_ACTION_FULL_SCAN, NULL);
+ mbim_device_command (ctx->device,
+ request,
+ 60, /* longer timeout, needs to scan */
+ ctx->cancellable,
+ (GAsyncReadyCallback)visible_providers_ready,
+ NULL);
+ mbim_message_unref (request);
+ return;
+ }
+
+ /* Query registration status? */
+ if (query_register_state_flag) {
+ MbimMessage *request;
+
+ request = mbim_message_register_state_query_new (NULL);
+ mbim_device_command (ctx->device,
+ request,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)register_state_ready,
+ GUINT_TO_POINTER (FALSE));
+ mbim_message_unref (request);
+ return;
+ }
+
+ /* Launch automatic registration? */
+ if (set_register_state_automatic_flag) {
+ MbimMessage *request;
+ GError *error = NULL;
+
+ request = mbim_message_register_state_set_new (NULL,
+ MBIM_REGISTER_ACTION_AUTOMATIC,
+ 0,
+ &error);
+ if (!request) {
+ g_printerr ("error: couldn't create request: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ mbim_device_command (ctx->device,
+ request,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)register_state_ready,
+ GUINT_TO_POINTER (TRUE));
+ mbim_message_unref (request);
+ return;
+ }
+
+ /* Query signal status? */
+ if (query_signal_state_flag) {
+ MbimMessage *request;
+
+ request = mbim_message_signal_state_query_new (NULL);
+ mbim_device_command (ctx->device,
+ request,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)signal_state_ready,
+ NULL);
+ mbim_message_unref (request);
+ return;
+ }
+
+ /* Query packet service status? */
+ if (query_packet_service_flag) {
+ MbimMessage *request;
+
+ request = mbim_message_packet_service_query_new (NULL);
+ mbim_device_command (ctx->device,
+ request,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)packet_service_ready,
+ GUINT_TO_POINTER (PACKET_SERVICE_STATUS));
+ mbim_message_unref (request);
+ return;
+ }
+
+ /* Launch packet attach or detach? */
+ if (set_packet_service_attach_flag ||
+ set_packet_service_detach_flag) {
+ MbimMessage *request;
+ MbimPacketServiceAction action;
+ GError *error = NULL;
+
+ if (set_packet_service_attach_flag)
+ action = MBIM_PACKET_SERVICE_ACTION_ATTACH;
+ else if (set_packet_service_detach_flag)
+ action = MBIM_PACKET_SERVICE_ACTION_DETACH;
+ else
+ g_assert_not_reached ();
+
+ request = mbim_message_packet_service_set_new (action, &error);
+ if (!request) {
+ g_printerr ("error: couldn't create request: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ mbim_device_command (ctx->device,
+ request,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)packet_service_ready,
+ GUINT_TO_POINTER (set_packet_service_attach_flag ?
+ PACKET_SERVICE_ATTACH :
+ PACKET_SERVICE_DETACH));
+ mbim_message_unref (request);
+ return;
+ }
+
+ /* Query connection status? */
+ if (query_connect_flag) {
+ MbimMessage *request;
+ GError *error = NULL;
+
+ request = mbim_message_connect_query_new (0,
+ MBIM_ACTIVATION_COMMAND_ACTIVATE,
+ MBIM_VOICE_CALL_STATE_NONE,
+ MBIM_CONTEXT_IP_TYPE_DEFAULT,
+ mbim_uuid_from_context_type (MBIM_CONTEXT_TYPE_INTERNET),
+ 0,
+ &error);
+ if (!request) {
+ g_printerr ("error: couldn't create request: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ mbim_device_command (ctx->device,
+ request,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)connect_ready,
+ GUINT_TO_POINTER (CONNECTION_STATUS));
+ mbim_message_unref (request);
+ return;
+ }
+
+ /* Connect? */
+ if (set_connect_activate_str) {
+ MbimMessage *request;
+ GError *error = NULL;
+ gchar *apn;
+ MbimAuthProtocol auth_protocol;
+ gchar *username = NULL;
+ gchar *password = NULL;
+
+ if (!set_connect_activate_parse (set_connect_activate_str,
+ &apn,
+ &auth_protocol,
+ &username,
+ &password)) {
+ shutdown (FALSE);
+ return;
+ }
+
+ request = mbim_message_connect_set_new (0,
+ MBIM_ACTIVATION_COMMAND_ACTIVATE,
+ apn,
+ username,
+ password,
+ MBIM_COMPRESSION_NONE,
+ auth_protocol,
+ MBIM_CONTEXT_IP_TYPE_DEFAULT,
+ mbim_uuid_from_context_type (MBIM_CONTEXT_TYPE_INTERNET),
+ &error);
+ g_free (apn);
+ g_free (username);
+ g_free (password);
+
+ if (!request) {
+ g_printerr ("error: couldn't create request: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ mbim_device_command (ctx->device,
+ request,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)connect_ready,
+ GUINT_TO_POINTER (CONNECT));
+ mbim_message_unref (request);
+ return;
+ }
+
+ /* Disconnect? */
+ if (set_connect_deactivate_flag) {
+ MbimMessage *request;
+ GError *error = NULL;
+
+ request = mbim_message_connect_set_new (0,
+ MBIM_ACTIVATION_COMMAND_DEACTIVATE,
+ NULL,
+ NULL,
+ NULL,
+ MBIM_COMPRESSION_NONE,
+ MBIM_AUTH_PROTOCOL_NONE,
+ MBIM_CONTEXT_IP_TYPE_DEFAULT,
+ mbim_uuid_from_context_type (MBIM_CONTEXT_TYPE_INTERNET),
+ &error);
+ if (!request) {
+ g_printerr ("error: couldn't create request: %s\n", error->message);
+ g_error_free (error);
+ shutdown (FALSE);
+ return;
+ }
+
+ mbim_device_command (ctx->device,
+ request,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)connect_ready,
+ GUINT_TO_POINTER (DISCONNECT));
+ mbim_message_unref (request);
+ return;
+ }
+
+ /* Packet statistics? */
+ if (query_packet_statistics_flag) {
+ MbimMessage *request;
+
+ request = mbim_message_packet_statistics_query_new (NULL);
+ mbim_device_command (ctx->device,
+ request,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)packet_statistics_ready,
+ NULL);
+ mbim_message_unref (request);
+ return;
+ }
+
+ g_warn_if_reached ();
+}
diff --git a/cli/mbimcli.c b/cli/mbimcli.c
new file mode 100644
index 0000000..e4f9215
--- /dev/null
+++ b/cli/mbimcli.c
@@ -0,0 +1,418 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * mbimcli -- Command line interface to control MBIM devices
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <gio/gio.h>
+
+#include <libmbim-glib.h>
+
+#include "mbimcli.h"
+
+#define PROGRAM_NAME "mbimcli"
+#define PROGRAM_VERSION PACKAGE_VERSION
+
+/* Globals */
+static GMainLoop *loop;
+static GCancellable *cancellable;
+static MbimDevice *device;
+static MbimService service;
+static gboolean operation_status;
+
+/* Main options */
+static gchar *device_str;
+static gchar *no_open_str;
+static gboolean no_close_flag;
+static gboolean noop_flag;
+static gboolean verbose_flag;
+static gboolean silent_flag;
+static gboolean version_flag;
+
+static GOptionEntry main_entries[] = {
+ { "device", 'd', 0, G_OPTION_ARG_STRING, &device_str,
+ "Specify device path",
+ "[PATH]"
+ },
+ { "no-open", 0, 0, G_OPTION_ARG_STRING, &no_open_str,
+ "Do not explicitly open the MBIM device before running the command",
+ "[Transaction ID]"
+ },
+ { "no-close", 0, 0, G_OPTION_ARG_NONE, &no_close_flag,
+ "Do not close the MBIM device after running the command",
+ NULL
+ },
+ { "noop", 0, 0, G_OPTION_ARG_NONE, &noop_flag,
+ "Don't run any command",
+ NULL
+ },
+ { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose_flag,
+ "Run action with verbose logs, including the debug ones",
+ NULL
+ },
+ { "silent", 0, 0, G_OPTION_ARG_NONE, &silent_flag,
+ "Run action with no logs; not even the error/warning ones",
+ NULL
+ },
+ { "version", 'V', 0, G_OPTION_ARG_NONE, &version_flag,
+ "Print version",
+ NULL
+ },
+ { NULL }
+};
+
+static void
+signals_handler (int signum)
+{
+ if (cancellable) {
+ /* Ignore consecutive requests of cancellation */
+ if (!g_cancellable_is_cancelled (cancellable)) {
+ g_printerr ("%s\n",
+ "cancelling the operation...\n");
+ g_cancellable_cancel (cancellable);
+ }
+ return;
+ }
+
+ if (loop &&
+ g_main_loop_is_running (loop)) {
+ g_printerr ("%s\n",
+ "cancelling the main loop...\n");
+ g_main_loop_quit (loop);
+ }
+}
+
+static void
+log_handler (const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer user_data)
+{
+ const gchar *log_level_str;
+ time_t now;
+ gchar time_str[64];
+ struct tm *local_time;
+ gboolean err;
+
+ /* Nothing to do if we're silent */
+ if (silent_flag)
+ return;
+
+ now = time ((time_t *) NULL);
+ local_time = localtime (&now);
+ strftime (time_str, 64, "%d %b %Y, %H:%M:%S", local_time);
+ err = FALSE;
+
+ switch (log_level) {
+ case G_LOG_LEVEL_WARNING:
+ log_level_str = "-Warning **";
+ err = TRUE;
+ break;
+
+ case G_LOG_LEVEL_CRITICAL:
+ case G_LOG_FLAG_FATAL:
+ case G_LOG_LEVEL_ERROR:
+ log_level_str = "-Error **";
+ err = TRUE;
+ break;
+
+ case G_LOG_LEVEL_DEBUG:
+ log_level_str = "[Debug]";
+ break;
+
+ default:
+ log_level_str = "";
+ break;
+ }
+
+ if (!verbose_flag && !err)
+ return;
+
+ g_fprintf (err ? stderr : stdout,
+ "[%s] %s %s\n",
+ time_str,
+ log_level_str,
+ message);
+}
+
+static void
+print_version_and_exit (void)
+{
+ g_print ("\n"
+ PROGRAM_NAME " " PROGRAM_VERSION "\n"
+ "Copyright (2013) Aleksander Morgado\n"
+ "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl-2.0.html>\n"
+ "This is free software: you are free to change and redistribute it.\n"
+ "There is NO WARRANTY, to the extent permitted by law.\n"
+ "\n");
+ exit (EXIT_SUCCESS);
+}
+
+/*****************************************************************************/
+/* Running asynchronously */
+
+static void
+device_close_ready (MbimDevice *dev,
+ GAsyncResult *res)
+{
+ GError *error = NULL;
+
+ if (!mbim_device_close_finish (dev, res, &error)) {
+ g_printerr ("error: couldn't close device: %s", error->message);
+ g_error_free (error);
+ } else
+ g_debug ("Device closed");
+
+ /* If we left the device open, dump next transaction id */
+ if (no_close_flag) {
+ guint transaction_id;
+
+ g_object_get (dev,
+ MBIM_DEVICE_TRANSACTION_ID, &transaction_id,
+ NULL);
+
+ g_print ("[%s] Session not closed:\n"
+ "\t TRID: '%u'\n",
+ mbim_device_get_path_display (dev),
+ transaction_id);
+ }
+
+ g_main_loop_quit (loop);
+}
+
+void
+mbimcli_async_operation_done (gboolean reported_operation_status)
+{
+ /* Keep the result of the operation */
+ operation_status = reported_operation_status;
+
+ if (cancellable) {
+ g_object_unref (cancellable);
+ cancellable = NULL;
+ }
+
+ /* Set the in-session setup */
+ g_object_set (device,
+ MBIM_DEVICE_IN_SESSION, no_close_flag,
+ NULL);
+
+ /* Close the device */
+ mbim_device_close (device,
+ 15,
+ cancellable,
+ (GAsyncReadyCallback) device_close_ready,
+ NULL);
+}
+
+static void
+device_open_ready (MbimDevice *dev,
+ GAsyncResult *res)
+{
+ GError *error = NULL;
+
+ if (!mbim_device_open_finish (dev, res, &error)) {
+ g_printerr ("error: couldn't open the MbimDevice: %s\n",
+ error->message);
+ exit (EXIT_FAILURE);
+ }
+
+ g_debug ("MBIM Device at '%s' ready",
+ mbim_device_get_path_display (dev));
+
+ /* If no operation requested, finish */
+ if (noop_flag) {
+ mbimcli_async_operation_done (TRUE);
+ return;
+ }
+
+ /* Run the service-specific action */
+ switch (service) {
+ case MBIM_SERVICE_BASIC_CONNECT:
+ mbimcli_basic_connect_run (dev, cancellable);
+ return;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static guint
+read_transaction_id (const gchar *str)
+{
+ gulong num;
+
+ if (!str || !str[0])
+ return 0;
+
+ for (num = 0; str[num]; num++) {
+ if (!g_ascii_isdigit (str[num]))
+ return 0;
+ }
+
+ errno = 0;
+ num = strtoul (str, NULL, 10);
+ if (!errno && num <= G_MAXUINT) {
+ return (guint)num;
+ }
+ return 0;
+}
+
+static void
+device_new_ready (GObject *unused,
+ GAsyncResult *res)
+{
+ GError *error = NULL;
+
+ device = mbim_device_new_finish (res, &error);
+ if (!device) {
+ g_printerr ("error: couldn't create MbimDevice: %s\n",
+ error->message);
+ exit (EXIT_FAILURE);
+ }
+
+ /* Set the in-session setup */
+ if (no_open_str) {
+ guint transaction_id;
+
+ transaction_id = read_transaction_id (no_open_str);
+ if (!transaction_id) {
+ g_printerr ("error: invalid transaction ID specified: %s\n",
+ no_open_str);
+ exit (EXIT_FAILURE);
+ }
+
+ g_object_set (device,
+ MBIM_DEVICE_IN_SESSION, TRUE,
+ MBIM_DEVICE_TRANSACTION_ID, transaction_id,
+ NULL);
+ }
+
+ /* Open the device */
+ mbim_device_open (device,
+ 15,
+ cancellable,
+ (GAsyncReadyCallback) device_open_ready,
+ NULL);
+}
+
+/*****************************************************************************/
+
+static void
+parse_actions (void)
+{
+ guint actions_enabled = 0;
+
+ /* Basic Connect options? */
+ if (mbimcli_basic_connect_options_enabled ()) {
+ service = MBIM_SERVICE_BASIC_CONNECT;
+ actions_enabled++;
+ }
+
+ /* Noop */
+ if (noop_flag)
+ actions_enabled++;
+
+ /* Cannot mix actions from different services */
+ if (actions_enabled > 1) {
+ g_printerr ("error: cannot execute multiple actions of different services\n");
+ exit (EXIT_FAILURE);
+ }
+
+ /* No options? */
+ if (actions_enabled == 0) {
+ g_printerr ("error: no actions specified\n");
+ exit (EXIT_FAILURE);
+ }
+
+ /* Go on! */
+}
+
+int main (int argc, char **argv)
+{
+ GError *error = NULL;
+ GFile *file;
+ GOptionContext *context;
+
+ setlocale (LC_ALL, "");
+
+ g_type_init ();
+
+ /* Setup option context, process it and destroy it */
+ context = g_option_context_new ("- Control MBIM devices");
+ g_option_context_add_group (context,
+ mbimcli_basic_connect_get_option_group ());
+ g_option_context_add_main_entries (context, main_entries, NULL);
+ if (!g_option_context_parse (context, &argc, &argv, &error)) {
+ g_printerr ("error: %s\n",
+ error->message);
+ exit (EXIT_FAILURE);
+ }
+ g_option_context_free (context);
+
+ if (version_flag)
+ print_version_and_exit ();
+
+ g_log_set_handler (NULL, G_LOG_LEVEL_MASK, log_handler, NULL);
+ g_log_set_handler ("Mbim", G_LOG_LEVEL_MASK, log_handler, NULL);
+ if (verbose_flag)
+ mbim_utils_set_traces_enabled (TRUE);
+
+ /* No device path given? */
+ if (!device_str) {
+ g_printerr ("error: no device path specified\n");
+ exit (EXIT_FAILURE);
+ }
+
+ /* Build new GFile from the commandline arg */
+ file = g_file_new_for_commandline_arg (device_str);
+
+ /* Setup signals */
+ signal (SIGINT, signals_handler);
+ signal (SIGHUP, signals_handler);
+ signal (SIGTERM, signals_handler);
+
+ /* Create requirements for async options */
+ cancellable = g_cancellable_new ();
+ loop = g_main_loop_new (NULL, FALSE);
+
+ parse_actions ();
+
+ /* Launch MbimDevice creation */
+ mbim_device_new (file,
+ cancellable,
+ (GAsyncReadyCallback)device_new_ready,
+ NULL);
+ g_main_loop_run (loop);
+
+ if (cancellable)
+ g_object_unref (cancellable);
+ if (device)
+ g_object_unref (device);
+ g_main_loop_unref (loop);
+ g_object_unref (file);
+
+ return (operation_status ? EXIT_SUCCESS : EXIT_FAILURE);
+}
diff --git a/cli/mbimcli.h b/cli/mbimcli.h
new file mode 100644
index 0000000..78942df
--- /dev/null
+++ b/cli/mbimcli.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * mbimcli -- Command line interface to control MBIM devices
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#include <glib.h>
+
+#ifndef __MBIMCLI_H__
+#define __MBIMCLI_H__
+
+/* Common */
+void mbimcli_async_operation_done (gboolean operation_status);
+
+/* Basic Connect group */
+GOptionGroup *mbimcli_basic_connect_get_option_group (void);
+gboolean mbimcli_basic_connect_options_enabled (void);
+void mbimcli_basic_connect_run (MbimDevice *device,
+ GCancellable *cancellable);
+
+
+#endif /* __MBIMCLI_H__ */
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..5b80910
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,117 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_PREREQ([2.68])
+
+dnl The libmbim version number
+m4_define([mbim_major_version], [1])
+m4_define([mbim_minor_version], [5])
+m4_define([mbim_micro_version], [0])
+m4_define([mbim_version],
+ [mbim_major_version.mbim_minor_version.mbim_micro_version])
+
+dnl libtool versioning for libmbim-glib (-version-info c:r:a)
+dnl If the interface is unchanged, but the implementation has changed or
+dnl been fixed, then increment r.
+dnl Otherwise, increment c and zero r.
+dnl If the interface has grown (that is, the new library is compatible
+dnl with old code), increment a.
+dnl If the interface has changed in an incompatible way (that is,
+dnl functions have changed or been removed), then zero a.
+m4_define([mbim_glib_lt_current], [2])
+m4_define([mbim_glib_lt_revision], [0])
+m4_define([mbim_glib_lt_age], [2])
+
+
+AC_INIT([libmbim], [mbim_version], [libmbim-devel@lists.freedesktop.org])
+AC_CONFIG_SRCDIR([config.h.in])
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+AM_INIT_AUTOMAKE([1.11 no-define no-dist-gzip dist-xz tar-ustar -Wno-portability])
+AM_MAINTAINER_MODE([enable])
+
+dnl Support silent build rules. Disable
+dnl by either passing --disable-silent-rules to configure or passing V=1
+dnl to make
+AM_SILENT_RULES([yes])
+
+dnl Required programs
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_INSTALL
+
+dnl Initialize libtool
+LT_PREREQ([2.2])
+LT_INIT
+
+dnl Specific warnings to always use
+LIBMBIM_COMPILER_WARNINGS
+
+dnl Version stuff
+MBIM_MAJOR_VERSION=mbim_major_version
+MBIM_MINOR_VERSION=mbim_minor_version
+MBIM_MICRO_VERSION=mbim_micro_version
+MBIM_VERSION=mbim_version
+AC_SUBST(MBIM_MAJOR_VERSION)
+AC_SUBST(MBIM_MINOR_VERSION)
+AC_SUBST(MBIM_MICRO_VERSION)
+AC_SUBST(MBIM_VERSION)
+
+dnl libtool version stuff
+MBIM_GLIB_LT_CURRENT=mbim_glib_lt_current
+MBIM_GLIB_LT_REVISION=mbim_glib_lt_revision
+MBIM_GLIB_LT_AGE=mbim_glib_lt_age
+AC_SUBST(MBIM_GLIB_LT_CURRENT)
+AC_SUBST(MBIM_GLIB_LT_REVISION)
+AC_SUBST(MBIM_GLIB_LT_AGE)
+
+dnl General dependencies for libmbim-glib
+PKG_CHECK_MODULES(LIBMBIM_GLIB,
+ glib-2.0 >= 2.32
+ gobject-2.0
+ gio-2.0
+ gudev-1.0 >= 147)
+AC_SUBST(LIBMBIM_GLIB_CFLAGS)
+AC_SUBST(LIBMBIM_GLIB_LIBS)
+
+dnl General dependencies for mbimcli
+PKG_CHECK_MODULES(MBIMCLI,
+ glib-2.0 >= 2.32
+ gobject-2.0
+ gio-2.0)
+AC_SUBST(MBIMCLI_CFLAGS)
+AC_SUBST(MBIMCLI_LIBS)
+
+GLIB_MKENUMS=`$PKG_CONFIG --variable=glib_mkenums glib-2.0`
+AC_SUBST(GLIB_MKENUMS)
+
+dnl Documentation
+GTK_DOC_CHECK(1.0)
+
+AC_CONFIG_FILES([Makefile
+ build-aux/Makefile
+ build-aux/templates/Makefile
+ build-aux/mbim-codegen/Makefile
+ data/Makefile
+ data/pkg-config/Makefile
+ data/pkg-config/mbim-glib.pc
+ libmbim-glib/Makefile
+ libmbim-glib/mbim-version.h
+ libmbim-glib/generated/Makefile
+ libmbim-glib/test/Makefile
+ cli/Makefile
+ utils/Makefile
+ docs/Makefile
+ docs/reference/Makefile
+ docs/reference/libmbim-glib/Makefile
+ docs/reference/libmbim-glib/version.xml])
+AC_OUTPUT
+
+echo "
+ libmbim $VERSION
+ ==============================================
+
+ compiler: ${CC}
+ cflags: ${CFLAGS}
+ Maintainer mode: ${USE_MAINTAINER_MODE}
+ Documentation: ${enable_gtk_doc}
+"
diff --git a/data/Makefile.am b/data/Makefile.am
new file mode 100644
index 0000000..091c2e2
--- /dev/null
+++ b/data/Makefile.am
@@ -0,0 +1,10 @@
+SUBDIRS = . pkg-config
+
+EXTRA_DIST = \
+ mbim-service-basic-connect.json \
+ mbim-service-sms.json \
+ mbim-service-ussd.json \
+ mbim-service-auth.json \
+ mbim-service-phonebook.json \
+ mbim-service-stk.json \
+ mbim-service-dss.json
diff --git a/data/mbim-service-auth.json b/data/mbim-service-auth.json
new file mode 100644
index 0000000..b518e38
--- /dev/null
+++ b/data/mbim-service-auth.json
@@ -0,0 +1,89 @@
+
+[
+ // *********************************************************************************
+ { "type" : "Service",
+ "name" : "Auth" },
+
+ // *********************************************************************************
+ { "name" : "Aka",
+ "service" : "Auth",
+ "type" : "Command",
+ "query" : [ { "name" : "Rand",
+ "format" : "byte-array",
+ "array-size" : "16" },
+ { "name" : "Autn",
+ "format" : "byte-array",
+ "array-size" : "16" } ],
+ "response" : [ { "name" : "Res",
+ "format" : "byte-array",
+ "array-size" : "16" },
+ { "name" : "ResLen",
+ "format" : "guint32" },
+ { "name" : "IntegratingKey",
+ "format" : "byte-array",
+ "array-size" : "16" },
+ { "name" : "CipheringKey",
+ "format" : "byte-array",
+ "array-size" : "16" },
+ { "name" : "Auts",
+ "format" : "byte-array",
+ "array-size" : "14" } ] },
+
+ // *********************************************************************************
+ { "name" : "Akap",
+ "service" : "Auth",
+ "type" : "Command",
+ "query" : [ { "name" : "Rand",
+ "format" : "byte-array",
+ "array-size" : "16" },
+ { "name" : "Autn",
+ "format" : "byte-array",
+ "array-size" : "16" },
+ { "name" : "NetworkName",
+ "format" : "string" } ],
+ "response" : [ { "name" : "Res",
+ "format" : "byte-array",
+ "array-size" : "16" },
+ { "name" : "ResLen",
+ "format" : "guint32" },
+ { "name" : "IntegratingKey",
+ "format" : "byte-array",
+ "array-size" : "16" },
+ { "name" : "CipheringKey",
+ "format" : "byte-array",
+ "array-size" : "16" },
+ { "name" : "Auts",
+ "format" : "byte-array",
+ "array-size" : "14" } ] },
+
+ // *********************************************************************************
+ { "name" : "Sim",
+ "service" : "Auth",
+ "type" : "Command",
+ "query" : [ { "name" : "Rand1",
+ "format" : "byte-array",
+ "array-size" : "16" },
+ { "name" : "Rand2",
+ "format" : "byte-array",
+ "array-size" : "16" },
+ { "name" : "Rand3",
+ "format" : "byte-array",
+ "array-size" : "16" },
+ { "name" : "N",
+ "format" : "guint32" } ],
+ "response" : [ { "name" : "Sres1",
+ "format" : "guint32" },
+ { "name" : "Kc1",
+ "format" : "guint64" },
+ { "name" : "Sres2",
+ "format" : "guint32" },
+ { "name" : "Kc2",
+ "format" : "guint64" },
+ { "name" : "Sres3",
+ "format" : "guint32" },
+ { "name" : "Kc3",
+ "format" : "guint64" },
+ { "name" : "N",
+ "format" : "guint32" } ] }
+
+]
diff --git a/data/mbim-service-basic-connect.json b/data/mbim-service-basic-connect.json
new file mode 100644
index 0000000..7a32409
--- /dev/null
+++ b/data/mbim-service-basic-connect.json
@@ -0,0 +1,796 @@
+
+[
+ // *********************************************************************************
+ { "type" : "Service",
+ "name" : "Basic Connect" },
+
+ // *********************************************************************************
+ { "name" : "Device Caps",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "query" : [],
+ "response" : [ { "name" : "DeviceType",
+ "format" : "guint32",
+ "public-format" : "MbimDeviceType" },
+ { "name" : "CellularClass",
+ "format" : "guint32",
+ "public-format" : "MbimCellularClass" },
+ { "name" : "VoiceClass",
+ "format" : "guint32",
+ "public-format" : "MbimVoiceClass" },
+ { "name" : "SimClass",
+ "format" : "guint32",
+ "public-format" : "MbimSimClass" },
+ { "name" : "DataClass",
+ "format" : "guint32",
+ "public-format" : "MbimDataClass" },
+ { "name" : "SmsCaps",
+ "format" : "guint32",
+ "public-format" : "MbimSmsCaps" },
+ { "name" : "ControlCaps",
+ "format" : "guint32",
+ "public-format" : "MbimCtrlCaps" },
+ { "name" : "MaxSessions",
+ "format" : "guint32" },
+ { "name" : "CustomDataClass",
+ "format" : "string",
+ "max-size" : "22" },
+ { "name" : "DeviceId",
+ "format" : "string",
+ "max-size" : "36" },
+ { "name" : "FirmwareInfo",
+ "format" : "string",
+ "max-size" : "60" },
+ { "name" : "HardwareInfo",
+ "format" : "string",
+ "max-size" : "60" } ] },
+
+ // *********************************************************************************
+ { "name" : "Subscriber Ready Status",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "query" : [],
+ "response" : [ { "name" : "ReadyState",
+ "format" : "guint32",
+ "public-format" : "MbimSubscriberReadyState" },
+ { "name" : "SubscriberID",
+ "format" : "string" },
+ { "name" : "SimIccId",
+ "format" : "string" },
+ { "name" : "ReadyInfo",
+ "format" : "guint32",
+ "public-format" : "MbimReadyInfoFlag" },
+ { "name" : "TelephoneNumbersCount",
+ "format" : "guint32" },
+ { "name" : "TelephoneNumbers",
+ "format" : "string-array",
+ "array-size-field" : "TelephoneNumbersCount" } ] },
+
+ // *********************************************************************************
+ { "name" : "Radio State",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "set" : [ { "name" : "RadioState",
+ "format" : "guint32",
+ "public-format" : "MbimRadioSwitchState" } ],
+ "query" : [],
+ "response" : [ { "name" : "HwRadioState",
+ "format" : "guint32",
+ "public-format" : "MbimRadioSwitchState" },
+ { "name" : "SwRadioState",
+ "format" : "guint32",
+ "public-format" : "MbimRadioSwitchState" } ],
+ "notification" : [ { "name" : "HwRadioState",
+ "format" : "guint32",
+ "public-format" : "MbimRadioSwitchState" },
+ { "name" : "SwRadioState",
+ "format" : "guint32",
+ "public-format" : "MbimRadioSwitchState" } ] },
+
+ // *********************************************************************************
+ { "name" : "Pin",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "set" : [ { "name" : "PinType",
+ "format" : "guint32",
+ "public-format" : "MbimPinType" },
+ { "name" : "PinOperation",
+ "format" : "guint32",
+ "public-format" : "MbimPinOperation" },
+ { "name" : "Pin",
+ "format" : "string" },
+ { "name" : "NewPin",
+ "format" : "string" } ],
+ "query" : [],
+ "response" : [ { "name" : "PinType",
+ "format" : "guint32",
+ "public-format" : "MbimPinType" },
+ { "name" : "PinState",
+ "format" : "guint32",
+ "public-format" : "MbimPinState" },
+ { "name" : "RemainingAttempts",
+ "format" : "guint32" } ] },
+
+ // *********************************************************************************
+ { "name" : "MbimPinDesc",
+ "type" : "Struct",
+ "contents" : [ { "name" : "PinMode",
+ "format" : "guint32",
+ "public-format" : "MbimPinMode" },
+ { "name" : "PinFormat",
+ "format" : "guint32",
+ "public-format" : "MbimPinFormat" },
+ { "name" : "PinLengthMin",
+ "format" : "guint32" },
+ { "name" : "PinLengthMax",
+ "format" : "guint32" } ] },
+
+ { "name" : "Pin List",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "query" : [],
+ "response" : [ { "name" : "PinDescPin1",
+ "format" : "struct",
+ "struct-type" : "MbimPinDesc" },
+ { "name" : "PinDescPin2",
+ "format" : "struct",
+ "struct-type" : "MbimPinDesc" },
+ { "name" : "PinDescDeviceSimPin",
+ "format" : "struct",
+ "struct-type" : "MbimPinDesc" },
+ { "name" : "PinDescDeviceFirstSimPin",
+ "format" : "struct",
+ "struct-type" : "MbimPinDesc" },
+ { "name" : "PinDescNetworkPin",
+ "format" : "struct",
+ "struct-type" : "MbimPinDesc" },
+ { "name" : "PinDescNetworkSubsetPin",
+ "format" : "struct",
+ "struct-type" : "MbimPinDesc" },
+ { "name" : "PinDescServiceProviderPin",
+ "format" : "struct",
+ "struct-type" : "MbimPinDesc" },
+ { "name" : "PinDescCorporatePin",
+ "format" : "struct",
+ "struct-type" : "MbimPinDesc" },
+ { "name" : "PinDescSubsidyLock",
+ "format" : "struct",
+ "struct-type" : "MbimPinDesc" },
+ { "name" : "PinDescCustom",
+ "format" : "struct",
+ "struct-type" : "MbimPinDesc" } ] },
+
+ // *********************************************************************************
+ { "name" : "MbimProvider",
+ "type" : "Struct",
+ "contents" : [ { "name" : "ProviderId",
+ "format" : "string" },
+ { "name" : "ProviderState",
+ "format" : "guint32",
+ "public-format" : "MbimProviderState" },
+ { "name" : "ProviderName",
+ "format" : "string" },
+ { "name" : "CellularClass",
+ "format" : "guint32",
+ "public-format" : "MbimCellularClass" },
+ { "name" : "RSSI",
+ "format" : "guint32" },
+ { "name" : "ErrorRate",
+ "format" : "guint32" } ] },
+
+ { "name" : "Home Provider",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "set" : [ { "name" : "Provider",
+ "format" : "struct" ,
+ "struct-type" : "MbimProvider" } ],
+ "query" : [],
+ "response" : [ { "name" : "Provider",
+ "format" : "struct",
+ "struct-type" : "MbimProvider" } ] },
+
+ // *********************************************************************************
+ { "name" : "Preferred Providers",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "set" : [ { "name" : "ProvidersCount",
+ "format" : "guint32" },
+ { "name" : "Providers",
+ "format" : "ref-struct-array" ,
+ "struct-type" : "MbimProvider",
+ "array-size-field" : "ProvidersCount" } ],
+ "query" : [],
+ "response" : [ { "name" : "ProvidersCount",
+ "format" : "guint32" },
+ { "name" : "Providers",
+ "format" : "ref-struct-array" ,
+ "struct-type" : "MbimProvider",
+ "array-size-field" : "ProvidersCount" } ],
+ "indication" : [ { "name" : "ProvidersCount",
+ "format" : "guint32" },
+ { "name" : "Providers",
+ "format" : "ref-struct-array" ,
+ "struct-type" : "MbimProvider",
+ "array-size-field" : "ProvidersCount" } ] },
+
+ // *********************************************************************************
+ { "name" : "Visible Providers",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "query" : [ { "name" : "Action",
+ "format": "guint32",
+ "public-format" : "MbimVisibleProvidersAction" } ],
+ "response" : [ { "name" : "ProvidersCount",
+ "format" : "guint32" },
+ { "name" : "Providers",
+ "format" : "ref-struct-array" ,
+ "struct-type" : "MbimProvider",
+ "array-size-field" : "ProvidersCount" } ] },
+
+ // *********************************************************************************
+ { "name" : "Register State",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "set" : [ { "name" : "ProviderId",
+ "format" : "string" },
+ { "name" : "RegisterAction",
+ "format" : "guint32",
+ "public-format" : "MbimRegisterAction" },
+ { "name" : "DataClass",
+ "format" : "guint32",
+ "public-format" : "MbimDataClass" } ],
+ "query" : [],
+ "response" : [ { "name" : "NwError",
+ "format" : "guint32",
+ "public-format" : "MbimNwError" },
+ { "name" : "RegisterState",
+ "format" : "guint32",
+ "public-format" : "MbimRegisterState" },
+ { "name" : "RegisterMode",
+ "format" : "guint32",
+ "public-format" : "MbimRegisterMode" },
+ { "name" : "AvailableDataClasses",
+ "format" : "guint32",
+ "public-format" : "MbimDataClass" },
+ { "name" : "CurrentCellularClass",
+ "format" : "guint32",
+ "public-format" : "MbimCellularClass" },
+ { "name" : "ProviderId",
+ "format" : "string" },
+ { "name" : "ProviderName",
+ "format" : "string" },
+ { "name" : "RoamingText",
+ "format" : "string" },
+ { "name" : "RegistrationFlag",
+ "format" : "guint32",
+ "public-format" : "MbimRegistrationFlag" } ],
+ "notification" : [ { "name" : "NwError",
+ "format" : "guint32",
+ "public-format" : "MbimNwError" },
+ { "name" : "RegisterState",
+ "format" : "guint32",
+ "public-format" : "MbimRegisterState" },
+ { "name" : "RegisterMode",
+ "format" : "guint32",
+ "public-format" : "MbimRegisterMode" },
+ { "name" : "AvailableDataClasses",
+ "format" : "guint32",
+ "public-format" : "MbimDataClass" },
+ { "name" : "CurrentCellularClass",
+ "format" : "guint32",
+ "public-format" : "MbimCellularClass" },
+ { "name" : "ProviderId",
+ "format" : "string" },
+ { "name" : "ProviderName",
+ "format" : "string" },
+ { "name" : "RoamingText",
+ "format" : "string" },
+ { "name" : "RegistrationFlag",
+ "format" : "guint32",
+ "public-format" : "MbimRegistrationFlag" } ] },
+
+ // *********************************************************************************
+ { "name" : "Signal State",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "set" : [ { "name" : "SignalStrengthInterval",
+ "format" : "guint32" },
+ { "name" : "RssiThreshold",
+ "format" : "guint32" },
+ { "name" : "ErrorRateThreshold",
+ "format" : "guint32" } ],
+ "query" : [],
+ "response" : [ { "name" : "Rssi",
+ "format" : "guint32" },
+ { "name" : "ErrorRate",
+ "format" : "guint32" },
+ { "name" : "SignalStrengthInterval",
+ "format" : "guint32" },
+ { "name" : "RssiThreshold",
+ "format" : "guint32" },
+ { "name" : "ErrorRateThreshold",
+ "format" : "guint32" } ],
+ "notification" : [ { "name" : "Rssi",
+ "format" : "guint32" },
+ { "name" : "ErrorRate",
+ "format" : "guint32" },
+ { "name" : "SignalStrengthInterval",
+ "format" : "guint32" },
+ { "name" : "RssiThreshold",
+ "format" : "guint32" },
+ { "name" : "ErrorRateThreshold",
+ "format" : "guint32" } ] },
+
+
+ // *********************************************************************************
+ { "name" : "Packet Service",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "set" : [ { "name" : "PacketServiceAction",
+ "format" : "guint32",
+ "public-format" : "MbimPacketServiceAction" } ],
+ "query" : [],
+ "response" : [ { "name" : "NwError",
+ "format" : "guint32" },
+ { "name" : "PacketServiceState",
+ "format" : "guint32",
+ "public-format" : "MbimPacketServiceState" },
+ { "name" : "HighestAvailableDataClass",
+ "format" : "guint32",
+ "public-format" : "MbimDataClass" },
+ { "name" : "UplinkSpeed",
+ "format" : "guint64" },
+ { "name" : "DownlinkSpeed",
+ "format" : "guint64" } ],
+ "notification" : [ { "name" : "NwError",
+ "format" : "guint32" },
+ { "name" : "PacketServiceState",
+ "format" : "guint32",
+ "public-format" : "MbimPacketServiceState" },
+ { "name" : "HighestAvailableDataClass",
+ "format" : "guint32",
+ "public-format" : "MbimDataClass" },
+ { "name" : "UplinkSpeed",
+ "format" : "guint64" },
+ { "name" : "DownlinkSpeed",
+ "format" : "guint64" } ] },
+
+ // *********************************************************************************
+ { "name" : "Connect",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "set" : [ { "name" : "SessionId",
+ "format" : "guint32" },
+ { "name" : "ActivationCommand",
+ "format" : "guint32",
+ "public-format" : "MbimActivationCommand" },
+ { "name" : "AccessString",
+ "format" : "string" },
+ { "name" : "UserName",
+ "format" : "string" },
+ { "name" : "Password",
+ "format" : "string" },
+ { "name" : "Compression",
+ "format" : "guint32",
+ "public-format" : "MbimCompression" },
+ { "name" : "AuthProtocol",
+ "format" : "guint32",
+ "public-format" : "MbimAuthProtocol" },
+ { "name" : "IpType",
+ "format" : "guint32",
+ "public-format" : "MbimContextIpType" },
+ { "name" : "ContextType",
+ "format" : "uuid" } ],
+ "query" : [ { "name" : "SessionId",
+ "format" : "guint32" },
+ { "name" : "ActivationState",
+ "format" : "guint32",
+ "public-format" : "MbimActivationState" },
+ { "name" : "VoiceCallState",
+ "format" : "guint32",
+ "public-format" : "MbimVoiceCallState" },
+ { "name" : "IpType",
+ "format" : "guint32",
+ "public-format" : "MbimContextIpType" },
+ { "name" : "ContextType",
+ "format" : "uuid" },
+ { "name" : "NwError",
+ "format" : "guint32" } ],
+ "response" : [ { "name" : "SessionId",
+ "format" : "guint32" },
+ { "name" : "ActivationState",
+ "format" : "guint32",
+ "public-format" : "MbimActivationState" },
+ { "name" : "VoiceCallState",
+ "format" : "guint32",
+ "public-format" : "MbimVoiceCallState" },
+ { "name" : "IpType",
+ "format" : "guint32",
+ "public-format" : "MbimContextIpType" },
+ { "name" : "ContextType",
+ "format" : "uuid" },
+ { "name" : "NwError",
+ "format" : "guint32" } ],
+ "notification" : [ { "name" : "SessionId",
+ "format" : "guint32" },
+ { "name" : "ActivationState",
+ "format" : "guint32",
+ "public-format" : "MbimActivationState" },
+ { "name" : "VoiceCallState",
+ "format" : "guint32",
+ "public-format" : "MbimVoiceCallState" },
+ { "name" : "IpType",
+ "format" : "guint32",
+ "public-format" : "MbimContextIpType" },
+ { "name" : "ContextType",
+ "format" : "uuid" },
+ { "name" : "NwError",
+ "format" : "guint32" } ] },
+
+ // *********************************************************************************
+ { "name" : "MbimProvisionedContextElement",
+ "type" : "Struct",
+ "contents" : [ { "name" : "ContextId",
+ "format" : "guint32" },
+ { "name" : "ContextType",
+ "format" : "uuid" },
+ { "name" : "AccessString",
+ "format" : "string" },
+ { "name" : "UserName",
+ "format" : "string" },
+ { "name" : "Password",
+ "format" : "string" },
+ { "name" : "Compression",
+ "format" : "guint32",
+ "public-format" : "MbimCompression" },
+ { "name" : "AuthProtocol",
+ "format" : "guint32",
+ "public-format" : "MbimAuthProtocol" } ] },
+
+ { "name" : "Provisioned Contexts",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "set" : [ { "name" : "ContextId",
+ "format" : "guint32" },
+ { "name" : "ContextType",
+ "format" : "uuid" },
+ { "name" : "AccessString",
+ "format" : "string" },
+ { "name" : "UserName",
+ "format" : "string" },
+ { "name" : "Password",
+ "format" : "string" },
+ { "name" : "Compression",
+ "format" : "guint32",
+ "public-format" : "MbimCompression" },
+ { "name" : "AuthProtocol",
+ "format" : "guint32",
+ "public-format" : "MbimAuthProtocol" },
+ { "name" : "ProviderId",
+ "format" : "string" } ],
+ "query" : [],
+ "response" : [ { "name" : "ProvisionedContextsCount",
+ "format" : "guint32" },
+ { "name" : "ProvisionedContexts",
+ "format" : "ref-struct-array",
+ "struct-type" : "MbimProvisionedContextElement",
+ "array-size-field" : "ProvisionedContextsCount" } ],
+ "notification" : [ { "name" : "ProvisionedContextsCount",
+ "format" : "guint32" },
+ { "name" : "ProvisionedContexts",
+ "format" : "ref-struct-array",
+ "struct-type" : "MbimProvisionedContextElement",
+ "array-size-field" : "ProvisionedContextsCount" } ] },
+
+ // *********************************************************************************
+
+ { "name" : "Service Activation",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "set" : [ { "name" : "Buffer",
+ "format" : "unsized-byte-array" } ],
+ "response" : [ { "name" : "NwError",
+ "format" : "guint32",
+ "public-format" : "MbimNwError" },
+ { "name" : "Buffer",
+ "format" : "unsized-byte-array" } ] },
+
+ // *********************************************************************************
+ { "name" : "MbimIPv4Element",
+ "type" : "Struct",
+ "contents" : [ { "name" : "OnLinkPrefixLength",
+ "format" : "guint32" },
+ { "name" : "IPv4Address",
+ "format" : "ipv4" } ] },
+
+ { "name" : "MbimIPv6Element",
+ "type" : "Struct",
+ "contents" : [ { "name" : "OnLinkPrefixLength",
+ "format" : "guint32" },
+ { "name" : "IPv6Address",
+ "format" : "ipv6" } ] },
+
+ { "name" : "IP Configuration",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "query" : [ { "name" : "SessionId",
+ "format" : "guint32" },
+ { "name" : "IPv4ConfigurationAvailable",
+ "format" : "guint32",
+ "public-format" : "MbimIPConfigurationAvailableFlag" },
+ { "name" : "IPv6ConfigurationAvailable",
+ "format" : "guint32",
+ "public-format" : "MbimIPConfigurationAvailableFlag" },
+ { "name" : "IPv4AddressCount",
+ "format" : "guint32" },
+ { "name" : "IPv4Address",
+ "format" : "struct-array",
+ "struct-type" : "MbimIPv4Element",
+ "array-size-field" : "IPv4AddressCount" },
+ { "name" : "IPv6AddressCount",
+ "format" : "guint32" },
+ { "name" : "IPv6Address",
+ "format" : "struct-array",
+ "struct-type" : "MbimIPv6Element",
+ "array-size-field" : "IPv6AddressCount" },
+ { "name" : "IPv4Gateway",
+ "format" : "ref-ipv4" },
+ { "name" : "IPv6Gateway",
+ "format" : "ref-ipv6" },
+ { "name" : "IPv4DnsServerCount",
+ "format" : "guint32" },
+ { "name" : "IPv4DnsServer",
+ "format" : "ipv4-array",
+ "array-size-field" : "IPv4DnsServerCount" },
+ { "name" : "IPv6DnsServerCount",
+ "format" : "guint32" },
+ { "name" : "IPv6DnsServer",
+ "format" : "ipv6-array",
+ "array-size-field" : "IPv6DnsServerCount" },
+ { "name" : "IPv4Mtu",
+ "format" : "guint32" },
+ { "name" : "IPv6Mtu",
+ "format" : "guint32" } ],
+ "response" : [ { "name" : "SessionId",
+ "format" : "guint32" },
+ { "name" : "IPv4ConfigurationAvailable",
+ "format" : "guint32",
+ "public-format" : "MbimIPConfigurationAvailableFlag" },
+ { "name" : "IPv6ConfigurationAvailable",
+ "format" : "guint32",
+ "public-format" : "MbimIPConfigurationAvailableFlag" },
+ { "name" : "IPv4AddressCount",
+ "format" : "guint32" },
+ { "name" : "IPv4Address",
+ "format" : "struct-array",
+ "struct-type" : "MbimIPv4Element",
+ "array-size-field" : "IPv4AddressCount" },
+ { "name" : "IPv6AddressCount",
+ "format" : "guint32" },
+ { "name" : "IPv6Address",
+ "format" : "struct-array",
+ "struct-type" : "MbimIPv6Element",
+ "array-size-field" : "IPv6AddressCount" },
+ { "name" : "IPv4Gateway",
+ "format" : "ref-ipv4" },
+ { "name" : "IPv6Gateway",
+ "format" : "ref-ipv6" },
+ { "name" : "IPv4DnsServerCount",
+ "format" : "guint32" },
+ { "name" : "IPv4DnsServer",
+ "format" : "ipv4-array",
+ "array-size-field" : "IPv4DnsServerCount" },
+ { "name" : "IPv6DnsServerCount",
+ "format" : "guint32" },
+ { "name" : "IPv6DnsServer",
+ "format" : "ipv6-array",
+ "array-size-field" : "IPv6DnsServerCount" },
+ { "name" : "IPv4Mtu",
+ "format" : "guint32" },
+ { "name" : "IPv6Mtu",
+ "format" : "guint32" } ],
+ "notification" : [ { "name" : "SessionId",
+ "format" : "guint32" },
+ { "name" : "IPv4ConfigurationAvailable",
+ "format" : "guint32",
+ "public-format" : "MbimIPConfigurationAvailableFlag" },
+ { "name" : "IPv6ConfigurationAvailable",
+ "format" : "guint32",
+ "public-format" : "MbimIPConfigurationAvailableFlag" },
+ { "name" : "IPv4AddressCount",
+ "format" : "guint32" },
+ { "name" : "IPv4Address",
+ "format" : "struct-array",
+ "struct-type" : "MbimIPv4Element",
+ "array-size-field" : "IPv4AddressCount" },
+ { "name" : "IPv6AddressCount",
+ "format" : "guint32" },
+ { "name" : "IPv6Address",
+ "format" : "struct-array",
+ "struct-type" : "MbimIPv6Element",
+ "array-size-field" : "IPv6AddressCount" },
+ { "name" : "IPv4Gateway",
+ "format" : "ref-ipv4" },
+ { "name" : "IPv6Gateway",
+ "format" : "ref-ipv6" },
+ { "name" : "IPv4DnsServerCount",
+ "format" : "guint32" },
+ { "name" : "IPv4DnsServer",
+ "format" : "ipv4-array",
+ "array-size-field" : "IPv4DnsServerCount" },
+ { "name" : "IPv6DnsServerCount",
+ "format" : "guint32" },
+ { "name" : "IPv6DnsServer",
+ "format" : "ipv6-array",
+ "array-size-field" : "IPv6DnsServerCount" },
+ { "name" : "IPv4Mtu",
+ "format" : "guint32" },
+ { "name" : "IPv6Mtu",
+ "format" : "guint32" } ] },
+
+ // *********************************************************************************
+ { "name" : "MbimDeviceServiceElement",
+ "type" : "Struct",
+ "contents" : [ { "name" : "DeviceServiceId",
+ "format" : "uuid" },
+ { "name" : "DssPayload",
+ "format" : "guint32" },
+ { "name" : "MaxDssInstances",
+ "format" : "guint32" },
+ { "name" : "CidsCount",
+ "format" : "guint32" },
+ { "name" : "Cids",
+ "format" : "guint32-array",
+ "array-size-field" : "CidsCount" } ] },
+
+ { "name" : "Device Services",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "query" : [],
+ "response" : [ { "name" : "DeviceServicesCount",
+ "format" : "guint32" },
+ { "name" : "MaxDssSessions",
+ "format" : "guint32" },
+ { "name" : "DeviceServices",
+ "format" : "ref-struct-array",
+ "struct-type" : "MbimDeviceServiceElement",
+ "array-size-field" : "DeviceServicesCount" } ] },
+
+ // *********************************************************************************
+ { "name" : "MbimEventEntry",
+ "type" : "Struct",
+ "contents" : [ { "name" : "DeviceServiceId",
+ "format" : "uuid" },
+ { "name" : "CidsCount",
+ "format" : "guint32" },
+ { "name" : "Cids",
+ "format" : "guint32-array",
+ "array-size-field" : "CidsCount" } ] },
+
+ { "name" : "Device Service Subscriber List",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "set" : [ { "name" : "EventsCount",
+ "format" : "guint32" },
+ { "name" : "Events",
+ "format" : "ref-struct-array",
+ "struct-type" : "MbimEventEntry",
+ "array-size-field" : "EventsCount" } ],
+ "response" : [ { "name" : "EventsCount",
+ "format" : "guint32" },
+ { "name" : "Events",
+ "format" : "ref-struct-array",
+ "struct-type" : "MbimEventEntry",
+ "array-size-field" : "EventsCount" } ] },
+
+ // *********************************************************************************
+ { "name" : "Packet Statistics",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "query" : [],
+ "response" : [ { "name" : "InDiscards",
+ "format" : "guint32" },
+ { "name" : "InErrors",
+ "format" : "guint32" },
+ { "name" : "InOctets",
+ "format" : "guint64" },
+ { "name" : "InPackets",
+ "format" : "guint64" },
+ { "name" : "OutOctets",
+ "format" : "guint64" },
+ { "name" : "OutPackets",
+ "format" : "guint64" },
+ { "name" : "OutErrors",
+ "format" : "guint32" },
+ { "name" : "OutDiscards",
+ "format" : "guint32" } ] },
+
+ // *********************************************************************************
+ { "name" : "Network Idle Hint",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "query" : [],
+ "set" : [ { "name" : "State",
+ "format" : "guint32",
+ "public-format" : "MbimNetworkIdleHintState" } ],
+ "response" : [ { "name" : "State",
+ "format" : "guint32",
+ "public-format" : "MbimNetworkIdleHintState" } ] },
+
+ // *********************************************************************************
+ { "name" : "Emergency Mode",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "query" : [],
+ "set" : [ { "name" : "State",
+ "format" : "guint32",
+ "public-format" : "MbimEmergencyModeState" } ],
+ "response" : [ { "name" : "State",
+ "format" : "guint32",
+ "public-format" : "MbimEmergencyModeState" } ] },
+
+ // *********************************************************************************
+ { "name" : "MbimPacketFilter",
+ "type" : "Struct",
+ "contents" : [ { "name" : "FilterSize",
+ "format" : "guint32" },
+ { "name" : "PacketFilter",
+ "format" : "ref-byte-array",
+ "array-size-field" : "FilterSize" },
+ { "name" : "PacketMask",
+ "format" : "ref-byte-array",
+ "array-size-field" : "FilterSize" } ] },
+
+ { "name" : "IP Packet Filters",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "query" : [ { "name" : "SessionId",
+ "format" : "guint32" },
+ { "name" : "PacketFiltersCount",
+ "format" : "guint32" },
+ { "name" : "PacketFilters",
+ "format" : "ref-struct-array",
+ "struct-type" : "MbimPacketFilter",
+ "array-size-field" : "PacketFiltersCount" } ],
+ "set" : [ { "name" : "SessionId",
+ "format" : "guint32" },
+ { "name" : "PacketFiltersCount",
+ "format" : "guint32" },
+ { "name" : "PacketFilters",
+ "format" : "ref-struct-array",
+ "struct-type" : "MbimPacketFilter",
+ "array-size-field" : "PacketFiltersCount" } ],
+ "response" : [ { "name" : "SessionId",
+ "format" : "guint32" },
+ { "name" : "PacketFiltersCount",
+ "format" : "guint32" },
+ { "name" : "PacketFilters",
+ "format" : "ref-struct-array",
+ "struct-type" : "MbimPacketFilter",
+ "array-size-field" : "PacketFiltersCount" } ] },
+
+ // *********************************************************************************
+ { "name" : "Multicarrier Providers",
+ "service" : "Basic Connect",
+ "type" : "Command",
+ "set" : [ { "name" : "ProvidersCount",
+ "format" : "guint32" },
+ { "name" : "Providers",
+ "format" : "ref-struct-array" ,
+ "struct-type" : "MbimProvider",
+ "array-size-field" : "ProvidersCount" } ],
+ "query" : [],
+ "response" : [ { "name" : "ProvidersCount",
+ "format" : "guint32" },
+ { "name" : "Providers",
+ "format" : "ref-struct-array" ,
+ "struct-type" : "MbimProvider",
+ "array-size-field" : "ProvidersCount" } ],
+ "indication" : [ { "name" : "ProvidersCount",
+ "format" : "guint32" },
+ { "name" : "Providers",
+ "format" : "ref-struct-array" ,
+ "struct-type" : "MbimProvider",
+ "array-size-field" : "ProvidersCount" } ] }
+
+]
diff --git a/data/mbim-service-dss.json b/data/mbim-service-dss.json
new file mode 100644
index 0000000..6beb300
--- /dev/null
+++ b/data/mbim-service-dss.json
@@ -0,0 +1,20 @@
+
+[
+ // *********************************************************************************
+ { "type" : "Service",
+ "name" : "DSS" },
+
+ // *********************************************************************************
+ { "name" : "Connect",
+ "service" : "DSS",
+ "type" : "Command",
+ "set" : [ { "name" : "DeviceServiceId",
+ "format" : "uuid" },
+ { "name" : "DssSessionId",
+ "format" : "guint32" },
+ { "name" : "DssLinkState",
+ "format" : "guint32",
+ "public-format" : "MbimDssLinkState" } ],
+ "response" : [] }
+
+]
diff --git a/data/mbim-service-phonebook.json b/data/mbim-service-phonebook.json
new file mode 100644
index 0000000..dffa598
--- /dev/null
+++ b/data/mbim-service-phonebook.json
@@ -0,0 +1,89 @@
+
+[
+ // *********************************************************************************
+ { "type" : "Service",
+ "name" : "Phonebook" },
+
+ // *********************************************************************************
+ { "name" : "Configuration",
+ "service" : "Phonebook",
+ "type" : "Command",
+ "query" : [],
+ "response" : [ { "name" : "State",
+ "format" : "guint32",
+ "public-format" : "MbimPhonebookState" },
+ { "name" : "NumberOfEntries",
+ "format" : "guint32" },
+ { "name" : "UsedEntries",
+ "format" : "guint32" },
+ { "name" : "MaxNumberLength",
+ "format" : "guint32" },
+ { "name" : "MaxName",
+ "format" : "guint32" } ],
+ "notification" : [ { "name" : "State",
+ "format" : "guint32",
+ "public-format" : "MbimPhonebookState" },
+ { "name" : "NumberOfEntries",
+ "format" : "guint32" },
+ { "name" : "UsedEntries",
+ "format" : "guint32" },
+ { "name" : "MaxNumberLength",
+ "format" : "guint32" },
+ { "name" : "MaxName",
+ "format" : "guint32" } ] },
+
+ // *********************************************************************************
+ { "name" : "MbimPhonebookEntry",
+ "type" : "Struct",
+ "contents" : [ { "name" : "EntryIndex",
+ "format" : "guint32" },
+ { "name" : "Number",
+ "format" : "string" },
+ { "name" : "Name",
+ "format" : "string" } ] },
+
+ { "name" : "Read",
+ "service" : "Phonebook",
+ "type" : "Command",
+ "query" : [ { "name" : "FilterFlag",
+ "format" : "guint32",
+ "public-format" : "MbimPhonebookFlag" },
+ { "name" : "FilterMessageIndex",
+ "format" : "guint32" } ],
+ "response" : [ { "name" : "EntryCount",
+ "format" : "guint32" },
+ { "name" : "Entries",
+ "format" : "ref-struct-array",
+ "struct-type" : "MbimPhonebookEntry",
+ "array-size-field" : "EntryCount" } ] },
+
+ // *********************************************************************************
+
+ { "name" : "Delete",
+ "service" : "Phonebook",
+ "type" : "Command",
+ "set" : [ { "name" : "FilterFlag",
+ "format" : "guint32",
+ "public-format" : "MbimPhonebookFlag" },
+ { "name" : "FilterMessageIndex",
+ "format" : "guint32" } ],
+ "response" : [] },
+
+
+ // *********************************************************************************
+
+ { "name" : "Write",
+ "service" : "Phonebook",
+ "type" : "Command",
+ "set" : [ { "name" : "SaveFlag",
+ "format" : "guint32",
+ "public-format" : "MbimPhonebookWriteFlag" },
+ { "name" : "SaveIndex",
+ "format" : "guint32" },
+ { "name" : "Number",
+ "format" : "string" },
+ { "name" : "Name",
+ "format" : "string" } ],
+ "response" : [] }
+
+]
diff --git a/data/mbim-service-sms.json b/data/mbim-service-sms.json
new file mode 100644
index 0000000..57e63c1
--- /dev/null
+++ b/data/mbim-service-sms.json
@@ -0,0 +1,181 @@
+
+[
+ // *********************************************************************************
+ { "type" : "Service",
+ "name" : "SMS" },
+
+ // *********************************************************************************
+ { "name" : "Configuration",
+ "service" : "SMS",
+ "type" : "Command",
+ "set" : [ { "name" : "Format",
+ "format" : "guint32",
+ "public-format" : "MbimSmsFormat" },
+ { "name" : "ScAddress",
+ "format" : "string" } ],
+ "query" : [],
+ "response" : [ { "name" : "SmsStorageState",
+ "format" : "guint32",
+ "public-format" : "MbimSmsStorageState" },
+ { "name" : "Format",
+ "format" : "guint32",
+ "public-format" : "MbimSmsFormat" },
+ { "name" : "MaxMessages",
+ "format" : "guint32" },
+ { "name" : "CdmaShortMessageSize",
+ "format" : "guint32" },
+ { "name" : "ScAddress",
+ "format" : "string" } ] },
+
+ // *********************************************************************************
+ { "name" : "MbimSmsPduReadRecord",
+ "type" : "Struct",
+ "contents" : [ { "name" : "MessageIndex",
+ "format" : "guint32" },
+ { "name" : "MessageStatus",
+ "format" : "guint32",
+ "public-format" : "MbimSmsStatus" },
+ { "name" : "PduData",
+ "format" : "ref-byte-array" } ] },
+
+ { "name" : "MbimSmsCdmaReadRecord",
+ "type" : "Struct",
+ "contents" : [ { "name" : "MessageIndex",
+ "format" : "guint32" },
+ { "name" : "MessageStatus",
+ "format" : "guint32",
+ "public-format" : "MbimSmsStatus" },
+ { "name" : "Address",
+ "format" : "string" },
+ { "name" : "Timestamp",
+ "format" : "string" },
+ { "name" : "Encoding",
+ "format" : "guint32",
+ "public-format" : "MbimSmsCdmaEncoding" },
+ { "name" : "Language",
+ "format" : "guint32",
+ "public-format" : "MbimSmsCdmaLanguage" },
+ { "name" : "EncodedMessage",
+ "format" : "ref-byte-array" },
+ { "name" : "EncodedMessageSizeInCharacters",
+ "format" : "guint32" } ] },
+
+ { "name" : "Read",
+ "service" : "SMS",
+ "type" : "Command",
+ "query" : [ { "name" : "Format",
+ "format" : "guint32",
+ "public-format" : "MbimSmsFormat" },
+ { "name" : "Flag",
+ "format" : "guint32",
+ "public-format" : "MbimSmsFlag" },
+ { "name" : "MessageIndex",
+ "format" : "guint32" } ],
+ "response" : [ { "name" : "Format",
+ "format" : "guint32",
+ "public-format" : "MbimSmsFormat" },
+ { "name" : "MessagesCount",
+ "format" : "guint32" },
+ { "name" : "PduMessages",
+ "format" : "ref-struct-array" ,
+ "struct-type" : "MbimSmsPduReadRecord",
+ "array-size-field" : "MessagesCount",
+ "available-if" : { "field" : "Format",
+ "operation" : "==",
+ "value" : "MBIM_SMS_FORMAT_PDU" } },
+ { "name" : "CdmaMessages",
+ "format" : "ref-struct-array" ,
+ "struct-type" : "MbimSmsCdmaReadRecord",
+ "array-size-field" : "MessagesCount",
+ "available-if" : { "field" : "Format",
+ "operation" : "==",
+ "value" : "MBIM_SMS_FORMAT_CDMA" } } ],
+ "notification" : [ { "name" : "Format",
+ "format" : "guint32",
+ "public-format" : "MbimSmsFormat" },
+ { "name" : "MessagesCount",
+ "format" : "guint32" },
+ { "name" : "PduMessages",
+ "format" : "ref-struct-array" ,
+ "struct-type" : "MbimSmsPduReadRecord",
+ "array-size-field" : "MessagesCount",
+ "available-if" : { "field" : "Format",
+ "operation" : "==",
+ "value" : "MBIM_SMS_FORMAT_PDU" } },
+ { "name" : "CdmaMessages",
+ "format" : "ref-struct-array" ,
+ "struct-type" : "MbimSmsCdmaReadRecord",
+ "array-size-field" : "MessagesCount",
+ "available-if" : { "field" : "Format",
+ "operation" : "==",
+ "value" : "MBIM_SMS_FORMAT_CDMA" } } ] },
+
+ // *********************************************************************************
+ { "name" : "MbimSmsPduSendRecord",
+ "type" : "Struct",
+ "contents" : [ { "name" : "PduData",
+ "format" : "ref-byte-array" } ] },
+
+ { "name" : "MbimSmsCdmaSendRecord",
+ "type" : "Struct",
+ "contents" : [ { "name" : "Encoding",
+ "format" : "guint32",
+ "public-format" : "MbimSmsCdmaEncoding" },
+ { "name" : "Language",
+ "format" : "guint32",
+ "public-format" : "MbimSmsCdmaLanguage" },
+ { "name" : "Address",
+ "format" : "string" },
+ { "name" : "EncodedMessage",
+ "format" : "ref-byte-array" },
+ { "name" : "EncodedMessageSizeInCharacters",
+ "format" : "guint32" } ] },
+
+ { "name" : "Send",
+ "service" : "SMS",
+ "type" : "Command",
+ "set" : [ { "name" : "Format",
+ "format" : "guint32",
+ "public-format" : "MbimSmsFormat" },
+ { "name" : "PduMessage",
+ "format" : "struct",
+ "struct-type" : "MbimSmsPduSendRecord",
+ "available-if" : { "field" : "Format",
+ "operation" : "==",
+ "value" : "MBIM_SMS_FORMAT_PDU" } },
+ { "name" : "CdmaMessage",
+ "format" : "struct",
+ "struct-type" : "MbimSmsCdmaSendRecord",
+ "available-if" : { "field" : "Format",
+ "operation" : "==",
+ "value" : "MBIM_SMS_FORMAT_CDMA" } } ],
+ "response" : [ { "name" : "MessageReference",
+ "format" : "guint32" } ] },
+
+ // *********************************************************************************
+ { "name" : "Delete",
+ "service" : "SMS",
+ "type" : "Command",
+ "set" : [ { "name" : "Flag",
+ "format" : "guint32",
+ "public-format" : "MbimSmsFlag" },
+ { "name" : "MessageIndex",
+ "format" : "guint32" } ],
+ "response" : [] },
+
+ // *********************************************************************************
+ { "name" : "Message Store Status",
+ "service" : "SMS",
+ "type" : "Command",
+ "query" : [],
+ "response" : [ { "name" : "Flag",
+ "format" : "guint32",
+ "public-format" : "MbimSmsStatusFlag" },
+ { "name" : "MessageIndex",
+ "format" : "guint32" } ],
+ "notification" : [ { "name" : "Flag",
+ "format" : "guint32",
+ "public-format" : "MbimSmsStatusFlag" },
+ { "name" : "MessageIndex",
+ "format" : "guint32" } ] }
+]
diff --git a/data/mbim-service-stk.json b/data/mbim-service-stk.json
new file mode 100644
index 0000000..2b9bbfe
--- /dev/null
+++ b/data/mbim-service-stk.json
@@ -0,0 +1,47 @@
+
+[
+ // *********************************************************************************
+ { "type" : "Service",
+ "name" : "STK" },
+
+ // *********************************************************************************
+ { "name" : "Pac",
+ "service" : "STK",
+ "type" : "Command",
+ "query" : [],
+ "set" : [ { "name" : "PacHostcontrol",
+ "format" : "byte-array",
+ "array-size" : "32" } ],
+
+ "response" : [ { "name" : "PacSupport",
+ "format" : "byte-array",
+ "array-size" : "256" } ],
+ "notification" : [ { "name" : "PacType",
+ "format" : "guint32",
+ "public-format" : "MbimStkPacType" },
+ { "name" : "DataBuffer",
+ "format" : "unsized-byte-array" } ] },
+
+ // *********************************************************************************
+ { "name" : "Terminal Response",
+ "service" : "STK",
+ "type" : "Command",
+ "set" : [ { "name" : "Response",
+ "format" : "ref-byte-array-no-offset" } ],
+ "response" : [ { "name" : "ResultData",
+ "format" : "ref-byte-array" },
+ { "name" : "StatusWords",
+ "format" : "guint32" } ] },
+
+ // *********************************************************************************
+ { "name" : "Envelope",
+ "service" : "STK",
+ "type" : "Command",
+ "query" : [],
+ "set" : [ { "name" : "Data",
+ "format" : "unsized-byte-array" } ],
+ // This response is only for the 'query', the 'set' one is empty...
+ "response" : [ { "name" : "EnvelopeSupport",
+ "format" : "byte-array",
+ "array-size" : "32" } ] }
+]
diff --git a/data/mbim-service-ussd.json b/data/mbim-service-ussd.json
new file mode 100644
index 0000000..10471e1
--- /dev/null
+++ b/data/mbim-service-ussd.json
@@ -0,0 +1,38 @@
+
+[
+ // *********************************************************************************
+ { "type" : "Service",
+ "name" : "USSD" },
+
+ // *********************************************************************************
+ { "name" : "",
+ "service" : "USSD",
+ "type" : "Command",
+ "set" : [ { "name" : "Action",
+ "format" : "guint32",
+ "public-format" : "MbimUssdAction" },
+ { "name" : "DataCodingScheme",
+ "format" : "guint32" },
+ { "name" : "Payload",
+ "format" : "ref-byte-array" } ],
+ "response" : [ { "name" : "Response",
+ "format" : "guint32",
+ "public-format" : "MbimUssdResponse" },
+ { "name" : "SessionState",
+ "format" : "guint32",
+ "public-format" : "MbimUssdSessionState" },
+ { "name" : "DataCodingScheme",
+ "format" : "guint32" },
+ { "name" : "Payload",
+ "format" : "ref-byte-array" } ],
+ "notification" : [ { "name" : "Response",
+ "format" : "guint32",
+ "public-format" : "MbimUssdResponse" },
+ { "name" : "SessionState",
+ "format" : "guint32",
+ "public-format" : "MbimUssdSessionState" },
+ { "name" : "DataCodingScheme",
+ "format" : "guint32" },
+ { "name" : "Payload",
+ "format" : "ref-byte-array" } ] }
+]
diff --git a/data/pkg-config/Makefile.am b/data/pkg-config/Makefile.am
new file mode 100644
index 0000000..033081e
--- /dev/null
+++ b/data/pkg-config/Makefile.am
@@ -0,0 +1,4 @@
+
+# Set up pkg-config .pc files for exported libraries
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = mbim-glib.pc
diff --git a/data/pkg-config/mbim-glib.pc.in b/data/pkg-config/mbim-glib.pc.in
new file mode 100644
index 0000000..898375e
--- /dev/null
+++ b/data/pkg-config/mbim-glib.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: mbim-glib
+Description: Library to communicate with MBIM-powered modems
+Version: @VERSION@
+Requires: glib-2.0 gobject-2.0 gio-2.0
+Cflags: -I${includedir}/libmbim-glib
+Libs: -L${libdir} -lmbim-glib
diff --git a/docs/Makefile.am b/docs/Makefile.am
new file mode 100644
index 0000000..f3ddc22
--- /dev/null
+++ b/docs/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = reference
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
new file mode 100644
index 0000000..452e53d
--- /dev/null
+++ b/docs/reference/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = libmbim-glib
diff --git a/docs/reference/libmbim-glib/Makefile.am b/docs/reference/libmbim-glib/Makefile.am
new file mode 100644
index 0000000..07bcbe9
--- /dev/null
+++ b/docs/reference/libmbim-glib/Makefile.am
@@ -0,0 +1,100 @@
+
+# The name of the module.
+DOC_MODULE = libmbim-glib
+
+# The top-level SGML file.
+DOC_MAIN_SGML_FILE = $(DOC_MODULE)-docs.xml
+
+# Sections file building
+ALL_SECTIONS = \
+ $(srcdir)/libmbim-glib-common.sections \
+ $(top_builddir)/libmbim-glib/generated/mbim-basic-connect.sections \
+ $(top_builddir)/libmbim-glib/generated/mbim-sms.sections \
+ $(top_builddir)/libmbim-glib/generated/mbim-ussd.sections \
+ $(top_builddir)/libmbim-glib/generated/mbim-auth.sections \
+ $(top_builddir)/libmbim-glib/generated/mbim-phonebook.sections \
+ $(top_builddir)/libmbim-glib/generated/mbim-stk.sections \
+ $(top_builddir)/libmbim-glib/generated/mbim-dss.sections
+
+$(DOC_MODULE)-sections.mstamp: $(ALL_SECTIONS)
+ $(AM_V_GEN) \
+ rm -f $(DOC_MODULE)-sections.txt && \
+ cat $(ALL_SECTIONS) > $(DOC_MODULE)-sections.txt && \
+ touch $(DOC_MODULE)-sections.mstamp
+
+BUILT_SOURCES = $(DOC_MODULE)-sections.mstamp
+
+# Extra options to supply to gtkdoc-scan
+SCAN_OPTIONS = --rebuild-types
+
+# The directory containing the source code.
+DOC_SOURCE_DIR = \
+ $(top_srcdir)/libmbim-glib \
+ $(top_builddir)/libmbim-glib \
+ $(top_builddir)/libmbim-glib/generated
+
+# Used for dependencies
+HFILE_GLOB = \
+ $(top_srcdir)/libmbim-glib/*.h \
+ $(top_builddir)/libmbim-glib/*.h \
+ $(top_builddir)/libmbim-glib/generated/*.h
+CFILE_GLOB = \
+ $(top_srcdir)/libmbim-glib/*.c \
+ $(top_builddir)/libmbim-glib/generated/*.c
+
+# Headers to ignore
+IGNORE_HFILES = \
+ mbim-message-private.h
+
+# CFLAGS and LDFLAGS for compiling scan program. Only needed
+# if $(DOC_MODULE).types is non-empty.
+AM_CPPFLAGS = \
+ -I$(srcdir) \
+ -I$(top_srcdir) \
+ -I$(top_builddir) \
+ $(LIBMBIM_GLIB_CFLAGS)
+
+GTKDOC_LIBS = \
+ $(LIBMBIM_GLIB_LIBS) \
+ $(top_builddir)/libmbim-glib/libmbim-glib.la
+
+# Extra options to supply to gtkdoc-mkdb
+MKDB_OPTIONS = --output-format=xml --sgml-mode --name-space=mbim
+
+# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE)
+content_files = version.xml
+
+expand_content_files =
+
+extra_files =
+
+include $(top_srcdir)/gtk-doc.make
+
+
+EXTRA_DIST += \
+ libmbim-glib-common.sections \
+ $(DOC_MODULE)-sections.txt \
+ $(DOC_MODULE)-sections.mstamp \
+ version.xml.in \
+ $(DIAGRAMS) \
+ $(NULL)
+
+CLEANFILES += \
+ $(DOC_MODULE)-decl-list.txt \
+ $(DOC_MODULE)-decl.txt \
+ $(DOC_MODULE)-overrides.txt \
+ $(DOC_MODULE)-undeclared.txt \
+ $(DOC_MODULE)-undocumented.txt \
+ $(DOC_MODULE)-overrides.txt \
+ $(DOC_MODULE)-unused.txt \
+ $(DOC_MODULE).args \
+ $(DOC_MODULE).hierarchy \
+ $(DOC_MODULE).interfaces \
+ $(DOC_MODULE).prerequisites \
+ $(DOC_MODULE).signals \
+ $(DOC_MODULE).types \
+ $(DOC_MODULE)-sections.txt \
+ $(DOC_MODULE)-sections.mstamp \
+ *.stamp \
+ -rf xml html tmpl \
+ $(NULL)
diff --git a/docs/reference/libmbim-glib/libmbim-glib-common.sections b/docs/reference/libmbim-glib/libmbim-glib-common.sections
new file mode 100644
index 0000000..ded145e
--- /dev/null
+++ b/docs/reference/libmbim-glib/libmbim-glib-common.sections
@@ -0,0 +1,477 @@
+<SECTION>
+<FILE>mbim-version</FILE>
+<TITLE>Version checks</TITLE>
+MBIM_MAJOR_VERSION
+MBIM_MINOR_VERSION
+MBIM_MICRO_VERSION
+MBIM_CHECK_VERSION
+</SECTION>
+
+<SECTION>
+<FILE>mbim-uuid</FILE>
+MbimService
+MbimContextType
+MbimUuid
+MBIM_UUID_INVALID
+MBIM_UUID_BASIC_CONNECT
+MBIM_UUID_SMS
+MBIM_UUID_USSD
+MBIM_UUID_PHONEBOOK
+MBIM_UUID_STK
+MBIM_UUID_AUTH
+MBIM_UUID_DSS
+<SUBSECTION Methods>
+mbim_service_get_string
+mbim_context_type_get_string
+mbim_uuid_cmp
+mbim_uuid_get_printable
+mbim_uuid_from_service
+mbim_uuid_to_service
+mbim_uuid_from_context_type
+mbim_uuid_to_context_type
+<SUBSECTION Private>
+MBIM_PACKED
+mbim_service_build_string_from_mask
+mbim_context_type_build_string_from_mask
+</SECTION>
+
+<SECTION>
+<FILE>mbim-cid</FILE>
+MbimCidBasicConnect
+MbimCidSms
+MbimCidUssd
+MbimCidPhonebook
+MbimCidStk
+MbimCidAuth
+MbimCidDss
+<SUBSECTION Methods>
+mbim_cid_can_set
+mbim_cid_can_query
+mbim_cid_can_notify
+mbim_cid_get_printable
+mbim_cid_basic_connect_get_string
+mbim_cid_sms_get_string
+mbim_cid_ussd_get_string
+mbim_cid_phonebook_get_string
+mbim_cid_stk_get_string
+mbim_cid_auth_get_string
+mbim_cid_dss_get_string
+<SUBSECTION Private>
+mbim_cid_basic_connect_build_string_from_mask
+mbim_cid_sms_build_string_from_mask
+mbim_cid_ussd_build_string_from_mask
+mbim_cid_phonebook_build_string_from_mask
+mbim_cid_stk_build_string_from_mask
+mbim_cid_auth_build_string_from_mask
+mbim_cid_dss_build_string_from_mask
+<SUBSECTION Standard>
+MBIM_TYPE_CID_AUTH
+MBIM_TYPE_CID_BASIC_CONNECT
+MBIM_TYPE_CID_DSS
+MBIM_TYPE_CID_PHONEBOOK
+MBIM_TYPE_CID_SMS
+MBIM_TYPE_CID_STK
+MBIM_TYPE_CID_USSD
+mbim_cid_auth_get_type
+mbim_cid_basic_connect_get_type
+mbim_cid_dss_get_type
+mbim_cid_phonebook_get_type
+mbim_cid_sms_get_type
+mbim_cid_stk_get_type
+mbim_cid_ussd_get_type
+</SECTION>
+
+<SECTION>
+<FILE>mbim-message</FILE>
+MbimMessage
+MbimMessageType
+MbimIPv4
+MbimIPv6
+MbimMessageCommandType
+<SUBSECTION Methods>
+mbim_message_new
+mbim_message_dup
+mbim_message_ref
+mbim_message_unref
+mbim_message_get_printable
+mbim_message_get_raw
+mbim_message_get_message_type
+mbim_message_get_message_length
+mbim_message_get_transaction_id
+mbim_message_set_transaction_id
+mbim_message_type_get_string
+<SUBSECTION MethodsOpen>
+mbim_message_open_new
+mbim_message_open_get_max_control_transfer
+<SUBSECTION MethodsOpenDone>
+mbim_message_open_done_get_status_code
+mbim_message_open_done_get_result
+<SUBSECTION MethodsClose>
+mbim_message_close_new
+<SUBSECTION MethodsCloseDone>
+mbim_message_close_done_get_status_code
+mbim_message_close_done_get_result
+<SUBSECTION MethodsError>
+mbim_message_error_new
+mbim_message_error_get_error_status_code
+mbim_message_error_get_error
+<SUBSECTION MethodsCommand>
+mbim_message_command_new
+mbim_message_command_append
+mbim_message_command_get_service
+mbim_message_command_get_service_id
+mbim_message_command_get_cid
+mbim_message_command_get_command_type
+mbim_message_command_get_raw_information_buffer
+mbim_message_command_type_get_string
+<SUBSECTION MethodsCommandDone>
+mbim_message_command_done_get_service
+mbim_message_command_done_get_service_id
+mbim_message_command_done_get_cid
+mbim_message_command_done_get_status_code
+mbim_message_command_done_get_result
+mbim_message_command_done_get_raw_information_buffer
+<SUBSECTION MethodsIndicateStatus>
+mbim_message_indicate_status_get_service
+mbim_message_indicate_status_get_service_id
+mbim_message_indicate_status_get_cid
+mbim_message_indicate_status_get_raw_information_buffer
+<SUBSECTION Private>
+mbim_message_type_build_string_from_mask
+mbim_message_command_type_build_string_from_mask
+<SUBSECTION Standard>
+MBIM_TYPE_MESSAGE
+mbim_message_get_type
+</SECTION>
+
+<SECTION>
+<FILE>mbim-device</FILE>
+<TITLE>MbimDevice</TITLE>
+MbimDevice
+mbim_device_new
+mbim_device_new_finish
+mbim_device_get_file
+mbim_device_peek_file
+mbim_device_get_path
+mbim_device_get_path_display
+mbim_device_is_open
+mbim_device_open
+mbim_device_open_finish
+mbim_device_close
+mbim_device_close_finish
+mbim_device_close_force
+mbim_device_get_next_transaction_id
+mbim_device_command
+mbim_device_command_finish
+<SUBSECTION Private>
+MbimDeviceClass
+MBIM_DEVICE_FILE
+MBIM_DEVICE_IN_SESSION
+MBIM_DEVICE_TRANSACTION_ID
+MBIM_DEVICE_SIGNAL_INDICATE_STATUS
+MBIM_DEVICE_SIGNAL_ERROR
+<SUBSECTION Standard>
+MBIM_DEVICE
+MBIM_DEVICE_CLASS
+MBIM_DEVICE_GET_CLASS
+MBIM_IS_DEVICE
+MBIM_IS_DEVICE_CLASS
+MBIM_TYPE_DEVICE
+MbimDevicePrivate
+mbim_device_get_type
+</SECTION>
+
+<SECTION>
+<FILE>mbim-enums</FILE>
+MbimDeviceType
+MbimCellularClass
+MbimVoiceClass
+MbimSimClass
+MbimDataClass
+MbimSmsCaps
+MbimCtrlCaps
+MbimSubscriberReadyState
+MbimReadyInfoFlag
+MbimRadioSwitchState
+MbimPinType
+MbimPinState
+MbimPinOperation
+MbimPinMode
+MbimPinFormat
+MbimProviderState
+MbimVisibleProvidersAction
+MbimNwError
+MbimRegisterAction
+MbimRegisterState
+MbimRegisterMode
+MbimRegistrationFlag
+MbimPacketServiceAction
+MbimPacketServiceState
+MbimActivationCommand
+MbimCompression
+MbimAuthProtocol
+MbimContextIpType
+MbimActivationState
+MbimVoiceCallState
+MbimIPConfigurationAvailableFlag
+MbimSmsStorageState
+MbimSmsFormat
+MbimSmsFlag
+MbimSmsCdmaLang
+MbimSmsCdmaEncoding
+MbimSmsStatus
+MbimSmsStatusFlag
+MbimUssdAction
+MbimUssdResponse
+MbimUssdSessionState
+MbimPhonebookFlag
+MbimPhonebookState
+MbimPhonebookWriteFlag
+MbimStkPacProfile
+MbimStkPacType
+MbimNetworkIdleHintState
+MbimEmergencyModeState
+MbimDssLinkState
+<SUBSECTION Methods>
+mbim_device_type_get_string
+mbim_cellular_class_build_string_from_mask
+mbim_voice_class_get_string
+mbim_sim_class_build_string_from_mask
+mbim_data_class_build_string_from_mask
+mbim_sms_caps_build_string_from_mask
+mbim_ctrl_caps_build_string_from_mask
+mbim_subscriber_ready_state_get_string
+mbim_ready_info_flag_build_string_from_mask
+mbim_radio_switch_state_get_string
+mbim_pin_type_get_string
+mbim_pin_state_get_string
+mbim_pin_operation_get_string
+mbim_pin_mode_get_string
+mbim_pin_format_get_string
+mbim_provider_state_build_string_from_mask
+mbim_visible_providers_action_get_string
+mbim_nw_error_get_string
+mbim_register_action_get_string
+mbim_register_state_get_string
+mbim_register_mode_get_string
+mbim_packet_service_action_get_string
+mbim_packet_service_state_get_string
+mbim_activation_command_get_string
+mbim_compression_get_string
+mbim_auth_protocol_get_string
+mbim_context_ip_type_get_string
+mbim_activation_state_get_string
+mbim_voice_call_state_get_string
+mbim_ip_configuration_available_flag_build_string_from_mask
+mbim_sms_storage_state_get_string
+mbim_sms_format_get_string
+mbim_sms_flag_get_string
+mbim_sms_cdma_lang_get_string
+mbim_sms_cdma_encoding_get_string
+mbim_sms_status_get_string
+mbim_sms_status_flag_get_string
+mbim_ussd_action_get_string
+mbim_ussd_response_get_string
+mbim_ussd_session_state_get_string
+mbim_phonebook_flag_get_string
+mbim_phonebook_state_get_string
+mbim_phonebook_write_flag_get_string
+mbim_stk_pac_profile_get_string
+mbim_stk_pac_type_get_string
+mbim_network_idle_hint_state_get_string
+mbim_emergency_mode_state_get_string
+mbim_dss_link_state_get_string
+<SUBSECTION Private>
+mbim_device_type_build_string_from_mask
+mbim_cellular_class_get_string
+mbim_voice_class_build_string_from_mask
+mbim_sim_class_get_string
+mbim_data_class_get_string
+mbim_sms_caps_get_string
+mbim_ctrl_caps_get_string
+mbim_subscriber_ready_state_build_string_from_mask
+mbim_ready_info_flag_get_string
+mbim_radio_switch_state_build_string_from_mask
+mbim_pin_type_build_string_from_mask
+mbim_pin_state_build_string_from_mask
+mbim_pin_operation_build_string_from_mask
+mbim_pin_mode_build_string_from_mask
+mbim_pin_format_build_string_from_mask
+mbim_provider_state_get_string
+mbim_visible_providers_action_build_string_from_mask
+mbim_nw_error_build_string_from_mask
+mbim_register_action_build_string_from_mask
+mbim_register_state_build_string_from_mask
+mbim_register_mode_build_string_from_mask
+mbim_registration_flag_get_string
+mbim_registration_flag_build_string_from_mask
+mbim_packet_service_action_build_string_from_mask
+mbim_packet_service_state_build_string_from_mask
+mbim_activation_command_build_string_from_mask
+mbim_compression_build_string_from_mask
+mbim_auth_protocol_build_string_from_mask
+mbim_context_ip_type_build_string_from_mask
+mbim_activation_state_build_string_from_mask
+mbim_voice_call_state_build_string_from_mask
+mbim_ip_configuration_available_flag_get_string
+mbim_sms_cdma_encoding_build_string_from_mask
+mbim_sms_cdma_lang_build_string_from_mask
+mbim_sms_flag_build_string_from_mask
+mbim_sms_format_build_string_from_mask
+mbim_sms_status_build_string_from_mask
+mbim_sms_status_flag_build_string_from_mask
+mbim_sms_storage_state_build_string_from_mask
+mbim_ussd_action_build_string_from_mask
+mbim_ussd_response_build_string_from_mask
+mbim_ussd_session_state_build_string_from_mask
+mbim_phonebook_flag_build_string_from_mask
+mbim_phonebook_state_build_string_from_mask
+mbim_phonebook_write_flag_build_string_from_mask
+mbim_stk_pac_profile_build_string_from_mask
+mbim_stk_pac_type_build_string_from_mask
+mbim_network_idle_hint_state_build_string_from_mask
+mbim_emergency_mode_state_build_string_from_mask
+mbim_dss_link_state_build_string_from_mask
+<SUBSECTION Standard>
+MBIM_TYPE_ACTIVATION_COMMAND
+MBIM_TYPE_ACTIVATION_STATE
+MBIM_TYPE_AUTH_PROTOCOL
+MBIM_TYPE_CELLULAR_CLASS
+MBIM_TYPE_COMPRESSION
+MBIM_TYPE_CONTEXT_IP_TYPE
+MBIM_TYPE_CONTEXT_TYPE
+MBIM_TYPE_CTRL_CAPS
+MBIM_TYPE_DATA_CLASS
+MBIM_TYPE_DEVICE_TYPE
+MBIM_TYPE_IP_CONFIGURATION_AVAILABLE_FLAG
+MBIM_TYPE_MESSAGE_COMMAND_TYPE
+MBIM_TYPE_MESSAGE_TYPE
+MBIM_TYPE_NW_ERROR
+MBIM_TYPE_PACKET_SERVICE_ACTION
+MBIM_TYPE_PACKET_SERVICE_STATE
+MBIM_TYPE_PIN_FORMAT
+MBIM_TYPE_PIN_MODE
+MBIM_TYPE_PIN_OPERATION
+MBIM_TYPE_PIN_STATE
+MBIM_TYPE_PIN_TYPE
+MBIM_TYPE_PROVIDER_STATE
+MBIM_TYPE_VISIBLE_PROVIDERS_ACTION
+MBIM_TYPE_RADIO_SWITCH_STATE
+MBIM_TYPE_READY_INFO_FLAG
+MBIM_TYPE_REGISTER_ACTION
+MBIM_TYPE_REGISTER_MODE
+MBIM_TYPE_REGISTER_STATE
+MBIM_TYPE_REGISTRATION_FLAG
+MBIM_TYPE_SERVICE
+MBIM_TYPE_SIM_CLASS
+MBIM_TYPE_SMS_CAPS
+MBIM_TYPE_SUBSCRIBER_READY_STATE
+MBIM_TYPE_VOICE_CALL_STATE
+MBIM_TYPE_VOICE_CLASS
+MBIM_TYPE_SMS_CDMA_ENCODING
+MBIM_TYPE_SMS_CDMA_LANG
+MBIM_TYPE_SMS_FLAG
+MBIM_TYPE_SMS_FORMAT
+MBIM_TYPE_SMS_STATUS
+MBIM_TYPE_SMS_STATUS_FLAG
+MBIM_TYPE_SMS_STORAGE_STATE
+MBIM_TYPE_USSD_ACTION
+MBIM_TYPE_USSD_RESPONSE
+MBIM_TYPE_USSD_SESSION_STATE
+MBIM_TYPE_PHONEBOOK_FLAG
+MBIM_TYPE_PHONEBOOK_STATE
+MBIM_TYPE_PHONEBOOK_WRITE_FLAG
+MBIM_TYPE_STK_PAC_PROFILE
+MBIM_TYPE_STK_PAC_TYPE
+MBIM_TYPE_NETWORK_IDLE_HINT_STATE
+MBIM_TYPE_EMERGENCY_MODE_STATE
+MBIM_TYPE_DSS_LINK_STATE
+mbim_activation_command_get_type
+mbim_activation_state_get_type
+mbim_auth_protocol_get_type
+mbim_cellular_class_get_type
+mbim_compression_get_type
+mbim_context_ip_type_get_type
+mbim_context_type_get_type
+mbim_ctrl_caps_get_type
+mbim_data_class_get_type
+mbim_device_type_get_type
+mbim_ip_configuration_available_flag_get_type
+mbim_message_command_type_get_type
+mbim_message_type_get_type
+mbim_nw_error_get_type
+mbim_packet_service_action_get_type
+mbim_packet_service_state_get_type
+mbim_pin_format_get_type
+mbim_pin_mode_get_type
+mbim_pin_operation_get_type
+mbim_pin_state_get_type
+mbim_pin_type_get_type
+mbim_provider_state_get_type
+mbim_visible_providers_action_get_type
+mbim_radio_switch_state_get_type
+mbim_ready_info_flag_get_type
+mbim_register_action_get_type
+mbim_register_mode_get_type
+mbim_register_state_get_type
+mbim_registration_flag_get_type
+mbim_service_get_type
+mbim_sim_class_get_type
+mbim_sms_caps_get_type
+mbim_subscriber_ready_state_get_type
+mbim_voice_call_state_get_type
+mbim_voice_class_get_type
+mbim_sms_cdma_encoding_get_type
+mbim_sms_cdma_lang_get_type
+mbim_sms_flag_get_type
+mbim_sms_format_get_type
+mbim_sms_status_flag_get_type
+mbim_sms_status_get_type
+mbim_sms_storage_state_get_type
+mbim_ussd_action_get_type
+mbim_ussd_response_get_type
+mbim_ussd_session_state_get_type
+mbim_phonebook_flag_get_type
+mbim_phonebook_state_get_type
+mbim_phonebook_write_flag_get_type
+mbim_stk_pac_profile_get_type
+mbim_stk_pac_type_get_type
+mbim_network_idle_hint_state_get_type
+mbim_emergency_mode_state_get_type
+mbim_dss_link_state_get_type
+</SECTION>
+
+<SECTION>
+<FILE>mbim-errors</FILE>
+MbimCoreError
+MbimProtocolError
+MbimStatusError
+<SUBSECTION Methods>
+mbim_core_error_get_string
+mbim_protocol_error_get_string
+mbim_status_error_get_string
+<SUBSECTION Private>
+MBIM_DBUS_ERROR_PREFIX
+MBIM_CORE_ERROR_DBUS_PREFIX
+MBIM_PROTOCOL_ERROR_DBUS_PREFIX
+MBIM_STATUS_ERROR_DBUS_PREFIX
+mbim_core_error_quark
+mbim_protocol_error_quark
+mbim_status_error_quark
+<SUBSECTION Standard>
+MBIM_CORE_ERROR
+MBIM_PROTOCOL_ERROR
+MBIM_STATUS_ERROR
+MBIM_TYPE_CORE_ERROR
+MBIM_TYPE_PROTOCOL_ERROR
+MBIM_TYPE_STATUS_ERROR
+mbim_core_error_get_type
+mbim_protocol_error_get_type
+mbim_status_error_get_type
+</SECTION>
+
+<SECTION>
+<FILE>mbim-utils</FILE>
+mbim_utils_get_traces_enabled
+mbim_utils_set_traces_enabled
+</SECTION>
diff --git a/docs/reference/libmbim-glib/libmbim-glib-docs.xml b/docs/reference/libmbim-glib/libmbim-glib-docs.xml
new file mode 100644
index 0000000..1018fb8
--- /dev/null
+++ b/docs/reference/libmbim-glib/libmbim-glib-docs.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+ "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
+[
+ <!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
+ <!ENTITY version SYSTEM "version.xml">
+]>
+<book id="libmbim-glib">
+ <bookinfo>
+ <title>libmbim-glib Reference Manual</title>
+ <releaseinfo>for libmbim-glib &version;</releaseinfo>
+
+ <copyright>
+ <year>2013</year>
+ <holder>The libmbim-glib authors</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.3 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>51 Franklin Street</street>, Suite 500
+ <city>Boston</city>, <state>MA</state> <postcode>02110-1335</postcode>
+ <country>USA</country>
+ </address>
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+ <chapter>
+ <title>Core</title>
+ <xi:include href="xml/mbim-version.xml"/>
+ <xi:include href="xml/mbim-uuid.xml"/>
+ <xi:include href="xml/mbim-cid.xml"/>
+ <xi:include href="xml/mbim-message.xml"/>
+ <xi:include href="xml/mbim-device.xml"/>
+ <xi:include href="xml/mbim-enums.xml"/>
+ <xi:include href="xml/mbim-errors.xml"/>
+ <xi:include href="xml/mbim-utils.xml"/>
+ </chapter>
+
+ <chapter>
+ <title>Services</title>
+ <xi:include href="xml/mbim-basic-connect.xml"/>
+ <xi:include href="xml/mbim-sms.xml"/>
+ <xi:include href="xml/mbim-ussd.xml"/>
+ <xi:include href="xml/mbim-auth.xml"/>
+ <xi:include href="xml/mbim-phonebook.xml"/>
+ <xi:include href="xml/mbim-stk.xml"/>
+ <xi:include href="xml/mbim-dss.xml"/>
+ </chapter>
+
+ <chapter id="object-tree">
+ <title>Object Hierarchy</title>
+ <xi:include href="xml/tree_index.sgml"/>
+ </chapter>
+ <index id="api-index-full">
+ <title>API Index</title>
+ <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
+ </index>
+ <index id="deprecated-api-index" role="deprecated">
+ <title>Index of deprecated API</title>
+ <xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
+ </index>
+
+ <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
+</book>
diff --git a/docs/reference/libmbim-glib/version.xml.in b/docs/reference/libmbim-glib/version.xml.in
new file mode 100644
index 0000000..d78bda9
--- /dev/null
+++ b/docs/reference/libmbim-glib/version.xml.in
@@ -0,0 +1 @@
+@VERSION@
diff --git a/gtester.make b/gtester.make
new file mode 100644
index 0000000..40348dc
--- /dev/null
+++ b/gtester.make
@@ -0,0 +1,91 @@
+
+GTESTER = gtester
+GTESTER_REPORT = gtester-report
+
+# initialize variables for unconditional += appending
+EXTRA_DIST =
+TEST_PROGS =
+
+### testing rules
+
+# test: run all tests in cwd and subdirs
+test: test-nonrecursive
+ @ for subdir in $(SUBDIRS) . ; do \
+ test "$$subdir" = "." -o "$$subdir" = "po" || \
+ ( cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $? ; \
+ done
+
+# test-nonrecursive: run tests only in cwd
+test-nonrecursive: ${TEST_PROGS}
+ @test -z "${TEST_PROGS}" || G_DEBUG=gc-friendly MALLOC_CHECK_=2 MALLOC_PERTURB_=$$(($${RANDOM:-256} % 256)) ${GTESTER} --verbose ${TEST_PROGS}
+
+# test-report: run tests in subdirs and generate report
+# perf-report: run tests in subdirs with -m perf and generate report
+# full-report: like test-report: with -m perf and -m slow
+test-report perf-report full-report: ${TEST_PROGS}
+ @test -z "${TEST_PROGS}" || { \
+ case $@ in \
+ test-report) test_options="-k";; \
+ perf-report) test_options="-k -m=perf";; \
+ full-report) test_options="-k -m=perf -m=slow";; \
+ esac ; \
+ if test -z "$$GTESTER_LOGDIR" ; then \
+ ${GTESTER} --verbose $$test_options -o test-report.xml ${TEST_PROGS} ; \
+ elif test -n "${TEST_PROGS}" ; then \
+ ${GTESTER} --verbose $$test_options -o `mktemp "$$GTESTER_LOGDIR/log-XXXXXX"` ${TEST_PROGS} ; \
+ fi ; \
+ }
+ @ ignore_logdir=true ; \
+ if test -z "$$GTESTER_LOGDIR" ; then \
+ GTESTER_LOGDIR=`mktemp -d "\`pwd\`/.testlogs-XXXXXX"`; export GTESTER_LOGDIR ; \
+ ignore_logdir=false ; \
+ fi ; \
+ if test -d "$(top_srcdir)/.git" ; then \
+ REVISION=`git describe` ; \
+ else \
+ REVISION=$(VERSION) ; \
+ fi ; \
+ for subdir in $(SUBDIRS) . ; do \
+ test "$$subdir" = "." -o "$$subdir" = "po" || \
+ ( cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $? ; \
+ done ; \
+ $$ignore_logdir || { \
+ echo '<?xml version="1.0"?>' > $@.xml ; \
+ echo '<report-collection>' >> $@.xml ; \
+ echo '<info>' >> $@.xml ; \
+ echo ' <package>$(PACKAGE)</package>' >> $@.xml ; \
+ echo ' <version>$(VERSION)</version>' >> $@.xml ; \
+ echo " <revision>$$REVISION</revision>" >> $@.xml ; \
+ echo '</info>' >> $@.xml ; \
+ for lf in `ls -L "$$GTESTER_LOGDIR"/.` ; do \
+ sed '1,1s/^<?xml\b[^>?]*?>//' <"$$GTESTER_LOGDIR"/"$$lf" >> $@.xml ; \
+ done ; \
+ echo >> $@.xml ; \
+ echo '</report-collection>' >> $@.xml ; \
+ rm -rf "$$GTESTER_LOGDIR"/ ; \
+ ${GTESTER_REPORT} --version 2>/dev/null 1>&2 ; test "$$?" != 0 || ${GTESTER_REPORT} $@.xml >$@.html ; \
+ }
+.PHONY: test test-report perf-report full-report test-nonrecursive
+
+.PHONY: lcov genlcov lcov-clean
+# use recursive makes in order to ignore errors during check
+lcov:
+ -$(MAKE) $(AM_MAKEFLAGS) -k check
+ $(MAKE) $(AM_MAKEFLAGS) genlcov
+
+# we have to massage the lcov.info file slightly to hide the effect of libtool
+# placing the objects files in the .libs/ directory separate from the *.c
+# we also have to delete tests/.libs/libmoduletestplugin_*.gcda
+genlcov:
+ rm -f $(top_builddir)/tests/.libs/libmoduletestplugin_*.gcda
+ $(LTP) --directory $(top_builddir) --capture --output-file glib-lcov.info --test-name GLIB_PERF --no-checksum --compat-libtool
+ LANG=C $(LTP_GENHTML) --prefix $(top_builddir) --output-directory glib-lcov --title "GLib Code Coverage" --legend --show-details glib-lcov.info
+ @echo "file://$(abs_top_builddir)/glib-lcov/index.html"
+
+lcov-clean:
+ -$(LTP) --directory $(top_builddir) -z
+ -rm -rf glib-lcov.info glib-lcov
+ -find -name '*.gcda' -print | xargs rm
+
+# run tests in cwd as part of make check
+check-local: test-nonrecursive
diff --git a/libmbim-glib/Makefile.am b/libmbim-glib/Makefile.am
new file mode 100644
index 0000000..01ccc76
--- /dev/null
+++ b/libmbim-glib/Makefile.am
@@ -0,0 +1,48 @@
+
+SUBDIRS = generated . test
+
+lib_LTLIBRARIES = libmbim-glib.la
+
+libmbim_glib_la_CPPFLAGS = \
+ $(LIBMBIM_GLIB_CFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/libmbim-glib \
+ -I$(top_srcdir)/libmbim-glib/generated \
+ -I$(top_builddir)/libmbim-glib \
+ -I$(top_builddir)/libmbim-glib/generated \
+ -DLIBMBIM_GLIB_COMPILATION \
+ -DG_LOG_DOMAIN=\"Mbim\"
+
+libmbim_glib_la_SOURCES = \
+ libmbim-glib.h \
+ mbim-version.h \
+ mbim-errors.h \
+ mbim-enums.h \
+ mbim-utils.h mbim-utils.c \
+ mbim-uuid.h mbim-uuid.c \
+ mbim-cid.h mbim-cid.c \
+ mbim-message-private.h mbim-message.h mbim-message.c \
+ mbim-device.h mbim-device.c
+
+libmbim_glib_la_LIBADD = \
+ ${top_builddir}/libmbim-glib/generated/libmbim-glib-generated.la \
+ $(LIBMBIM_GLIB_LIBS)
+
+libmbim_glib_la_LDFLAGS = \
+ -version-info $(MBIM_GLIB_LT_CURRENT):$(MBIM_GLIB_LT_REVISION):$(MBIM_GLIB_LT_AGE)
+
+includedir = @includedir@/libmbim-glib
+include_HEADERS = \
+ libmbim-glib.h \
+ mbim-version.h \
+ mbim-errors.h \
+ mbim-enums.h \
+ mbim-utils.h \
+ mbim-uuid.h \
+ mbim-cid.h \
+ mbim-message.h \
+ mbim-device.h
+
+EXTRA_DIST = \
+ mbim-version.h.in
diff --git a/libmbim-glib/generated/Makefile.am b/libmbim-glib/generated/Makefile.am
new file mode 100644
index 0000000..fd5876a
--- /dev/null
+++ b/libmbim-glib/generated/Makefile.am
@@ -0,0 +1,158 @@
+noinst_LTLIBRARIES = libmbim-glib-generated.la
+
+GENERATED_H = \
+ mbim-error-types.h \
+ mbim-enum-types.h \
+ mbim-basic-connect.h \
+ mbim-sms.h \
+ mbim-ussd.h \
+ mbim-auth.h \
+ mbim-phonebook.h \
+ mbim-stk.h \
+ mbim-dss.h
+
+GENERATED_C = \
+ mbim-error-types.c \
+ mbim-error-quarks.c \
+ mbim-enum-types.c \
+ mbim-basic-connect.c \
+ mbim-sms.c \
+ mbim-ussd.c \
+ mbim-auth.c \
+ mbim-phonebook.c \
+ mbim-stk.c \
+ mbim-dss.c
+
+GENERATED_SECTIONS = \
+ mbim-basic-connect.sections \
+ mbim-sms.sections \
+ mbim-ussd.sections \
+ mbim-auth.sections \
+ mbim-phonebook.sections \
+ mbim-stk.sections \
+ mbim-dss.sections
+
+# Error types
+mbim-error-types.h: $(top_srcdir)/libmbim-glib/mbim-errors.h $(top_srcdir)/build-aux/templates/mbim-error-types-template.h
+ $(AM_V_GEN) $(GLIB_MKENUMS) \
+ --fhead "#ifndef __LIBMBIM_GLIB_ERROR_TYPES_H__\n#define __LIBMBIM_GLIB_ERROR_TYPES_H__\n#include \"mbim-errors.h\"\n" \
+ --template $(top_srcdir)/build-aux/templates/mbim-error-types-template.h \
+ --ftail "#endif /* __LIBMBIM_GLIB_ERROR_TYPES_H__ */\n" \
+ $(top_srcdir)/libmbim-glib/mbim-errors.h > $@
+
+mbim-error-types.c: $(top_srcdir)/libmbim-glib/mbim-errors.h mbim-error-types.h $(top_srcdir)/build-aux/templates/mbim-error-types-template.c
+ $(AM_V_GEN) $(GLIB_MKENUMS) \
+ --fhead "#include \"mbim-errors.h\"\n#include \"mbim-error-types.h\"\n" \
+ --template $(top_srcdir)/build-aux/templates/mbim-error-types-template.c \
+ $(top_srcdir)/libmbim-glib/mbim-errors.h > $@
+
+mbim-error-quarks.c: $(top_srcdir)/libmbim-glib/mbim-errors.h mbim-error-types.h $(top_srcdir)/build-aux/templates/mbim-error-quarks-template.c
+ $(AM_V_GEN) $(GLIB_MKENUMS) \
+ --fhead "#include \"mbim-errors.h\"\n#include \"mbim-error-types.h\"\n" \
+ --template $(top_srcdir)/build-aux/templates/mbim-error-quarks-template.c \
+ $(top_srcdir)/libmbim-glib/mbim-errors.h > $@
+
+# Enum/Flag types
+ENUMS = \
+ $(top_srcdir)/libmbim-glib/mbim-uuid.h \
+ $(top_srcdir)/libmbim-glib/mbim-cid.h \
+ $(top_srcdir)/libmbim-glib/mbim-message.h \
+ $(top_srcdir)/libmbim-glib/mbim-enums.h
+mbim-enum-types.h: $(ENUMS) $(top_srcdir)/build-aux/templates/mbim-enum-types-template.h
+ $(AM_V_GEN) $(GLIB_MKENUMS) \
+ --fhead "#ifndef __LIBMBIM_GLIB_ENUM_TYPES_H__\n#define __LIBMBIM_GLIB_ENUM_TYPES_H__\n#include \"mbim-uuid.h\"\n#include \"mbim-cid.h\"\n#include \"mbim-message.h\"\n#include \"mbim-enums.h\"\n" \
+ --template $(top_srcdir)/build-aux/templates/mbim-enum-types-template.h \
+ --ftail "#endif /* __LIBMBIM_GLIB_ENUM_TYPES_H__ */\n" \
+ $(ENUMS) > $@
+
+mbim-enum-types.c: $(ENUMS) mbim-enum-types.h $(top_srcdir)/build-aux/templates/mbim-enum-types-template.c
+ $(AM_V_GEN) $(GLIB_MKENUMS) \
+ --fhead "#include \"mbim-enum-types.h\"\n" \
+ --template $(top_srcdir)/build-aux/templates/mbim-enum-types-template.c \
+ $(ENUMS) > $@
+
+# Basic Connect service
+mbim-basic-connect.h mbim-basic-connect.c mbim-basic-connect.sections: $(top_srcdir)/data/mbim-service-basic-connect.json $(top_srcdir)/build-aux/mbim-codegen/*.py $(top_srcdir)/build-aux/mbim-codegen/mbim-codegen
+ $(AM_V_GEN) \
+ rm -f mbim-basic-connect.h && \
+ rm -f mbim-basic-connect.c && \
+ $(top_srcdir)/build-aux/mbim-codegen/mbim-codegen \
+ --input $(top_srcdir)/data/mbim-service-basic-connect.json \
+ --output mbim-basic-connect
+
+# SMS service
+mbim-sms.h mbim-sms.c mbim-sms.sections: $(top_srcdir)/data/mbim-service-sms.json $(top_srcdir)/build-aux/mbim-codegen/*.py $(top_srcdir)/build-aux/mbim-codegen/mbim-codegen
+ $(AM_V_GEN) \
+ rm -f mbim-sms.h && \
+ rm -f mbim-sms.c && \
+ $(top_srcdir)/build-aux/mbim-codegen/mbim-codegen \
+ --input $(top_srcdir)/data/mbim-service-sms.json \
+ --output mbim-sms
+
+# USSD service
+mbim-ussd.h mbim-ussd.c mbim-ussd.sections: $(top_srcdir)/data/mbim-service-ussd.json $(top_srcdir)/build-aux/mbim-codegen/*.py $(top_srcdir)/build-aux/mbim-codegen/mbim-codegen
+ $(AM_V_GEN) \
+ rm -f mbim-ussd.h && \
+ rm -f mbim-ussd.c && \
+ $(top_srcdir)/build-aux/mbim-codegen/mbim-codegen \
+ --input $(top_srcdir)/data/mbim-service-ussd.json \
+ --output mbim-ussd
+
+# Auth service
+mbim-auth.h mbim-auth.c mbim-auth.sections: $(top_srcdir)/data/mbim-service-auth.json $(top_srcdir)/build-aux/mbim-codegen/*.py $(top_srcdir)/build-aux/mbim-codegen/mbim-codegen
+ $(AM_V_GEN) \
+ rm -f mbim-auth.h && \
+ rm -f mbim-auth.c && \
+ $(top_srcdir)/build-aux/mbim-codegen/mbim-codegen \
+ --input $(top_srcdir)/data/mbim-service-auth.json \
+ --output mbim-auth
+
+# Phonebook service
+mbim-phonebook.h mbim-phonebook.c mbim-phonebook.sections: $(top_srcdir)/data/mbim-service-phonebook.json $(top_srcdir)/build-aux/mbim-codegen/*.py $(top_srcdir)/build-aux/mbim-codegen/mbim-codegen
+ $(AM_V_GEN) \
+ rm -f mbim-phonebook.h && \
+ rm -f mbim-phonebook.c && \
+ $(top_srcdir)/build-aux/mbim-codegen/mbim-codegen \
+ --input $(top_srcdir)/data/mbim-service-phonebook.json \
+ --output mbim-phonebook
+
+# STK service
+mbim-stk.h mbim-stk.c mbim-stk.sections: $(top_srcdir)/data/mbim-service-stk.json $(top_srcdir)/build-aux/mbim-codegen/*.py $(top_srcdir)/build-aux/mbim-codegen/mbim-codegen
+ $(AM_V_GEN) \
+ rm -f mbim-stk.h && \
+ rm -f mbim-stk.c && \
+ $(top_srcdir)/build-aux/mbim-codegen/mbim-codegen \
+ --input $(top_srcdir)/data/mbim-service-stk.json \
+ --output mbim-stk
+
+# DSS service
+mbim-dss.h mbim-dss.c mbim-dss.sections: $(top_srcdir)/data/mbim-service-dss.json $(top_srcdir)/build-aux/mbim-codegen/*.py $(top_srcdir)/build-aux/mbim-codegen/mbim-codegen
+ $(AM_V_GEN) \
+ rm -f mbim-dss.h && \
+ rm -f mbim-dss.c && \
+ $(top_srcdir)/build-aux/mbim-codegen/mbim-codegen \
+ --input $(top_srcdir)/data/mbim-service-dss.json \
+ --output mbim-dss
+
+BUILT_SOURCES = $(GENERATED_H) $(GENERATED_C)
+
+nodist_libmbim_glib_generated_la_SOURCES = \
+ $(GENERATED_H) \
+ $(GENERATED_C)
+
+libmbim_glib_generated_la_CPPFLAGS = \
+ $(LIBMBIM_GLIB_CFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libmbim-glib \
+ -I$(top_builddir)/libmbim-glib \
+ -DLIBMBIM_GLIB_COMPILATION \
+ -DG_LOG_DOMAIN=\"Mbim\" \
+ -Wno-unused-function
+
+libmbim_glib_generated_la_LIBADD = \
+ $(LIBMBIM_GLIB_LIBS)
+
+includedir = @includedir@/libmbim-glib
+nodist_include_HEADERS = $(GENERATED_H)
+
+CLEANFILES = $(GENERATED_H) $(GENERATED_C) $(GENERATED_SECTIONS)
diff --git a/libmbim-glib/libmbim-glib.h b/libmbim-glib/libmbim-glib.h
new file mode 100644
index 0000000..05cd71c
--- /dev/null
+++ b/libmbim-glib/libmbim-glib.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * libmbim-glib -- GLib/GIO based library to control MBIM devices
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#ifndef _LIBMBIM_GLIB_H_
+#define _LIBMBIM_GLIB_H_
+
+#define __LIBMBIM_GLIB_H_INSIDE__
+
+/* libmbim-glib headers */
+
+#include "mbim-version.h"
+#include "mbim-utils.h"
+#include "mbim-uuid.h"
+#include "mbim-cid.h"
+#include "mbim-message.h"
+#include "mbim-device.h"
+#include "mbim-enums.h"
+
+/* generated */
+#include "mbim-enum-types.h"
+#include "mbim-error-types.h"
+#include "mbim-basic-connect.h"
+#include "mbim-sms.h"
+#include "mbim-ussd.h"
+#include "mbim-auth.h"
+#include "mbim-phonebook.h"
+#include "mbim-stk.h"
+#include "mbim-dss.h"
+
+#endif /* _LIBMBIM_GLIB_H_ */
diff --git a/libmbim-glib/mbim-cid.c b/libmbim-glib/mbim-cid.c
new file mode 100644
index 0000000..de86c93
--- /dev/null
+++ b/libmbim-glib/mbim-cid.c
@@ -0,0 +1,275 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/*
+ * libmbim-glib -- GLib/GIO based library to control MBIM devices
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#include "mbim-cid.h"
+#include "mbim-enum-types.h"
+
+/**
+ * SECTION: mbim-cid
+ * @title: Command IDs
+ *
+ * This section defines the interface of the known command IDs.
+ */
+
+typedef struct {
+ gboolean set;
+ gboolean query;
+ gboolean notify;
+} CidConfig;
+
+/* Note: index of the array is CID-1 */
+#define MBIM_CID_BASIC_CONNECT_LAST MBIM_CID_BASIC_CONNECT_MULTICARRIER_PROVIDERS
+static const CidConfig cid_basic_connect_config [MBIM_CID_BASIC_CONNECT_LAST] = {
+ { FALSE, TRUE, FALSE }, /* MBIM_CID_BASIC_CONNECT_DEVICE_CAPSo */
+ { FALSE, TRUE, TRUE }, /* MBIM_CID_BASIC_CONNECT_SUBSCRIBER_READY_STATUS */
+ { TRUE, TRUE, TRUE }, /* MBIM_CID_BASIC_CONNECT_RADIO_STATE */
+ { TRUE, TRUE, FALSE }, /* MBIM_CID_BASIC_CONNECT_PIN */
+ { FALSE, TRUE, FALSE }, /* MBIM_CID_BASIC_CONNECT_PIN_LIST */
+ { TRUE, TRUE, FALSE }, /* MBIM_CID_BASIC_CONNECT_HOME_PROVIDER */
+ { TRUE, TRUE, TRUE }, /* MBIM_CID_BASIC_CONNECT_PREFERRED_PROVIDERS */
+ { FALSE, TRUE, FALSE }, /* MBIM_CID_BASIC_CONNECT_VISIBLE_PROVIDERS */
+ { TRUE, TRUE, TRUE }, /* MBIM_CID_BASIC_CONNECT_REGISTER_STATE */
+ { TRUE, TRUE, TRUE }, /* MBIM_CID_BASIC_CONNECT_PACKET_SERVICE */
+ { TRUE, TRUE, TRUE }, /* MBIM_CID_BASIC_CONNECT_SIGNAL_STATE */
+ { TRUE, TRUE, TRUE }, /* MBIM_CID_BASIC_CONNECT_CONNECT */
+ { TRUE, TRUE, TRUE }, /* MBIM_CID_BASIC_CONNECT_PROVISIONED_CONTEXTS */
+ { TRUE, FALSE, FALSE }, /* MBIM_CID_BASIC_CONNECT_SERVICE_ACTIVATION */
+ { FALSE, TRUE, TRUE }, /* MBIM_CID_BASIC_CONNECT_IP_CONFIGURATION */
+ { FALSE, TRUE, FALSE }, /* MBIM_CID_BASIC_CONNECT_DEVICE_SERVICES */
+ { FALSE, FALSE, FALSE }, /* 17 reserved */
+ { FALSE, FALSE, FALSE }, /* 18 reserved */
+ { TRUE, FALSE, FALSE }, /* MBIM_CID_BASIC_CONNECT_DEVICE_SERVICE_SUBSCRIBER_LIST */
+ { FALSE, TRUE, FALSE }, /* MBIM_CID_BASIC_CONNECT_PACKET_STATISTICS */
+ { TRUE, TRUE, FALSE }, /* MBIM_CID_BASIC_CONNECT_NETWORK_IDLE_HINT */
+ { FALSE, TRUE, TRUE }, /* MBIM_CID_BASIC_CONNECT_EMERGENCY_MODE */
+ { TRUE, TRUE, FALSE }, /* MBIM_CID_BASIC_CONNECT_IP_PACKET_FILTERS */
+ { TRUE, TRUE, TRUE }, /* MBIM_CID_BASIC_CONNECT_MULTICARRIER_PROVIDERS */
+};
+
+/* Note: index of the array is CID-1 */
+#define MBIM_CID_SMS_LAST MBIM_CID_SMS_MESSAGE_STORE_STATUS
+static const CidConfig cid_sms_config [MBIM_CID_SMS_LAST] = {
+ { TRUE, TRUE, TRUE }, /* MBIM_CID_SMS_CONFIGURATION */
+ { FALSE, TRUE, TRUE }, /* MBIM_CID_SMS_READ */
+ { TRUE, FALSE, FALSE }, /* MBIM_CID_SMS_SEND */
+ { TRUE, FALSE, FALSE }, /* MBIM_CID_SMS_DELETE */
+ { FALSE, TRUE, TRUE }, /* MBIM_CID_SMS_MESSAGE_STORE_STATUS */
+};
+
+/* Note: index of the array is CID-1 */
+#define MBIM_CID_USSD_LAST MBIM_CID_USSD
+static const CidConfig cid_ussd_config [MBIM_CID_USSD_LAST] = {
+ { TRUE, FALSE, TRUE }, /* MBIM_CID_USSD */
+};
+
+/* Note: index of the array is CID-1 */
+#define MBIM_CID_PHONEBOOK_LAST MBIM_CID_PHONEBOOK_WRITE
+static const CidConfig cid_phonebook_config [MBIM_CID_PHONEBOOK_LAST] = {
+ { FALSE, TRUE, TRUE }, /* MBIM_CID_PHONEBOOK_CONFIGURATION */
+ { FALSE, TRUE, FALSE }, /* MBIM_CID_PHONEBOOK_READ */
+ { TRUE, FALSE, FALSE }, /* MBIM_CID_PHONEBOOK_DELETE */
+ { TRUE, FALSE, FALSE }, /* MBIM_CID_PHONEBOOK_WRITE */
+};
+
+/* Note: index of the array is CID-1 */
+#define MBIM_CID_STK_LAST MBIM_CID_STK_ENVELOPE
+static const CidConfig cid_stk_config [MBIM_CID_STK_LAST] = {
+ { TRUE, TRUE, TRUE }, /* MBIM_CID_STK_PAC */
+ { TRUE, FALSE, FALSE }, /* MBIM_CID_STK_TERMINAL_RESPONSE */
+ { TRUE, TRUE, FALSE }, /* MBIM_CID_STK_ENVELOPE */
+};
+
+/* Note: index of the array is CID-1 */
+#define MBIM_CID_AUTH_LAST MBIM_CID_AUTH_SIM
+static const CidConfig cid_auth_config [MBIM_CID_AUTH_LAST] = {
+ { FALSE, TRUE, FALSE }, /* MBIM_CID_AUTH_AKA */
+ { FALSE, TRUE, FALSE }, /* MBIM_CID_AUTH_AKAP */
+ { FALSE, TRUE, FALSE }, /* MBIM_CID_AUTH_SIM */
+};
+
+/* Note: index of the array is CID-1 */
+#define MBIM_CID_DSS_LAST MBIM_CID_DSS_CONNECT
+static const CidConfig cid_dss_config [MBIM_CID_DSS_LAST] = {
+ { TRUE, FALSE, FALSE }, /* MBIM_CID_DSS_CONNECT */
+};
+
+/**
+ * mbim_cid_can_set:
+ * @service: a #MbimService.
+ * @cid: a command ID.
+ *
+ * Checks whether the given command allows setting.
+ *
+ * Returns: %TRUE if the command allows setting, %FALSE otherwise.
+ */
+gboolean
+mbim_cid_can_set (MbimService service,
+ guint cid)
+{
+ /* CID = 0 is never a valid command */
+ g_return_val_if_fail (cid > 0, FALSE);
+ /* Known service required */
+ g_return_val_if_fail (service > MBIM_SERVICE_INVALID, FALSE);
+ g_return_val_if_fail (service <= MBIM_SERVICE_DSS, FALSE);
+
+ switch (service) {
+ case MBIM_SERVICE_BASIC_CONNECT:
+ return cid_basic_connect_config[cid - 1].set;
+ case MBIM_SERVICE_SMS:
+ return cid_sms_config[cid - 1].set;
+ case MBIM_SERVICE_USSD:
+ return cid_ussd_config[cid - 1].set;
+ case MBIM_SERVICE_PHONEBOOK:
+ return cid_phonebook_config[cid - 1].set;
+ case MBIM_SERVICE_STK:
+ return cid_stk_config[cid - 1].set;
+ case MBIM_SERVICE_AUTH:
+ return cid_auth_config[cid - 1].set;
+ case MBIM_SERVICE_DSS:
+ return cid_dss_config[cid - 1].set;
+ default:
+ g_assert_not_reached ();
+ return FALSE;
+ }
+}
+
+/**
+ * mbim_cid_can_query:
+ * @service: a #MbimService.
+ * @cid: a command ID.
+ *
+ * Checks whether the given command allows querying.
+ *
+ * Returns: %TRUE if the command allows querying, %FALSE otherwise.
+ */
+gboolean
+mbim_cid_can_query (MbimService service,
+ guint cid)
+{
+ /* CID = 0 is never a valid command */
+ g_return_val_if_fail (cid > 0, FALSE);
+ /* Known service required */
+ g_return_val_if_fail (service > MBIM_SERVICE_INVALID, FALSE);
+ g_return_val_if_fail (service <= MBIM_SERVICE_DSS, FALSE);
+
+ switch (service) {
+ case MBIM_SERVICE_BASIC_CONNECT:
+ return cid_basic_connect_config[cid - 1].query;
+ case MBIM_SERVICE_SMS:
+ return cid_sms_config[cid - 1].query;
+ case MBIM_SERVICE_USSD:
+ return cid_ussd_config[cid - 1].query;
+ case MBIM_SERVICE_PHONEBOOK:
+ return cid_phonebook_config[cid - 1].query;
+ case MBIM_SERVICE_STK:
+ return cid_stk_config[cid - 1].query;
+ case MBIM_SERVICE_AUTH:
+ return cid_auth_config[cid - 1].query;
+ case MBIM_SERVICE_DSS:
+ return cid_dss_config[cid - 1].query;
+ default:
+ g_assert_not_reached ();
+ return FALSE;
+ }
+}
+
+/**
+ * mbim_cid_can_notify:
+ * @service: a #MbimService.
+ * @cid: a command ID.
+ *
+ * Checks whether the given command allows notifying.
+ *
+ * Returns: %TRUE if the command allows notifying, %FALSE otherwise.
+ */
+gboolean
+mbim_cid_can_notify (MbimService service,
+ guint cid)
+{
+ /* CID = 0 is never a valid command */
+ g_return_val_if_fail (cid > 0, FALSE);
+ /* Known service required */
+ g_return_val_if_fail (service > MBIM_SERVICE_INVALID, FALSE);
+ g_return_val_if_fail (service <= MBIM_SERVICE_DSS, FALSE);
+
+ switch (service) {
+ case MBIM_SERVICE_BASIC_CONNECT:
+ return cid_basic_connect_config[cid - 1].notify;
+ case MBIM_SERVICE_SMS:
+ return cid_sms_config[cid - 1].notify;
+ case MBIM_SERVICE_USSD:
+ return cid_ussd_config[cid - 1].notify;
+ case MBIM_SERVICE_PHONEBOOK:
+ return cid_phonebook_config[cid - 1].notify;
+ case MBIM_SERVICE_STK:
+ return cid_stk_config[cid - 1].notify;
+ case MBIM_SERVICE_AUTH:
+ return cid_auth_config[cid - 1].notify;
+ case MBIM_SERVICE_DSS:
+ return cid_dss_config[cid - 1].notify;
+ default:
+ g_assert_not_reached ();
+ return FALSE;
+ }
+}
+
+/**
+ * mbim_cid_get_printable:
+ * @service: a #MbimService.
+ * @cid: a command ID.
+ *
+ * Gets a printable string for the command specified by the @service and the
+ * @cid.
+ *
+ * Returns: (transfer none): a constant string.
+ */
+const gchar *
+mbim_cid_get_printable (MbimService service,
+ guint cid)
+{
+ /* CID = 0 is never a valid command */
+ g_return_val_if_fail (cid > 0, NULL);
+ /* Known service required */
+ g_return_val_if_fail (service > MBIM_SERVICE_INVALID, NULL);
+ g_return_val_if_fail (service <= MBIM_SERVICE_DSS, NULL);
+
+ switch (service) {
+ case MBIM_SERVICE_BASIC_CONNECT:
+ return mbim_cid_basic_connect_get_string (cid);
+ case MBIM_SERVICE_SMS:
+ return mbim_cid_sms_get_string (cid);
+ case MBIM_SERVICE_USSD:
+ return mbim_cid_ussd_get_string (cid);
+ case MBIM_SERVICE_PHONEBOOK:
+ return mbim_cid_phonebook_get_string (cid);
+ case MBIM_SERVICE_STK:
+ return mbim_cid_stk_get_string (cid);
+ case MBIM_SERVICE_AUTH:
+ return mbim_cid_auth_get_string (cid);
+ case MBIM_SERVICE_DSS:
+ return mbim_cid_dss_get_string (cid);
+ default:
+ g_assert_not_reached ();
+ return FALSE;
+ }
+}
diff --git a/libmbim-glib/mbim-cid.h b/libmbim-glib/mbim-cid.h
new file mode 100644
index 0000000..031baa0
--- /dev/null
+++ b/libmbim-glib/mbim-cid.h
@@ -0,0 +1,199 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/*
+ * libmbim-glib -- GLib/GIO based library to control MBIM devices
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#ifndef _LIBMBIM_GLIB_MBIM_CID_H_
+#define _LIBMBIM_GLIB_MBIM_CID_H_
+
+#if !defined (__LIBMBIM_GLIB_H_INSIDE__) && !defined (LIBMBIM_GLIB_COMPILATION)
+#error "Only <libmbim-glib.h> can be included directly."
+#endif
+
+#include <glib.h>
+
+#include "mbim-uuid.h"
+
+G_BEGIN_DECLS
+
+/**
+ * MbimCidBasicConnect:
+ * @MBIM_CID_BASIC_CONNECT_UNKNOWN: Unknown command.
+ * @MBIM_CID_BASIC_CONNECT_DEVICE_CAPS: Device capabilities.
+ * @MBIM_CID_BASIC_CONNECT_SUBSCRIBER_READY_STATUS: Subscriber ready status.
+ * @MBIM_CID_BASIC_CONNECT_RADIO_STATE: Radio state.
+ * @MBIM_CID_BASIC_CONNECT_PIN: PIN.
+ * @MBIM_CID_BASIC_CONNECT_PIN_LIST: PIN list.
+ * @MBIM_CID_BASIC_CONNECT_HOME_PROVIDER: Home provider.
+ * @MBIM_CID_BASIC_CONNECT_PREFERRED_PROVIDERS: Preferred providers.
+ * @MBIM_CID_BASIC_CONNECT_VISIBLE_PROVIDERS: Visible providers.
+ * @MBIM_CID_BASIC_CONNECT_REGISTER_STATE: Register state.
+ * @MBIM_CID_BASIC_CONNECT_PACKET_SERVICE: Packet service.
+ * @MBIM_CID_BASIC_CONNECT_SIGNAL_STATE: Signal state.
+ * @MBIM_CID_BASIC_CONNECT_CONNECT: Connect.
+ * @MBIM_CID_BASIC_CONNECT_PROVISIONED_CONTEXTS: Provisioned contexts.
+ * @MBIM_CID_BASIC_CONNECT_SERVICE_ACTIVATION: Service activation.
+ * @MBIM_CID_BASIC_CONNECT_IP_CONFIGURATION: IP configuration.
+ * @MBIM_CID_BASIC_CONNECT_DEVICE_SERVICES: Device services.
+ * @MBIM_CID_BASIC_CONNECT_DEVICE_SERVICE_SUBSCRIBER_LIST: Device service subscriber list.
+ * @MBIM_CID_BASIC_CONNECT_PACKET_STATISTICS: Packet statistics.
+ * @MBIM_CID_BASIC_CONNECT_NETWORK_IDLE_HINT: Network idle hint.
+ * @MBIM_CID_BASIC_CONNECT_EMERGENCY_MODE: Emergency mode.
+ * @MBIM_CID_BASIC_CONNECT_IP_PACKET_FILTERS: IP packet filters.
+ * @MBIM_CID_BASIC_CONNECT_MULTICARRIER_PROVIDERS: Multicarrier providers.
+ *
+ * MBIM commands in the %MBIM_SERVICE_BASIC_CONNECT service.
+ */
+typedef enum {
+ MBIM_CID_BASIC_CONNECT_UNKNOWN = 0,
+ MBIM_CID_BASIC_CONNECT_DEVICE_CAPS = 1,
+ MBIM_CID_BASIC_CONNECT_SUBSCRIBER_READY_STATUS = 2,
+ MBIM_CID_BASIC_CONNECT_RADIO_STATE = 3,
+ MBIM_CID_BASIC_CONNECT_PIN = 4,
+ MBIM_CID_BASIC_CONNECT_PIN_LIST = 5,
+ MBIM_CID_BASIC_CONNECT_HOME_PROVIDER = 6,
+ MBIM_CID_BASIC_CONNECT_PREFERRED_PROVIDERS = 7,
+ MBIM_CID_BASIC_CONNECT_VISIBLE_PROVIDERS = 8,
+ MBIM_CID_BASIC_CONNECT_REGISTER_STATE = 9,
+ MBIM_CID_BASIC_CONNECT_PACKET_SERVICE = 10,
+ MBIM_CID_BASIC_CONNECT_SIGNAL_STATE = 11,
+ MBIM_CID_BASIC_CONNECT_CONNECT = 12,
+ MBIM_CID_BASIC_CONNECT_PROVISIONED_CONTEXTS = 13,
+ MBIM_CID_BASIC_CONNECT_SERVICE_ACTIVATION = 14,
+ MBIM_CID_BASIC_CONNECT_IP_CONFIGURATION = 15,
+ MBIM_CID_BASIC_CONNECT_DEVICE_SERVICES = 16,
+ /* 17, 18 reserved */
+ MBIM_CID_BASIC_CONNECT_DEVICE_SERVICE_SUBSCRIBER_LIST = 19,
+ MBIM_CID_BASIC_CONNECT_PACKET_STATISTICS = 20,
+ MBIM_CID_BASIC_CONNECT_NETWORK_IDLE_HINT = 21,
+ MBIM_CID_BASIC_CONNECT_EMERGENCY_MODE = 22,
+ MBIM_CID_BASIC_CONNECT_IP_PACKET_FILTERS = 23,
+ MBIM_CID_BASIC_CONNECT_MULTICARRIER_PROVIDERS = 24,
+} MbimCidBasicConnect;
+
+/**
+ * MbimCidSms:
+ * @MBIM_CID_SMS_UNKNOWN: Unknown command.
+ * @MBIM_CID_SMS_CONFIGURATION: SMS configuration.
+ * @MBIM_CID_SMS_READ: Read.
+ * @MBIM_CID_SMS_SEND: Send.
+ * @MBIM_CID_SMS_DELETE: Delete.
+ * @MBIM_CID_SMS_MESSAGE_STORE_STATUS: Store message status.
+ *
+ * MBIM commands in the %MBIM_SERVICE_SMS service.
+ */
+typedef enum {
+ MBIM_CID_SMS_UNKNOWN = 0,
+ MBIM_CID_SMS_CONFIGURATION = 1,
+ MBIM_CID_SMS_READ = 2,
+ MBIM_CID_SMS_SEND = 3,
+ MBIM_CID_SMS_DELETE = 4,
+ MBIM_CID_SMS_MESSAGE_STORE_STATUS = 5,
+} MbimCidSms;
+
+/**
+ * MbimCidUssd:
+ * @MBIM_CID_USSD_UNKNOWN: Unknown command.
+ * @MBIM_CID_USSD: USSD operation.
+ *
+ * MBIM commands in the %MBIM_SERVICE_USSD service.
+ */
+typedef enum {
+ MBIM_CID_USSD_UNKNOWN = 0,
+ MBIM_CID_USSD = 1,
+} MbimCidUssd;
+
+/**
+ * MbimCidPhonebook:
+ * @MBIM_CID_PHONEBOOK_UNKNOWN: Unknown command.
+ * @MBIM_CID_PHONEBOOK_CONFIGURATION: Configuration.
+ * @MBIM_CID_PHONEBOOK_READ: Read.
+ * @MBIM_CID_PHONEBOOK_DELETE: Delete.
+ * @MBIM_CID_PHONEBOOK_WRITE: Write.
+ *
+ * MBIM commands in the %MBIM_SERVICE_PHONEBOOK service.
+ */
+typedef enum {
+ MBIM_CID_PHONEBOOK_UNKNOWN = 0,
+ MBIM_CID_PHONEBOOK_CONFIGURATION = 1,
+ MBIM_CID_PHONEBOOK_READ = 2,
+ MBIM_CID_PHONEBOOK_DELETE = 3,
+ MBIM_CID_PHONEBOOK_WRITE = 4,
+} MbimCidPhonebook;
+
+/**
+ * MbimCidStk:
+ * @MBIM_CID_STK_UNKNOWN: Unknown command.
+ * @MBIM_CID_STK_PAC: PAC.
+ * @MBIM_CID_STK_TERMINAL_RESPONSE: Terminal response.
+ * @MBIM_CID_STK_ENVELOPE: Envelope.
+ *
+ * MBIM commands in the %MBIM_SERVICE_STK service.
+ */
+typedef enum {
+ MBIM_CID_STK_UNKNOWN = 0,
+ MBIM_CID_STK_PAC = 1,
+ MBIM_CID_STK_TERMINAL_RESPONSE = 2,
+ MBIM_CID_STK_ENVELOPE = 3,
+} MbimCidStk;
+
+/**
+ * MbimCidAuth:
+ * @MBIM_CID_AUTH_UNKNOWN: Unknow command
+ * @MBIM_CID_AUTH_AKA: AKA.
+ * @MBIM_CID_AUTH_AKAP: AKAP.
+ * @MBIM_CID_AUTH_SIM: SIM.
+ *
+ * MBIM commands in the %MBIM_SERVICE_AUTH service.
+ */
+typedef enum {
+ MBIM_CID_AUTH_UNKNOWN = 0,
+ MBIM_CID_AUTH_AKA = 1,
+ MBIM_CID_AUTH_AKAP = 2,
+ MBIM_CID_AUTH_SIM = 3,
+} MbimCidAuth;
+
+/**
+ * MbimCidDss:
+ * @MBIM_CID_DSS_UNKNOWN: Unknown command.
+ * @MBIM_CID_DSS_CONNECT: Connect.
+ *
+ * MBIM commands in the %MBIM_SERVICE_DSS service.
+ */
+typedef enum {
+ MBIM_CID_DSS_UNKNOWN = 0,
+ MBIM_CID_DSS_CONNECT = 1
+} MbimCidDss;
+
+/* Command helpers */
+
+gboolean mbim_cid_can_set (MbimService service,
+ guint cid);
+gboolean mbim_cid_can_query (MbimService service,
+ guint cid);
+gboolean mbim_cid_can_notify (MbimService service,
+ guint cid);
+const gchar *mbim_cid_get_printable (MbimService service,
+ guint cid);
+
+G_END_DECLS
+
+#endif /* _LIBMBIM_GLIB_MBIM_CID_H_ */
diff --git a/libmbim-glib/mbim-device.c b/libmbim-glib/mbim-device.c
new file mode 100644
index 0000000..d8c6f81
--- /dev/null
+++ b/libmbim-glib/mbim-device.c
@@ -0,0 +1,1836 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * libmbim-glib -- GLib/GIO based library to control MBIM devices
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2013 Aleksander Morgado <aleksander@lanedo.com>
+ *
+ * Implementation based on the 'QmiDevice' GObject from libqmi-glib.
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <unistd.h>
+#include <gio/gio.h>
+#include <gudev/gudev.h>
+#include <sys/ioctl.h>
+#define IOCTL_WDM_MAX_COMMAND _IOR('H', 0xA0, guint16)
+
+#include "mbim-utils.h"
+#include "mbim-device.h"
+#include "mbim-message.h"
+#include "mbim-message-private.h"
+#include "mbim-error-types.h"
+
+/**
+ * SECTION:mbim-device
+ * @title: MbimDevice
+ * @short_description: Generic MBIM device handling routines
+ *
+ * #MbimDevice is a generic type in charge of controlling the access to the
+ * managed MBIM port.
+ *
+ * A #MbimDevice can only handle one single MBIM port.
+ */
+
+static void async_initable_iface_init (GAsyncInitableIface *iface);
+
+G_DEFINE_TYPE_EXTENDED (MbimDevice, mbim_device, G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init))
+
+enum {
+ PROP_0,
+ PROP_FILE,
+ PROP_TRANSACTION_ID,
+ PROP_IN_SESSION,
+ PROP_LAST
+};
+
+static GParamSpec *properties[PROP_LAST];
+
+enum {
+ SIGNAL_INDICATE_STATUS,
+ SIGNAL_ERROR,
+ SIGNAL_LAST
+};
+
+static guint signals[SIGNAL_LAST] = { 0 };
+
+typedef enum {
+ TRANSACTION_TYPE_HOST = 0,
+ TRANSACTION_TYPE_MODEM = 1,
+ TRANSACTION_TYPE_LAST = 2
+} TransactionType;
+
+struct _MbimDevicePrivate {
+ /* File */
+ GFile *file;
+ gchar *path;
+ gchar *path_display;
+
+ /* I/O channel, set when the file is open */
+ GIOChannel *iochannel;
+ guint watch_id;
+ GByteArray *response;
+
+ /* HT to keep track of ongoing host/function transactions
+ * Host transactions: created by us
+ * Modem transactions: modem-created indications with multiple fragments
+ */
+ GHashTable *transactions[TRANSACTION_TYPE_LAST];
+
+ /* Transaction ID in the device */
+ guint32 transaction_id;
+
+ /* Flag to specify whether we're in a session */
+ gboolean in_session;
+
+ /* message size */
+ guint16 max_control_transfer;
+};
+
+#define MAX_CONTROL_TRANSFER 4096
+#define MAX_TIME_BETWEEN_FRAGMENTS_MS 1250
+
+static void device_report_error (MbimDevice *self,
+ guint32 transaction_id,
+ const GError *error);
+
+/*****************************************************************************/
+/* Message transactions (private) */
+
+typedef struct {
+ MbimDevice *self;
+ guint32 transaction_id;
+ TransactionType type;
+} TransactionWaitContext;
+
+typedef struct {
+ MbimMessage *fragments;
+ guint32 transaction_id;
+ GSimpleAsyncResult *result;
+ guint timeout_id;
+ GCancellable *cancellable;
+ gulong cancellable_id;
+ TransactionWaitContext *wait_ctx;
+} Transaction;
+
+static Transaction *
+transaction_new (MbimDevice *self,
+ guint32 transaction_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ Transaction *tr;
+
+ tr = g_slice_new0 (Transaction);
+ tr->transaction_id = transaction_id;
+ tr->result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ transaction_new);
+ if (cancellable)
+ tr->cancellable = g_object_ref (cancellable);
+
+ return tr;
+}
+
+static void
+transaction_complete_and_free (Transaction *tr,
+ const GError *error)
+{
+ if (tr->timeout_id)
+ g_source_remove (tr->timeout_id);
+
+ if (tr->cancellable) {
+ if (tr->cancellable_id)
+ g_cancellable_disconnect (tr->cancellable, tr->cancellable_id);
+ g_object_unref (tr->cancellable);
+ }
+
+ if (tr->wait_ctx)
+ g_slice_free (TransactionWaitContext, tr->wait_ctx);
+
+ if (error) {
+ g_simple_async_result_set_from_error (tr->result, error);
+ if (tr->fragments)
+ mbim_message_unref (tr->fragments);
+ } else {
+ g_assert (tr->fragments != NULL);
+ g_simple_async_result_set_op_res_gpointer (tr->result,
+ tr->fragments,
+ (GDestroyNotify) mbim_message_unref);
+ }
+
+ g_simple_async_result_complete_in_idle (tr->result);
+ g_object_unref (tr->result);
+ g_slice_free (Transaction, tr);
+}
+
+static Transaction *
+device_release_transaction (MbimDevice *self,
+ TransactionType type,
+ guint32 transaction_id)
+{
+ Transaction *tr = NULL;
+
+ if (self->priv->transactions[type]) {
+ tr = g_hash_table_lookup (self->priv->transactions[type], GUINT_TO_POINTER (transaction_id));
+ if (tr)
+ /* If found, remove it from the HT */
+ g_hash_table_remove (self->priv->transactions[type], GUINT_TO_POINTER (transaction_id));
+ }
+
+ return tr;
+}
+
+static gboolean
+transaction_timed_out (TransactionWaitContext *ctx)
+{
+ Transaction *tr;
+ GError *error = NULL;
+
+ tr = device_release_transaction (ctx->self, ctx->type, ctx->transaction_id);
+ tr->timeout_id = 0;
+
+ /* If no fragment was received, complete transaction with a timeout error */
+ if (!tr->fragments)
+ error = g_error_new (MBIM_CORE_ERROR,
+ MBIM_CORE_ERROR_TIMEOUT,
+ "Transaction timed out");
+ else {
+ /* Fragment timeout... */
+ error = g_error_new (MBIM_PROTOCOL_ERROR,
+ MBIM_PROTOCOL_ERROR_TIMEOUT_FRAGMENT,
+ "Fragment timed out");
+
+ /* Also notify to the modem */
+ device_report_error (ctx->self,
+ tr->transaction_id,
+ error);
+ }
+
+ transaction_complete_and_free (tr, error);
+ g_error_free (error);
+
+ return FALSE;
+}
+
+static void
+transaction_cancelled (GCancellable *cancellable,
+ TransactionWaitContext *ctx)
+{
+ Transaction *tr;
+ GError *error = NULL;
+
+ tr = device_release_transaction (ctx->self, ctx->type, ctx->transaction_id);
+ tr->cancellable_id = 0;
+
+ /* Complete transaction with an abort error */
+ error = g_error_new (MBIM_CORE_ERROR,
+ MBIM_CORE_ERROR_ABORTED,
+ "Transaction aborted");
+ transaction_complete_and_free (tr, error);
+ g_error_free (error);
+}
+
+static gboolean
+device_store_transaction (MbimDevice *self,
+ TransactionType type,
+ Transaction *tr,
+ guint timeout_ms,
+ GError **error)
+{
+ if (G_UNLIKELY (!self->priv->transactions[type]))
+ self->priv->transactions[type] = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ tr->wait_ctx = g_slice_new (TransactionWaitContext);
+ tr->wait_ctx->self = self;
+ /* valid as long as the transaction is in the HT */
+ tr->wait_ctx->transaction_id = tr->transaction_id;
+ tr->wait_ctx->type = type;
+
+ tr->timeout_id = g_timeout_add (timeout_ms,
+ (GSourceFunc)transaction_timed_out,
+ tr->wait_ctx);
+
+ if (tr->cancellable) {
+ tr->cancellable_id = g_cancellable_connect (tr->cancellable,
+ (GCallback)transaction_cancelled,
+ tr->wait_ctx,
+ NULL);
+ if (!tr->cancellable_id) {
+ g_set_error_literal (error,
+ MBIM_CORE_ERROR,
+ MBIM_CORE_ERROR_ABORTED,
+ "Request is already cancelled");
+ return FALSE;
+ }
+ }
+
+ /* Keep in the HT */
+ g_hash_table_insert (self->priv->transactions[type], GUINT_TO_POINTER (tr->transaction_id), tr);
+
+ return TRUE;
+}
+
+static Transaction *
+device_match_transaction (MbimDevice *self,
+ TransactionType type,
+ const MbimMessage *message)
+{
+ /* msg can be either the original message or the response */
+ return device_release_transaction (self, type, mbim_message_get_transaction_id (message));
+}
+
+/*****************************************************************************/
+
+/**
+ * mbim_device_get_file:
+ * @self: a #MbimDevice.
+ *
+ * Get the #GFile associated with this #MbimDevice.
+ *
+ * Returns: a #GFile that must be freed with g_object_unref().
+ */
+GFile *
+mbim_device_get_file (MbimDevice *self)
+{
+ GFile *file = NULL;
+
+ g_return_val_if_fail (MBIM_IS_DEVICE (self), NULL);
+
+ g_object_get (G_OBJECT (self),
+ MBIM_DEVICE_FILE, &file,
+ NULL);
+ return file;
+}
+
+/**
+ * mbim_device_peek_file:
+ * @self: a #MbimDevice.
+ *
+ * Get the #GFile associated with this #MbimDevice, without increasing the reference count
+ * on the returned object.
+ *
+ * Returns: a #GFile. Do not free the returned object, it is owned by @self.
+ */
+GFile *
+mbim_device_peek_file (MbimDevice *self)
+{
+ g_return_val_if_fail (MBIM_IS_DEVICE (self), NULL);
+
+ return self->priv->file;
+}
+
+/**
+ * mbim_device_get_path:
+ * @self: a #MbimDevice.
+ *
+ * Get the system path of the underlying MBIM device.
+ *
+ * Returns: the system path of the device.
+ */
+const gchar *
+mbim_device_get_path (MbimDevice *self)
+{
+ g_return_val_if_fail (MBIM_IS_DEVICE (self), NULL);
+
+ return self->priv->path;
+}
+
+/**
+ * mbim_device_get_path_display:
+ * @self: a #MbimDevice.
+ *
+ * Get the system path of the underlying MBIM device in UTF-8.
+ *
+ * Returns: UTF-8 encoded system path of the device.
+ */
+const gchar *
+mbim_device_get_path_display (MbimDevice *self)
+{
+ g_return_val_if_fail (MBIM_IS_DEVICE (self), NULL);
+
+ return self->priv->path_display;
+}
+
+/**
+ * mbim_device_is_open:
+ * @self: a #MbimDevice.
+ *
+ * Checks whether the #MbimDevice is open for I/O.
+ *
+ * Returns: %TRUE if @self is open, %FALSE otherwise.
+ */
+gboolean
+mbim_device_is_open (MbimDevice *self)
+{
+ g_return_val_if_fail (MBIM_IS_DEVICE (self), FALSE);
+
+ return !!self->priv->iochannel;
+}
+
+/*****************************************************************************/
+/* Open device */
+
+static void
+indication_ready (MbimDevice *self,
+ GAsyncResult *res)
+{
+ GError *error = NULL;
+ MbimMessage *indication;
+
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), &error)) {
+ g_debug ("[%s] Error processing indication message: %s",
+ self->priv->path_display,
+ error->message);
+ g_error_free (error);
+ return;
+ }
+
+ indication = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
+ g_signal_emit (self, signals[SIGNAL_INDICATE_STATUS], 0, indication);
+}
+
+static void
+process_message (MbimDevice *self,
+ const MbimMessage *message)
+{
+ if (mbim_utils_get_traces_enabled ()) {
+ gchar *printable;
+ gboolean is_partial_fragment;
+
+ is_partial_fragment = (_mbim_message_is_fragment (message) &&
+ _mbim_message_fragment_get_total (message) > 1);
+
+ printable = __mbim_utils_str_hex (((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ ':');
+ g_debug ("[%s] Received message...%s\n"
+ ">>>>>> RAW:\n"
+ ">>>>>> length = %u\n"
+ ">>>>>> data = %s\n",
+ self->priv->path_display,
+ is_partial_fragment ? " (partial fragment)" : "",
+ ((GByteArray *)message)->len,
+ printable);
+ g_free (printable);
+
+ if (is_partial_fragment) {
+ printable = mbim_message_get_printable (message, ">>>>>> ", TRUE);
+ g_debug ("[%s] Received message fragment (translated)...\n%s",
+ self->priv->path_display,
+ printable);
+ g_free (printable);
+ }
+ }
+
+ switch (MBIM_MESSAGE_GET_MESSAGE_TYPE (message)) {
+ case MBIM_MESSAGE_TYPE_OPEN_DONE:
+ case MBIM_MESSAGE_TYPE_CLOSE_DONE:
+ case MBIM_MESSAGE_TYPE_COMMAND_DONE:
+ case MBIM_MESSAGE_TYPE_INDICATE_STATUS: {
+ GError *error = NULL;
+ Transaction *tr;
+
+ if (MBIM_MESSAGE_GET_MESSAGE_TYPE (message) == MBIM_MESSAGE_TYPE_INDICATE_STATUS) {
+ /* Grab transaction */
+ tr = device_match_transaction (self, TRANSACTION_TYPE_MODEM, message);
+ if (!tr)
+ /* Create new transaction for the indication */
+ tr = transaction_new (self,
+ mbim_message_get_transaction_id (message),
+ NULL, /* no cancellable */
+ (GAsyncReadyCallback)indication_ready,
+ NULL);
+ } else {
+ /* Grab transaction */
+ tr = device_match_transaction (self, TRANSACTION_TYPE_HOST, message);
+ if (!tr) {
+ g_debug ("[%s] No transaction matched in received message",
+ self->priv->path_display);
+ return;
+ }
+
+ /* If the message doesn't have fragments, we're done */
+ if (!_mbim_message_is_fragment (message)) {
+ g_assert (tr->fragments == NULL);
+ tr->fragments = mbim_message_dup (message);
+ transaction_complete_and_free (tr, NULL);
+ return;
+ }
+ }
+
+ /* More than one fragment expected; is this the first one? */
+ if (!tr->fragments)
+ tr->fragments = _mbim_message_fragment_collector_init (message, &error);
+ else
+ _mbim_message_fragment_collector_add (tr->fragments, message, &error);
+
+ if (error) {
+ device_report_error (self,
+ tr->transaction_id,
+ error);
+ transaction_complete_and_free (tr, error);
+ g_error_free (error);
+ return;
+ }
+
+ /* Did we get all needed fragments? */
+ if (_mbim_message_fragment_collector_complete (tr->fragments)) {
+ /* Now, translate the whole message */
+ if (mbim_utils_get_traces_enabled ()) {
+ gchar *printable;
+
+ printable = mbim_message_get_printable (tr->fragments, ">>>>>> ", FALSE);
+ g_debug ("[%s] Received message (translated)...\n%s",
+ self->priv->path_display,
+ printable);
+ g_free (printable);
+ }
+
+ transaction_complete_and_free (tr, NULL);
+ return;
+ }
+
+ /* Need more fragments, store transaction */
+ g_assert (device_store_transaction (self,
+ TRANSACTION_TYPE_HOST,
+ tr,
+ MAX_TIME_BETWEEN_FRAGMENTS_MS,
+ NULL));
+ return;
+ }
+
+ case MBIM_MESSAGE_TYPE_FUNCTION_ERROR: {
+ GError *error_indication;
+
+ if (mbim_utils_get_traces_enabled ()) {
+ gchar *printable;
+
+ printable = mbim_message_get_printable (message, ">>>>>> ", FALSE);
+ g_debug ("[%s] Received message (translated)...\n%s",
+ self->priv->path_display,
+ printable);
+ g_free (printable);
+ }
+
+ error_indication = mbim_message_error_get_error (message);
+ g_signal_emit (self, signals[SIGNAL_ERROR], 0, error_indication);
+ g_error_free (error_indication);
+ return;
+ }
+
+ case MBIM_MESSAGE_TYPE_INVALID:
+ case MBIM_MESSAGE_TYPE_OPEN:
+ case MBIM_MESSAGE_TYPE_CLOSE:
+ case MBIM_MESSAGE_TYPE_COMMAND:
+ case MBIM_MESSAGE_TYPE_HOST_ERROR:
+ /* Shouldn't expect host-generated messages as replies */
+ g_warning ("[%s] Host-generated message received: ignoring",
+ self->priv->path_display);
+ return;
+ }
+}
+
+static void
+parse_response (MbimDevice *self)
+{
+ do {
+ const MbimMessage *message;
+ guint32 in_length;
+
+ /* If not even the MBIM header available, just return */
+ if (self->priv->response->len < 12)
+ return;
+
+ message = (const MbimMessage *)self->priv->response;
+
+ /* No full message yet */
+ in_length = mbim_message_get_message_length (message);
+
+ if (self->priv->response->len < in_length)
+ return;
+
+ /* Play with the received message */
+ process_message (self, message);
+
+ /* Remove message from buffer */
+ g_byte_array_remove_range (self->priv->response, 0, in_length);
+ } while (self->priv->response->len > 0);
+}
+
+static gboolean
+data_available (GIOChannel *source,
+ GIOCondition condition,
+ MbimDevice *self)
+{
+ gsize bytes_read;
+ GIOStatus status;
+ gchar buffer[MAX_CONTROL_TRANSFER + 1];
+
+ if (condition & G_IO_HUP) {
+ g_debug ("[%s] unexpected port hangup!",
+ self->priv->path_display);
+
+ if (self->priv->response &&
+ self->priv->response->len)
+ g_byte_array_remove_range (self->priv->response, 0, self->priv->response->len);
+
+ mbim_device_close_force (self, NULL);
+ return FALSE;
+ }
+
+ if (condition & G_IO_ERR) {
+ if (self->priv->response &&
+ self->priv->response->len)
+ g_byte_array_remove_range (self->priv->response, 0, self->priv->response->len);
+ return TRUE;
+ }
+
+ /* If not ready yet, prepare the response with default initial size. */
+ if (G_UNLIKELY (!self->priv->response))
+ self->priv->response = g_byte_array_sized_new (500);
+
+ do {
+ GError *error = NULL;
+
+ status = g_io_channel_read_chars (source,
+ buffer,
+ self->priv->max_control_transfer,
+ &bytes_read,
+ &error);
+ if (status == G_IO_STATUS_ERROR) {
+ if (error) {
+ g_warning ("[%s] error reading from the IOChannel: '%s'",
+ self->priv->path_display,
+ error->message);
+ g_error_free (error);
+ }
+
+ /* Port is closed; we're done */
+ if (self->priv->watch_id == 0)
+ break;
+ }
+
+ /* If no bytes read, just let g_io_channel wait for more data */
+ if (bytes_read == 0)
+ break;
+
+ if (bytes_read > 0)
+ g_byte_array_append (self->priv->response, (const guint8 *)buffer, bytes_read);
+
+ /* Try to parse what we already got */
+ parse_response (self);
+
+ /* And keep on if we were told to keep on */
+ } while (bytes_read == self->priv->max_control_transfer || status == G_IO_STATUS_AGAIN);
+
+ return TRUE;
+}
+
+/* "MBIM Control Model Functional Descriptor" */
+struct usb_cdc_mbim_desc {
+ guint8 bLength;
+ guint8 bDescriptorType;
+ guint8 bDescriptorSubType;
+ guint16 bcdMBIMVersion;
+ guint16 wMaxControlMessage;
+ guint8 bNumberFilters;
+ guint8 bMaxFilterSize;
+ guint16 wMaxSegmentSize;
+ guint8 bmNetworkCapabilities;
+} __attribute__ ((packed));
+
+static guint16
+read_max_control_transfer (MbimDevice *self)
+{
+ static const guint8 mbim_signature[4] = { 0x0c, 0x24, 0x1b, 0x00 };
+ guint16 max = MAX_CONTROL_TRANSFER;
+ GUdevClient *client;
+ GUdevDevice *device = NULL;
+ GUdevDevice *parent_device = NULL;
+ GUdevDevice *grandparent_device = NULL;
+ gchar *descriptors_path = NULL;
+ gchar *device_basename = NULL;
+ GError *error = NULL;
+ gchar *contents = NULL;
+ gsize length = 0;
+ guint i;
+
+ client = g_udev_client_new (NULL);
+ if (!G_UDEV_IS_CLIENT (client)) {
+ g_warning ("[%s] Couldn't get udev client",
+ self->priv->path_display);
+ goto out;
+ }
+
+ /* We need to get the sysfs of the cdc-wdm's grandfather:
+ *
+ * * Device's sysfs path is like:
+ * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.5/2-1.5:2.0/usbmisc/cdc-wdm0
+ * * Parent's sysfs path is like:
+ * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.5/2-1.5:2.0
+ * * Grandparent's sysfs path is like:
+ * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.5
+ *
+ * Which is the one with the descriptors file.
+ */
+
+ device_basename = g_path_get_basename (self->priv->path);
+ device = g_udev_client_query_by_subsystem_and_name (client, "usb", device_basename);
+ if (!device) {
+ device = g_udev_client_query_by_subsystem_and_name (client, "usbmisc", device_basename);
+ if (!device) {
+ g_warning ("[%s] Couldn't find udev device",
+ self->priv->path_display);
+ goto out;
+ }
+ }
+
+ parent_device = g_udev_device_get_parent (device);
+ if (!parent_device) {
+ g_warning ("[%s] Couldn't find parent udev device",
+ self->priv->path_display);
+ goto out;
+ }
+
+ grandparent_device = g_udev_device_get_parent (parent_device);
+ if (!grandparent_device) {
+ g_warning ("[%s] Couldn't find grandparent udev device",
+ self->priv->path_display);
+ goto out;
+ }
+
+ descriptors_path = g_build_path (G_DIR_SEPARATOR_S,
+ g_udev_device_get_sysfs_path (grandparent_device),
+ "descriptors",
+ NULL);
+ if (!g_file_get_contents (descriptors_path,
+ &contents,
+ &length,
+ &error)) {
+ g_warning ("[%s] Couldn't read descriptors file: %s",
+ self->priv->path_display,
+ error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ i = 0;
+ while (i <= (length - sizeof (struct usb_cdc_mbim_desc))) {
+ /* Try to match the MBIM descriptor signature */
+ if ((memcmp (&contents[i], mbim_signature, sizeof (mbim_signature)) == 0)) {
+ /* Found! */
+ max = GUINT16_FROM_LE (((struct usb_cdc_mbim_desc *)&contents[i])->wMaxControlMessage);
+ g_debug ("[%s] Read max control message size from descriptors file: %" G_GUINT16_FORMAT,
+ self->priv->path_display,
+ max);
+ goto out;
+ }
+
+ /* The first byte of the descriptor info is the length; so keep on
+ * skipping descriptors until we match the MBIM one */
+ i += contents[i];
+ }
+
+ g_warning ("[%s] Couldn't find MBIM signature in descriptors file",
+ self->priv->path_display);
+
+out:
+ g_free (contents);
+ g_free (device_basename);
+ g_free (descriptors_path);
+ if (parent_device)
+ g_object_unref (parent_device);
+ if (grandparent_device)
+ g_object_unref (grandparent_device);
+ if (device)
+ g_object_unref (device);
+ if (client)
+ g_object_unref (client);
+
+ return max;
+}
+
+static gboolean
+create_iochannel (MbimDevice *self,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ gint fd;
+ guint16 max;
+
+ if (self->priv->iochannel) {
+ g_set_error_literal (error,
+ MBIM_CORE_ERROR,
+ MBIM_CORE_ERROR_WRONG_STATE,
+ "Already open");
+ return FALSE;
+ }
+
+ g_assert (self->priv->file);
+ g_assert (self->priv->path);
+
+ errno = 0;
+ fd = open (self->priv->path, O_RDWR | O_EXCL | O_NONBLOCK | O_NOCTTY);
+ if (fd < 0) {
+ g_set_error (error,
+ MBIM_CORE_ERROR,
+ MBIM_CORE_ERROR_FAILED,
+ "Cannot open device file '%s': %s",
+ self->priv->path_display,
+ strerror (errno));
+ return FALSE;
+ }
+
+ /* Query message size */
+ if (ioctl (fd, IOCTL_WDM_MAX_COMMAND, &max) < 0) {
+ g_debug ("[%s] Couldn't query maximum message size: "
+ "IOCTL_WDM_MAX_COMMAND failed: %s",
+ self->priv->path_display,
+ strerror (errno));
+ /* Fallback, try to read the descriptor file */
+ max = read_max_control_transfer (self);
+ } else {
+ g_debug ("[%s] Queried max control message size: %" G_GUINT16_FORMAT,
+ self->priv->path_display,
+ max);
+ }
+ self->priv->max_control_transfer = max;
+
+ /* Create new GIOChannel */
+ self->priv->iochannel = g_io_channel_unix_new (fd);
+
+ /* We don't want UTF-8 encoding, we're playing with raw binary data */
+ g_io_channel_set_encoding (self->priv->iochannel, NULL, NULL);
+
+ /* We don't want to get the channel buffered */
+ g_io_channel_set_buffered (self->priv->iochannel, FALSE);
+
+ /* Let the GIOChannel own the FD */
+ g_io_channel_set_close_on_unref (self->priv->iochannel, TRUE);
+
+ /* We don't want to get blocked while writing stuff */
+ if (!g_io_channel_set_flags (self->priv->iochannel,
+ G_IO_FLAG_NONBLOCK,
+ &inner_error)) {
+ g_prefix_error (&inner_error, "Cannot set non-blocking channel: ");
+ g_propagate_error (error, inner_error);
+ g_io_channel_shutdown (self->priv->iochannel, FALSE, NULL);
+ g_io_channel_unref (self->priv->iochannel);
+ self->priv->iochannel = NULL;
+ return FALSE;
+ }
+
+ self->priv->watch_id = g_io_add_watch (self->priv->iochannel,
+ G_IO_IN | G_IO_ERR | G_IO_HUP,
+ (GIOFunc)data_available,
+ self);
+
+ return !!self->priv->iochannel;
+}
+
+typedef struct {
+ MbimDevice *self;
+ GSimpleAsyncResult *result;
+ GCancellable *cancellable;
+ guint timeout;
+} DeviceOpenContext;
+
+static void
+device_open_context_complete_and_free (DeviceOpenContext *ctx)
+{
+ g_simple_async_result_complete_in_idle (ctx->result);
+ g_object_unref (ctx->result);
+ if (ctx->cancellable)
+ g_object_unref (ctx->cancellable);
+ g_object_unref (ctx->self);
+ g_slice_free (DeviceOpenContext, ctx);
+}
+
+/**
+ * mbim_device_open_finish:
+ * @self: a #MbimDevice.
+ * @res: a #GAsyncResult.
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes an asynchronous open operation started with mbim_device_open().
+ *
+ * Returns: %TRUE if successful, %FALSE if @error is set.
+ */
+gboolean
+mbim_device_open_finish (MbimDevice *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
+}
+
+static void open_message (DeviceOpenContext *ctx);
+
+static void
+open_message_ready (MbimDevice *self,
+ GAsyncResult *res,
+ DeviceOpenContext *ctx)
+{
+ MbimMessage *response;
+ GError *error = NULL;
+
+ response = mbim_device_command_finish (self, res, &error);
+ if (!response) {
+ /* Check if we should be retrying */
+ if (g_error_matches (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_TIMEOUT)) {
+ /* The timeout will tell us how many retries we should do */
+ ctx->timeout--;
+ if (ctx->timeout) {
+ g_error_free (error);
+ open_message (ctx);
+ return;
+ }
+
+ /* No more seconds left in the timeout... return error */
+ }
+
+ g_simple_async_result_take_error (ctx->result, error);
+ } else if (!mbim_message_open_done_get_result (response, &error))
+ g_simple_async_result_take_error (ctx->result, error);
+ else
+ g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
+
+ if (response)
+ mbim_message_unref (response);
+ device_open_context_complete_and_free (ctx);
+}
+
+static void
+open_message (DeviceOpenContext *ctx)
+{
+ MbimMessage *request;
+
+ /* Launch 'Open' command */
+ request = mbim_message_open_new (mbim_device_get_next_transaction_id (ctx->self),
+ ctx->self->priv->max_control_transfer);
+ mbim_device_command (ctx->self,
+ request,
+ 1, /* 1s per retry */
+ ctx->cancellable,
+ (GAsyncReadyCallback)open_message_ready,
+ ctx);
+ mbim_message_unref (request);
+}
+
+/**
+ * mbim_device_open:
+ * @self: a #MbimDevice.
+ * @timeout: maximum time, in seconds, to wait for the device to be opened.
+ * @cancellable: optional #GCancellable object, #NULL to ignore.
+ * @callback: a #GAsyncReadyCallback to call when the operation is finished.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously opens a #MbimDevice for I/O.
+ *
+ * When the operation is finished @callback will be called. You can then call
+ * mbim_device_open_finish() to get the result of the operation.
+ */
+void
+mbim_device_open (MbimDevice *self,
+ guint timeout,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ DeviceOpenContext *ctx;
+ GError *error = NULL;
+
+ g_return_if_fail (MBIM_IS_DEVICE (self));
+ g_return_if_fail (timeout > 0);
+
+ ctx = g_slice_new (DeviceOpenContext);
+ ctx->self = g_object_ref (self);
+ ctx->result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ mbim_device_open);
+ ctx->timeout = timeout;
+ ctx->cancellable = (cancellable ? g_object_ref (cancellable) : NULL);
+
+ if (!create_iochannel (self, &error)) {
+ g_prefix_error (&error,
+ "Cannot open MBIM device: ");
+ g_simple_async_result_take_error (ctx->result, error);
+ device_open_context_complete_and_free (ctx);
+ return;
+ }
+
+ /* If the device is already in-session, avoid the open message */
+ if (self->priv->in_session) {
+ g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
+ device_open_context_complete_and_free (ctx);
+ return;
+ }
+
+ open_message (ctx);
+}
+
+/*****************************************************************************/
+/* Close channel */
+
+static gboolean
+destroy_iochannel (MbimDevice *self,
+ GError **error)
+{
+ GError *inner_error = NULL;
+
+ g_io_channel_shutdown (self->priv->iochannel, TRUE, &inner_error);
+
+ /* Failures when closing still make the device to get closed */
+ g_io_channel_unref (self->priv->iochannel);
+ self->priv->iochannel = NULL;
+
+ if (self->priv->watch_id) {
+ g_source_remove (self->priv->watch_id);
+ self->priv->watch_id = 0;
+ }
+
+ if (self->priv->response) {
+ g_byte_array_unref (self->priv->response);
+ self->priv->response = NULL;
+ }
+
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * mbim_device_close_force:
+ * @self: a #MbimDevice.
+ * @error: Return location for error or %NULL.
+ *
+ * Forces the #MbimDevice to be closed.
+ *
+ * Returns: %TRUE if @self if no error happens, otherwise %FALSE and @error is set.
+ */
+gboolean
+mbim_device_close_force (MbimDevice *self,
+ GError **error)
+{
+ g_return_val_if_fail (MBIM_IS_DEVICE (self), FALSE);
+
+ /* Already closed? */
+ if (!self->priv->iochannel)
+ return TRUE;
+
+ return destroy_iochannel (self, error);
+}
+
+typedef struct {
+ MbimDevice *self;
+ GSimpleAsyncResult *result;
+ GCancellable *cancellable;
+ guint timeout;
+} DeviceCloseContext;
+
+static void
+device_close_context_complete_and_free (DeviceCloseContext *ctx)
+{
+ g_simple_async_result_complete_in_idle (ctx->result);
+ g_object_unref (ctx->result);
+ if (ctx->cancellable)
+ g_object_unref (ctx->cancellable);
+ g_object_unref (ctx->self);
+ g_slice_free (DeviceCloseContext, ctx);
+}
+
+/**
+ * mbim_device_close_finish:
+ * @self: a #MbimDevice.
+ * @res: a #GAsyncResult.
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes an asynchronous close operation started with mbim_device_close().
+ *
+ * Returns: %TRUE if successful, %FALSE if @error is set.
+ */
+gboolean
+mbim_device_close_finish (MbimDevice *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
+}
+
+static void
+close_message_ready (MbimDevice *self,
+ GAsyncResult *res,
+ DeviceCloseContext *ctx)
+{
+ MbimMessage *response;
+ GError *error = NULL;
+
+ response = mbim_device_command_finish (self, res, &error);
+ if (!response)
+ g_simple_async_result_take_error (ctx->result, error);
+ else if (!mbim_message_close_done_get_result (response, &error))
+ g_simple_async_result_take_error (ctx->result, error);
+ else if (!destroy_iochannel (self, &error))
+ g_simple_async_result_take_error (ctx->result, error);
+ else
+ g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
+
+ if (response)
+ mbim_message_unref (response);
+ device_close_context_complete_and_free (ctx);
+}
+
+/**
+ * mbim_device_close:
+ * @self: a #MbimDevice.
+ * @timeout: maximum time, in seconds, to wait for the device to be closed.
+ * @cancellable: optional #GCancellable object, #NULL to ignore.
+ * @callback: a #GAsyncReadyCallback to call when the operation is finished.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously closes a #MbimDevice for I/O.
+ *
+ * When the operation is finished @callback will be called. You can then call
+ * mbim_device_close_finish() to get the result of the operation.
+ */
+void
+mbim_device_close (MbimDevice *self,
+ guint timeout,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ MbimMessage *request;
+ DeviceCloseContext *ctx;
+
+ g_return_if_fail (MBIM_IS_DEVICE (self));
+
+ ctx = g_slice_new (DeviceCloseContext);
+ ctx->self = g_object_ref (self);
+ ctx->result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ mbim_device_close);
+ ctx->timeout = timeout;
+ ctx->cancellable = (cancellable ? g_object_ref (cancellable) : NULL);
+
+ /* Already closed? */
+ if (!self->priv->iochannel) {
+ g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
+ device_close_context_complete_and_free (ctx);
+ return;
+ }
+
+ /* If the device is in-session, avoid the close message */
+ if (self->priv->in_session) {
+ GError *error = NULL;
+
+ if (!destroy_iochannel (self, &error))
+ g_simple_async_result_take_error (ctx->result, error);
+ else
+ g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
+ device_close_context_complete_and_free (ctx);
+ return;
+ }
+
+ /* Launch 'Close' command */
+ request = mbim_message_close_new (mbim_device_get_next_transaction_id (self));
+ mbim_device_command (self,
+ request,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback) close_message_ready,
+ ctx);
+ mbim_message_unref (request);
+}
+
+/*****************************************************************************/
+
+/**
+ * mbim_device_get_next_transaction_id:
+ * @self: A #MbimDevice.
+ *
+ * Acquire the next transaction ID of this #MbimDevice.
+ * The internal transaction ID gets incremented.
+ *
+ * Returns: the next transaction ID.
+ */
+guint32
+mbim_device_get_next_transaction_id (MbimDevice *self)
+{
+ guint32 next;
+
+ g_return_val_if_fail (MBIM_IS_DEVICE (self), 0);
+
+ next = self->priv->transaction_id;
+
+ /* Don't go further than 8bits in the CTL service */
+ if (self->priv->transaction_id == G_MAXUINT32)
+ /* Reset! */
+ self->priv->transaction_id = 0x01;
+ else
+ self->priv->transaction_id++;
+
+ return next;
+}
+
+/*****************************************************************************/
+
+static gboolean
+device_write (MbimDevice *self,
+ const guint8 *data,
+ guint32 data_length,
+ GError **error)
+{
+ gsize written;
+ GIOStatus write_status;
+
+ written = 0;
+ write_status = G_IO_STATUS_AGAIN;
+ while (write_status == G_IO_STATUS_AGAIN) {
+ write_status = g_io_channel_write_chars (self->priv->iochannel,
+ (gconstpointer)data,
+ (gssize)data_length,
+ &written,
+ error);
+ switch (write_status) {
+ case G_IO_STATUS_ERROR:
+ g_prefix_error (error, "Cannot write message: ");
+ return FALSE;
+
+ case G_IO_STATUS_EOF:
+ /* We shouldn't get EOF when writing */
+ g_assert_not_reached ();
+ break;
+
+ case G_IO_STATUS_NORMAL:
+ /* All good, we'll exit the loop now */
+ break;
+
+ case G_IO_STATUS_AGAIN:
+ /* We're in a non-blocking channel and therefore we're up to receive
+ * EAGAIN; just retry in this case. TODO: in an idle? */
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+device_send (MbimDevice *self,
+ MbimMessage *message,
+ GError **error)
+{
+ const guint8 *raw_message;
+ guint32 raw_message_len;
+ struct fragment_info *fragments;
+ guint n_fragments;
+ guint i;
+
+ raw_message = mbim_message_get_raw (message, &raw_message_len, NULL);
+ g_assert (raw_message);
+
+ if (mbim_utils_get_traces_enabled ()) {
+ gchar *printable;
+
+ printable = __mbim_utils_str_hex (raw_message, raw_message_len, ':');
+ g_debug ("[%s] Sent message...\n"
+ "<<<<<< RAW:\n"
+ "<<<<<< length = %u\n"
+ "<<<<<< data = %s\n",
+ self->priv->path_display,
+ ((GByteArray *)message)->len,
+ printable);
+ g_free (printable);
+
+ printable = mbim_message_get_printable (message, "<<<<<< ", FALSE);
+ g_debug ("[%s] Sent message (translated)...\n%s",
+ self->priv->path_display,
+ printable);
+ g_free (printable);
+ }
+
+ /* Single fragment? Send it! */
+ if (raw_message_len <= MAX_CONTROL_TRANSFER)
+ return device_write (self, raw_message, raw_message_len, error);
+
+ /* The message to send must be able to handle fragments */
+ g_assert (_mbim_message_is_fragment (message));
+
+ fragments = _mbim_message_split_fragments (message,
+ MAX_CONTROL_TRANSFER,
+ &n_fragments);
+ for (i = 0; i < n_fragments; i++) {
+ if (mbim_utils_get_traces_enabled ()) {
+ GByteArray *bytearray;
+ gchar *printable;
+ gchar *printable_h;
+ gchar *printable_fh;
+ gchar *printable_d;
+
+ printable_h = __mbim_utils_str_hex (&fragments[i].header, sizeof (fragments[i].header), ':');
+ printable_fh = __mbim_utils_str_hex (&fragments[i].fragment_header, sizeof (fragments[i].fragment_header), ':');
+ printable_d = __mbim_utils_str_hex (fragments[i].data, fragments[i].data_length, ':');
+ g_debug ("[%s] Sent fragment (%u)...\n"
+ "<<<<<< RAW:\n"
+ "<<<<<< length = %u\n"
+ "<<<<<< data = %s%s%s\n",
+ self->priv->path_display, i,
+ (guint)(sizeof (fragments[i].header) +
+ sizeof (fragments[i].fragment_header) +
+ fragments[i].data_length),
+ printable_h, printable_fh, printable_d);
+ g_free (printable_h);
+ g_free (printable_fh);
+ g_free (printable_d);
+
+ /* Dummy message for printable purposes only */
+ bytearray = g_byte_array_new ();
+ g_byte_array_append (bytearray, (guint8 *)&fragments[i].header, sizeof (fragments[i].header));
+ g_byte_array_append (bytearray, (guint8 *)&fragments[i].fragment_header, sizeof (fragments[i].fragment_header));
+ printable = mbim_message_get_printable ((MbimMessage *)bytearray, "<<<<<< ", TRUE);
+ g_debug ("[%s] Sent fragment (translated)...\n%s",
+ self->priv->path_display,
+ printable);
+ g_free (printable);
+ g_byte_array_unref (bytearray);
+ }
+
+ /* Write fragment headers */
+ if (!device_write (self,
+ (guint8 *)&fragments[i].header,
+ sizeof (fragments[i].header),
+ error))
+ return FALSE;
+
+ if (!device_write (self,
+ (guint8 *)&fragments[i].fragment_header,
+ sizeof (fragments[i].fragment_header),
+ error))
+ return FALSE;
+
+ /* Write fragment data */
+ if (!device_write (self,
+ fragments[i].data,
+ fragments[i].data_length,
+ error))
+ return FALSE;
+ }
+ g_free (fragments);
+
+ return TRUE;
+}
+
+/*****************************************************************************/
+/* Report error */
+
+typedef struct {
+ MbimDevice *self;
+ MbimMessage *message;
+} ReportErrorContext;
+
+static void
+device_report_error_context_free (ReportErrorContext *ctx)
+{
+ mbim_message_unref (ctx->message);
+ g_object_unref (ctx->self);
+ g_slice_free (ReportErrorContext, ctx);
+}
+
+static gboolean
+device_report_error_in_idle (ReportErrorContext *ctx)
+{
+ /* Device must be open */
+ if (ctx->self->priv->iochannel) {
+ GError *error = NULL;
+
+ if (!device_send (ctx->self, ctx->message, &error)) {
+ g_warning ("[%s] Couldn't send host error message: %s",
+ ctx->self->priv->path_display,
+ error->message);
+ g_error_free (error);
+ }
+ }
+
+ device_report_error_context_free (ctx);
+ return FALSE;
+}
+
+static void
+device_report_error (MbimDevice *self,
+ guint32 transaction_id,
+ const GError *error)
+{
+ ReportErrorContext *ctx;
+
+ /* Only protocol errors to be reported to the modem */
+ if (error->domain != MBIM_PROTOCOL_ERROR)
+ return;
+
+ ctx = g_slice_new (ReportErrorContext);
+ ctx->self = g_object_ref (self);
+ ctx->message = mbim_message_error_new (transaction_id, error->code);
+
+ g_idle_add ((GSourceFunc) device_report_error_in_idle, ctx);
+}
+
+/*****************************************************************************/
+/* Command */
+
+/**
+ * mbim_device_command_finish:
+ * @self: a #MbimDevice.
+ * @res: a #GAsyncResult.
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes an operation started with mbim_device_command().
+ *
+ * Returns: a #MbimMessage response, or #NULL if @error is set. The returned value should be freed with mbim_message_unref().
+ */
+MbimMessage *
+mbim_device_command_finish (MbimDevice *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
+ return NULL;
+
+ return mbim_message_ref (g_simple_async_result_get_op_res_gpointer (
+ G_SIMPLE_ASYNC_RESULT (res)));
+}
+
+/**
+ * mbim_device_command:
+ * @self: a #MbimDevice.
+ * @message: the message to send.
+ * @timeout: maximum time, in seconds, to wait for the response.
+ * @cancellable: a #GCancellable, or %NULL.
+ * @callback: a #GAsyncReadyCallback to call when the operation is finished.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously sends a #MbimMessage to the device.
+ *
+ * When the operation is finished @callback will be called. You can then call
+ * mbim_device_command_finish() to get the result of the operation.
+ */
+void
+mbim_device_command (MbimDevice *self,
+ MbimMessage *message,
+ guint timeout,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ Transaction *tr;
+ guint32 transaction_id;
+
+ g_return_if_fail (MBIM_IS_DEVICE (self));
+ g_return_if_fail (message != NULL);
+
+ /* If the message comes without a explicit transaction ID, add one
+ * ourselves */
+ transaction_id = mbim_message_get_transaction_id (message);
+ if (!transaction_id) {
+ transaction_id = mbim_device_get_next_transaction_id (self);
+ mbim_message_set_transaction_id (message, transaction_id);
+ }
+
+ tr = transaction_new (self,
+ transaction_id,
+ cancellable,
+ callback,
+ user_data);
+
+ /* Device must be open */
+ if (!self->priv->iochannel) {
+ error = g_error_new (MBIM_CORE_ERROR,
+ MBIM_CORE_ERROR_WRONG_STATE,
+ "Device must be open to send commands");
+ transaction_complete_and_free (tr, error);
+ g_error_free (error);
+ return;
+ }
+
+ /* Setup context to match response */
+ if (!device_store_transaction (self, TRANSACTION_TYPE_HOST, tr, timeout * 1000, &error)) {
+ g_prefix_error (&error, "Cannot store transaction: ");
+ transaction_complete_and_free (tr, error);
+ g_error_free (error);
+ return;
+ }
+
+ if (!device_send (self, message, &error)) {
+ /* Match transaction so that we remove it from our tracking table */
+ tr = device_match_transaction (self, TRANSACTION_TYPE_HOST, message);
+ transaction_complete_and_free (tr, error);
+ g_error_free (error);
+ return;
+ }
+
+ /* Just return, we'll get response asynchronously */
+}
+
+/*****************************************************************************/
+/* New MBIM device */
+
+/**
+ * mbim_device_new_finish:
+ * @res: a #GAsyncResult.
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes an operation started with mbim_device_new().
+ *
+ * Returns: A newly created #MbimDevice, or #NULL if @error is set.
+ */
+MbimDevice *
+mbim_device_new_finish (GAsyncResult *res,
+ GError **error)
+{
+ GObject *ret;
+ GObject *source_object;
+
+ source_object = g_async_result_get_source_object (res);
+ ret = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), res, error);
+ g_object_unref (source_object);
+
+ return (ret ? MBIM_DEVICE (ret) : NULL);
+}
+
+/**
+ * mbim_device_new:
+ * @file: a #GFile.
+ * @cancellable: optional #GCancellable object, #NULL to ignore.
+ * @callback: a #GAsyncReadyCallback to call when the initialization is finished.
+ * @user_data: the data to pass to callback function.
+ *
+ * Asynchronously creates a #MbimDevice object to manage @file.
+ * When the operation is finished, @callback will be invoked. You can then call
+ * mbim_device_new_finish() to get the result of the operation.
+ */
+void
+mbim_device_new (GFile *file,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_async_initable_new_async (MBIM_TYPE_DEVICE,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ callback,
+ user_data,
+ MBIM_DEVICE_FILE, file,
+ NULL);
+}
+
+/*****************************************************************************/
+/* Async init */
+
+typedef struct {
+ MbimDevice *self;
+ GSimpleAsyncResult *result;
+ GCancellable *cancellable;
+} InitContext;
+
+static void
+init_context_complete_and_free (InitContext *ctx)
+{
+ g_simple_async_result_complete_in_idle (ctx->result);
+ if (ctx->cancellable)
+ g_object_unref (ctx->cancellable);
+ g_object_unref (ctx->result);
+ g_object_unref (ctx->self);
+ g_slice_free (InitContext, ctx);
+}
+
+static gboolean
+initable_init_finish (GAsyncInitable *initable,
+ GAsyncResult *result,
+ GError **error)
+{
+ return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
+}
+
+static void
+query_info_async_ready (GFile *file,
+ GAsyncResult *res,
+ InitContext *ctx)
+{
+ GError *error = NULL;
+ GFileInfo *info;
+
+ info = g_file_query_info_finish (file, res, &error);
+ if (!info) {
+ g_prefix_error (&error,
+ "Couldn't query file info: ");
+ g_simple_async_result_take_error (ctx->result, error);
+ init_context_complete_and_free (ctx);
+ return;
+ }
+
+ /* Our MBIM device must be of SPECIAL type */
+ if (g_file_info_get_file_type (info) != G_FILE_TYPE_SPECIAL) {
+ g_simple_async_result_set_error (ctx->result,
+ MBIM_CORE_ERROR,
+ MBIM_CORE_ERROR_FAILED,
+ "Wrong file type");
+ init_context_complete_and_free (ctx);
+ return;
+ }
+ g_object_unref (info);
+
+ /* Done we are */
+ g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
+ init_context_complete_and_free (ctx);
+}
+
+static void
+initable_init_async (GAsyncInitable *initable,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ InitContext *ctx;
+
+ ctx = g_slice_new0 (InitContext);
+ ctx->self = g_object_ref (initable);
+ if (cancellable)
+ ctx->cancellable = g_object_ref (cancellable);
+ ctx->result = g_simple_async_result_new (G_OBJECT (initable),
+ callback,
+ user_data,
+ initable_init_async);
+
+ /* We need a proper file to initialize */
+ if (!ctx->self->priv->file) {
+ g_simple_async_result_set_error (ctx->result,
+ MBIM_CORE_ERROR,
+ MBIM_CORE_ERROR_INVALID_ARGS,
+ "Cannot initialize MBIM device: No file given");
+ init_context_complete_and_free (ctx);
+ return;
+ }
+
+ /* Check the file type. Note that this is just a quick check to avoid
+ * creating MbimDevices pointing to a location already known not to be a MBIM
+ * device. */
+ g_file_query_info_async (ctx->self->priv->file,
+ G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ G_PRIORITY_DEFAULT,
+ ctx->cancellable,
+ (GAsyncReadyCallback)query_info_async_ready,
+ ctx);
+}
+
+/*****************************************************************************/
+
+static void
+set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MbimDevice *self = MBIM_DEVICE (object);
+
+ switch (prop_id) {
+ case PROP_FILE:
+ g_assert (self->priv->file == NULL);
+ self->priv->file = g_value_dup_object (value);
+ self->priv->path = g_file_get_path (self->priv->file);
+ self->priv->path_display = g_filename_display_name (self->priv->path);
+ break;
+ case PROP_TRANSACTION_ID:
+ self->priv->transaction_id = g_value_get_uint (value);
+ break;
+ case PROP_IN_SESSION:
+ self->priv->in_session = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MbimDevice *self = MBIM_DEVICE (object);
+
+ switch (prop_id) {
+ case PROP_FILE:
+ g_value_set_object (value, self->priv->file);
+ break;
+ case PROP_TRANSACTION_ID:
+ g_value_set_uint (value, self->priv->transaction_id);
+ break;
+ case PROP_IN_SESSION:
+ g_value_set_boolean (value, self->priv->in_session);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+mbim_device_init (MbimDevice *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
+ MBIM_TYPE_DEVICE,
+ MbimDevicePrivate);
+
+ /* Initialize transaction ID */
+ self->priv->transaction_id = 0x01;
+}
+
+static void
+dispose (GObject *object)
+{
+ MbimDevice *self = MBIM_DEVICE (object);
+
+ g_clear_object (&self->priv->file);
+
+ G_OBJECT_CLASS (mbim_device_parent_class)->dispose (object);
+}
+
+static void
+finalize (GObject *object)
+{
+ MbimDevice *self = MBIM_DEVICE (object);
+ guint i;
+
+ /* Transactions keep refs to the device, so it's actually
+ * impossible to have any content in the HT */
+ for (i = 0; i < TRANSACTION_TYPE_LAST; i++) {
+ if (self->priv->transactions[i]) {
+ g_assert (g_hash_table_size (self->priv->transactions[i]) == 0);
+ g_hash_table_unref (self->priv->transactions[i]);
+ }
+ }
+
+ g_free (self->priv->path);
+ g_free (self->priv->path_display);
+ if (self->priv->watch_id)
+ g_source_remove (self->priv->watch_id);
+ if (self->priv->response)
+ g_byte_array_unref (self->priv->response);
+ if (self->priv->iochannel)
+ g_io_channel_unref (self->priv->iochannel);
+
+ G_OBJECT_CLASS (mbim_device_parent_class)->finalize (object);
+}
+
+static void
+async_initable_iface_init (GAsyncInitableIface *iface)
+{
+ iface->init_async = initable_init_async;
+ iface->init_finish = initable_init_finish;
+}
+
+static void
+mbim_device_class_init (MbimDeviceClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MbimDevicePrivate));
+
+ object_class->get_property = get_property;
+ object_class->set_property = set_property;
+ object_class->finalize = finalize;
+ object_class->dispose = dispose;
+
+ properties[PROP_FILE] =
+ g_param_spec_object (MBIM_DEVICE_FILE,
+ "Device file",
+ "File to the underlying MBIM device",
+ G_TYPE_FILE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class, PROP_FILE, properties[PROP_FILE]);
+
+ properties[PROP_TRANSACTION_ID] =
+ g_param_spec_uint (MBIM_DEVICE_TRANSACTION_ID,
+ "Transaction ID",
+ "Current transaction ID",
+ 0x01,
+ G_MAXUINT32,
+ 0x01,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_TRANSACTION_ID, properties[PROP_TRANSACTION_ID]);
+
+ properties[PROP_IN_SESSION] =
+ g_param_spec_boolean (MBIM_DEVICE_IN_SESSION,
+ "In session",
+ "Flag to specify if the device is within a session",
+ FALSE,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_IN_SESSION, properties[PROP_IN_SESSION]);
+
+ /**
+ * MbimDevice::device-indicate-status:
+ * @self: the #MbimDevice
+ * @message: the #MbimMessage indication
+ *
+ * The ::device-indication-status signal is emitted when a MBIM indication is received.
+ */
+ signals[SIGNAL_INDICATE_STATUS] =
+ g_signal_new (MBIM_DEVICE_SIGNAL_INDICATE_STATUS,
+ G_OBJECT_CLASS_TYPE (G_OBJECT_CLASS (klass)),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 1,
+ MBIM_TYPE_MESSAGE);
+
+ /**
+ * MbimDevice::device-error:
+ * @self: the #MbimDevice
+ * @message: the #MbimMessage error
+ *
+ * The ::device-error signal is emitted when a MBIM error is received.
+ */
+ signals[SIGNAL_ERROR] =
+ g_signal_new (MBIM_DEVICE_SIGNAL_ERROR,
+ G_OBJECT_CLASS_TYPE (G_OBJECT_CLASS (klass)),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_ERROR);
+}
diff --git a/libmbim-glib/mbim-device.h b/libmbim-glib/mbim-device.h
new file mode 100644
index 0000000..963571f
--- /dev/null
+++ b/libmbim-glib/mbim-device.h
@@ -0,0 +1,122 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * libmbim-glib -- GLib/GIO based library to control MBIM devices
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2013 Aleksander Morgado <aleksander@lanedo.com>
+ */
+
+#ifndef _LIBMBIM_GLIB_MBIM_DEVICE_H_
+#define _LIBMBIM_GLIB_MBIM_DEVICE_H_
+
+#if !defined (__LIBMBIM_GLIB_H_INSIDE__) && !defined (LIBMBIM_GLIB_COMPILATION)
+#error "Only <libmbim-glib.h> can be included directly."
+#endif
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include "mbim-message.h"
+
+G_BEGIN_DECLS
+
+#define MBIM_TYPE_DEVICE (mbim_device_get_type ())
+#define MBIM_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MBIM_TYPE_DEVICE, MbimDevice))
+#define MBIM_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MBIM_TYPE_DEVICE, MbimDeviceClass))
+#define MBIM_IS_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MBIM_TYPE_DEVICE))
+#define MBIM_IS_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MBIM_TYPE_DEVICE))
+#define MBIM_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MBIM_TYPE_DEVICE, MbimDeviceClass))
+
+typedef struct _MbimDevice MbimDevice;
+typedef struct _MbimDeviceClass MbimDeviceClass;
+typedef struct _MbimDevicePrivate MbimDevicePrivate;
+
+#define MBIM_DEVICE_FILE "device-file"
+#define MBIM_DEVICE_TRANSACTION_ID "device-transaction-id"
+#define MBIM_DEVICE_IN_SESSION "device-in-session"
+
+#define MBIM_DEVICE_SIGNAL_INDICATE_STATUS "device-indicate-status"
+#define MBIM_DEVICE_SIGNAL_ERROR "device-error"
+
+/**
+ * MbimDevice:
+ *
+ * The #MbimDevice structure contains private data and should only be accessed
+ * using the provided API.
+ */
+struct _MbimDevice {
+ /*< private >*/
+ GObject parent;
+ MbimDevicePrivate *priv;
+};
+
+struct _MbimDeviceClass {
+ /*< private >*/
+ GObjectClass parent;
+};
+
+GType mbim_device_get_type (void);
+
+void mbim_device_new (GFile *file,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+MbimDevice *mbim_device_new_finish (GAsyncResult *res,
+ GError **error);
+
+GFile *mbim_device_get_file (MbimDevice *self);
+GFile *mbim_device_peek_file (MbimDevice *self);
+const gchar *mbim_device_get_path (MbimDevice *self);
+const gchar *mbim_device_get_path_display (MbimDevice *self);
+gboolean mbim_device_is_open (MbimDevice *self);
+
+void mbim_device_open (MbimDevice *self,
+ guint timeout,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mbim_device_open_finish (MbimDevice *self,
+ GAsyncResult *res,
+ GError **error);
+
+void mbim_device_close (MbimDevice *self,
+ guint timeout,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mbim_device_close_finish (MbimDevice *self,
+ GAsyncResult *res,
+ GError **error);
+
+gboolean mbim_device_close_force (MbimDevice *self,
+ GError **error);
+
+guint32 mbim_device_get_next_transaction_id (MbimDevice *self);
+
+void mbim_device_command (MbimDevice *self,
+ MbimMessage *message,
+ guint timeout,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+MbimMessage *mbim_device_command_finish (MbimDevice *self,
+ GAsyncResult *res,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* _LIBMBIM_GLIB_MBIM_DEVICE_H_ */
diff --git a/libmbim-glib/mbim-enums.h b/libmbim-glib/mbim-enums.h
new file mode 100644
index 0000000..6275537
--- /dev/null
+++ b/libmbim-glib/mbim-enums.h
@@ -0,0 +1,922 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/*
+ * libmbim-glib -- GLib/GIO based library to control MBIM devices
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#ifndef _LIBMBIM_GLIB_MBIM_ENUMS_H_
+#define _LIBMBIM_GLIB_MBIM_ENUMS_H_
+
+#if !defined (__LIBMBIM_GLIB_H_INSIDE__) && !defined (LIBMBIM_GLIB_COMPILATION)
+#error "Only <libmbim-glib.h> can be included directly."
+#endif
+
+G_BEGIN_DECLS
+
+/**
+ * SECTION: mbim-enums
+ * @title: Enumerations and Flags
+ *
+ * This section defines common enum and flag types used in the interface.
+ */
+
+/*****************************************************************************/
+/* 'Device Caps' enums */
+
+/**
+ * MbimDeviceType:
+ * @MBIM_DEVICE_TYPE_UNKNOWN: Unknown type.
+ * @MBIM_DEVICE_TYPE_EMBEDDED: Device is embedded in the system.
+ * @MBIM_DEVICE_TYPE_REMOVABLE: Device is removable.
+ * @MBIM_DEVICE_TYPE_REMOTE: Device is remote.
+ *
+ * Type of device.
+ */
+typedef enum {
+ MBIM_DEVICE_TYPE_UNKNOWN = 0,
+ MBIM_DEVICE_TYPE_EMBEDDED = 1,
+ MBIM_DEVICE_TYPE_REMOVABLE = 2,
+ MBIM_DEVICE_TYPE_REMOTE = 3
+} MbimDeviceType;
+
+/**
+ * MbimCellularClass:
+ * @MBIM_CELLULAR_CLASS_GSM: Device is 3GPP.
+ * @MBIM_CELLULAR_CLASS_CDMA: Device is 3GPP2.
+ *
+ * Cellular class.
+ */
+typedef enum {
+ MBIM_CELLULAR_CLASS_GSM = 1 << 0,
+ MBIM_CELLULAR_CLASS_CDMA = 1 << 1
+} MbimCellularClass;
+
+/**
+ * MbimVoiceClass:
+ * @MBIM_VOICE_CLASS_UNKNOWN: Unknown voice class.
+ * @MBIM_VOICE_CLASS_NO_VOICE: Device doesn't support voice.
+ * @MBIM_VOICE_CLASS_SEPARATED_VOICE_DATA: Device supports separate voice and data connections.
+ * @MBIM_VOICE_CLASS_SIMULTANEOUS_VOICE_DATA: Device supports simultaneous voice and data connections.
+ *
+ * Voice class.
+ */
+typedef enum {
+ MBIM_VOICE_CLASS_UNKNOWN = 0,
+ MBIM_VOICE_CLASS_NO_VOICE = 1,
+ MBIM_VOICE_CLASS_SEPARATED_VOICE_DATA = 2,
+ MBIM_VOICE_CLASS_SIMULTANEOUS_VOICE_DATA = 3
+} MbimVoiceClass;
+
+/**
+ * MbimSimClass:
+ * @MBIM_SIM_CLASS_LOGICAL: No physical SIM.
+ * @MBIM_SIM_CLASS_REMOVABLE: Physical removable SIM.
+ *
+ * SIM class.
+ */
+typedef enum {
+ MBIM_SIM_CLASS_LOGICAL = 1 << 0,
+ MBIM_SIM_CLASS_REMOVABLE = 1 << 1
+} MbimSimClass;
+
+/**
+ * MbimDataClass:
+ * @MBIM_DATA_CLASS_GPRS: GPRS.
+ * @MBIM_DATA_CLASS_EDGE: EDGE.
+ * @MBIM_DATA_CLASS_UMTS: UMTS.
+ * @MBIM_DATA_CLASS_HSDPA: HSDPA.
+ * @MBIM_DATA_CLASS_HSUPA: HSUPA.
+ * @MBIM_DATA_CLASS_LTE: LTE.
+ * @MBIM_DATA_CLASS_1XRTT: 1xRTT.
+ * @MBIM_DATA_CLASS_1XEVDO: 1xEV-DO.
+ * @MBIM_DATA_CLASS_1XEVDO_REVA: 1xEV-DO RevA
+ * @MBIM_DATA_CLASS_1XEVDV: 1xEV-DV.
+ * @MBIM_DATA_CLASS_3XRTT: 3xRTT.
+ * @MBIM_DATA_CLASS_1XEVDO_REVB: 1xEV-DO RevB.
+ * @MBIM_DATA_CLASS_UMB: UMB.
+ * @MBIM_DATA_CLASS_CUSTOM: Custom.
+ *
+ * Data class.
+ */
+typedef enum {
+ MBIM_DATA_CLASS_GPRS = 1 << 0,
+ MBIM_DATA_CLASS_EDGE = 1 << 1,
+ MBIM_DATA_CLASS_UMTS = 1 << 2,
+ MBIM_DATA_CLASS_HSDPA = 1 << 3,
+ MBIM_DATA_CLASS_HSUPA = 1 << 4,
+ MBIM_DATA_CLASS_LTE = 1 << 5,
+ /* Bits 6 to 15 reserved for future 3GPP classes */
+ MBIM_DATA_CLASS_1XRTT = 1 << 16,
+ MBIM_DATA_CLASS_1XEVDO = 1 << 17,
+ MBIM_DATA_CLASS_1XEVDO_REVA = 1 << 18,
+ MBIM_DATA_CLASS_1XEVDV = 1 << 19,
+ MBIM_DATA_CLASS_3XRTT = 1 << 20,
+ MBIM_DATA_CLASS_1XEVDO_REVB = 1 << 21,
+ MBIM_DATA_CLASS_UMB = 1 << 22,
+ /* Bits 23 to 30 reserved for future 3GPP2 classes */
+ MBIM_DATA_CLASS_CUSTOM = 1 << 31
+} MbimDataClass;
+
+/**
+ * MbimSmsCaps:
+ * @MBIM_SMS_CAPS_PDU_RECEIVE: Can receive in PDU mode.
+ * @MBIM_SMS_CAPS_PDU_SEND: Can send in PDU mode.
+ * @MBIM_SMS_CAPS_TEXT_RECEIVE: Can receive in text mode.
+ * @MBIM_SMS_CAPS_TEXT_SEND: Can send in text mode.
+ *
+ * SMS capabilities.
+ */
+typedef enum {
+ MBIM_SMS_CAPS_PDU_RECEIVE = 1 << 0,
+ MBIM_SMS_CAPS_PDU_SEND = 1 << 1,
+ MBIM_SMS_CAPS_TEXT_RECEIVE = 1 << 2,
+ MBIM_SMS_CAPS_TEXT_SEND = 1 << 3
+} MbimSmsCaps;
+
+/**
+ * MbimCtrlCaps:
+ * @MBIM_CTRL_CAPS_REG_MANUAL: Device allows manual network selection.
+ * @MBIM_CTRL_CAPS_HW_RADIO_SWITCH: Device has a hardware radio power switch.
+ * @MBIM_CTRL_CAPS_CDMA_MOBILE_IP: The CDMA function supports Mobile IP.
+ * @MBIM_CTRL_CAPS_CDMA_SIMPLE_IP: The CDMA function supports Simple IP.
+ * @MBIM_CTRL_CAPS_MULTI_CARRIER: Device can work with multiple providers.
+ *
+ * Control capabilities.
+ */
+typedef enum {
+ MBIM_CTRL_CAPS_REG_MANUAL = 1 << 0,
+ MBIM_CTRL_CAPS_HW_RADIO_SWITCH = 1 << 1,
+ MBIM_CTRL_CAPS_CDMA_MOBILE_IP = 1 << 2,
+ MBIM_CTRL_CAPS_CDMA_SIMPLE_IP = 1 << 3,
+ MBIM_CTRL_CAPS_MULTI_CARRIER = 1 << 4
+} MbimCtrlCaps;
+
+/*****************************************************************************/
+/* 'Subscriber Ready Status' enums */
+
+/**
+ * MbimSubscriberReadyState:
+ * @MBIM_SUBSCRIBER_READY_STATE_NOT_INITIALIZED: Not initialized.
+ * @MBIM_SUBSCRIBER_READY_STATE_INITIALIZED: Initialized.
+ * @MBIM_SUBSCRIBER_READY_STATE_SIM_NOT_INSERTED: SIM not inserted.
+ * @MBIM_SUBSCRIBER_READY_STATE_BAD_SIM: Bad SIM.
+ * @MBIM_SUBSCRIBER_READY_STATE_FAILURE: Failure.
+ * @MBIM_SUBSCRIBER_READY_STATE_NOT_ACTIVATED: Not activated.
+ * @MBIM_SUBSCRIBER_READY_STATE_DEVICE_LOCKED: Device locked.
+ *
+ * Ready state of the subscriber.
+ */
+typedef enum {
+ MBIM_SUBSCRIBER_READY_STATE_NOT_INITIALIZED = 0,
+ MBIM_SUBSCRIBER_READY_STATE_INITIALIZED = 1,
+ MBIM_SUBSCRIBER_READY_STATE_SIM_NOT_INSERTED = 2,
+ MBIM_SUBSCRIBER_READY_STATE_BAD_SIM = 3,
+ MBIM_SUBSCRIBER_READY_STATE_FAILURE = 4,
+ MBIM_SUBSCRIBER_READY_STATE_NOT_ACTIVATED = 5,
+ MBIM_SUBSCRIBER_READY_STATE_DEVICE_LOCKED = 6,
+} MbimSubscriberReadyState;
+
+/**
+ * MbimReadyInfoFlag:
+ * @MBIM_READY_INFO_FLAG_PROTECT_UNIQUE_ID: Request to avoid displaying subscriber ID.
+ */
+typedef enum {
+ MBIM_READY_INFO_FLAG_PROTECT_UNIQUE_ID = 1 << 0
+} MbimReadyInfoFlag;
+
+/*****************************************************************************/
+/* 'Radio State' enums */
+
+/**
+ * MbimRadioSwitchState:
+ * @MBIM_RADIO_SWITCH_STATE_OFF: Radio is off.
+ * @MBIM_RADIO_SWITCH_STATE_ON: Radio is on.
+ *
+ * Radio switch state.
+ */
+typedef enum {
+ MBIM_RADIO_SWITCH_STATE_OFF = 0,
+ MBIM_RADIO_SWITCH_STATE_ON = 1
+} MbimRadioSwitchState;
+
+/*****************************************************************************/
+/* 'Pin' enums */
+
+/**
+ * MbimPinType:
+ * @MBIM_PIN_TYPE_UNKNOWN: Unknown or unset.
+ * @MBIM_PIN_TYPE_CUSTOM: The PIN type is a custom type and is none of the other PIN types listed in this enumeration.
+ * @MBIM_PIN_TYPE_PIN1: The PIN1 key.
+ * @MBIM_PIN_TYPE_PIN2: The PIN2 key.
+ * @MBIM_PIN_TYPE_DEVICE_SIM_PIN: The device to SIM key.
+ * @MBIM_PIN_TYPE_DEVICE_FIRST_SIM_PIN: The device to very first SIM key.
+ * @MBIM_PIN_TYPE_NETWORK_PIN: The network personalization key.
+ * @MBIM_PIN_TYPE_NETWORK_SUBSET_PIN: The network subset personalization key.
+ * @MBIM_PIN_TYPE_SERVICE_PROVIDER_PIN: The service provider (SP) personalization key.
+ * @MBIM_PIN_TYPE_CORPORATE_PIN: The corporate personalization key.
+ * @MBIM_PIN_TYPE_SUBSIDY_PIN: The subsidy unlock key.
+ * @MBIM_PIN_TYPE_PUK1: The Personal Identification Number1 Unlock Key (PUK1).
+ * @MBIM_PIN_TYPE_PUK2: The Personal Identification Number2 Unlock Key (PUK2).
+ * @MBIM_PIN_TYPE_DEVICE_FIRST_SIM_PUK: The device to very first SIM PIN unlock key.
+ * @MBIM_PIN_TYPE_NETWORK_PUK: The network personalization unlock key.
+ * @MBIM_PIN_TYPE_NETWORK_SUBSET_PUK: The network subset personalization unlock key.
+ * @MBIM_PIN_TYPE_SERVICE_PROVIDER_PUK: The service provider (SP) personalization unlock key.
+ * @MBIM_PIN_TYPE_CORPORATE_PUK: The corporate personalization unlock key.
+ *
+ * PIN Types.
+ */
+typedef enum {
+ MBIM_PIN_TYPE_UNKNOWN = 0,
+ MBIM_PIN_TYPE_CUSTOM = 1,
+ MBIM_PIN_TYPE_PIN1 = 2,
+ MBIM_PIN_TYPE_PIN2 = 3,
+ MBIM_PIN_TYPE_DEVICE_SIM_PIN = 4,
+ MBIM_PIN_TYPE_DEVICE_FIRST_SIM_PIN = 5,
+ MBIM_PIN_TYPE_NETWORK_PIN = 6,
+ MBIM_PIN_TYPE_NETWORK_SUBSET_PIN = 7,
+ MBIM_PIN_TYPE_SERVICE_PROVIDER_PIN = 8,
+ MBIM_PIN_TYPE_CORPORATE_PIN = 9,
+ MBIM_PIN_TYPE_SUBSIDY_PIN = 10,
+ MBIM_PIN_TYPE_PUK1 = 11,
+ MBIM_PIN_TYPE_PUK2 = 12,
+ MBIM_PIN_TYPE_DEVICE_FIRST_SIM_PUK = 13,
+ MBIM_PIN_TYPE_NETWORK_PUK = 14,
+ MBIM_PIN_TYPE_NETWORK_SUBSET_PUK = 15,
+ MBIM_PIN_TYPE_SERVICE_PROVIDER_PUK = 16,
+ MBIM_PIN_TYPE_CORPORATE_PUK = 17
+} MbimPinType;
+
+/**
+ * MbimPinState:
+ * @MBIM_PIN_STATE_UNLOCKED: The device does not require a PIN.
+ * @MBIM_PIN_STATE_LOCKED: The device requires the user to enter a PIN.
+ *
+ * PIN States.
+ */
+typedef enum {
+ MBIM_PIN_STATE_UNLOCKED = 0,
+ MBIM_PIN_STATE_LOCKED = 1
+} MbimPinState;
+
+/**
+ * MbimPinOperation:
+ * @MBIM_PIN_OPERATION_ENTER: Enter the specified PIN into the device.
+ * @MBIM_PIN_OPERATION_ENABLE: Enable the specified PIN.
+ * @MBIM_PIN_OPERATION_DISABLE: Disable the specified PIN.
+ * @MBIM_PIN_OPERATION_CHANGE: Change the specified PIN.
+*/
+typedef enum {
+ MBIM_PIN_OPERATION_ENTER = 0,
+ MBIM_PIN_OPERATION_ENABLE = 1,
+ MBIM_PIN_OPERATION_DISABLE = 2,
+ MBIM_PIN_OPERATION_CHANGE = 3
+} MbimPinOperation;
+
+/*****************************************************************************/
+/* 'Pin List' enums */
+
+/**
+ * MbimPinMode:
+ * @MBIM_PIN_MODE_NOT_SUPPORTED: Not supported.
+ * @MBIM_PIN_MODE_ENABLED: Enabled.
+ * @MBIM_PIN_MODE_DISABLED: Disabled.
+ *
+ * Whether the lock is enabled or disabled.
+ */
+typedef enum {
+ MBIM_PIN_MODE_NOT_SUPPORTED = 0,
+ MBIM_PIN_MODE_ENABLED = 1,
+ MBIM_PIN_MODE_DISABLED = 2
+} MbimPinMode;
+
+/**
+ * MbimPinFormat:
+ * @MBIM_PIN_FORMAT_UNKNOWN: Unknown format.
+ * @MBIM_PIN_FORMAT_NUMERIC: Numeric-only format.
+ * @MBIM_PIN_FORMAT_ALPHANUMERIC: Alphanumeric format.
+ *
+ * Format of the expected PIN code.
+ */
+typedef enum {
+ MBIM_PIN_FORMAT_UNKNOWN = 0,
+ MBIM_PIN_FORMAT_NUMERIC = 1,
+ MBIM_PIN_FORMAT_ALPHANUMERIC = 2
+} MbimPinFormat;
+
+/*****************************************************************************/
+/* 'Home Provider' enums */
+
+/**
+ * MbimProviderState:
+ * @MBIM_PROVIDER_STATE_UNKNOWN: Unknown.
+ * @MBIM_PROVIDER_STATE_HOME: Home operator.
+ * @MBIM_PROVIDER_STATE_FORBIDDEN: Provider blocked.
+ * @MBIM_PROVIDER_STATE_PREFERRED: Provider is in the preferred list.
+ * @MBIM_PROVIDER_STATE_VISIBLE: Provider is visible.
+ * @MBIM_PROVIDER_STATE_REGISTERED: Currently registered to the provider.
+ * @MBIM_PROVIDER_STATE_PREFERRED_MULTICARRIER: Provider is a preferred multicarrier network.
+ *
+ * State of the provider.
+ */
+typedef enum {
+ MBIM_PROVIDER_STATE_UNKNOWN = 0,
+ MBIM_PROVIDER_STATE_HOME = 1 << 0,
+ MBIM_PROVIDER_STATE_FORBIDDEN = 1 << 1,
+ MBIM_PROVIDER_STATE_PREFERRED = 1 << 2,
+ MBIM_PROVIDER_STATE_VISIBLE = 1 << 3,
+ MBIM_PROVIDER_STATE_REGISTERED = 1 << 4,
+ MBIM_PROVIDER_STATE_PREFERRED_MULTICARRIER = 1 << 5
+} MbimProviderState;
+
+/*****************************************************************************/
+/* 'Visible Providers' enums */
+
+/**
+ * MbimVisibleProvidersAction:
+ * @MBIM_VISIBLE_PROVIDERS_ACTION_FULL_SCAN: Full scan.
+ * @MBIM_VISIBLE_PROVIDERS_ACTION_RESTRICTED_SCAN: Locate preferred multicarrier providers.
+ *
+ * Type of action to perform when listing visible providers.
+ */
+typedef enum {
+ MBIM_VISIBLE_PROVIDERS_ACTION_FULL_SCAN = 0,
+ MBIM_VISIBLE_PROVIDERS_ACTION_RESTRICTED_SCAN = 1
+} MbimVisibleProvidersAction;
+
+/*****************************************************************************/
+/* 'Register State' enums */
+
+/**
+ * MbimNwError:
+ * @MBIM_NW_ERROR_UNKNOWN: Unknown or unset error.
+ * @MBIM_NW_ERROR_IMSI_UNKNOWN_IN_HLR: IMSI unknown in the HLR.
+ * @MBIM_NW_ERROR_IMSI_UNKNOWN_IN_VLR: IMSI unknown in the VLR.
+ * @MBIM_NW_ERROR_ILLEGAL_ME: Illegal ME.
+ * @MBIM_NW_ERROR_GPRS_NOT_ALLOWED: GPRS not allowed.
+ * @MBIM_NW_ERROR_GPRS_AND_NON_GPRS_NOT_ALLOWED: GPRS and non-GPRS not allowed.
+ * @MBIM_NW_ERROR_PLMN_NOT_ALLOWED: PLMN not allowed.
+ * @MBIM_NW_ERROR_LOCATION_AREA_NOT_ALLOWED: Location area not allowed.
+ * @MBIM_NW_ERROR_ROAMING_NOT_ALLOWED_IN_LOCATION_AREA: Roaming not allowed in the location area.
+ * @MBIM_NW_ERROR_GPRS_NOT_ALLOWED_IN_PLMN: GPRS not allowed in PLMN.
+ * @MBIM_NW_ERROR_NO_CELLS_IN_LOCATION_AREA: No cells in location area.
+ * @MBIM_NW_ERROR_NETWORK_FAILURE: Network failure.
+ * @MBIM_NW_ERROR_CONGESTION: Congestion.
+ *
+ * Network errors.
+ */
+typedef enum {
+ MBIM_NW_ERROR_UNKNOWN = 0,
+ MBIM_NW_ERROR_IMSI_UNKNOWN_IN_HLR = 2,
+ MBIM_NW_ERROR_IMSI_UNKNOWN_IN_VLR = 4,
+ MBIM_NW_ERROR_ILLEGAL_ME = 6,
+ MBIM_NW_ERROR_GPRS_NOT_ALLOWED = 7,
+ MBIM_NW_ERROR_GPRS_AND_NON_GPRS_NOT_ALLOWED = 8,
+ MBIM_NW_ERROR_PLMN_NOT_ALLOWED = 11,
+ MBIM_NW_ERROR_LOCATION_AREA_NOT_ALLOWED = 12,
+ MBIM_NW_ERROR_ROAMING_NOT_ALLOWED_IN_LOCATION_AREA = 13,
+ MBIM_NW_ERROR_GPRS_NOT_ALLOWED_IN_PLMN = 14,
+ MBIM_NW_ERROR_NO_CELLS_IN_LOCATION_AREA = 15,
+ MBIM_NW_ERROR_NETWORK_FAILURE = 17,
+ MBIM_NW_ERROR_CONGESTION = 22
+} MbimNwError;
+
+/**
+ * MbimRegisterAction:
+ * @MBIM_REGISTER_ACTION_AUTOMATIC: Automatic registration.
+ * @MBIM_REGISTER_ACTION_MANUAL: Manual registration.
+ *
+ * Type of registration requested.
+ */
+typedef enum {
+ MBIM_REGISTER_ACTION_AUTOMATIC = 0,
+ MBIM_REGISTER_ACTION_MANUAL = 1
+} MbimRegisterAction;
+
+/**
+ * MbimRegisterState:
+ * @MBIM_REGISTER_STATE_UNKNOWN: Unknown registration state.
+ * @MBIM_REGISTER_STATE_DEREGISTERED: Not registered.
+ * @MBIM_REGISTER_STATE_SEARCHING: Searching.
+ * @MBIM_REGISTER_STATE_HOME: Registered in home network.
+ * @MBIM_REGISTER_STATE_ROAMING: Registered in roaming network.
+ * @MBIM_REGISTER_STATE_PARTNER: Registered in a preferred roaming network.
+ * @MBIM_REGISTER_STATE_DENIED: Registration denied.
+ *
+ * Registration state.
+ */
+typedef enum {
+ MBIM_REGISTER_STATE_UNKNOWN = 0,
+ MBIM_REGISTER_STATE_DEREGISTERED = 1,
+ MBIM_REGISTER_STATE_SEARCHING = 2,
+ MBIM_REGISTER_STATE_HOME = 3,
+ MBIM_REGISTER_STATE_ROAMING = 4,
+ MBIM_REGISTER_STATE_PARTNER = 5,
+ MBIM_REGISTER_STATE_DENIED = 6
+} MbimRegisterState;
+
+/**
+ * MbimRegisterMode:
+ * @MBIM_REGISTER_MODE_UNKNOWN: Unknown.
+ * @MBIM_REGISTER_MODE_AUTOMATIC: Automatic registration.
+ * @MBIM_REGISTER_MODE_MANUAL: Manual registration.
+ *
+ * Type of registration requested.
+ */
+typedef enum {
+ MBIM_REGISTER_MODE_UNKNOWN = 0,
+ MBIM_REGISTER_MODE_AUTOMATIC = 1,
+ MBIM_REGISTER_MODE_MANUAL = 2
+} MbimRegisterMode;
+
+/**
+ * MbimRegistrationFlag:
+ * @MBIM_REGISTRATION_FLAG_NONE: None.
+ * @MBIM_REGISTRATION_FLAG_MANUAL_SELECTION_NOT_AVAILABLE: Network doesn't support manual network selection.
+ * @MBIM_REGISTRATION_FLAG_MANUAL_PACKET_SERVICE_AUTOMATIC_ATTACH: Modem should auto-attach to the network after registration.
+ *
+ * Registration flags.
+ */
+typedef enum {
+ MBIM_REGISTRATION_FLAG_NONE = 0,
+ MBIM_REGISTRATION_FLAG_MANUAL_SELECTION_NOT_AVAILABLE = 1 << 0,
+ MBIM_REGISTRATION_FLAG_MANUAL_PACKET_SERVICE_AUTOMATIC_ATTACH = 1 << 2,
+} MbimRegistrationFlag;
+
+/*****************************************************************************/
+/* 'Packet Service' enums */
+
+/**
+ * MbimPacketServiceAction:
+ * @MBIM_PACKET_SERVICE_ACTION_ATTACH: Attach.
+ * @MBIM_PACKET_SERVICE_ACTION_DETACH: Detach.
+ *
+ * Packet Service Action.
+ */
+typedef enum {
+ MBIM_PACKET_SERVICE_ACTION_ATTACH = 0,
+ MBIM_PACKET_SERVICE_ACTION_DETACH = 1
+} MbimPacketServiceAction;
+
+/**
+ * MbimPacketServiceState:
+ * @MBIM_PACKET_SERVICE_STATE_UNKNOWN: Unknown.
+ * @MBIM_PACKET_SERVICE_STATE_ATTACHING: Attaching.
+ * @MBIM_PACKET_SERVICE_STATE_ATTACHED: Attached.
+ * @MBIM_PACKET_SERVICE_STATE_DETACHING: Detaching.
+ * @MBIM_PACKET_SERVICE_STATE_DETACHED: Detached.
+ *
+ * Packet Service State.
+ */
+typedef enum {
+ MBIM_PACKET_SERVICE_STATE_UNKNOWN = 0,
+ MBIM_PACKET_SERVICE_STATE_ATTACHING = 1,
+ MBIM_PACKET_SERVICE_STATE_ATTACHED = 2,
+ MBIM_PACKET_SERVICE_STATE_DETACHING = 3,
+ MBIM_PACKET_SERVICE_STATE_DETACHED = 4
+} MbimPacketServiceState;
+
+/*****************************************************************************/
+/* 'Connect' enums */
+
+/**
+ * MbimActivationCommand:
+ * @MBIM_ACTIVATION_COMMAND_DEACTIVATE: Deactivate.
+ * @MBIM_ACTIVATION_COMMAND_ACTIVATE: Activate.
+ *
+ * Activation Command.
+ */
+typedef enum {
+ MBIM_ACTIVATION_COMMAND_DEACTIVATE = 0,
+ MBIM_ACTIVATION_COMMAND_ACTIVATE = 1
+} MbimActivationCommand;
+
+/**
+ * MbimCompression:
+ * @MBIM_COMPRESSION_NONE: None.
+ * @MBIM_COMPRESSION_ENABLE: Enable.
+ *
+ * Compression.
+ */
+typedef enum {
+ MBIM_COMPRESSION_NONE = 0,
+ MBIM_COMPRESSION_ENABLE = 1
+} MbimCompression;
+
+/**
+ * MbimAuthProtocol:
+ * @MBIM_AUTH_PROTOCOL_NONE: None.
+ * @MBIM_AUTH_PROTOCOL_PAP: Pap.
+ * @MBIM_AUTH_PROTOCOL_CHAP: Chap.
+ * @MBIM_AUTH_PROTOCOL_MSCHAPV2: V2.
+ *
+ * Auth Protocol.
+ */
+typedef enum {
+ MBIM_AUTH_PROTOCOL_NONE = 0,
+ MBIM_AUTH_PROTOCOL_PAP = 1,
+ MBIM_AUTH_PROTOCOL_CHAP = 2,
+ MBIM_AUTH_PROTOCOL_MSCHAPV2 = 3
+} MbimAuthProtocol;
+
+/**
+ * MbimContextIpType:
+ * @MBIM_CONTEXT_IP_TYPE_DEFAULT: It is up to the function to decide, the host does not care.
+ * @MBIM_CONTEXT_IP_TYPE_IPV4: IPv4 context.
+ * @MBIM_CONTEXT_IP_TYPE_IPV6: IPv6 context.
+ * @MBIM_CONTEXT_IP_TYPE_IPV4V6: The context is IPv4, IPv6 or dualstack IPv4v6.
+ * @MBIM_CONTEXT_IP_TYPE_IPV4_AND_IPV6: Both an IPv4 and an IPv6 context.
+ *
+ * Context IP Type.
+ */
+typedef enum {
+ MBIM_CONTEXT_IP_TYPE_DEFAULT = 0,
+ MBIM_CONTEXT_IP_TYPE_IPV4 = 1,
+ MBIM_CONTEXT_IP_TYPE_IPV6 = 2,
+ MBIM_CONTEXT_IP_TYPE_IPV4V6 = 3,
+ MBIM_CONTEXT_IP_TYPE_IPV4_AND_IPV6 = 4
+} MbimContextIpType;
+
+/**
+ * MbimActivationState:
+ * @MBIM_ACTIVATION_STATE_UNKNOWN: Unknown.
+ * @MBIM_ACTIVATION_STATE_ACTIVATED: Activated.
+ * @MBIM_ACTIVATION_STATE_ACTIVATING: Activating.
+ * @MBIM_ACTIVATION_STATE_DEACTIVATED: Deactivated.
+ * @MBIM_ACTIVATION_STATE_DEACTIVATING: Deactivating.
+ *
+ * Activation State.
+ */
+typedef enum {
+ MBIM_ACTIVATION_STATE_UNKNOWN = 0,
+ MBIM_ACTIVATION_STATE_ACTIVATED = 1,
+ MBIM_ACTIVATION_STATE_ACTIVATING = 2,
+ MBIM_ACTIVATION_STATE_DEACTIVATED = 3,
+ MBIM_ACTIVATION_STATE_DEACTIVATING = 4
+} MbimActivationState;
+
+/**
+ * MbimVoiceCallState:
+ * @MBIM_VOICE_CALL_STATE_NONE: None.
+ * @MBIM_VOICE_CALL_STATE_IN_PROGRESS: Progress.
+ * @MBIM_VOICE_CALL_STATE_HANG_UP: Up.
+ *
+ * Voice Call State.
+ */
+typedef enum {
+ MBIM_VOICE_CALL_STATE_NONE = 0,
+ MBIM_VOICE_CALL_STATE_IN_PROGRESS = 1,
+ MBIM_VOICE_CALL_STATE_HANG_UP = 2
+} MbimVoiceCallState;
+
+/*****************************************************************************/
+/* 'IP Configuration' enums */
+
+/**
+ * MbimIPConfigurationAvailableFlag:
+ * @MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_NONE: No info available.
+ * @MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_ADDRESS: Address info available.
+ * @MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_GATEWAY: Gateway info available.
+ * @MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_DNS: DNS info available.
+ * @MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_MTU: MTU info available.
+ *
+ * Mask of available information about an IP address.
+ */
+typedef enum { /*< underscore_name=mbim_ip_configuration_available_flag >*/
+ MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_NONE = 0,
+ MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_ADDRESS = 1 << 0,
+ MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_GATEWAY = 1 << 1,
+ MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_DNS = 1 << 2,
+ MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_MTU = 1 << 3,
+} MbimIPConfigurationAvailableFlag;
+
+/*****************************************************************************/
+/* 'SMS Configuration' enums */
+
+/**
+ * MbimSmsStorageState:
+ * @MBIM_SMS_STORAGE_STATE_NOT_INITIALIZED: Storage not initialized.
+ * @MBIM_SMS_STORAGE_STATE_INITIALIZED: Storage initialized.
+ *
+ * State of the SMS storage.
+ */
+typedef enum {
+ MBIM_SMS_STORAGE_STATE_NOT_INITIALIZED = 0,
+ MBIM_SMS_STORAGE_STATE_INITIALIZED = 1
+} MbimSmsStorageState;
+
+/**
+ * MbimSmsFormat:
+ * @MBIM_SMS_FORMAT_PDU: PDU format.
+ * @MBIM_SMS_FORMAT_CDMA: CDMA format.
+ *
+ * SMS format.
+ */
+typedef enum {
+ MBIM_SMS_FORMAT_PDU = 0,
+ MBIM_SMS_FORMAT_CDMA = 1
+} MbimSmsFormat;
+
+/*****************************************************************************/
+/* 'SMS Read' enums */
+
+/**
+ * MbimSmsFlag:
+ * @MBIM_SMS_FLAG_ALL: All.
+ * @MBIM_SMS_FLAG_INDEX: Index.
+ * @MBIM_SMS_FLAG_NEW: New.
+ * @MBIM_SMS_FLAG_OLD: Old.
+ * @MBIM_SMS_FLAG_SENT: Sent.
+ * @MBIM_SMS_FLAG_DRAFT: Draft.
+ *
+ * Flags to use when requesting to read SMS. @MBIM_SMS_FLAG_ALL and
+ * @MBIM_SMS_FLAG_NEW are mandatory, all the others are optional.
+*/
+typedef enum {
+ MBIM_SMS_FLAG_ALL = 0,
+ MBIM_SMS_FLAG_INDEX = 1,
+ MBIM_SMS_FLAG_NEW = 2,
+ MBIM_SMS_FLAG_OLD = 3,
+ MBIM_SMS_FLAG_SENT = 4,
+ MBIM_SMS_FLAG_DRAFT = 5
+} MbimSmsFlag;
+
+/**
+ * MbimSmsCdmaLang:
+ * @MBIM_SMS_CDMA_LANG_UNKNOWN: Unknown language.
+ * @MBIM_SMS_CDMA_LANG_ENGLISH: English.
+ * @MBIM_SMS_CDMA_LANG_FRENCH: French.
+ * @MBIM_SMS_CDMA_LANG_SPANISH: Spanish.
+ * @MBIM_SMS_CDMA_LANG_JAPANESE: Japanese.
+ * @MBIM_SMS_CDMA_LANG_KOREAN: Korean.
+ * @MBIM_SMS_CDMA_LANG_CHINESE: Chinese.
+ * @MBIM_SMS_CDMA_LANG_HEBREW: Hebrew.
+ *
+ * Language of a CDMA SMS.
+ */
+typedef enum {
+ MBIM_SMS_CDMA_LANG_UNKNOWN = 0,
+ MBIM_SMS_CDMA_LANG_ENGLISH = 1,
+ MBIM_SMS_CDMA_LANG_FRENCH = 2,
+ MBIM_SMS_CDMA_LANG_SPANISH = 3,
+ MBIM_SMS_CDMA_LANG_JAPANESE = 4,
+ MBIM_SMS_CDMA_LANG_KOREAN = 5,
+ MBIM_SMS_CDMA_LANG_CHINESE = 6,
+ MBIM_SMS_CDMA_LANG_HEBREW = 7
+} MbimSmsCdmaLang;
+
+/**
+ * MbimSmsCdmaEncoding:
+ * @MBIM_SMS_CDMA_ENCODING_OCTET: Octet.
+ * @MBIM_SMS_CDMA_ENCODING_EPM: EPM.
+ * @MBIM_SMS_CDMA_ENCODING_7BIT_ASCII: 7-bit ASCII.
+ * @MBIM_SMS_CDMA_ENCODING_LA5: LA5.
+ * @MBIM_SMS_CDMA_ENCODING_UNICODE: Unicode.
+ * @MBIM_SMS_CDMA_ENCODING_SHIFT_JIS: Shift JIS.
+ * @MBIM_SMS_CDMA_ENCODING_KOREAN: Korean.
+ * @MBIM_SMS_CDMA_ENCODING_LATIN_HEBREW: Latin hebrew.
+ * @MBIM_SMS_CDMA_ENCODING_LATIN: Latin.
+ * @MBIM_SMS_CDMA_ENCODING_GSM_7BIT: 7-bit GSM.
+ *
+ * Type of encoding of a CDMA SMS.
+ */
+typedef enum {
+ MBIM_SMS_CDMA_ENCODING_OCTET = 0,
+ MBIM_SMS_CDMA_ENCODING_EPM = 1,
+ MBIM_SMS_CDMA_ENCODING_7BIT_ASCII = 2,
+ MBIM_SMS_CDMA_ENCODING_LA5 = 3,
+ MBIM_SMS_CDMA_ENCODING_UNICODE = 4,
+ MBIM_SMS_CDMA_ENCODING_SHIFT_JIS = 5,
+ MBIM_SMS_CDMA_ENCODING_KOREAN = 6,
+ MBIM_SMS_CDMA_ENCODING_LATIN_HEBREW = 7,
+ MBIM_SMS_CDMA_ENCODING_LATIN = 8,
+ MBIM_SMS_CDMA_ENCODING_GSM_7BIT = 9
+} MbimSmsCdmaEncoding;
+
+/**
+ * MbimSmsStatus:
+ * @MBIM_SMS_STATUS_NEW: New.
+ * @MBIM_SMS_STATUS_OLD: Old.
+ * @MBIM_SMS_STATUS_DRAFT: Draft.
+ * @MBIM_SMS_STATUS_SENT: Sent.
+ *
+ * Status of a SMS message.
+ */
+typedef enum {
+ MBIM_SMS_STATUS_NEW = 0,
+ MBIM_SMS_STATUS_OLD = 1,
+ MBIM_SMS_STATUS_DRAFT = 2,
+ MBIM_SMS_STATUS_SENT = 3
+} MbimSmsStatus;
+
+/*****************************************************************************/
+/* 'SMS Message Store Status' enums */
+
+/**
+ * MbimSmsStatusFlag:
+ * @MBIM_SMS_STATUS_FLAG_NONE: None.
+ * @MBIM_SMS_STATUS_FLAG_MESSAGE_STORE_FULL: Message store is full.
+ * @MBIM_SMS_STATUS_FLAG_NEW_MESSAGE: New non-Class 0 message arrived.
+ *
+ * SMS status flags.
+ */
+typedef enum {
+ MBIM_SMS_STATUS_FLAG_NONE = 0,
+ MBIM_SMS_STATUS_FLAG_MESSAGE_STORE_FULL = 1,
+ MBIM_SMS_STATUS_FLAG_NEW_MESSAGE = 2
+} MbimSmsStatusFlag;
+
+/*****************************************************************************/
+/* 'USSD' enums */
+
+/**
+ * MbimUssdAction:
+ * @MBIM_USSD_ACTION_INITIATE: Initiate USSD session.
+ * @MBIM_USSD_ACTION_CONTINUE: Continue USSD session.
+ * @MBIM_USSD_ACTION_CANCEL: Cancel USSD session.
+ *
+ * USSD action.
+ */
+typedef enum {
+ MBIM_USSD_ACTION_INITIATE = 0,
+ MBIM_USSD_ACTION_CONTINUE = 1,
+ MBIM_USSD_ACTION_CANCEL = 2
+} MbimUssdAction;
+
+/**
+ * MbimUssdResponse:
+ * @MBIM_USSD_RESPONSE_NO_ACTION_REQUIRED: No action required.
+ * @MBIM_USSD_RESPONSE_ACTION_REQUIRED: An action is required.
+ * @MBIM_USSD_RESPONSE_TERMINATED_BY_NETWORK: Terminated by network
+ * @MBIM_USSD_RESPONSE_OTHER_LOCAL_CLIENT: Other local client.
+ * @MBIM_USSD_RESPONSE_OPERATION_NOT_SUPPORTED: Operation not supported.
+ * @MBIM_USSD_RESPONSE_NETWORK_TIMEOUT: Network timeout.
+ *
+ * USSD response.
+ */
+typedef enum {
+ MBIM_USSD_RESPONSE_NO_ACTION_REQUIRED = 0,
+ MBIM_USSD_RESPONSE_ACTION_REQUIRED = 1,
+ MBIM_USSD_RESPONSE_TERMINATED_BY_NETWORK = 2,
+ MBIM_USSD_RESPONSE_OTHER_LOCAL_CLIENT = 3,
+ MBIM_USSD_RESPONSE_OPERATION_NOT_SUPPORTED = 4,
+ MBIM_USSD_RESPONSE_NETWORK_TIMEOUT = 5
+} MbimUssdResponse;
+
+/**
+ * MbimUssdSessionState:
+ * @MBIM_USSD_SESSION_STATE_NEW_SESSION: New session.
+ * @MBIM_USSD_SESSION_STATE_EXISTING_SESSION: Existing session.
+ *
+ * Session state.
+ */
+typedef enum {
+ MBIM_USSD_SESSION_STATE_NEW_SESSION = 0,
+ MBIM_USSD_SESSION_STATE_EXISTING_SESSION = 1
+} MbimUssdSessionState;
+
+/*****************************************************************************/
+/* 'Phonebook configuration' enums */
+
+/**
+ * MbimPhonebookState:
+ * @MBIM_PHONEBOOK_STATE_NOT_INITIALIZED: Not initialized.
+ * @MBIM_PHONEBOOK_STATE_INITIALIZED: Initialized
+ *
+ * Phonebook state.
+ */
+typedef enum {
+ MBIM_PHONEBOOK_STATE_NOT_INITIALIZED = 0,
+ MBIM_PHONEBOOK_STATE_INITIALIZED = 1
+} MbimPhonebookState;
+
+/*****************************************************************************/
+/* 'Phonebook read' enums */
+
+/**
+ * MbimPhonebookFlag:
+ * @MBIM_PHONEBOOK_FLAG_ALL: Request all.
+ * @MBIM_PHONEBOOK_FLAG_INDEX: Request single entry by index.
+ *
+ * Flags to use when reading the phonebook.
+ */
+typedef enum {
+ MBIM_PHONEBOOK_FLAG_ALL = 0,
+ MBIM_PHONEBOOK_FLAG_INDEX = 1
+} MbimPhonebookFlag;
+
+/**
+ * MbimPhonebookWriteFlag:
+ * @MBIM_PHONEBOOK_WRITE_FLAG_SAVE_UNUSED: Store the record in an unused slot.
+ * @MBIM_PHONEBOOK_WRITE_FLAG_SAVE_INDEX: Index where to store the record.
+ *
+ * Flags to use when writing the phonebook.
+ */
+typedef enum {
+ MBIM_PHONEBOOK_WRITE_FLAG_SAVE_UNUSED = 0,
+ MBIM_PHONEBOOK_WRITE_FLAG_SAVE_INDEX = 1,
+} MbimPhonebookWriteFlag;
+
+/*****************************************************************************/
+/* 'STK PAC' enums */
+
+/**
+ * MbimStkPacProfile:
+ * @MBIM_STK_PAC_PROFILE_NOT_HANDLED_BY_FUNCTION_HANDLED_BY_HOST: Command not handled by function but handled by host.
+ * @MBIM_STK_PAC_PROFILE_NOT_HANDLED_BY_FUNCTION_MAY_BE_HANDLED_BY_HOST: Command not handled by function but may be handled by host.
+ * @MBIM_STK_PAC_PROFILE_HANDLED_BY_FUNCTION_ONLY_TRANSPARENT_TO_HOST: Command handled by function without informing the host.
+ * @MBIM_STK_PAC_PROFILE_HANDLED_BY_FUNCTION_NOTIFICATION_TO_HOST_POSSIBLE: Command handled by function without informing the host, but notifications may be sent to host.
+ * @MBIM_STK_PAC_PROFILE_HANDLED_BY_FUNCTION_NOTIFICATIONS_TO_HOST_ENABLED: Command handled by function, and the function wil also send notification to the host.
+ * @MBIM_STK_PAC_PROFILE_HANDLED_BY_FUNCTION_CAN_BE_OVERRIDEN_BY_HOST: Command handled by function, but the host may request full control of the command.
+ * @MBIM_STK_PAC_PROFILE_HANDLED_BY_HOST_FUNCTION_NOT_ABLE_TO_HANDLE: Command will be forwarded to the host. If the host decides not to receive the command, the function will not handle it.
+ * @MBIM_STK_PAC_PROFILE_HANDLED_BY_HOST_FUNCTION_ABLE_TO_HANDLE: Command will be forwarded to the host. If the host decides not to receive the command, the function will handle it.
+ *
+ * Proactive command profile.
+ */
+typedef enum {
+ MBIM_STK_PAC_PROFILE_NOT_HANDLED_BY_FUNCTION_HANDLED_BY_HOST = 0,
+ MBIM_STK_PAC_PROFILE_NOT_HANDLED_BY_FUNCTION_MAY_BE_HANDLED_BY_HOST = 1,
+ MBIM_STK_PAC_PROFILE_HANDLED_BY_FUNCTION_ONLY_TRANSPARENT_TO_HOST = 2,
+ MBIM_STK_PAC_PROFILE_HANDLED_BY_FUNCTION_NOTIFICATION_TO_HOST_POSSIBLE = 3,
+ MBIM_STK_PAC_PROFILE_HANDLED_BY_FUNCTION_NOTIFICATIONS_TO_HOST_ENABLED = 4,
+ MBIM_STK_PAC_PROFILE_HANDLED_BY_FUNCTION_CAN_BE_OVERRIDEN_BY_HOST = 5,
+ MBIM_STK_PAC_PROFILE_HANDLED_BY_HOST_FUNCTION_NOT_ABLE_TO_HANDLE = 6,
+ MBIM_STK_PAC_PROFILE_HANDLED_BY_HOST_FUNCTION_ABLE_TO_HANDLE = 7
+} MbimStkPacProfile;
+
+/**
+ * MbimStkPacType:
+ * @MBIM_STK_PAC_TYPE_PROACTIVE_COMMAND: Host is requested to handle the Proactive command.
+ * @MBIM_STK_PAC_TYPE_NOTIFICATION: Proactive command is handled by the function, but the host is notified.
+ *
+ * Type of proactive command.
+ */
+typedef enum {
+ MBIM_STK_PAC_TYPE_PROACTIVE_COMMAND = 0,
+ MBIM_STK_PAC_TYPE_NOTIFICATION = 1
+} MbimStkPacType;
+
+/*****************************************************************************/
+/* 'Network idle hint' enums */
+
+/**
+ * MbimNetworkIdleHintState:
+ * @MBIM_NETWORK_IDLE_HINT_STATE_DISABLED: Disabled.
+ * @MBIM_NETWORK_IDLE_HINT_STATE_ENABLED: Enabled.
+ *
+ * Enable or disable network idle hint.
+ */
+typedef enum {
+ MBIM_NETWORK_IDLE_HINT_STATE_DISABLED = 0,
+ MBIM_NETWORK_IDLE_HINT_STATE_ENABLED = 1
+} MbimNetworkIdleHintState;
+
+/*****************************************************************************/
+/* 'Emergency mode' enums */
+
+/**
+ * MbimEmergencyModeState:
+ * @MBIM_EMERGENCY_MODE_STATE_OFF: Off.
+ * @MBIM_EMERGENCY_MODE_STATE_ON: On.
+ *
+ * Emergency mode state.
+ */
+typedef enum {
+ MBIM_EMERGENCY_MODE_STATE_OFF = 0,
+ MBIM_EMERGENCY_MODE_STATE_ON = 1
+} MbimEmergencyModeState;
+
+/*****************************************************************************/
+/* 'DSS connect' enums */
+
+/**
+ * MbimDssLinkState:
+ * @MBIM_DSS_LINK_STATE_DEACTIVATE: Deactivate.
+ * @MBIM_DSS_LINK_STATE_ACTIVATE: Activate.
+ *
+ * Action performed in the link state.
+ */
+typedef enum {
+ MBIM_DSS_LINK_STATE_DEACTIVATE = 0,
+ MBIM_DSS_LINK_STATE_ACTIVATE = 1
+} MbimDssLinkState;
+
+G_END_DECLS
+
+#endif /* _LIBMBIM_GLIB_MBIM_ENUMS_H_ */
diff --git a/libmbim-glib/mbim-errors.h b/libmbim-glib/mbim-errors.h
new file mode 100644
index 0000000..644a534
--- /dev/null
+++ b/libmbim-glib/mbim-errors.h
@@ -0,0 +1,185 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * libmbim-glib -- GLib/GIO based library to control MBIM devices
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2012 Aleksander Morgado <aleksander@lanedo.com>
+ */
+
+#ifndef _LIBMBIM_GLIB_MBIM_ERRORS_H_
+#define _LIBMBIM_GLIB_MBIM_ERRORS_H_
+
+#if !defined (__LIBMBIM_GLIB_H_INSIDE__) && !defined (LIBMBIM_GLIB_COMPILATION)
+#error "Only <libmbim-glib.h> can be included directly."
+#endif
+
+/**
+ * SECTION: mbim-errors
+ * @title: Errors
+ *
+ * This section defines common error types used in the interface.
+ */
+
+/* Prefixes for errors registered in DBus */
+#define MBIM_DBUS_ERROR_PREFIX "org.freedesktop.libmbim.Error"
+#define MBIM_CORE_ERROR_DBUS_PREFIX MBIM_DBUS_ERROR_PREFIX ".Core"
+#define MBIM_PROTOCOL_ERROR_DBUS_PREFIX MBIM_DBUS_ERROR_PREFIX ".Protocol"
+#define MBIM_STATUS_ERROR_DBUS_PREFIX MBIM_DBUS_ERROR_PREFIX ".Status"
+
+/**
+ * MbimCoreError:
+ * @MBIM_CORE_ERROR_FAILED: Operation failed.
+ * @MBIM_CORE_ERROR_WRONG_STATE: Operation cannot be executed in the current state.
+ * @MBIM_CORE_ERROR_TIMEOUT: Operation timed out.
+ * @MBIM_CORE_ERROR_INVALID_ARGS: Invalid arguments given.
+ * @MBIM_CORE_ERROR_INVALID_MESSAGE: MBIM message is invalid.
+ * @MBIM_CORE_ERROR_UNSUPPORTED: Not supported.
+ * @MBIM_CORE_ERROR_ABORTED: Operation aborted..
+ *
+ * Common errors that may be reported by libmbim-glib.
+ */
+typedef enum { /*< underscore_name=mbim_core_error >*/
+ MBIM_CORE_ERROR_FAILED = 0, /*< nick=Failed >*/
+ MBIM_CORE_ERROR_WRONG_STATE = 1, /*< nick=WrongState >*/
+ MBIM_CORE_ERROR_TIMEOUT = 2, /*< nick=Timeout >*/
+ MBIM_CORE_ERROR_INVALID_ARGS = 3, /*< nick=InvalidArgs >*/
+ MBIM_CORE_ERROR_INVALID_MESSAGE = 4, /*< nick=InvalidMessage >*/
+ MBIM_CORE_ERROR_UNSUPPORTED = 5, /*< nick=Unsupported >*/
+ MBIM_CORE_ERROR_ABORTED = 6 /*< nick=Aborted >*/
+} MbimCoreError;
+
+/**
+ * MbimProtocolError:
+ * @MBIM_PROTOCOL_ERROR_INVALID: Invalid MBIM error.
+ * @MBIM_PROTOCOL_ERROR_TIMEOUT_FRAGMENT: Timeout waiting for fragment.
+ * @MBIM_PROTOCOL_ERROR_FRAGMENT_OUT_OF_SEQUENCE: Fragment received out of sequence.
+ * @MBIM_PROTOCOL_ERROR_LENGTH_MISMATCH: Length mismatch.
+ * @MBIM_PROTOCOL_ERROR_DUPLICATED_TID: Duplicated transaction ID.
+ * @MBIM_PROTOCOL_ERROR_NOT_OPENED: Not opened.
+ * @MBIM_PROTOCOL_ERROR_UNKNOWN: Unknown error.
+ * @MBIM_PROTOCOL_ERROR_CANCEL: Cancel the operation.
+ * @MBIM_PROTOCOL_ERROR_MAX_TRANSFER: Maximum control transfer not supported.
+ *
+ * MBIM protocol errors.
+ */
+typedef enum {
+ MBIM_PROTOCOL_ERROR_INVALID = 0, /*< nick=Invalid >*/
+ MBIM_PROTOCOL_ERROR_TIMEOUT_FRAGMENT = 1, /*< nick=TimeoutFragment >*/
+ MBIM_PROTOCOL_ERROR_FRAGMENT_OUT_OF_SEQUENCE = 2, /*< nick=FragmentOutOfSequence >*/
+ MBIM_PROTOCOL_ERROR_LENGTH_MISMATCH = 3, /*< nick=LengthMismatch >*/
+ MBIM_PROTOCOL_ERROR_DUPLICATED_TID = 4, /*< nick=DuplicatedTid >*/
+ MBIM_PROTOCOL_ERROR_NOT_OPENED = 5, /*< nick=NotOpened >*/
+ MBIM_PROTOCOL_ERROR_UNKNOWN = 6, /*< nick=Unknown >*/
+ MBIM_PROTOCOL_ERROR_CANCEL = 7, /*< nick=Cancel >*/
+ MBIM_PROTOCOL_ERROR_MAX_TRANSFER = 8 /*< nick=MaxTransfer >*/
+} MbimProtocolError;
+
+
+/**
+ * MbimStatusError:
+ * @MBIM_STATUS_ERROR_NONE: Success, no error.
+ * @MBIM_STATUS_ERROR_BUSY: Busy.
+ * @MBIM_STATUS_ERROR_FAILURE: Failure.
+ * @MBIM_STATUS_ERROR_SIM_NOT_INSERTED: SIM not inserted.
+ * @MBIM_STATUS_ERROR_BAD_SIM: Bad SIM.
+ * @MBIM_STATUS_ERROR_PIN_REQUIRED: PIN required.
+ * @MBIM_STATUS_ERROR_PIN_DISABLED: PIN disabled.
+ * @MBIM_STATUS_ERROR_NOT_REGISTERED: Not registered.
+ * @MBIM_STATUS_ERROR_PROVIDERS_NOT_FOUND: Providers not found.
+ * @MBIM_STATUS_ERROR_NO_DEVICE_SUPPORT: No device support.
+ * @MBIM_STATUS_ERROR_PROVIDER_NOT_VISIBLE: Provider not visible.
+ * @MBIM_STATUS_ERROR_DATA_CLASS_NOT_AVAILABLE: Data class not available.
+ * @MBIM_STATUS_ERROR_PACKET_SERVICE_DETACHED: Packet service detached.
+ * @MBIM_STATUS_ERROR_MAX_ACTIVATED_CONTEXTS: Max activated contexts.
+ * @MBIM_STATUS_ERROR_NOT_INITIALIZED: Not initialized.
+ * @MBIM_STATUS_ERROR_VOICE_CALL_IN_PROGRESS: Voice call in progress.
+ * @MBIM_STATUS_ERROR_CONTEXT_NOT_ACTIVATED: Context not activated.
+ * @MBIM_STATUS_ERROR_SERVICE_NOT_ACTIVATED: Service not activated.
+ * @MBIM_STATUS_ERROR_INVALID_ACCESS_STRING: Invalid access string.
+ * @MBIM_STATUS_ERROR_INVALID_USER_NAME_PWD: Invalid user name or password.
+ * @MBIM_STATUS_ERROR_RADIO_POWER_OFF: Radio power off.
+ * @MBIM_STATUS_ERROR_INVALID_PARAMETERS: Invalid parameters.
+ * @MBIM_STATUS_ERROR_READ_FAILURE: Read failure.
+ * @MBIM_STATUS_ERROR_WRITE_FAILURE: Write failure.
+ * @MBIM_STATUS_ERROR_NO_PHONEBOOK: No phonebook.
+ * @MBIM_STATUS_ERROR_PARAMETER_TOO_LONG: Parameter too long.
+ * @MBIM_STATUS_ERROR_STK_BUSY: SIM toolkit busy.
+ * @MBIM_STATUS_ERROR_OPERATION_NOT_ALLOWED: Operation not allowed.
+ * @MBIM_STATUS_ERROR_MEMORY_FAILURE: Memory failure.
+ * @MBIM_STATUS_ERROR_INVALID_MEMORY_INDEX: Invalid memory index.
+ * @MBIM_STATUS_ERROR_MEMORY_FULL: Memory full.
+ * @MBIM_STATUS_ERROR_FILTER_NOT_SUPPORTED: Filter not supported.
+ * @MBIM_STATUS_ERROR_DSS_INSTANCE_LIMIT: DSS instance limit.
+ * @MBIM_STATUS_ERROR_INVALID_DEVICE_SERVICE_OPERATION: Invalid device service operation.
+ * @MBIM_STATUS_ERROR_AUTH_INCORRECT_AUTN: Incorrect AUTN when sending authentication.
+ * @MBIM_STATUS_ERROR_AUTH_SYNC_FAILURE: Synchronization failure during the authentication.
+ * @MBIM_STATUS_ERROR_AUTH_AMF_NOT_SET: AMF bit not set in the authentication.
+ * @MBIM_STATUS_ERROR_SMS_UNKNOWN_SMSC_ADDRESS: Unknown SMSC address.
+ * @MBIM_STATUS_ERROR_SMS_NETWORK_TIMEOUT: Network timeout when sending SMS.
+ * @MBIM_STATUS_ERROR_SMS_LANG_NOT_SUPPORTED: Language not supported in SMS.
+ * @MBIM_STATUS_ERROR_SMS_ENCODING_NOT_SUPPORTED: Encoding not supported in SMS.
+ * @MBIM_STATUS_ERROR_SMS_FORMAT_NOT_SUPPORTED: Format not supported in SMS.
+ *
+ * Status of the MBIM request.
+ */
+typedef enum {
+ MBIM_STATUS_ERROR_NONE = 0, /*< nick=None >*/
+ MBIM_STATUS_ERROR_BUSY = 1, /*< nick=Busy >*/
+ MBIM_STATUS_ERROR_FAILURE = 2, /*< nick=Failure >*/
+ MBIM_STATUS_ERROR_SIM_NOT_INSERTED = 3, /*< nick=SimNotInserted >*/
+ MBIM_STATUS_ERROR_BAD_SIM = 4, /*< nick=BadSim >*/
+ MBIM_STATUS_ERROR_PIN_REQUIRED = 5, /*< nick=PinRequired >*/
+ MBIM_STATUS_ERROR_PIN_DISABLED = 6, /*< nick=PinDisabled >*/
+ MBIM_STATUS_ERROR_NOT_REGISTERED = 7, /*< nick=NotRegistered >*/
+ MBIM_STATUS_ERROR_PROVIDERS_NOT_FOUND = 8, /*< nick=ProvidersNotFound >*/
+ MBIM_STATUS_ERROR_NO_DEVICE_SUPPORT = 9, /*< nick=NoDeviceSupport >*/
+ MBIM_STATUS_ERROR_PROVIDER_NOT_VISIBLE = 10, /*< nick=ProviderNotVisible >*/
+ MBIM_STATUS_ERROR_DATA_CLASS_NOT_AVAILABLE = 11, /*< nick=DataClassNotAvailable >*/
+ MBIM_STATUS_ERROR_PACKET_SERVICE_DETACHED = 12, /*< nick=PacketServiceDetached >*/
+ MBIM_STATUS_ERROR_MAX_ACTIVATED_CONTEXTS = 13, /*< nick=MaxActivatedContexts >*/
+ MBIM_STATUS_ERROR_NOT_INITIALIZED = 14, /*< nick=NotInitialized >*/
+ MBIM_STATUS_ERROR_VOICE_CALL_IN_PROGRESS = 15, /*< nick=VoiceCallInProgress >*/
+ MBIM_STATUS_ERROR_CONTEXT_NOT_ACTIVATED = 16, /*< nick=ContextNotActivated >*/
+ MBIM_STATUS_ERROR_SERVICE_NOT_ACTIVATED = 17, /*< nick=ServiceNotActivated >*/
+ MBIM_STATUS_ERROR_INVALID_ACCESS_STRING = 18, /*< nick=InvalidAccessString >*/
+ MBIM_STATUS_ERROR_INVALID_USER_NAME_PWD = 19, /*< nick=InvalidUserNamePwd >*/
+ MBIM_STATUS_ERROR_RADIO_POWER_OFF = 20, /*< nick=RadioPowerOff >*/
+ MBIM_STATUS_ERROR_INVALID_PARAMETERS = 21, /*< nick=InvalidParameters >*/
+ MBIM_STATUS_ERROR_READ_FAILURE = 22, /*< nick=ReadFailure >*/
+ MBIM_STATUS_ERROR_WRITE_FAILURE = 23, /*< nick=WriteFailure >*/
+ /* 24 = reserved */
+ MBIM_STATUS_ERROR_NO_PHONEBOOK = 25, /*< nick=NoPhonebook >*/
+ MBIM_STATUS_ERROR_PARAMETER_TOO_LONG = 26, /*< nick=ParameterTooLong >*/
+ MBIM_STATUS_ERROR_STK_BUSY = 27, /*< nick=StkBusy >*/
+ MBIM_STATUS_ERROR_OPERATION_NOT_ALLOWED = 28, /*< nick=OperationNotAllowed >*/
+ MBIM_STATUS_ERROR_MEMORY_FAILURE = 29, /*< nick=MemoryFailure >*/
+ MBIM_STATUS_ERROR_INVALID_MEMORY_INDEX = 30, /*< nick=InvalidMemoryIndex >*/
+ MBIM_STATUS_ERROR_MEMORY_FULL = 31, /*< nick=MemoryFull >*/
+ MBIM_STATUS_ERROR_FILTER_NOT_SUPPORTED = 32, /*< nick=FilterNotSupported >*/
+ MBIM_STATUS_ERROR_DSS_INSTANCE_LIMIT = 33, /*< nick=DssInstanceLimit >*/
+ MBIM_STATUS_ERROR_INVALID_DEVICE_SERVICE_OPERATION = 34, /*< nick=InvalidDeviceServiceOperation >*/
+ MBIM_STATUS_ERROR_AUTH_INCORRECT_AUTN = 35, /*< nick=AuthIncorrectAuth >*/
+ MBIM_STATUS_ERROR_AUTH_SYNC_FAILURE = 36, /*< nick=AuthSyncFailure >*/
+ MBIM_STATUS_ERROR_AUTH_AMF_NOT_SET = 37, /*< nick=AuthAmfNotSet >*/
+ MBIM_STATUS_ERROR_SMS_UNKNOWN_SMSC_ADDRESS = 100, /*< nick=SmsUnknownSmscAddress >*/
+ MBIM_STATUS_ERROR_SMS_NETWORK_TIMEOUT = 101, /*< nick=SmsNetworkTimeout >*/
+ MBIM_STATUS_ERROR_SMS_LANG_NOT_SUPPORTED = 102, /*< nick=SmsLangNotSupported >*/
+ MBIM_STATUS_ERROR_SMS_ENCODING_NOT_SUPPORTED = 103, /*< nick=SmsEncodingNotSupported >*/
+ MBIM_STATUS_ERROR_SMS_FORMAT_NOT_SUPPORTED = 104 /*< nick=SmsFormatNotSupported >*/
+} MbimStatusError;
+
+#endif /* _LIBMBIM_GLIB_MBIM_ERRORS_H_ */
diff --git a/libmbim-glib/mbim-message-private.h b/libmbim-glib/mbim-message-private.h
new file mode 100644
index 0000000..5d9d509
--- /dev/null
+++ b/libmbim-glib/mbim-message-private.h
@@ -0,0 +1,296 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/*
+ * libmbim-glib -- GLib/GIO based library to control MBIM devices
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+ *
+ * This is a private non-installed header
+ */
+
+#ifndef _LIBMBIM_GLIB_MBIM_MESSAGE_PRIVATE_H_
+#define _LIBMBIM_GLIB_MBIM_MESSAGE_PRIVATE_H_
+
+#if !defined (LIBMBIM_GLIB_COMPILATION)
+#error "This is a private header!!"
+#endif
+
+#include <glib.h>
+
+#include "mbim-message.h"
+
+G_BEGIN_DECLS
+
+/*****************************************************************************/
+/* The MbimMessage */
+
+/* Defined in the same way as GByteArray */
+struct _MbimMessage {
+ guint8 *data;
+ guint len;
+};
+
+/*****************************************************************************/
+/* Basic message types */
+
+struct header {
+ guint32 type;
+ guint32 length;
+ guint32 transaction_id;
+} __attribute__((packed));
+
+#define MBIM_MESSAGE_GET_MESSAGE_TYPE(self) \
+ (MbimMessageType) GUINT32_FROM_LE (((struct header *)(self->data))->type)
+#define MBIM_MESSAGE_GET_MESSAGE_LENGTH(self) \
+ GUINT32_FROM_LE (((struct header *)(self->data))->length)
+#define MBIM_MESSAGE_GET_TRANSACTION_ID(self) \
+ GUINT32_FROM_LE (((struct header *)(self->data))->transaction_id)
+
+struct open_message {
+ guint32 max_control_transfer;
+} __attribute__((packed));
+
+struct open_done_message {
+ guint32 status_code;
+} __attribute__((packed));
+
+struct close_done_message {
+ guint32 status_code;
+} __attribute__((packed));
+
+struct error_message {
+ guint32 error_status_code;
+} __attribute__((packed));
+
+struct fragment_header {
+ guint32 total;
+ guint32 current;
+} __attribute__((packed));
+
+struct fragment_message {
+ struct fragment_header fragment_header;
+ guint8 buffer[];
+} __attribute__((packed));
+
+struct command_message {
+ struct fragment_header fragment_header;
+ guint8 service_id[16];
+ guint32 command_id;
+ guint32 command_type;
+ guint32 buffer_length;
+ guint8 buffer[];
+} __attribute__((packed));
+
+struct command_done_message {
+ struct fragment_header fragment_header;
+ guint8 service_id[16];
+ guint32 command_id;
+ guint32 status_code;
+ guint32 buffer_length;
+ guint8 buffer[];
+} __attribute__((packed));
+
+struct indicate_status_message {
+ struct fragment_header fragment_header;
+ guint8 service_id[16];
+ guint32 command_id;
+ guint32 buffer_length;
+ guint8 buffer[];
+} __attribute__((packed));
+
+struct full_message {
+ struct header header;
+ union {
+ struct open_message open;
+ struct open_done_message open_done;
+ /* nothing needed for close_message */
+ struct close_done_message close_done;
+ struct error_message error;
+ struct fragment_message fragment;
+ struct command_message command;
+ struct command_done_message command_done;
+ struct indicate_status_message indicate_status;
+ } message;
+} __attribute__((packed));
+
+/*****************************************************************************/
+/* Fragment interface */
+
+gboolean _mbim_message_is_fragment (const MbimMessage *self);
+guint32 _mbim_message_fragment_get_total (const MbimMessage *self);
+guint32 _mbim_message_fragment_get_current (const MbimMessage *self);
+const guint8 *_mbim_message_fragment_get_payload (const MbimMessage *self,
+ guint32 *length);
+
+/* Merge fragments into a message... */
+
+MbimMessage *_mbim_message_fragment_collector_init (const MbimMessage *fragment,
+ GError **error);
+gboolean _mbim_message_fragment_collector_add (MbimMessage *self,
+ const MbimMessage *fragment,
+ GError **error);
+gboolean _mbim_message_fragment_collector_complete (MbimMessage *self);
+
+/* Split message into fragments... */
+
+struct fragment_info {
+ struct header header;
+ struct fragment_header fragment_header;
+ guint32 data_length;
+ const guint8 *data;
+} __attribute__((packed));
+
+struct fragment_info *_mbim_message_split_fragments (const MbimMessage *self,
+ guint32 max_fragment_size,
+ guint *n_fragments);
+
+/*****************************************************************************/
+/* Struct builder */
+
+typedef struct {
+ GByteArray *fixed_buffer;
+ GByteArray *variable_buffer;
+ GArray *offsets;
+} MbimStructBuilder;
+
+MbimStructBuilder *_mbim_struct_builder_new (void);
+GByteArray *_mbim_struct_builder_complete (MbimStructBuilder *builder);
+void _mbim_struct_builder_append_byte_array (MbimStructBuilder *builder,
+ gboolean with_offset,
+ gboolean with_length,
+ const guint8 *buffer,
+ guint32 buffer_len);
+void _mbim_struct_builder_append_uuid (MbimStructBuilder *builder,
+ const MbimUuid *value);
+void _mbim_struct_builder_append_guint32 (MbimStructBuilder *builder,
+ guint32 value);
+void _mbim_struct_builder_append_guint32_array (MbimStructBuilder *builder,
+ const guint32 *values,
+ guint32 n_values);
+void _mbim_struct_builder_append_guint64 (MbimStructBuilder *builder,
+ guint64 value);
+void _mbim_struct_builder_append_guint64_array (MbimStructBuilder *builder,
+ const guint64 *values,
+ guint32 n_values);
+void _mbim_struct_builder_append_string (MbimStructBuilder *builder,
+ const gchar *value);
+void _mbim_struct_builder_append_string_array (MbimStructBuilder *builder,
+ const gchar *const *values,
+ guint32 n_values);
+void _mbim_struct_builder_append_ipv4 (MbimStructBuilder *builder,
+ const MbimIPv4 *value,
+ gboolean ref);
+void _mbim_struct_builder_append_ipv4_array (MbimStructBuilder *builder,
+ const MbimIPv4 *values,
+ guint32 n_values);
+void _mbim_struct_builder_append_ipv6 (MbimStructBuilder *builder,
+ const MbimIPv6 *value,
+ gboolean ref);
+void _mbim_struct_builder_append_ipv6_array (MbimStructBuilder *builder,
+ const MbimIPv6 *values,
+ guint32 n_values);
+
+/*****************************************************************************/
+/* Message builder */
+
+typedef struct {
+ MbimMessage *message;
+ MbimStructBuilder *contents_builder;
+} MbimMessageCommandBuilder;
+
+MbimMessageCommandBuilder *_mbim_message_command_builder_new (guint32 transaction_id,
+ MbimService service,
+ guint32 cid,
+ MbimMessageCommandType command_type);
+MbimMessage *_mbim_message_command_builder_complete (MbimMessageCommandBuilder *builder);
+void _mbim_message_command_builder_append_byte_array (MbimMessageCommandBuilder *builder,
+ gboolean with_offset,
+ gboolean with_length,
+ const guint8 *buffer,
+ guint32 buffer_len);
+void _mbim_message_command_builder_append_uuid (MbimMessageCommandBuilder *builder,
+ const MbimUuid *value);
+void _mbim_message_command_builder_append_guint32 (MbimMessageCommandBuilder *builder,
+ guint32 value);
+void _mbim_message_command_builder_append_guint32_array (MbimMessageCommandBuilder *builder,
+ const guint32 *values,
+ guint32 n_values);
+void _mbim_message_command_builder_append_guint64 (MbimMessageCommandBuilder *builder,
+ guint64 value);
+void _mbim_message_command_builder_append_guint64_array (MbimMessageCommandBuilder *builder,
+ const guint64 *values,
+ guint32 n_values);
+void _mbim_message_command_builder_append_string (MbimMessageCommandBuilder *builder,
+ const gchar *value);
+void _mbim_message_command_builder_append_string_array (MbimMessageCommandBuilder *builder,
+ const gchar *const *values,
+ guint32 n_values);
+void _mbim_message_command_builder_append_ipv4 (MbimMessageCommandBuilder *builder,
+ const MbimIPv4 *value,
+ gboolean ref);
+void _mbim_message_command_builder_append_ipv4_array (MbimMessageCommandBuilder *builder,
+ const MbimIPv4 *values,
+ guint32 n_values);
+void _mbim_message_command_builder_append_ipv6 (MbimMessageCommandBuilder *builder,
+ const MbimIPv6 *value,
+ gboolean ref);
+void _mbim_message_command_builder_append_ipv6_array (MbimMessageCommandBuilder *builder,
+ const MbimIPv6 *values,
+ guint32 n_values);
+
+/*****************************************************************************/
+/* Message parser */
+
+const guint8 *_mbim_message_read_byte_array (const MbimMessage *self,
+ guint32 struct_start_offset,
+ guint32 relative_offset,
+ gboolean has_offset,
+ gboolean has_length,
+ guint32 *array_size);
+const MbimUuid *_mbim_message_read_uuid (const MbimMessage *self,
+ guint32 relative_offset);
+guint32 _mbim_message_read_guint32 (const MbimMessage *self,
+ guint32 relative_offset);
+guint32 *_mbim_message_read_guint32_array (const MbimMessage *self,
+ guint32 array_size,
+ guint32 relative_offset_array_start);
+guint64 _mbim_message_read_guint64 (const MbimMessage *self,
+ guint64 relative_offset);
+gchar *_mbim_message_read_string (const MbimMessage *self,
+ guint32 struct_start_offset,
+ guint32 relative_offset);
+gchar **_mbim_message_read_string_array (const MbimMessage *self,
+ guint32 array_size,
+ guint32 struct_start_offset,
+ guint32 relative_offset_array_start);
+const MbimIPv4 *_mbim_message_read_ipv4 (const MbimMessage *self,
+ guint32 relative_offset,
+ gboolean ref);
+MbimIPv4 *_mbim_message_read_ipv4_array (const MbimMessage *self,
+ guint32 array_size,
+ guint32 relative_offset_array_start);
+const MbimIPv6 *_mbim_message_read_ipv6 (const MbimMessage *self,
+ guint32 relative_offset,
+ gboolean ref);
+MbimIPv6 *_mbim_message_read_ipv6_array (const MbimMessage *self,
+ guint32 array_size,
+ guint32 relative_offset_array_start);
+
+G_END_DECLS
+
+#endif /* _LIBMBIM_GLIB_MBIM_MESSAGE_PRIVATE_H_ */
diff --git a/libmbim-glib/mbim-message.c b/libmbim-glib/mbim-message.c
new file mode 100644
index 0000000..deb2c52
--- /dev/null
+++ b/libmbim-glib/mbim-message.c
@@ -0,0 +1,2075 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/*
+ * libmbim-glib -- GLib/GIO based library to control MBIM devices
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#include <glib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <endian.h>
+
+#include "mbim-message.h"
+#include "mbim-message-private.h"
+#include "mbim-error-types.h"
+#include "mbim-enum-types.h"
+
+/**
+ * SECTION:mbim-message
+ * @title: MbimMessage
+ * @short_description: Generic MBIM message handling routines
+ *
+ * #MbimMessage is a generic type representing a MBIM message of any kind
+ * (request, response, indication).
+ **/
+
+/*****************************************************************************/
+
+GType
+mbim_message_get_type (void)
+{
+ static volatile gsize g_define_type_id__volatile = 0;
+
+ if (g_once_init_enter (&g_define_type_id__volatile)) {
+ GType g_define_type_id =
+ g_boxed_type_register_static (g_intern_static_string ("MbimMessage"),
+ (GBoxedCopyFunc) mbim_message_ref,
+ (GBoxedFreeFunc) mbim_message_unref);
+
+ g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+ }
+
+ return g_define_type_id__volatile;
+}
+
+/*****************************************************************************/
+
+static GByteArray *
+_mbim_message_allocate (MbimMessageType message_type,
+ guint32 transaction_id,
+ guint32 additional_size)
+{
+ GByteArray *self;
+ guint32 len;
+
+ /* Compute size of the basic empty message and allocate heap for it */
+ len = sizeof (struct header) + additional_size;
+ self = g_byte_array_sized_new (len);
+ g_byte_array_set_size (self, len);
+
+ /* Set MBIM header */
+ ((struct header *)(self->data))->type = GUINT32_TO_LE (message_type);
+ ((struct header *)(self->data))->length = GUINT32_TO_LE (len);
+ ((struct header *)(self->data))->transaction_id = GUINT32_TO_LE (transaction_id);
+
+ return self;
+}
+
+static guint32
+_mbim_message_get_information_buffer_offset (const MbimMessage *self)
+{
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_COMMAND ||
+ MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_COMMAND_DONE ||
+ MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_INDICATE_STATUS, 0);
+
+ switch (MBIM_MESSAGE_GET_MESSAGE_TYPE (self)) {
+ case MBIM_MESSAGE_TYPE_COMMAND:
+ return (sizeof (struct header) +
+ G_STRUCT_OFFSET (struct command_message, buffer));
+
+ case MBIM_MESSAGE_TYPE_COMMAND_DONE:
+ return (sizeof (struct header) +
+ G_STRUCT_OFFSET (struct command_done_message, buffer));
+ break;
+
+ case MBIM_MESSAGE_TYPE_INDICATE_STATUS:
+ return (sizeof (struct header) +
+ G_STRUCT_OFFSET (struct indicate_status_message, buffer));
+ break;
+
+ default:
+ g_assert_not_reached ();
+ return 0;
+ }
+}
+
+guint32
+_mbim_message_read_guint32 (const MbimMessage *self,
+ guint32 relative_offset)
+{
+ guint32 information_buffer_offset;
+
+ information_buffer_offset = _mbim_message_get_information_buffer_offset (self);
+ return GUINT32_FROM_LE (G_STRUCT_MEMBER (
+ guint32,
+ self->data,
+ (information_buffer_offset + relative_offset)));
+}
+
+guint32 *
+_mbim_message_read_guint32_array (const MbimMessage *self,
+ guint32 array_size,
+ guint32 relative_offset_array_start)
+{
+ guint i;
+ guint32 *out;
+ guint32 information_buffer_offset;
+
+ if (!array_size)
+ return NULL;
+
+ information_buffer_offset = _mbim_message_get_information_buffer_offset (self);
+
+ out = g_new (guint32, array_size + 1);
+ for (i = 0; i < array_size; i++) {
+ out[i] = GUINT32_FROM_LE (G_STRUCT_MEMBER (
+ guint32,
+ self->data,
+ (information_buffer_offset +
+ relative_offset_array_start +
+ (4 * i))));
+ }
+ out[array_size] = 0;
+
+ return out;
+}
+
+guint64
+_mbim_message_read_guint64 (const MbimMessage *self,
+ guint64 relative_offset)
+{
+ guint64 information_buffer_offset;
+
+ information_buffer_offset = _mbim_message_get_information_buffer_offset (self);
+ return GUINT64_FROM_LE (G_STRUCT_MEMBER (
+ guint64,
+ self->data,
+ (information_buffer_offset + relative_offset)));
+}
+
+gchar *
+_mbim_message_read_string (const MbimMessage *self,
+ guint32 struct_start_offset,
+ guint32 relative_offset)
+{
+ guint32 offset;
+ guint32 size;
+ gchar *str;
+ GError *error = NULL;
+ guint32 information_buffer_offset;
+
+ information_buffer_offset = _mbim_message_get_information_buffer_offset (self);
+
+ offset = GUINT32_FROM_LE (G_STRUCT_MEMBER (
+ guint32,
+ self->data,
+ (information_buffer_offset + relative_offset)));
+ size = GUINT32_FROM_LE (G_STRUCT_MEMBER (
+ guint32,
+ self->data,
+ (information_buffer_offset + relative_offset + 4)));
+ if (!size)
+ return NULL;
+
+ str = g_convert (G_STRUCT_MEMBER_P (
+ self->data,
+ (information_buffer_offset + struct_start_offset + offset)),
+ size,
+ "utf-8",
+ "utf-16le",
+ NULL,
+ NULL,
+ &error);
+ if (error) {
+ g_warning ("Error converting string: %s", error->message);
+ g_error_free (error);
+ }
+
+ return str;
+}
+
+gchar **
+_mbim_message_read_string_array (const MbimMessage *self,
+ guint32 array_size,
+ guint32 struct_start_offset,
+ guint32 relative_offset_array_start)
+{
+ gchar **array;
+ guint32 offset;
+ guint32 i;
+
+ if (!array_size)
+ return NULL;
+
+ array = g_new (gchar *, array_size + 1);
+ for (i = 0, offset = relative_offset_array_start;
+ i < array_size;
+ offset += 8, i++) {
+ /* Read next string in the OL pair list */
+ array[i] = _mbim_message_read_string (self, struct_start_offset, offset);
+ }
+ array[i] = NULL;
+
+ return array;
+}
+
+/*
+ * Byte arrays may be given in very different ways:
+ * - (a) Offset + Length pair in static buffer, data in variable buffer.
+ * - (b) Just length in static buffer, data just afterwards.
+ * - (c) Just offset in static buffer, length given in another variable, data in variable buffer.
+ * - (d) Fixed-sized array directly in the static buffer.
+ * - (e) Unsized array directly in the variable buffer, length is assumed until end of message.
+ */
+const guint8 *
+_mbim_message_read_byte_array (const MbimMessage *self,
+ guint32 struct_start_offset,
+ guint32 relative_offset,
+ gboolean has_offset,
+ gboolean has_length,
+ guint32 *array_size)
+{
+ guint32 information_buffer_offset;
+
+ information_buffer_offset = _mbim_message_get_information_buffer_offset (self);
+
+ /* (a) Offset + Length pair in static buffer, data in variable buffer. */
+ if (has_offset && has_length) {
+ guint32 offset;
+
+ g_assert (array_size != NULL);
+
+ offset = GUINT32_FROM_LE (G_STRUCT_MEMBER (
+ guint32,
+ self->data,
+ (information_buffer_offset + relative_offset)));
+ *array_size = GUINT32_FROM_LE (G_STRUCT_MEMBER (
+ guint32,
+ self->data,
+ (information_buffer_offset + relative_offset + 4)));
+ return (const guint8 *) G_STRUCT_MEMBER_P (self->data,
+ (information_buffer_offset + struct_start_offset + offset));
+ }
+
+ /* (b) Just length in static buffer, data just afterwards. */
+ if (!has_offset && has_length) {
+ g_assert (array_size != NULL);
+
+ *array_size = GUINT32_FROM_LE (G_STRUCT_MEMBER (
+ guint32,
+ self->data,
+ (information_buffer_offset + relative_offset)));
+ return (const guint8 *) G_STRUCT_MEMBER_P (self->data,
+ (information_buffer_offset + relative_offset + 4));
+ }
+
+ /* (c) Just offset in static buffer, length given in another variable, data in variable buffer. */
+ if (has_offset && !has_length) {
+ guint32 offset;
+
+ g_assert (array_size == NULL);
+
+ offset = GUINT32_FROM_LE (G_STRUCT_MEMBER (
+ guint32,
+ self->data,
+ (information_buffer_offset + relative_offset)));
+ return (const guint8 *) G_STRUCT_MEMBER_P (self->data,
+ (information_buffer_offset + struct_start_offset + offset));
+ }
+
+ /* (d) Fixed-sized array directly in the static buffer.
+ * (e) Unsized array directly in the variable buffer, length is assumed until end of message. */
+ if (!has_offset && !has_length) {
+ /* If array size is requested, it's case (e) */
+ if (array_size)
+ *array_size = self->len - (information_buffer_offset + relative_offset);
+
+ return (const guint8 *) G_STRUCT_MEMBER_P (self->data,
+ (information_buffer_offset + relative_offset));
+ }
+
+ g_assert_not_reached ();
+}
+
+const MbimUuid *
+_mbim_message_read_uuid (const MbimMessage *self,
+ guint32 relative_offset)
+{
+ guint32 information_buffer_offset;
+
+ information_buffer_offset = _mbim_message_get_information_buffer_offset (self);
+
+ return (const MbimUuid *) G_STRUCT_MEMBER_P (self->data,
+ (information_buffer_offset + relative_offset));
+}
+
+const MbimIPv4 *
+_mbim_message_read_ipv4 (const MbimMessage *self,
+ guint32 relative_offset,
+ gboolean ref)
+{
+ guint32 information_buffer_offset;
+ guint32 offset;
+
+ information_buffer_offset = _mbim_message_get_information_buffer_offset (self);
+
+ if (ref) {
+ offset = GUINT32_FROM_LE (G_STRUCT_MEMBER (guint32,
+ self->data,
+ (information_buffer_offset + relative_offset)));
+ if (!offset)
+ return NULL;
+ } else
+ offset = relative_offset;
+
+ return (const MbimIPv4 *) G_STRUCT_MEMBER_P (self->data,
+ (information_buffer_offset + offset));
+}
+
+MbimIPv4 *
+_mbim_message_read_ipv4_array (const MbimMessage *self,
+ guint32 array_size,
+ guint32 relative_offset_array_start)
+{
+ MbimIPv4 *array;
+ guint32 offset;
+ guint32 i;
+ guint32 information_buffer_offset;
+
+ if (!array_size)
+ return NULL;
+
+ information_buffer_offset = _mbim_message_get_information_buffer_offset (self);
+
+ array = g_new (MbimIPv4, array_size);
+ offset = GUINT32_FROM_LE (G_STRUCT_MEMBER (
+ guint32,
+ self->data,
+ (information_buffer_offset + relative_offset_array_start)));
+
+ for (i = 0; i < array_size; i++, offset += 4) {
+ memcpy (&array[i],
+ G_STRUCT_MEMBER_P (self->data,
+ (information_buffer_offset + offset)),
+ 4);
+ }
+
+ return array;
+}
+
+const MbimIPv6 *
+_mbim_message_read_ipv6 (const MbimMessage *self,
+ guint32 relative_offset,
+ gboolean ref)
+{
+ guint32 information_buffer_offset;
+ guint32 offset;
+
+ information_buffer_offset = _mbim_message_get_information_buffer_offset (self);
+
+ if (ref) {
+ offset = GUINT32_FROM_LE (G_STRUCT_MEMBER (guint32,
+ self->data,
+ (information_buffer_offset + relative_offset)));
+ if (!offset)
+ return NULL;
+ } else
+ offset = relative_offset;
+
+ return (const MbimIPv6 *) G_STRUCT_MEMBER_P (self->data,
+ (information_buffer_offset + offset));
+}
+
+MbimIPv6 *
+_mbim_message_read_ipv6_array (const MbimMessage *self,
+ guint32 array_size,
+ guint32 relative_offset_array_start)
+{
+ MbimIPv6 *array;
+ guint32 offset;
+ guint32 i;
+ guint32 information_buffer_offset;
+
+ if (!array_size)
+ return NULL;
+
+ information_buffer_offset = _mbim_message_get_information_buffer_offset (self);
+
+ array = g_new (MbimIPv6, array_size);
+ offset = GUINT32_FROM_LE (G_STRUCT_MEMBER (
+ guint32,
+ self->data,
+ (information_buffer_offset + relative_offset_array_start)));
+ for (i = 0; i < array_size; i++, offset += 16) {
+ memcpy (&array[i],
+ G_STRUCT_MEMBER_P (self->data,
+ (information_buffer_offset + offset)),
+ 16);
+ }
+
+ return array;
+}
+
+/*****************************************************************************/
+/* Struct builder interface
+ *
+ * Types like structs consist of a fixed sized prefix plus a variable length
+ * data buffer. Items of variable size are usually given as an offset (with
+ * respect to the start of the struct) plus a size field. */
+
+MbimStructBuilder *
+_mbim_struct_builder_new (void)
+{
+ MbimStructBuilder *builder;
+
+ builder = g_slice_new (MbimStructBuilder);
+ builder->fixed_buffer = g_byte_array_new ();
+ builder->variable_buffer = g_byte_array_new ();
+ builder->offsets = g_array_new (FALSE, FALSE, sizeof (guint32));
+ return builder;
+}
+
+GByteArray *
+_mbim_struct_builder_complete (MbimStructBuilder *builder)
+{
+ GByteArray *out;
+ guint i;
+
+ /* Update offsets with the length of the information buffer, and store them
+ * in LE. */
+ for (i = 0; i < builder->offsets->len; i++) {
+ guint32 offset_offset;
+ guint32 *offset_value;
+
+ offset_offset = g_array_index (builder->offsets, guint32, i);
+ offset_value = (guint32 *) &builder->fixed_buffer->data[offset_offset];
+ *offset_value = GUINT32_TO_LE (*offset_value + builder->fixed_buffer->len);
+ }
+
+ /* Merge both buffers */
+ g_byte_array_append (builder->fixed_buffer,
+ (const guint8 *)builder->variable_buffer->data,
+ (guint32)builder->variable_buffer->len);
+
+ /* Steal the buffer to return */
+ out = builder->fixed_buffer;
+
+ /* Dispose the builder */
+ g_array_unref (builder->offsets);
+ g_byte_array_unref (builder->variable_buffer);
+ g_slice_free (MbimStructBuilder, builder);
+
+ return out;
+}
+
+/*
+ * Byte arrays may be given in very different ways:
+ * - (a) Offset + Length pair in static buffer, data in variable buffer.
+ * - (b) Just length in static buffer, data just afterwards.
+ * - (c) Just offset in static buffer, length given in another variable, data in variable buffer.
+ * - (d) Fixed-sized array directly in the static buffer.
+ * - (e) Unsized array directly in the variable buffer, length is assumed until end of message.
+ */
+void
+_mbim_struct_builder_append_byte_array (MbimStructBuilder *builder,
+ gboolean with_offset,
+ gboolean with_length,
+ const guint8 *buffer,
+ guint32 buffer_len)
+{
+ /*
+ * (d) Fixed-sized array directly in the static buffer.
+ * (e) Unsized array directly in the variable buffer (here end of static buffer is also beginning of variable)
+ */
+ if (!with_offset && !with_length) {
+ g_byte_array_append (builder->fixed_buffer, buffer, buffer_len);
+ while (buffer_len % 4 != 0) {
+ const guint8 padding = 0;
+
+ g_byte_array_append (builder->fixed_buffer, &padding, 1);
+ buffer_len++;
+ }
+ return;
+ }
+
+ /* (a) Offset + Length pair in static buffer, data in variable buffer.
+ * This case is the sum of cases b+c */
+
+ /* (c) Just offset in static buffer, length given in another variable, data in variable buffer. */
+ if (with_offset) {
+ guint32 offset;
+
+ /* If string length is greater than 0, add the offset to fix, otherwise set
+ * the offset to 0 and don't configure the update */
+ if (buffer_len == 0) {
+ offset = 0;
+ g_byte_array_append (builder->fixed_buffer, (guint8 *)&offset, sizeof (offset));
+ } else {
+ guint32 offset_offset;
+
+ /* Offset of the offset */
+ offset_offset = builder->fixed_buffer->len;
+
+ /* Length *not* in LE yet */
+ offset = builder->variable_buffer->len;
+ /* Add the offset value */
+ g_byte_array_append (builder->fixed_buffer, (guint8 *)&offset, sizeof (offset));
+ /* Configure the value to get updated */
+ g_array_append_val (builder->offsets, offset_offset);
+ }
+ }
+
+ /* (b) Just length in static buffer, data just afterwards. */
+ if (with_length) {
+ guint32 length;
+
+ /* Add the length value */
+ length = GUINT32_TO_LE (buffer_len);
+ g_byte_array_append (builder->fixed_buffer, (guint8 *)&length, sizeof (length));
+ }
+
+ /* And finally, the bytearray itself to the variable buffer */
+ if (buffer_len) {
+ g_byte_array_append (builder->variable_buffer, (const guint8 *)buffer, (guint)buffer_len);
+
+ while (buffer_len % 4 != 0) {
+ const guint8 padding = 0;
+
+ g_byte_array_append (builder->variable_buffer, &padding, 1);
+ buffer_len++;
+ }
+ }
+}
+
+void
+_mbim_struct_builder_append_uuid (MbimStructBuilder *builder,
+ const MbimUuid *value)
+{
+ static const MbimUuid uuid_invalid = {
+ .a = { 0x00, 0x00, 0x00, 0x00 },
+ .b = { 0x00, 0x00 },
+ .c = { 0x00, 0x00 },
+ .d = { 0x00, 0x00 },
+ .e = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+ };
+
+ /* uuids are added in the static buffer only */
+ g_byte_array_append (builder->fixed_buffer,
+ value ? (guint8 *)value : (guint8 *)&uuid_invalid,
+ sizeof (MbimUuid));
+}
+
+void
+_mbim_struct_builder_append_guint32 (MbimStructBuilder *builder,
+ guint32 value)
+{
+ guint32 tmp;
+
+ /* guint32 values are added in the static buffer only */
+ tmp = GUINT32_TO_LE (value);
+ g_byte_array_append (builder->fixed_buffer, (guint8 *)&tmp, sizeof (tmp));
+}
+
+void
+_mbim_struct_builder_append_guint32_array (MbimStructBuilder *builder,
+ const guint32 *values,
+ guint32 n_values)
+{
+ guint i;
+
+ /* guint32 array added directly in the static buffer */
+ for (i = 0; i < n_values; i++)
+ _mbim_struct_builder_append_guint32 (builder, values[i]);
+}
+
+void
+_mbim_struct_builder_append_guint64 (MbimStructBuilder *builder,
+ guint64 value)
+{
+ guint64 tmp;
+
+ /* guint64 values are added in the static buffer only */
+ tmp = GUINT64_TO_LE (value);
+ g_byte_array_append (builder->fixed_buffer, (guint8 *)&tmp, sizeof (tmp));
+}
+
+void
+_mbim_struct_builder_append_guint64_array (MbimStructBuilder *builder,
+ const guint64 *values,
+ guint32 n_values)
+{
+ guint i;
+
+ /* guint64 array added directly in the static buffer */
+ for (i = 0; i < n_values; i++)
+ _mbim_struct_builder_append_guint64 (builder, values[i]);
+}
+
+void
+_mbim_struct_builder_append_string (MbimStructBuilder *builder,
+ const gchar *value)
+{
+ guint32 offset;
+ guint32 length;
+ gchar *utf16le = NULL;
+ gsize utf16le_bytes = 0;
+ GError *error = NULL;
+
+ /* A string consists of Offset+Size in the static buffer, plus the
+ * string itself in the variable buffer */
+
+ /* Convert the string from UTF-8 to UTF-16LE */
+ if (value && value[0]) {
+ utf16le = g_convert (value,
+ -1,
+ "utf-16le",
+ "utf-8",
+ NULL,
+ &utf16le_bytes,
+ &error);
+ if (error) {
+ g_warning ("Error converting string: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+ }
+
+ /* If string length is greater than 0, add the offset to fix, otherwise set
+ * the offset to 0 and don't configure the update */
+ if (utf16le_bytes == 0) {
+ offset = 0;
+ g_byte_array_append (builder->fixed_buffer, (guint8 *)&offset, sizeof (offset));
+ } else {
+ guint32 offset_offset;
+
+ /* Offset of the offset */
+ offset_offset = builder->fixed_buffer->len;
+
+ /* Length *not* in LE yet */
+ offset = builder->variable_buffer->len;
+ /* Add the offset value */
+ g_byte_array_append (builder->fixed_buffer, (guint8 *)&offset, sizeof (offset));
+ /* Configure the value to get updated */
+ g_array_append_val (builder->offsets, offset_offset);
+ }
+
+ /* Add the length value */
+ length = GUINT32_TO_LE ((guint32)utf16le_bytes);
+ g_byte_array_append (builder->fixed_buffer, (guint8 *)&length, sizeof (length));
+
+ /* And finally, the string itself to the variable buffer */
+ if (utf16le_bytes) {
+ g_byte_array_append (builder->variable_buffer, (const guint8 *)utf16le, (guint)utf16le_bytes);
+ while (utf16le_bytes % 4 != 0) {
+ const guint8 padding = 0;
+
+ g_byte_array_append (builder->variable_buffer, &padding, 1);
+ utf16le_bytes++;
+ }
+ }
+ g_free (utf16le);
+}
+
+void
+_mbim_struct_builder_append_string_array (MbimStructBuilder *builder,
+ const gchar *const *values,
+ guint32 n_values)
+{
+ /* TODO */
+ g_assert_not_reached ();
+}
+
+void
+_mbim_struct_builder_append_ipv4 (MbimStructBuilder *builder,
+ const MbimIPv4 *value,
+ gboolean ref)
+{
+ if (ref)
+ _mbim_struct_builder_append_ipv4_array (builder, value, value ? 1 : 0);
+ else
+ g_byte_array_append (builder->fixed_buffer, (guint8 *)value, sizeof (MbimIPv4));
+}
+
+void
+_mbim_struct_builder_append_ipv4_array (MbimStructBuilder *builder,
+ const MbimIPv4 *values,
+ guint32 n_values)
+{
+ guint32 offset;
+
+ if (!n_values) {
+ offset = 0;
+ g_byte_array_append (builder->fixed_buffer, (guint8 *)&offset, sizeof (offset));
+ } else {
+ guint32 offset_offset;
+
+ /* Offset of the offset */
+ offset_offset = builder->fixed_buffer->len;
+
+ /* Length *not* in LE yet */
+ offset = builder->variable_buffer->len;
+ /* Add the offset value */
+ g_byte_array_append (builder->fixed_buffer, (guint8 *)&offset, sizeof (offset));
+ /* Configure the value to get updated */
+ g_array_append_val (builder->offsets, offset_offset);
+
+ /* NOTE: length of the array must be given in a separate variable */
+
+ /* And finally, the array of IPs itself to the variable buffer */
+ g_byte_array_append (builder->variable_buffer, (guint8 *)values, n_values * sizeof (MbimIPv4));
+ }
+}
+
+void
+_mbim_struct_builder_append_ipv6 (MbimStructBuilder *builder,
+ const MbimIPv6 *value,
+ gboolean ref)
+{
+ if (ref)
+ _mbim_struct_builder_append_ipv6_array (builder, value, value ? 1 : 0);
+ else
+ g_byte_array_append (builder->fixed_buffer, (guint8 *)value, sizeof (MbimIPv6));
+}
+
+void
+_mbim_struct_builder_append_ipv6_array (MbimStructBuilder *builder,
+ const MbimIPv6 *values,
+ guint32 n_values)
+{
+ guint32 offset;
+
+ if (!n_values) {
+ offset = 0;
+ g_byte_array_append (builder->fixed_buffer, (guint8 *)&offset, sizeof (offset));
+ } else {
+ guint32 offset_offset;
+
+ /* Offset of the offset */
+ offset_offset = builder->fixed_buffer->len;
+
+ /* Length *not* in LE yet */
+ offset = builder->variable_buffer->len;
+ /* Add the offset value */
+ g_byte_array_append (builder->fixed_buffer, (guint8 *)&offset, sizeof (offset));
+ /* Configure the value to get updated */
+ g_array_append_val (builder->offsets, offset_offset);
+
+ /* NOTE: length of the array must be given in a separate variable */
+
+ /* And finally, the array of IPs itself to the variable buffer */
+ g_byte_array_append (builder->variable_buffer, (guint8 *)values, n_values * sizeof (MbimIPv6));
+ }
+}
+
+/*****************************************************************************/
+/* Command message builder interface */
+
+MbimMessageCommandBuilder *
+_mbim_message_command_builder_new (guint32 transaction_id,
+ MbimService service,
+ guint32 cid,
+ MbimMessageCommandType command_type)
+{
+ MbimMessageCommandBuilder *builder;
+
+ builder = g_slice_new (MbimMessageCommandBuilder);
+ builder->message = mbim_message_command_new (transaction_id, service, cid, command_type);
+ builder->contents_builder = _mbim_struct_builder_new ();
+ return builder;
+}
+
+MbimMessage *
+_mbim_message_command_builder_complete (MbimMessageCommandBuilder *builder)
+{
+ MbimMessage *message;
+ GByteArray *contents;
+
+ /* Complete contents, which disposes the builder itself */
+ contents = _mbim_struct_builder_complete (builder->contents_builder);
+
+ /* Merge both buffers */
+ mbim_message_command_append (builder->message,
+ (const guint8 *)contents->data,
+ (guint32)contents->len);
+ g_byte_array_unref (contents);
+
+ /* Steal the message to return */
+ message = builder->message;
+
+ /* Dispose the remaining stuff from the message builder */
+ g_slice_free (MbimMessageCommandBuilder, builder);
+
+ return message;
+}
+
+void
+_mbim_message_command_builder_append_byte_array (MbimMessageCommandBuilder *builder,
+ gboolean with_offset,
+ gboolean with_length,
+ const guint8 *buffer,
+ guint32 buffer_len)
+{
+ _mbim_struct_builder_append_byte_array (builder->contents_builder, with_offset, with_length, buffer, buffer_len);
+}
+
+void
+_mbim_message_command_builder_append_uuid (MbimMessageCommandBuilder *builder,
+ const MbimUuid *value)
+{
+ _mbim_struct_builder_append_uuid (builder->contents_builder, value);
+}
+
+void
+_mbim_message_command_builder_append_guint32 (MbimMessageCommandBuilder *builder,
+ guint32 value)
+{
+ _mbim_struct_builder_append_guint32 (builder->contents_builder, value);
+}
+
+void
+_mbim_message_command_builder_append_guint32_array (MbimMessageCommandBuilder *builder,
+ const guint32 *values,
+ guint32 n_values)
+{
+ _mbim_struct_builder_append_guint32_array (builder->contents_builder, values, n_values);
+}
+
+void
+_mbim_message_command_builder_append_guint64 (MbimMessageCommandBuilder *builder,
+ guint64 value)
+{
+ _mbim_struct_builder_append_guint64 (builder->contents_builder, value);
+}
+
+void
+_mbim_message_command_builder_append_guint64_array (MbimMessageCommandBuilder *builder,
+ const guint64 *values,
+ guint32 n_values)
+{
+ _mbim_struct_builder_append_guint64_array (builder->contents_builder, values, n_values);
+}
+
+void
+_mbim_message_command_builder_append_string (MbimMessageCommandBuilder *builder,
+ const gchar *value)
+{
+ _mbim_struct_builder_append_string (builder->contents_builder, value);
+}
+
+void
+_mbim_message_command_builder_append_string_array (MbimMessageCommandBuilder *builder,
+ const gchar *const *values,
+ guint32 n_values)
+{
+ _mbim_struct_builder_append_string_array (builder->contents_builder, values, n_values);
+}
+
+void
+_mbim_message_command_builder_append_ipv4 (MbimMessageCommandBuilder *builder,
+ const MbimIPv4 *value,
+ gboolean ref)
+{
+ _mbim_struct_builder_append_ipv4 (builder->contents_builder, value, ref);
+}
+
+void
+_mbim_message_command_builder_append_ipv4_array (MbimMessageCommandBuilder *builder,
+ const MbimIPv4 *values,
+ guint32 n_values)
+{
+ _mbim_struct_builder_append_ipv4_array (builder->contents_builder, values, n_values);
+}
+
+void
+_mbim_message_command_builder_append_ipv6 (MbimMessageCommandBuilder *builder,
+ const MbimIPv6 *value,
+ gboolean ref)
+{
+ _mbim_struct_builder_append_ipv6 (builder->contents_builder, value, ref);
+}
+
+void
+_mbim_message_command_builder_append_ipv6_array (MbimMessageCommandBuilder *builder,
+ const MbimIPv6 *values,
+ guint32 n_values)
+{
+ _mbim_struct_builder_append_ipv6_array (builder->contents_builder, values, n_values);
+}
+
+/*****************************************************************************/
+/* Generic message interface */
+
+/**
+ * mbim_message_ref:
+ * @self: a #MbimMessage.
+ *
+ * Atomically increments the reference count of @self by one.
+ *
+ * Returns: (transfer full) the new reference to @self.
+ */
+MbimMessage *
+mbim_message_ref (MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+
+ return (MbimMessage *) g_byte_array_ref ((GByteArray *)self);
+}
+
+/**
+ * mbim_message_unref:
+ * @self: a #MbimMessage.
+ *
+ * Atomically decrements the reference count of @self by one.
+ * If the reference count drops to 0, @self is completely disposed.
+ */
+void
+mbim_message_unref (MbimMessage *self)
+{
+ g_return_if_fail (self != NULL);
+
+ g_byte_array_unref ((GByteArray *)self);
+}
+
+/**
+ * mbim_message_get_message_type:
+ * @self: a #MbimMessage.
+ *
+ * Gets the message type.
+ *
+ * Returns: a #MbimMessageType.
+ */
+MbimMessageType
+mbim_message_get_message_type (const MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, MBIM_MESSAGE_TYPE_INVALID);
+
+ return MBIM_MESSAGE_GET_MESSAGE_TYPE (self);
+}
+
+/**
+ * mbim_message_get_message_length:
+ * @self: a #MbimMessage.
+ *
+ * Gets the whole message length.
+ *
+ * Returns: the length of the message.
+ */
+guint32
+mbim_message_get_message_length (const MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, 0);
+
+ return MBIM_MESSAGE_GET_MESSAGE_LENGTH (self);
+}
+
+/**
+ * mbim_message_get_transaction_id:
+ * @self: a #MbimMessage.
+ *
+ * Gets the transaction ID of the message.
+ *
+ * Returns: the transaction ID.
+ */
+guint32
+mbim_message_get_transaction_id (const MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, 0);
+
+ return MBIM_MESSAGE_GET_TRANSACTION_ID (self);
+}
+
+/**
+ * mbim_message_set_transaction_id:
+ * @self: a #MbimMessage.
+ * @transaction_id: the transaction id.
+ *
+ * Sets the transaction ID of the message.
+ */
+void
+mbim_message_set_transaction_id (MbimMessage *self,
+ guint32 transaction_id)
+{
+ /* Only allow setting transaction ID in host-generated messages */
+ g_return_if_fail (self != NULL);
+ g_return_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_COMMAND ||
+ MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_OPEN ||
+ MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_CLOSE ||
+ MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_HOST_ERROR);
+
+ ((struct header *)(self->data))->transaction_id = GUINT32_TO_LE (transaction_id);
+}
+
+/**
+ * mbim_message_new:
+ * @data: contents of the message.
+ * @data_length: length of the message.
+ *
+ * Create a #MbimMessage with the given contents.
+ *
+ * Returns: (transfer full): a newly created #MbimMessage, which should be freed with mbim_message_unref().
+ */
+MbimMessage *
+mbim_message_new (const guint8 *data,
+ guint32 data_length)
+{
+ GByteArray *out;
+
+ /* Create output MbimMessage */
+ out = g_byte_array_sized_new (data_length);
+ g_byte_array_append (out, data, data_length);
+
+ return (MbimMessage *)out;
+}
+
+/**
+ * mbim_message_dup:
+ * @self: a #MbimMessage to duplicate.
+ *
+ * Create a #MbimMessage with the same contents as @self.
+ *
+ * Returns: (transfer full): a newly created #MbimMessage, which should be freed with mbim_message_unref().
+ */
+MbimMessage *
+mbim_message_dup (const MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+
+ return mbim_message_new (((GByteArray *)self)->data,
+ MBIM_MESSAGE_GET_MESSAGE_LENGTH (self));
+}
+
+/**
+ * mbim_message_get_raw:
+ * @self: a #MbimMessage.
+ * @length: (out): return location for the size of the output buffer.
+ * @error: return location for error or %NULL.
+ *
+ * Gets the whole raw data buffer of the #MbimMessage.
+ *
+ * Returns: (transfer none): The raw data buffer, or #NULL if @error is set.
+ */
+const guint8 *
+mbim_message_get_raw (const MbimMessage *self,
+ guint32 *length,
+ GError **error)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (length != NULL, NULL);
+
+ if (!self->data || !self->len) {
+ g_set_error_literal (error,
+ MBIM_CORE_ERROR,
+ MBIM_CORE_ERROR_FAILED,
+ "Message is empty");
+ return NULL;
+ }
+
+ *length = (guint32) self->len;
+ return self->data;
+}
+
+/**
+ * mbim_message_get_printable:
+ * @self: a #MbimMessage.
+ * @line_prefix: prefix string to use in each new generated line.
+ * @headers_only: %TRUE if only basic headers should be printed.
+ *
+ * Gets a printable string with the contents of the whole MBIM message.
+ *
+ * Returns: (transfer full): a newly allocated string, which should be freed with g_free().
+ */
+gchar *
+mbim_message_get_printable (const MbimMessage *self,
+ const gchar *line_prefix,
+ gboolean headers_only)
+{
+ GString *printable;
+
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (line_prefix != NULL, NULL);
+
+ if (!line_prefix)
+ line_prefix = "";
+
+ printable = g_string_new ("");
+ g_string_append_printf (printable,
+ "%sHeader:\n"
+ "%s length = %u\n"
+ "%s type = %s (0x%08x)\n"
+ "%s transaction = %u\n",
+ line_prefix,
+ line_prefix, MBIM_MESSAGE_GET_MESSAGE_LENGTH (self),
+ line_prefix, mbim_message_type_get_string (MBIM_MESSAGE_GET_MESSAGE_TYPE (self)), MBIM_MESSAGE_GET_MESSAGE_TYPE (self),
+ line_prefix, MBIM_MESSAGE_GET_TRANSACTION_ID (self));
+
+ switch (MBIM_MESSAGE_GET_MESSAGE_TYPE (self)) {
+ case MBIM_MESSAGE_TYPE_INVALID:
+ g_warn_if_reached ();
+ break;
+
+ case MBIM_MESSAGE_TYPE_OPEN:
+ if (!headers_only)
+ g_string_append_printf (printable,
+ "%sContents:\n"
+ "%s max_control_transfer = %u\n",
+ line_prefix,
+ line_prefix, mbim_message_open_get_max_control_transfer (self));
+ break;
+
+ case MBIM_MESSAGE_TYPE_CLOSE:
+ break;
+
+ case MBIM_MESSAGE_TYPE_OPEN_DONE:
+ if (!headers_only) {
+ MbimStatusError status;
+
+ status = mbim_message_open_done_get_status_code (self);
+ g_string_append_printf (printable,
+ "%sContents:\n"
+ "%s status error = '%s' (0x%08x)\n",
+ line_prefix,
+ line_prefix, mbim_status_error_get_string (status), status);
+ }
+ break;
+
+ case MBIM_MESSAGE_TYPE_CLOSE_DONE:
+ if (!headers_only) {
+ MbimStatusError status;
+
+ status = mbim_message_close_done_get_status_code (self);
+ g_string_append_printf (printable,
+ "%sContents:\n"
+ "%s status error = '%s' (0x%08x)\n",
+ line_prefix,
+ line_prefix, mbim_status_error_get_string (status), status);
+ }
+ break;
+
+ case MBIM_MESSAGE_TYPE_HOST_ERROR:
+ case MBIM_MESSAGE_TYPE_FUNCTION_ERROR:
+ if (!headers_only) {
+ MbimProtocolError error;
+
+ error = mbim_message_error_get_error_status_code (self);
+ g_string_append_printf (printable,
+ "%sContents:\n"
+ "%s error = '%s' (0x%08x)\n",
+ line_prefix,
+ line_prefix, mbim_protocol_error_get_string (error), error);
+ }
+ break;
+
+ case MBIM_MESSAGE_TYPE_COMMAND:
+ g_string_append_printf (printable,
+ "%sFragment header:\n"
+ "%s total = %u\n"
+ "%s current = %u\n",
+ line_prefix,
+ line_prefix, _mbim_message_fragment_get_total (self),
+ line_prefix, _mbim_message_fragment_get_current (self));
+ if (!headers_only) {
+ gchar *uuid_printable;
+ const gchar *cid_printable;
+
+ uuid_printable = mbim_uuid_get_printable (mbim_message_command_get_service_id (self));
+ cid_printable = mbim_cid_get_printable (mbim_message_command_get_service (self),
+ mbim_message_command_get_cid (self));
+ g_string_append_printf (printable,
+ "%sContents:\n"
+ "%s service = '%s' (%s)\n"
+ "%s cid = '%s' (0x%08x)\n"
+ "%s type = '%s' (0x%08x)\n",
+ line_prefix,
+ line_prefix, mbim_service_get_string (mbim_message_command_get_service (self)), uuid_printable,
+ line_prefix, cid_printable, mbim_message_command_get_cid (self),
+ line_prefix, mbim_message_command_type_get_string (mbim_message_command_get_command_type (self)), mbim_message_command_get_command_type (self));
+ g_free (uuid_printable);
+ }
+ break;
+
+ case MBIM_MESSAGE_TYPE_COMMAND_DONE:
+ g_string_append_printf (printable,
+ "%sFragment header:\n"
+ "%s total = %u\n"
+ "%s current = %u\n",
+ line_prefix,
+ line_prefix, _mbim_message_fragment_get_total (self),
+ line_prefix, _mbim_message_fragment_get_current (self));
+ if (!headers_only) {
+ gchar *uuid_printable;
+ MbimStatusError status;
+ const gchar *cid_printable;
+
+ status = mbim_message_command_done_get_status_code (self);
+ uuid_printable = mbim_uuid_get_printable (mbim_message_command_done_get_service_id (self));
+ cid_printable = mbim_cid_get_printable (mbim_message_command_done_get_service (self),
+ mbim_message_command_done_get_cid (self));
+ g_string_append_printf (printable,
+ "%sContents:\n"
+ "%s status error = '%s' (0x%08x)\n"
+ "%s service = '%s' (%s)\n"
+ "%s cid = '%s' (0x%08x)\n",
+ line_prefix,
+ line_prefix, mbim_status_error_get_string (status), status,
+ line_prefix, mbim_service_get_string (mbim_message_command_done_get_service (self)), uuid_printable,
+ line_prefix, cid_printable, mbim_message_command_done_get_cid (self));
+ g_free (uuid_printable);
+ }
+ break;
+
+ case MBIM_MESSAGE_TYPE_INDICATE_STATUS:
+ g_string_append_printf (printable,
+ "%sFragment header:\n"
+ "%s total = %u\n"
+ "%s current = %u\n",
+ line_prefix,
+ line_prefix, _mbim_message_fragment_get_total (self),
+ line_prefix, _mbim_message_fragment_get_current (self));
+ if (!headers_only) {
+ gchar *uuid_printable;
+ const gchar *cid_printable;
+
+ uuid_printable = mbim_uuid_get_printable (mbim_message_indicate_status_get_service_id (self));
+ cid_printable = mbim_cid_get_printable (mbim_message_indicate_status_get_service (self),
+ mbim_message_indicate_status_get_cid (self));
+ g_string_append_printf (printable,
+ "%sContents:\n"
+ "%s service = '%s' (%s)\n"
+ "%s cid = '%s' (0x%08x)\n",
+ line_prefix,
+ line_prefix, mbim_service_get_string (mbim_message_indicate_status_get_service (self)), uuid_printable,
+ line_prefix, cid_printable, mbim_message_indicate_status_get_cid (self));
+ g_free (uuid_printable);
+ }
+ break;
+ }
+
+ return g_string_free (printable, FALSE);
+}
+
+/*****************************************************************************/
+/* Fragment interface */
+
+#define MBIM_MESSAGE_IS_FRAGMENT(self) \
+ (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_COMMAND || \
+ MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_COMMAND_DONE || \
+ MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_INDICATE_STATUS)
+
+#define MBIM_MESSAGE_FRAGMENT_GET_TOTAL(self) \
+ GUINT32_FROM_LE (((struct full_message *)(self->data))->message.fragment.fragment_header.total)
+
+#define MBIM_MESSAGE_FRAGMENT_GET_CURRENT(self) \
+ GUINT32_FROM_LE (((struct full_message *)(self->data))->message.fragment.fragment_header.current)
+
+
+gboolean
+_mbim_message_is_fragment (const MbimMessage *self)
+{
+ return MBIM_MESSAGE_IS_FRAGMENT (self);
+}
+
+guint32
+_mbim_message_fragment_get_total (const MbimMessage *self)
+{
+ g_assert (MBIM_MESSAGE_IS_FRAGMENT (self));
+
+ return MBIM_MESSAGE_FRAGMENT_GET_TOTAL (self);
+}
+
+guint32
+_mbim_message_fragment_get_current (const MbimMessage *self)
+{
+ g_assert (MBIM_MESSAGE_IS_FRAGMENT (self));
+
+ return MBIM_MESSAGE_FRAGMENT_GET_CURRENT (self);
+}
+
+const guint8 *
+_mbim_message_fragment_get_payload (const MbimMessage *self,
+ guint32 *length)
+{
+ g_assert (MBIM_MESSAGE_IS_FRAGMENT (self));
+
+ *length = (MBIM_MESSAGE_GET_MESSAGE_LENGTH (self) - \
+ sizeof (struct header) - \
+ sizeof (struct fragment_header));
+ return ((struct full_message *)(self->data))->message.fragment.buffer;
+}
+
+MbimMessage *
+_mbim_message_fragment_collector_init (const MbimMessage *fragment,
+ GError **error)
+{
+ g_assert (MBIM_MESSAGE_IS_FRAGMENT (fragment));
+
+ /* Collector must start with fragment #0 */
+ if (MBIM_MESSAGE_FRAGMENT_GET_CURRENT (fragment) != 0) {
+ g_set_error (error,
+ MBIM_PROTOCOL_ERROR,
+ MBIM_PROTOCOL_ERROR_FRAGMENT_OUT_OF_SEQUENCE,
+ "Expecting fragment '0/%u', got '%u/%u'",
+ MBIM_MESSAGE_FRAGMENT_GET_TOTAL (fragment),
+ MBIM_MESSAGE_FRAGMENT_GET_CURRENT (fragment),
+ MBIM_MESSAGE_FRAGMENT_GET_TOTAL (fragment));
+ return NULL;
+ }
+
+ return mbim_message_dup (fragment);
+}
+
+gboolean
+_mbim_message_fragment_collector_add (MbimMessage *self,
+ const MbimMessage *fragment,
+ GError **error)
+{
+ guint32 buffer_len;
+ const guint8 *buffer;
+
+ g_assert (MBIM_MESSAGE_IS_FRAGMENT (self));
+ g_assert (MBIM_MESSAGE_IS_FRAGMENT (fragment));
+
+ /* We can only add a fragment if it is the next one we're expecting.
+ * Otherwise, we return an error. */
+ if (MBIM_MESSAGE_FRAGMENT_GET_CURRENT (self) != (MBIM_MESSAGE_FRAGMENT_GET_CURRENT (fragment) - 1)) {
+ g_set_error (error,
+ MBIM_PROTOCOL_ERROR,
+ MBIM_PROTOCOL_ERROR_FRAGMENT_OUT_OF_SEQUENCE,
+ "Expecting fragment '%u/%u', got '%u/%u'",
+ MBIM_MESSAGE_FRAGMENT_GET_CURRENT (self) + 1,
+ MBIM_MESSAGE_FRAGMENT_GET_TOTAL (self),
+ MBIM_MESSAGE_FRAGMENT_GET_CURRENT (fragment),
+ MBIM_MESSAGE_FRAGMENT_GET_TOTAL (fragment));
+ return FALSE;
+ }
+
+ buffer = _mbim_message_fragment_get_payload (fragment, &buffer_len);
+ if (buffer_len) {
+ /* Concatenate information buffers */
+ g_byte_array_append ((GByteArray *)self, buffer, buffer_len);
+ /* Update the whole message length */
+ ((struct header *)(self->data))->length =
+ GUINT32_TO_LE (MBIM_MESSAGE_GET_MESSAGE_LENGTH (self) + buffer_len);
+ }
+
+ /* Update the current fragment info in the main message; skip endian changes */
+ ((struct full_message *)(self->data))->message.fragment.fragment_header.current =
+ ((struct full_message *)(fragment->data))->message.fragment.fragment_header.current;
+
+ return TRUE;
+}
+
+gboolean
+_mbim_message_fragment_collector_complete (MbimMessage *self)
+{
+ g_assert (MBIM_MESSAGE_IS_FRAGMENT (self));
+
+ if (MBIM_MESSAGE_FRAGMENT_GET_CURRENT (self) != (MBIM_MESSAGE_FRAGMENT_GET_TOTAL (self) - 1))
+ /* Not complete yet */
+ return FALSE;
+
+ /* Reset current & total */
+ ((struct full_message *)(self->data))->message.fragment.fragment_header.current = 0;
+ ((struct full_message *)(self->data))->message.fragment.fragment_header.total = GUINT32_TO_LE (1);
+ return TRUE;
+}
+
+struct fragment_info *
+_mbim_message_split_fragments (const MbimMessage *self,
+ guint32 max_fragment_size,
+ guint *n_fragments)
+{
+ GArray *array;
+ guint32 total_message_length;
+ guint32 total_payload_length;
+ guint32 fragment_header_length;
+ guint32 fragment_payload_length;
+ guint32 total_fragments;
+ guint i;
+ const guint8 *data;
+ guint32 data_length;
+
+ /* A message which is longer than the maximum fragment size needs to be
+ * split in different fragments before sending it. */
+
+ total_message_length = mbim_message_get_message_length (self);
+
+ /* If a single fragment is enough, don't try to split */
+ if (total_message_length <= max_fragment_size)
+ return NULL;
+
+ /* Total payload length is the total length minus the headers of the
+ * input message */
+ fragment_header_length = sizeof (struct header) + sizeof (struct fragment_header);
+ total_payload_length = total_message_length - fragment_header_length;
+
+ /* Fragment payload length is the maximum amount of data that can fit in a
+ * single fragment */
+ fragment_payload_length = max_fragment_size - fragment_header_length;
+
+ /* We can now compute the number of fragments that we'll get */
+ total_fragments = total_payload_length / fragment_payload_length;
+ if (total_payload_length % fragment_payload_length)
+ total_fragments++;
+
+ array = g_array_sized_new (FALSE,
+ FALSE,
+ sizeof (struct fragment_info),
+ total_fragments);
+
+ /* Initialize data walkers */
+ data = ((struct full_message *)(((GByteArray *)self)->data))->message.fragment.buffer;
+ data_length = total_payload_length;
+
+ /* Create fragment infos */
+ for (i = 0; i < total_fragments; i++) {
+ struct fragment_info info;
+
+ /* Set data info */
+ info.data = data;
+ info.data_length = (data_length > fragment_payload_length ? fragment_payload_length : data_length);
+
+ /* Set header info */
+ info.header.type = GUINT32_TO_LE (MBIM_MESSAGE_GET_MESSAGE_TYPE (self));
+ info.header.length = GUINT32_TO_LE (fragment_header_length + info.data_length);
+ info.header.transaction_id = GUINT32_TO_LE (MBIM_MESSAGE_GET_TRANSACTION_ID (self));
+ info.fragment_header.total = GUINT32_TO_LE (total_fragments);
+ info.fragment_header.current = GUINT32_TO_LE (i);
+
+ g_array_insert_val (array, i, info);
+
+ /* Update walkers */
+ data = &data[info.data_length];
+ data_length -= info.data_length;
+ }
+
+ g_warn_if_fail (data_length == 0);
+
+ *n_fragments = total_fragments;
+ return (struct fragment_info *) g_array_free (array, FALSE);
+}
+
+/*****************************************************************************/
+/* 'Open' message interface */
+
+/**
+ * mbim_message_open_new:
+ * @transaction_id: transaction ID.
+ * @max_control_transfer: maximum control transfer.
+ *
+ * Create a new #MbimMessage of type %MBIM_MESSAGE_TYPE_OPEN with the specified
+ * parameters.
+ *
+ * Returns: (transfer full): a newly created #MbimMessage. The returned value
+ * should be freed with mbim_message_unref().
+ */
+MbimMessage *
+mbim_message_open_new (guint32 transaction_id,
+ guint32 max_control_transfer)
+{
+ GByteArray *self;
+
+ self = _mbim_message_allocate (MBIM_MESSAGE_TYPE_OPEN,
+ transaction_id,
+ sizeof (struct open_message));
+
+ /* Open header */
+ ((struct full_message *)(self->data))->message.open.max_control_transfer = GUINT32_TO_LE (max_control_transfer);
+
+ return (MbimMessage *)self;
+}
+
+/**
+ * mbim_message_open_get_max_control_transfer:
+ * @self: a #MbimMessage.
+ *
+ * Get the maximum control transfer set to be used in the #MbimMessage of type
+ * %MBIM_MESSAGE_TYPE_OPEN.
+ *
+ * Returns: the maximum control transfer.
+ */
+guint32
+mbim_message_open_get_max_control_transfer (const MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, 0);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_OPEN, 0);
+
+ return GUINT32_FROM_LE (((struct full_message *)(self->data))->message.open.max_control_transfer);
+}
+
+/*****************************************************************************/
+/* 'Open Done' message interface */
+
+/**
+ * mbim_message_open_done_get_status_code:
+ * @self: a #MbimMessage.
+ *
+ * Get status code from the %MBIM_MESSAGE_TYPE_OPEN_DONE message.
+ *
+ * Returns: a #MbimStatusError.
+ */
+MbimStatusError
+mbim_message_open_done_get_status_code (const MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, MBIM_STATUS_ERROR_FAILURE);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_OPEN_DONE, MBIM_STATUS_ERROR_FAILURE);
+
+ return (MbimStatusError) GUINT32_FROM_LE (((struct full_message *)(self->data))->message.open_done.status_code);
+}
+
+/**
+ * mbim_message_open_done_get_result:
+ * @self: a #MbimMessage.
+ * @error: return location for error or %NULL.
+ *
+ * Gets the result of the 'Open' operation in the %MBIM_MESSAGE_TYPE_OPEN_DONE message.
+ *
+ * Returns: %TRUE if the operation succeeded, %FALSE if @error is set.
+ */
+gboolean
+mbim_message_open_done_get_result (const MbimMessage *self,
+ GError **error)
+{
+ MbimStatusError status;
+
+ g_return_val_if_fail (self != NULL, FALSE);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_OPEN_DONE, FALSE);
+
+ status = (MbimStatusError) GUINT32_FROM_LE (((struct full_message *)(self->data))->message.open_done.status_code);
+ if (status == MBIM_STATUS_ERROR_NONE)
+ return TRUE;
+
+ g_set_error_literal (error,
+ MBIM_STATUS_ERROR,
+ status,
+ mbim_status_error_get_string (status));
+ return FALSE;
+}
+
+/*****************************************************************************/
+/* 'Close' message interface */
+
+/**
+ * mbim_message_close_new:
+ * @transaction_id: transaction ID.
+ *
+ * Create a new #MbimMessage of type %MBIM_MESSAGE_TYPE_CLOSE with the specified
+ * parameters.
+ *
+ * Returns: (transfer full): a newly created #MbimMessage. The returned value
+ * should be freed with mbim_message_unref().
+ */
+MbimMessage *
+mbim_message_close_new (guint32 transaction_id)
+{
+ return (MbimMessage *) _mbim_message_allocate (MBIM_MESSAGE_TYPE_CLOSE,
+ transaction_id,
+ 0);
+}
+
+/*****************************************************************************/
+/* 'Close Done' message interface */
+
+/**
+ * mbim_message_close_done_get_status_code:
+ * @self: a #MbimMessage.
+ *
+ * Get status code from the %MBIM_MESSAGE_TYPE_CLOSE_DONE message.
+ *
+ * Returns: a #MbimStatusError.
+ */
+MbimStatusError
+mbim_message_close_done_get_status_code (const MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, MBIM_STATUS_ERROR_FAILURE);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_CLOSE_DONE, MBIM_STATUS_ERROR_FAILURE);
+
+ return (MbimStatusError) GUINT32_FROM_LE (((struct full_message *)(self->data))->message.close_done.status_code);
+}
+
+/**
+ * mbim_message_close_done_get_result:
+ * @self: a #MbimMessage.
+ * @error: return location for error or %NULL.
+ *
+ * Gets the result of the 'Close' operation in the %MBIM_MESSAGE_TYPE_CLOSE_DONE message.
+ *
+ * Returns: %TRUE if the operation succeeded, %FALSE if @error is set.
+ */
+gboolean
+mbim_message_close_done_get_result (const MbimMessage *self,
+ GError **error)
+{
+ MbimStatusError status;
+
+ g_return_val_if_fail (self != NULL, FALSE);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_CLOSE_DONE, FALSE);
+
+ status = (MbimStatusError) GUINT32_FROM_LE (((struct full_message *)(self->data))->message.close_done.status_code);
+ if (status == MBIM_STATUS_ERROR_NONE)
+ return TRUE;
+
+ g_set_error_literal (error,
+ MBIM_STATUS_ERROR,
+ status,
+ mbim_status_error_get_string (status));
+ return FALSE;
+}
+
+/*****************************************************************************/
+/* 'Error' message interface */
+
+/**
+ * mbim_message_error_new:
+ * @transaction_id: transaction ID.
+ * @error_status_code: a #MbimProtocolError.
+ *
+ * Create a new #MbimMessage of type %MBIM_MESSAGE_TYPE_HOST_ERROR with the specified
+ * parameters.
+ *
+ * Returns: (transfer full): a newly created #MbimMessage. The returned value
+ * should be freed with mbim_message_unref().
+ */
+MbimMessage *
+mbim_message_error_new (guint32 transaction_id,
+ MbimProtocolError error_status_code)
+{
+ GByteArray *self;
+
+ self = _mbim_message_allocate (MBIM_MESSAGE_TYPE_HOST_ERROR,
+ transaction_id,
+ sizeof (struct open_message));
+
+ /* Open header */
+ ((struct full_message *)(self->data))->message.error.error_status_code = GUINT32_TO_LE (error_status_code);
+
+ return (MbimMessage *)self;
+}
+
+/**
+ * mbim_message_error_get_error_status_code:
+ * @self: a #MbimMessage.
+ *
+ * Get the error code in a %MBIM_MESSAGE_TYPE_HOST_ERROR or
+ * %MBIM_MESSAGE_TYPE_FUNCTION_ERROR message.
+ *
+ * Returns: a #MbimProtocolError.
+ */
+MbimProtocolError
+mbim_message_error_get_error_status_code (const MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, MBIM_PROTOCOL_ERROR_INVALID);
+ g_return_val_if_fail ((MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_HOST_ERROR ||
+ MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_FUNCTION_ERROR),
+ MBIM_PROTOCOL_ERROR_INVALID);
+
+ return (MbimProtocolError) GUINT32_FROM_LE (((struct full_message *)(self->data))->message.error.error_status_code);
+}
+
+/**
+ * mbim_message_error_get_error:
+ * @self: a #MbimMessage.
+ *
+ * Get the error in a %MBIM_MESSAGE_TYPE_HOST_ERROR or
+ * %MBIM_MESSAGE_TYPE_FUNCTION_ERROR message.
+ *
+ * Returns: a newly allocated #GError, which should be freed with g_error_free().
+ */
+GError *
+mbim_message_error_get_error (const MbimMessage *self)
+{
+ MbimProtocolError error_status_code;
+
+
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail ((MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_HOST_ERROR ||
+ MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_FUNCTION_ERROR),
+ NULL);
+
+ error_status_code = (MbimProtocolError) GUINT32_FROM_LE (((struct full_message *)(self->data))->message.error.error_status_code);
+
+ return g_error_new (MBIM_PROTOCOL_ERROR,
+ error_status_code,
+ "MBIM protocol error: %s",
+ mbim_protocol_error_get_string (error_status_code));
+}
+
+/*****************************************************************************/
+/* 'Command' message interface */
+
+/**
+ * mbim_message_command_new:
+ * @transaction_id: transaction ID.
+ * @service: a #MbimService.
+ * @cid: the command ID.
+ * @command_type: the command type.
+ *
+ * Create a new #MbimMessage of type %MBIM_MESSAGE_TYPE_COMMAND with the
+ * specified parameters and an empty information buffer.
+ *
+ * Returns: (transfer full): a newly created #MbimMessage. The returned value
+ * should be freed with mbim_message_unref().
+ */
+MbimMessage *
+mbim_message_command_new (guint32 transaction_id,
+ MbimService service,
+ guint32 cid,
+ MbimMessageCommandType command_type)
+{
+ GByteArray *self;
+ const MbimUuid *service_id;
+
+ /* Known service required */
+ g_return_val_if_fail (service > MBIM_SERVICE_INVALID, FALSE);
+ g_return_val_if_fail (service <= MBIM_SERVICE_DSS, FALSE);
+ service_id = mbim_uuid_from_service (service);
+
+ self = _mbim_message_allocate (MBIM_MESSAGE_TYPE_COMMAND,
+ transaction_id,
+ sizeof (struct command_message));
+
+ /* Fragment header */
+ ((struct full_message *)(self->data))->message.command.fragment_header.total = GUINT32_TO_LE (1);
+ ((struct full_message *)(self->data))->message.command.fragment_header.current = 0;
+
+ /* Command header */
+ memcpy (((struct full_message *)(self->data))->message.command.service_id, service_id, sizeof (*service_id));
+ ((struct full_message *)(self->data))->message.command.command_id = GUINT32_TO_LE (cid);
+ ((struct full_message *)(self->data))->message.command.command_type = GUINT32_TO_LE (command_type);
+ ((struct full_message *)(self->data))->message.command.buffer_length = 0;
+
+ return (MbimMessage *)self;
+}
+
+/**
+ * mbim_message_command_append:
+ * @self: a #MbimMessage.
+ * @buffer: raw buffer to append to the message.
+ * @buffer_size: length of the data in @buffer.
+ *
+ * Appends the contents of @buffer to @self.
+ */
+void
+mbim_message_command_append (MbimMessage *self,
+ const guint8 *buffer,
+ guint32 buffer_size)
+{
+ g_byte_array_append ((GByteArray *)self, buffer, buffer_size);
+
+ /* Update message and buffer length */
+ ((struct header *)(self->data))->length =
+ GUINT32_TO_LE (MBIM_MESSAGE_GET_MESSAGE_LENGTH (self) + buffer_size);
+ ((struct full_message *)(self->data))->message.command.buffer_length =
+ GUINT32_TO_LE (GUINT32_FROM_LE (((struct full_message *)(self->data))->message.command.buffer_length) + buffer_size);
+}
+
+/**
+ * mbim_message_command_get_service:
+ * @self: a #MbimMessage.
+ *
+ * Get the service of a %MBIM_MESSAGE_TYPE_COMMAND message.
+ *
+ * Returns: a #MbimService.
+ */
+MbimService
+mbim_message_command_get_service (const MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, MBIM_SERVICE_INVALID);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_COMMAND, MBIM_SERVICE_INVALID);
+
+ return mbim_uuid_to_service ((const MbimUuid *)&(((struct full_message *)(self->data))->message.command.service_id));
+}
+
+/**
+ * mbim_message_command_get_service_id:
+ * @self: a #MbimMessage.
+ *
+ * Get the service UUID of a %MBIM_MESSAGE_TYPE_COMMAND message.
+ *
+ * Returns: a #MbimUuid.
+ */
+const MbimUuid *
+mbim_message_command_get_service_id (const MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, MBIM_UUID_INVALID);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_COMMAND, MBIM_UUID_INVALID);
+
+ return (const MbimUuid *)&(((struct full_message *)(self->data))->message.command.service_id);
+}
+
+/**
+ * mbim_message_command_get_cid:
+ * @self: a #MbimMessage.
+ *
+ * Get the command id of a %MBIM_MESSAGE_TYPE_COMMAND message.
+ *
+ * Returns: a CID.
+ */
+guint32
+mbim_message_command_get_cid (const MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, 0);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_COMMAND, 0);
+
+ return GUINT32_FROM_LE (((struct full_message *)(self->data))->message.command.command_id);
+}
+
+/**
+ * mbim_message_command_get_command_type:
+ * @self: a #MbimMessage.
+ *
+ * Get the command type of a %MBIM_MESSAGE_TYPE_COMMAND message.
+ *
+ * Returns: a #MbimMessageCommandType.
+ */
+MbimMessageCommandType
+mbim_message_command_get_command_type (const MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, MBIM_MESSAGE_COMMAND_TYPE_UNKNOWN);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_COMMAND, MBIM_MESSAGE_COMMAND_TYPE_UNKNOWN);
+
+ return (MbimMessageCommandType) GUINT32_FROM_LE (((struct full_message *)(self->data))->message.command.command_type);
+}
+
+/**
+ * mbim_message_command_get_raw_information_buffer:
+ * @self: a #MbimMessage.
+ * @length: (out): return location for the size of the output buffer.
+ *
+ * Gets the information buffer of the %MBIM_MESSAGE_TYPE_COMMAND message.
+ *
+ * Returns: (transfer none): The raw data buffer, or #NULL if empty.
+ */
+const guint8 *
+mbim_message_command_get_raw_information_buffer (const MbimMessage *self,
+ guint32 *length)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (length != NULL, NULL);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_COMMAND, NULL);
+
+ *length = GUINT32_FROM_LE (((struct full_message *)(self->data))->message.command.buffer_length);
+
+ return (*length > 0 ?
+ ((struct full_message *)(self->data))->message.command.buffer :
+ NULL);
+}
+
+/*****************************************************************************/
+/* 'Command Done' message interface */
+
+/**
+ * mbim_message_command_done_get_service:
+ * @self: a #MbimMessage.
+ *
+ * Get the service of a %MBIM_MESSAGE_TYPE_COMMAND_DONE message.
+ *
+ * Returns: a #MbimService.
+ */
+MbimService
+mbim_message_command_done_get_service (const MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, MBIM_SERVICE_INVALID);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_COMMAND_DONE, MBIM_SERVICE_INVALID);
+
+ return mbim_uuid_to_service ((const MbimUuid *)&(((struct full_message *)(self->data))->message.command_done.service_id));
+}
+
+/**
+ * mbim_message_command_done_get_service_id:
+ * @self: a #MbimMessage.
+ *
+ * Get the service UUID of a %MBIM_MESSAGE_TYPE_COMMAND_DONE message.
+ *
+ * Returns: a #MbimUuid.
+ */
+const MbimUuid *
+mbim_message_command_done_get_service_id (const MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, MBIM_UUID_INVALID);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_COMMAND_DONE, MBIM_UUID_INVALID);
+
+ return (const MbimUuid *)&(((struct full_message *)(self->data))->message.command_done.service_id);
+}
+
+/**
+ * mbim_message_command_done_get_cid:
+ * @self: a #MbimMessage.
+ *
+ * Get the command id of a %MBIM_MESSAGE_TYPE_COMMAND_DONE message.
+ *
+ * Returns: a CID.
+ */
+guint32
+mbim_message_command_done_get_cid (const MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, 0);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_COMMAND_DONE, 0);
+
+ return GUINT32_FROM_LE (((struct full_message *)(self->data))->message.command_done.command_id);
+}
+
+/**
+ * mbim_message_command_done_get_status_code:
+ * @self: a #MbimMessage.
+ *
+ * Get status code from the %MBIM_MESSAGE_TYPE_COMMAND_DONE message.
+ *
+ * Returns: a #MbimStatusError.
+ */
+MbimStatusError
+mbim_message_command_done_get_status_code (const MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, MBIM_STATUS_ERROR_FAILURE);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_COMMAND_DONE, MBIM_STATUS_ERROR_FAILURE);
+
+ return (MbimStatusError) GUINT32_FROM_LE (((struct full_message *)(self->data))->message.command_done.status_code);
+}
+
+/**
+ * mbim_message_command_done_get_result:
+ * @self: a #MbimMessage.
+ * @error: return location for error or %NULL.
+ *
+ * Gets the result of the 'Command' operation in the %MBIM_MESSAGE_TYPE_COMMAND_DONE message.
+ *
+ * Returns: %TRUE if the operation succeeded, %FALSE if @error is set.
+ */
+gboolean
+mbim_message_command_done_get_result (const MbimMessage *self,
+ GError **error)
+{
+ MbimStatusError status;
+
+ g_return_val_if_fail (self != NULL, FALSE);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_COMMAND_DONE, FALSE);
+
+ status = (MbimStatusError) GUINT32_FROM_LE (((struct full_message *)(self->data))->message.command_done.status_code);
+ if (status == MBIM_STATUS_ERROR_NONE)
+ return TRUE;
+
+ g_set_error_literal (error,
+ MBIM_STATUS_ERROR,
+ status,
+ mbim_status_error_get_string (status));
+ return FALSE;
+}
+
+/**
+ * mbim_message_command_done_get_raw_information_buffer:
+ * @self: a #MbimMessage.
+ * @length: (out): return location for the size of the output buffer.
+ *
+ * Gets the information buffer of the %MBIM_MESSAGE_TYPE_COMMAND_DONE message.
+ *
+ * Returns: (transfer none): The raw data buffer, or #NULL if empty.
+ */
+const guint8 *
+mbim_message_command_done_get_raw_information_buffer (const MbimMessage *self,
+ guint32 *length)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_COMMAND_DONE, NULL);
+ g_return_val_if_fail (length != NULL, NULL);
+
+ *length = GUINT32_FROM_LE (((struct full_message *)(self->data))->message.command_done.buffer_length);
+
+ return (*length > 0 ?
+ ((struct full_message *)(self->data))->message.command_done.buffer :
+ NULL);
+}
+
+/*****************************************************************************/
+/* 'Indicate Status' message interface */
+
+/**
+ * mbim_message_indicate_status_get_service:
+ * @self: a #MbimMessage.
+ *
+ * Get the service of a %MBIM_MESSAGE_TYPE_INDICATE_STATUS message.
+ *
+ * Returns: a #MbimService.
+ */
+MbimService
+mbim_message_indicate_status_get_service (const MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, MBIM_SERVICE_INVALID);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_INDICATE_STATUS, MBIM_SERVICE_INVALID);
+
+ return mbim_uuid_to_service ((const MbimUuid *)&(((struct full_message *)(self->data))->message.indicate_status.service_id));
+}
+
+/**
+ * mbim_message_indicate_status_get_service_id:
+ * @self: a #MbimMessage.
+ *
+ * Get the service UUID of a %MBIM_MESSAGE_TYPE_INDICATE_STATUS message.
+ *
+ * Returns: a #MbimUuid.
+ */
+const MbimUuid *
+mbim_message_indicate_status_get_service_id (const MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, MBIM_UUID_INVALID);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_INDICATE_STATUS, MBIM_UUID_INVALID);
+
+ return (const MbimUuid *)&(((struct full_message *)(self->data))->message.indicate_status.service_id);
+}
+
+/**
+ * mbim_message_indicate_status_get_cid:
+ * @self: a #MbimMessage.
+ *
+ * Get the command id of a %MBIM_MESSAGE_TYPE_INDICATE_STATUS message.
+ *
+ * Returns: a CID.
+ */
+guint32
+mbim_message_indicate_status_get_cid (const MbimMessage *self)
+{
+ g_return_val_if_fail (self != NULL, 0);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_INDICATE_STATUS, 0);
+
+ return GUINT32_FROM_LE (((struct full_message *)(self->data))->message.indicate_status.command_id);
+}
+
+/**
+ * mbim_message_indicate_status_get_raw_information_buffer:
+ * @self: a #MbimMessage.
+ * @length: (out): return location for the size of the output buffer.
+ *
+ * Gets the information buffer of the %MBIM_MESSAGE_TYPE_INDICATE_STATUS message.
+ *
+ * Returns: (transfer none): The raw data buffer, or #NULL if empty.
+ */
+const guint8 *
+mbim_message_indicate_status_get_raw_information_buffer (const MbimMessage *self,
+ guint32 *length)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (MBIM_MESSAGE_GET_MESSAGE_TYPE (self) == MBIM_MESSAGE_TYPE_INDICATE_STATUS, NULL);
+ g_return_val_if_fail (length != NULL, NULL);
+
+ *length = GUINT32_FROM_LE (((struct full_message *)(self->data))->message.indicate_status.buffer_length);
+
+ return (*length > 0 ?
+ ((struct full_message *)(self->data))->message.indicate_status.buffer :
+ NULL);
+}
diff --git a/libmbim-glib/mbim-message.h b/libmbim-glib/mbim-message.h
new file mode 100644
index 0000000..d5ac8e5
--- /dev/null
+++ b/libmbim-glib/mbim-message.h
@@ -0,0 +1,213 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/*
+ * libmbim-glib -- GLib/GIO based library to control MBIM devices
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#ifndef _LIBMBIM_GLIB_MBIM_MESSAGE_H_
+#define _LIBMBIM_GLIB_MBIM_MESSAGE_H_
+
+#if !defined (__LIBMBIM_GLIB_H_INSIDE__) && !defined (LIBMBIM_GLIB_COMPILATION)
+#error "Only <libmbim-glib.h> can be included directly."
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "mbim-uuid.h"
+#include "mbim-errors.h"
+
+G_BEGIN_DECLS
+
+/**
+ * MbimMessage:
+ *
+ * An opaque type representing a MBIM message.
+ */
+typedef struct _MbimMessage MbimMessage;
+
+GType mbim_message_get_type (void) G_GNUC_CONST;
+#define MBIM_TYPE_MESSAGE (mbim_message_get_type ())
+
+/**
+ * MbimIPv4:
+ * @addr: 4 bytes specifying the IPv4 address.
+ *
+ * An IPv4 address.
+ */
+typedef struct _MbimIPv4 MbimIPv4;
+struct _MbimIPv4 {
+ guint8 addr[4];
+};
+
+/**
+ * MbimIPv6:
+ * @addr: 16 bytes specifying the IPv6 address.
+ *
+ * An IPv6 address.
+ */
+typedef struct _MbimIPv6 MbimIPv6;
+struct _MbimIPv6 {
+ guint8 addr[16];
+};
+
+/**
+ * MbimMessageType:
+ * @MBIM_MESSAGE_TYPE_INVALID: Invalid MBIM message.
+ * @MBIM_MESSAGE_TYPE_OPEN: Initialization request.
+ * @MBIM_MESSAGE_TYPE_CLOSE: Close request.
+ * @MBIM_MESSAGE_TYPE_COMMAND: Command request.
+ * @MBIM_MESSAGE_TYPE_HOST_ERROR: Host-reported error in the communication.
+ * @MBIM_MESSAGE_TYPE_OPEN_DONE: Response to initialization request.
+ * @MBIM_MESSAGE_TYPE_CLOSE_DONE: Response to close request.
+ * @MBIM_MESSAGE_TYPE_COMMAND_DONE: Response to command request.
+ * @MBIM_MESSAGE_TYPE_FUNCTION_ERROR: Function-reported error in the communication.
+ * @MBIM_MESSAGE_TYPE_INDICATE_STATUS: Unsolicited message from the function.
+ *
+ * Type of MBIM messages.
+ */
+typedef enum {
+ MBIM_MESSAGE_TYPE_INVALID = 0x00000000,
+ /* From Host to Function */
+ MBIM_MESSAGE_TYPE_OPEN = 0x00000001,
+ MBIM_MESSAGE_TYPE_CLOSE = 0x00000002,
+ MBIM_MESSAGE_TYPE_COMMAND = 0x00000003,
+ MBIM_MESSAGE_TYPE_HOST_ERROR = 0x00000004,
+ /* From Function to Host */
+ MBIM_MESSAGE_TYPE_OPEN_DONE = 0x80000001,
+ MBIM_MESSAGE_TYPE_CLOSE_DONE = 0x80000002,
+ MBIM_MESSAGE_TYPE_COMMAND_DONE = 0x80000003,
+ MBIM_MESSAGE_TYPE_FUNCTION_ERROR = 0x80000004,
+ MBIM_MESSAGE_TYPE_INDICATE_STATUS = 0x80000007
+} MbimMessageType;
+
+/*****************************************************************************/
+/* Generic message interface */
+
+MbimMessage *mbim_message_new (const guint8 *data,
+ guint32 data_length);
+MbimMessage *mbim_message_dup (const MbimMessage *self);
+MbimMessage *mbim_message_ref (MbimMessage *self);
+void mbim_message_unref (MbimMessage *self);
+
+gchar *mbim_message_get_printable (const MbimMessage *self,
+ const gchar *line_prefix,
+ gboolean headers_only);
+const guint8 *mbim_message_get_raw (const MbimMessage *self,
+ guint32 *length,
+ GError **error);
+
+MbimMessageType mbim_message_get_message_type (const MbimMessage *self);
+guint32 mbim_message_get_message_length (const MbimMessage *self);
+guint32 mbim_message_get_transaction_id (const MbimMessage *self);
+
+void mbim_message_set_transaction_id (MbimMessage *self,
+ guint32 transaction_id);
+
+/*****************************************************************************/
+/* 'Open' message interface */
+
+MbimMessage *mbim_message_open_new (guint32 transaction_id,
+ guint32 max_control_transfer);
+guint32 mbim_message_open_get_max_control_transfer (const MbimMessage *self);
+
+/*****************************************************************************/
+/* 'Open Done' message interface */
+
+MbimStatusError mbim_message_open_done_get_status_code (const MbimMessage *self);
+gboolean mbim_message_open_done_get_result (const MbimMessage *self,
+ GError **error);
+
+/*****************************************************************************/
+/* 'Close' message interface */
+
+MbimMessage *mbim_message_close_new (guint32 transaction_id);
+
+/*****************************************************************************/
+/* 'Close Done' message interface */
+
+MbimStatusError mbim_message_close_done_get_status_code (const MbimMessage *self);
+gboolean mbim_message_close_done_get_result (const MbimMessage *self,
+ GError **error);
+
+/*****************************************************************************/
+/* 'Error' message interface */
+
+MbimMessage *mbim_message_error_new (guint32 transaction_id,
+ MbimProtocolError error_status_code);
+MbimProtocolError mbim_message_error_get_error_status_code (const MbimMessage *self);
+GError *mbim_message_error_get_error (const MbimMessage *self);
+
+/*****************************************************************************/
+/* 'Command' message interface */
+
+/**
+ * MbimMessageCommandType:
+ * @MBIM_MESSAGE_COMMAND_TYPE_UNKNOWN: Unknown type.
+ * @MBIM_MESSAGE_COMMAND_TYPE_QUERY: Query command.
+ * @MBIM_MESSAGE_COMMAND_TYPE_SET: Set command.
+ *
+ * Type of command message.
+ */
+typedef enum {
+ MBIM_MESSAGE_COMMAND_TYPE_UNKNOWN = -1,
+ MBIM_MESSAGE_COMMAND_TYPE_QUERY = 0,
+ MBIM_MESSAGE_COMMAND_TYPE_SET = 1
+} MbimMessageCommandType;
+
+MbimMessage *mbim_message_command_new (guint32 transaction_id,
+ MbimService service,
+ guint32 cid,
+ MbimMessageCommandType command_type);
+void mbim_message_command_append (MbimMessage *self,
+ const guint8 *buffer,
+ guint32 buffer_size);
+
+MbimService mbim_message_command_get_service (const MbimMessage *self);
+const MbimUuid *mbim_message_command_get_service_id (const MbimMessage *self);
+guint32 mbim_message_command_get_cid (const MbimMessage *self);
+MbimMessageCommandType mbim_message_command_get_command_type (const MbimMessage *self);
+const guint8 *mbim_message_command_get_raw_information_buffer (const MbimMessage *self,
+ guint32 *length);
+
+/*****************************************************************************/
+/* 'Command Done' message interface */
+
+MbimService mbim_message_command_done_get_service (const MbimMessage *self);
+const MbimUuid *mbim_message_command_done_get_service_id (const MbimMessage *self);
+guint32 mbim_message_command_done_get_cid (const MbimMessage *self);
+MbimStatusError mbim_message_command_done_get_status_code (const MbimMessage *self);
+gboolean mbim_message_command_done_get_result (const MbimMessage *self,
+ GError **error);
+const guint8 *mbim_message_command_done_get_raw_information_buffer (const MbimMessage *self,
+ guint32 *length);
+
+/*****************************************************************************/
+/* 'Indicate Status' message interface */
+
+MbimService mbim_message_indicate_status_get_service (const MbimMessage *self);
+const MbimUuid *mbim_message_indicate_status_get_service_id (const MbimMessage *self);
+guint32 mbim_message_indicate_status_get_cid (const MbimMessage *self);
+const guint8 *mbim_message_indicate_status_get_raw_information_buffer (const MbimMessage *self,
+ guint32 *length);
+
+G_END_DECLS
+
+#endif /* _LIBMBIM_GLIB_MBIM_MESSAGE_H_ */
diff --git a/libmbim-glib/mbim-utils.c b/libmbim-glib/mbim-utils.c
new file mode 100644
index 0000000..e2220c0
--- /dev/null
+++ b/libmbim-glib/mbim-utils.c
@@ -0,0 +1,102 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/*
+ * libmbim-glib -- GLib/GIO based library to control MBIM devices
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2013 Aleksander Morgado <aleksander@lanedo.com>
+ */
+
+#include <config.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "mbim-utils.h"
+
+/**
+ * SECTION:mbim-utils
+ * @title: Common utilities
+ *
+ * This section exposes a set of common utilities that may be used to work
+ * with the MBIM library.
+ **/
+
+/*****************************************************************************/
+
+gchar *
+__mbim_utils_str_hex (gconstpointer mem,
+ gsize size,
+ gchar delimiter)
+{
+ const guint8 *data = mem;
+ gsize i;
+ gsize j;
+ gsize new_str_length;
+ gchar *new_str;
+
+ /* Get new string length. If input string has N bytes, we need:
+ * - 1 byte for last NUL char
+ * - 2N bytes for hexadecimal char representation of each byte...
+ * - N-1 bytes for the separator ':'
+ * So... a total of (1+2N+N-1) = 3N bytes are needed... */
+ new_str_length = 3 * size;
+
+ /* Allocate memory for new array and initialize contents to NUL */
+ new_str = g_malloc0 (new_str_length);
+
+ /* Print hexadecimal representation of each byte... */
+ for (i = 0, j = 0; i < size; i++, j += 3) {
+ /* Print character in output string... */
+ snprintf (&new_str[j], 3, "%02X", data[i]);
+ /* And if needed, add separator */
+ if (i != (size - 1) )
+ new_str[j + 2] = delimiter;
+ }
+
+ /* Set output string */
+ return new_str;
+}
+
+/*****************************************************************************/
+
+static volatile gint __traces_enabled = FALSE;
+
+/**
+ * mbim_utils_get_traces_enabled:
+ *
+ * Checks whether MBIM message traces are currently enabled.
+ *
+ * Returns: %TRUE if traces are enabled, %FALSE otherwise.
+ */
+gboolean
+mbim_utils_get_traces_enabled (void)
+{
+ return (gboolean) g_atomic_int_get (&__traces_enabled);
+}
+
+/**
+ * mbim_utils_set_traces_enabled:
+ * @enabled: %TRUE to enable traces, %FALSE to disable them.
+ *
+ * Sets whether MBIM message traces are enabled or disabled.
+ */
+void
+mbim_utils_set_traces_enabled (gboolean enabled)
+{
+ g_atomic_int_set (&__traces_enabled, enabled);
+}
diff --git a/libmbim-glib/mbim-utils.h b/libmbim-glib/mbim-utils.h
new file mode 100644
index 0000000..ec477e8
--- /dev/null
+++ b/libmbim-glib/mbim-utils.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/*
+ * libmbim-glib -- GLib/GIO based library to control MBIM devices
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2013 Aleksander Morgado <aleksander@lanedo.com>
+ */
+
+#ifndef _LIBMBIM_GLIB_MBIM_UTILS_H_
+#define _LIBMBIM_GLIB_MBIM_UTILS_H_
+
+#if !defined (__LIBMBIM_GLIB_H_INSIDE__) && !defined (LIBMBIM_GLIB_COMPILATION)
+#error "Only <libmbim-glib.h> can be included directly."
+#endif
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+/* Enabling/Disabling traces */
+gboolean mbim_utils_get_traces_enabled (void);
+void mbim_utils_set_traces_enabled (gboolean enabled);
+
+/* Other private methods */
+
+#if defined (LIBMBIM_GLIB_COMPILATION)
+gchar *__mbim_utils_str_hex (gconstpointer mem,
+ gsize size,
+ gchar delimiter);
+#endif
+
+G_END_DECLS
+
+#endif /* _LIBMBIM_GLIB_MBIM_UTILS_H_ */
diff --git a/libmbim-glib/mbim-uuid.c b/libmbim-glib/mbim-uuid.c
new file mode 100644
index 0000000..7c7160e
--- /dev/null
+++ b/libmbim-glib/mbim-uuid.c
@@ -0,0 +1,373 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/*
+ * libmbim-glib -- GLib/GIO based library to control MBIM devices
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "mbim-uuid.h"
+
+/**
+ * SECTION: mbim-uuid
+ * @title: UUIDs
+ *
+ * This section defines the data type for unique identifiers.
+ */
+
+/*****************************************************************************/
+
+/**
+ * mbim_uuid_cmp:
+ * @a: a #MbimUuid.
+ * @b: a #MbimUuid.
+ *
+ * Compare two %MbimUuid values.
+ *
+ * Returns: %TRUE if @a and @b are equal, %FALSE otherwise.
+ */
+gboolean
+mbim_uuid_cmp (const MbimUuid *a,
+ const MbimUuid *b)
+{
+ return (memcmp (a, b, sizeof (*a)) == 0);
+}
+
+/**
+ * mbim_uuid_get_printable:
+ * @uuid: a #MbimUuid.
+ *
+ * Get a string with the UUID.
+ *
+ * Returns: (transfer full): a newly allocated string, which should be freed with g_free().
+ */
+gchar *
+mbim_uuid_get_printable (const MbimUuid *uuid)
+
+{
+ return (g_strdup_printf (
+ "%02x%02x%02x%02x-"
+ "%02x%02x-"
+ "%02x%02x-"
+ "%02x%02x-"
+ "%02x%02x%02x%02x%02x%02x",
+ uuid->a[0], uuid->a[1], uuid->a[2], uuid->a[3],
+ uuid->b[0], uuid->b[1],
+ uuid->c[0], uuid->c[1],
+ uuid->d[0], uuid->d[1],
+ uuid->e[0], uuid->e[1], uuid->e[2], uuid->e[3], uuid->e[4], uuid->e[5]));
+}
+
+/*****************************************************************************/
+
+static const MbimUuid uuid_invalid = {
+ .a = { 0x00, 0x00, 0x00, 0x00 },
+ .b = { 0x00, 0x00 },
+ .c = { 0x00, 0x00 },
+ .d = { 0x00, 0x00 },
+ .e = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+};
+
+static const MbimUuid uuid_basic_connect = {
+ .a = { 0xa2, 0x89, 0xcc, 0x33 },
+ .b = { 0xbc, 0xbb },
+ .c = { 0x8b, 0x4f },
+ .d = { 0xb6, 0xb0 },
+ .e = { 0x13, 0x3e, 0xc2, 0xaa, 0xe6, 0xdf }
+};
+
+static const MbimUuid uuid_sms = {
+ .a = { 0x53, 0x3f, 0xbe, 0xeb },
+ .b = { 0x14, 0xfe },
+ .c = { 0x44, 0x67 },
+ .d = { 0x9f, 0x90 },
+ .e = { 0x33, 0xa2, 0x23, 0xe5, 0x6c, 0x3f }
+};
+
+static const MbimUuid uuid_ussd = {
+ .a = { 0xe5, 0x50, 0xa0, 0xc8 },
+ .b = { 0x5e, 0x82 },
+ .c = { 0x47, 0x9e },
+ .d = { 0x82, 0xf7 },
+ .e = { 0x10, 0xab, 0xf4, 0xc3, 0x35, 0x1f }
+};
+
+static const MbimUuid uuid_phonebook = {
+ .a = { 0x4b, 0xf3, 0x84, 0x76 },
+ .b = { 0x1e, 0x6a },
+ .c = { 0x41, 0xdb },
+ .d = { 0xb1, 0xd8 },
+ .e = { 0xbe, 0xd2, 0x89, 0xc2, 0x5b, 0xdb }
+};
+
+static const MbimUuid uuid_stk = {
+ .a = { 0xd8, 0xf2, 0x01, 0x31 },
+ .b = { 0xfc, 0xb5 },
+ .c = { 0x4e, 0x17 },
+ .d = { 0x86, 0x02 },
+ .e = { 0xd6, 0xed, 0x38, 0x16, 0x16, 0x4c }
+};
+
+static const MbimUuid uuid_auth = {
+ .a = { 0x1d, 0x2b, 0x5f, 0xf7 },
+ .b = { 0x0a, 0xa1 },
+ .c = { 0x48, 0xb2 },
+ .d = { 0xaa, 0x52 },
+ .e = { 0x50, 0xf1, 0x57, 0x67, 0x17, 0x4e }
+};
+
+static const MbimUuid uuid_dss = {
+ .a = { 0xc0, 0x8a, 0x26, 0xdd },
+ .b = { 0x77, 0x18 },
+ .c = { 0x43, 0x82 },
+ .d = { 0x84, 0x82 },
+ .e = { 0x6e, 0x0d, 0x58, 0x3c, 0x4d, 0x0e }
+};
+
+/**
+ * mbim_uuid_from_service:
+ * @service: a #MbimService.
+ *
+ * Get the UUID corresponding to @service.
+ *
+ * Returns: (transfer none): a #MbimUuid.
+ */
+const MbimUuid *
+mbim_uuid_from_service (MbimService service)
+{
+ g_return_val_if_fail (service >= MBIM_SERVICE_INVALID && service <= MBIM_SERVICE_DSS,
+ &uuid_invalid);
+
+ switch (service) {
+ case MBIM_SERVICE_INVALID:
+ return &uuid_invalid;
+ case MBIM_SERVICE_BASIC_CONNECT:
+ return &uuid_basic_connect;
+ case MBIM_SERVICE_SMS:
+ return &uuid_sms;
+ case MBIM_SERVICE_USSD:
+ return &uuid_ussd;
+ case MBIM_SERVICE_PHONEBOOK:
+ return &uuid_phonebook;
+ case MBIM_SERVICE_STK:
+ return &uuid_stk;
+ case MBIM_SERVICE_AUTH:
+ return &uuid_auth;
+ case MBIM_SERVICE_DSS:
+ return &uuid_dss;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+/**
+ * mbim_uuid_to_service:
+ * @uuid: a #MbimUuid.
+ *
+ * Get the service corresponding to @uuid.
+ *
+ * Returns: a #MbimService.
+ */
+MbimService
+mbim_uuid_to_service (const MbimUuid *uuid)
+{
+ if (mbim_uuid_cmp (uuid, &uuid_basic_connect))
+ return MBIM_SERVICE_BASIC_CONNECT;
+
+ if (mbim_uuid_cmp (uuid, &uuid_sms))
+ return MBIM_SERVICE_SMS;
+
+ if (mbim_uuid_cmp (uuid, &uuid_ussd))
+ return MBIM_SERVICE_USSD;
+
+ if (mbim_uuid_cmp (uuid, &uuid_phonebook))
+ return MBIM_SERVICE_PHONEBOOK;
+
+ if (mbim_uuid_cmp (uuid, &uuid_stk))
+ return MBIM_SERVICE_STK;
+
+ if (mbim_uuid_cmp (uuid, &uuid_auth))
+ return MBIM_SERVICE_AUTH;
+
+ if (mbim_uuid_cmp (uuid, &uuid_dss))
+ return MBIM_SERVICE_DSS;
+
+ return MBIM_SERVICE_INVALID;
+}
+
+/*****************************************************************************/
+
+static const MbimUuid uuid_context_type_none = {
+ .a = { 0xB4, 0x3F, 0x75, 0x8C },
+ .b = { 0xA5, 0x60 },
+ .c = { 0x4B, 0x46 },
+ .d = { 0xB3, 0x5E },
+ .e = { 0xC5, 0x86, 0x96, 0x41, 0xFB, 0x54 }
+};
+
+static const MbimUuid uuid_context_type_internet = {
+ .a = { 0x7E, 0x5E, 0x2A, 0x7E },
+ .b = { 0x4E, 0x6F },
+ .c = { 0x72, 0x72 },
+ .d = { 0x73, 0x6B },
+ .e = { 0x65, 0x6E, 0x7E, 0x5E, 0x2A, 0x7E }
+};
+
+static const MbimUuid uuid_context_type_vpn = {
+ .a = { 0x9B, 0x9F, 0x7B, 0xBE },
+ .b = { 0x89, 0x52 },
+ .c = { 0x44, 0xB7 },
+ .d = { 0x83, 0xAC },
+ .e = { 0xCA, 0x41, 0x31, 0x8D, 0xF7, 0xA0 }
+};
+
+static const MbimUuid uuid_context_type_voice = {
+ .a = { 0x88, 0x91, 0x82, 0x94 },
+ .b = { 0x0E, 0xF4 },
+ .c = { 0x43, 0x96 },
+ .d = { 0x8C, 0xCA },
+ .e = { 0xA8, 0x58, 0x8F, 0xBC, 0x02, 0xB2 }
+};
+
+static const MbimUuid uuid_context_type_video_share = {
+ .a = { 0x05, 0xA2, 0xA7, 0x16 },
+ .b = { 0x7C, 0x34 },
+ .c = { 0x4B, 0x4D },
+ .d = { 0x9A, 0x91 },
+ .e = { 0xC5, 0xEF, 0x0C, 0x7A, 0xAA, 0xCC }
+};
+
+static const MbimUuid uuid_context_type_purchase = {
+ .a = { 0xB3, 0x27, 0x24, 0x96 },
+ .b = { 0xAC, 0x6C },
+ .c = { 0x42, 0x2B },
+ .d = { 0xA8, 0xC0 },
+ .e = { 0xAC, 0xF6, 0x87, 0xA2, 0x72, 0x17 }
+};
+
+static const MbimUuid uuid_context_type_ims = {
+ .a = { 0x21, 0x61, 0x0D, 0x01 },
+ .b = { 0x30, 0x74 },
+ .c = { 0x4B, 0xCE },
+ .d = { 0x94, 0x25 },
+ .e = { 0xB5, 0x3A, 0x07, 0xD6, 0x97, 0xD6 }
+};
+
+static const MbimUuid uuid_context_type_mms = {
+ .a = { 0x46, 0x72, 0x66, 0x64 },
+ .b = { 0x72, 0x69 },
+ .c = { 0x6B, 0xC6 },
+ .d = { 0x96, 0x24 },
+ .e = { 0xD1, 0xD3, 0x53, 0x89, 0xAC, 0xA9 }
+};
+
+static const MbimUuid uuid_context_type_local = {
+ .a = { 0xA5, 0x7A, 0x9A, 0xFC },
+ .b = { 0xB0, 0x9F },
+ .c = { 0x45, 0xD7 },
+ .d = { 0xBB, 0x40 },
+ .e = { 0x03, 0x3C, 0x39, 0xF6, 0x0D, 0xB9 }
+};
+
+/**
+ * mbim_uuid_from_context_type:
+ * @context_type: a #MbimContextType.
+ *
+ * Get the UUID corresponding to @context_type.
+ *
+ * Returns: (transfer none): a #MbimUuid.
+ */
+const MbimUuid *
+mbim_uuid_from_context_type (MbimContextType context_type)
+{
+ g_return_val_if_fail (context_type >= MBIM_CONTEXT_TYPE_INVALID && context_type <= MBIM_CONTEXT_TYPE_LOCAL,
+ &uuid_invalid);
+
+ switch (context_type) {
+ case MBIM_CONTEXT_TYPE_INVALID:
+ return &uuid_invalid;
+ case MBIM_CONTEXT_TYPE_NONE:
+ return &uuid_context_type_none;
+ case MBIM_CONTEXT_TYPE_INTERNET:
+ return &uuid_context_type_internet;
+ case MBIM_CONTEXT_TYPE_VPN:
+ return &uuid_context_type_vpn;
+ case MBIM_CONTEXT_TYPE_VOICE:
+ return &uuid_context_type_none;
+ case MBIM_CONTEXT_TYPE_VIDEO_SHARE:
+ return &uuid_context_type_video_share;
+ case MBIM_CONTEXT_TYPE_PURCHASE:
+ return &uuid_context_type_purchase;
+ case MBIM_CONTEXT_TYPE_IMS:
+ return &uuid_context_type_ims;
+ case MBIM_CONTEXT_TYPE_MMS:
+ return &uuid_context_type_mms;
+ case MBIM_CONTEXT_TYPE_LOCAL:
+ return &uuid_context_type_local;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+/**
+ * mbim_uuid_to_context_type:
+ * @uuid: a #MbimUuid.
+ *
+ * Get the context type corresponding to @uuid.
+ *
+ * Returns: a #MbimContextType.
+ */
+MbimContextType
+mbim_uuid_to_context_type (const MbimUuid *uuid)
+{
+ if (mbim_uuid_cmp (uuid, &uuid_dss))
+ return MBIM_SERVICE_DSS;
+
+ if (mbim_uuid_cmp (uuid, &uuid_context_type_none))
+ return MBIM_CONTEXT_TYPE_NONE;
+
+ if (mbim_uuid_cmp (uuid, &uuid_context_type_internet))
+ return MBIM_CONTEXT_TYPE_INTERNET;
+
+ if (mbim_uuid_cmp (uuid, &uuid_context_type_vpn))
+ return MBIM_CONTEXT_TYPE_VPN;
+
+ if (mbim_uuid_cmp (uuid, &uuid_context_type_voice))
+ return MBIM_CONTEXT_TYPE_VOICE;
+
+ if (mbim_uuid_cmp (uuid, &uuid_context_type_video_share))
+ return MBIM_CONTEXT_TYPE_VIDEO_SHARE;
+
+ if (mbim_uuid_cmp (uuid, &uuid_context_type_purchase))
+ return MBIM_CONTEXT_TYPE_PURCHASE;
+
+ if (mbim_uuid_cmp (uuid, &uuid_context_type_ims))
+ return MBIM_CONTEXT_TYPE_IMS;
+
+ if (mbim_uuid_cmp (uuid, &uuid_context_type_mms))
+ return MBIM_CONTEXT_TYPE_MMS;
+
+ if (mbim_uuid_cmp (uuid, &uuid_context_type_local))
+ return MBIM_CONTEXT_TYPE_LOCAL;
+
+ return MBIM_CONTEXT_TYPE_INVALID;
+}
diff --git a/libmbim-glib/mbim-uuid.h b/libmbim-glib/mbim-uuid.h
new file mode 100644
index 0000000..0676861
--- /dev/null
+++ b/libmbim-glib/mbim-uuid.h
@@ -0,0 +1,195 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/*
+ * libmbim-glib -- GLib/GIO based library to control MBIM devices
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#ifndef _LIBMBIM_GLIB_MBIM_UUID_H_
+#define _LIBMBIM_GLIB_MBIM_UUID_H_
+
+#if !defined (__LIBMBIM_GLIB_H_INSIDE__) && !defined (LIBMBIM_GLIB_COMPILATION)
+#error "Only <libmbim-glib.h> can be included directly."
+#endif
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+/*****************************************************************************/
+
+/**
+ * MbimUuid:
+ *
+ * A UUID as defined in MBIM.
+ */
+typedef struct _MbimUuid MbimUuid;
+#define MBIM_PACKED __attribute__((__packed__))
+struct MBIM_PACKED _MbimUuid {
+ guint8 a[4];
+ guint8 b[2];
+ guint8 c[2];
+ guint8 d[2];
+ guint8 e[6];
+};
+#undef MBIM_PACKED
+
+gboolean mbim_uuid_cmp (const MbimUuid *a,
+ const MbimUuid *b);
+gchar *mbim_uuid_get_printable (const MbimUuid *uuid);
+
+/*****************************************************************************/
+
+/**
+ * MbimService:
+ * @MBIM_SERVICE_INVALID: Invalid service.
+ * @MBIM_SERVICE_BASIC_CONNECT: Basic connectivity service.
+ * @MBIM_SERVICE_SMS: SMS messaging service.
+ * @MBIM_SERVICE_USSD: USSD service.
+ * @MBIM_SERVICE_PHONEBOOK: Phonebook service.
+ * @MBIM_SERVICE_STK: SIM toolkit service.
+ * @MBIM_SERVICE_AUTH: Authentication service.
+ * @MBIM_SERVICE_DSS: Device Service Stream service.
+ *
+ * Enumeration of the generic MBIM services.
+ */
+typedef enum {
+ MBIM_SERVICE_INVALID = 0,
+ MBIM_SERVICE_BASIC_CONNECT = 1,
+ MBIM_SERVICE_SMS = 2,
+ MBIM_SERVICE_USSD = 3,
+ MBIM_SERVICE_PHONEBOOK = 4,
+ MBIM_SERVICE_STK = 5,
+ MBIM_SERVICE_AUTH = 6,
+ MBIM_SERVICE_DSS = 7,
+} MbimService;
+
+/**
+ * MBIM_UUID_INVALID:
+ *
+ * Get the UUID of the %MBIM_SERVICE_INVALID service.
+ *
+ * Returns: (transfer none): a #MbimUuid.
+ */
+#define MBIM_UUID_INVALID mbim_uuid_from_service (MBIM_SERVICE_INVALID)
+
+/**
+ * MBIM_UUID_BASIC_CONNECT:
+ *
+ * Get the UUID of the %MBIM_SERVICE_BASIC_CONNECT service.
+ *
+ * Returns: (transfer none): a #MbimUuid.
+ */
+#define MBIM_UUID_BASIC_CONNECT mbim_uuid_from_service (MBIM_SERVICE_BASIC_CONNECT)
+
+/**
+ * MBIM_UUID_SMS:
+ *
+ * Get the UUID of the %MBIM_SERVICE_SMS service.
+ *
+ * Returns: (transfer none): a #MbimUuid.
+ */
+#define MBIM_UUID_SMS mbim_uuid_from_service (MBIM_SERVICE_SMS)
+
+/**
+ * MBIM_UUID_USSD:
+ *
+ * Get the UUID of the %MBIM_SERVICE_USSD service.
+ *
+ * Returns: (transfer none): a #MbimUuid.
+ */
+#define MBIM_UUID_USSD mbim_uuid_from_service (MBIM_SERVICE_USSD)
+
+/**
+ * MBIM_UUID_PHONEBOOK:
+ *
+ * Get the UUID of the %MBIM_SERVICE_PHONEBOOK service.
+ *
+ * Returns: (transfer none): a #MbimUuid.
+ */
+#define MBIM_UUID_PHONEBOOK mbim_uuid_from_service (MBIM_SERVICE_PHONEBOOK)
+
+/**
+ * MBIM_UUID_STK:
+ *
+ * Get the UUID of the %MBIM_SERVICE_STK service.
+ *
+ * Returns: (transfer none): a #MbimUuid.
+ */
+#define MBIM_UUID_STK mbim_uuid_from_service (MBIM_SERVICE_STK)
+
+/**
+ * MBIM_UUID_AUTH:
+ *
+ * Get the UUID of the %MBIM_SERVICE_AUTH service.
+ *
+ * Returns: (transfer none): a #MbimUuid.
+ */
+#define MBIM_UUID_AUTH mbim_uuid_from_service (MBIM_SERVICE_AUTH)
+
+/**
+ * MBIM_UUID_DSS:
+ *
+ * Get the UUID of the %MBIM_SERVICE_DSS service.
+ *
+ * Returns: (transfer none): a #MbimUuid.
+ */
+#define MBIM_UUID_DSS mbim_uuid_from_service (MBIM_SERVICE_DSS)
+
+/* To/From service */
+const MbimUuid *mbim_uuid_from_service (MbimService service);
+MbimService mbim_uuid_to_service (const MbimUuid *uuid);
+
+/*****************************************************************************/
+
+/**
+ * MbimContextType:
+ * @MBIM_CONTEXT_TYPE_INVALID: Invalid context type.
+ * @MBIM_CONTEXT_TYPE_NONE: Context not yet provisioned.
+ * @MBIM_CONTEXT_TYPE_INTERNET: Connection to the Internet.
+ * @MBIM_CONTEXT_TYPE_VPN: Connection to a VPN.
+ * @MBIM_CONTEXT_TYPE_VOICE: Connection to a VoIP service.
+ * @MBIM_CONTEXT_TYPE_VIDEO_SHARE: Connection to a video sharing service.
+ * @MBIM_CONTEXT_TYPE_PURCHASE: Connection to an over-the-air activation site.
+ * @MBIM_CONTEXT_TYPE_IMS: Connection to IMS.
+ * @MBIM_CONTEXT_TYPE_MMS: Connection to MMS.
+ * @MBIM_CONTEXT_TYPE_LOCAL: A local.
+ *
+ * Enumeration of the generic MBIM context types.
+ */
+typedef enum {
+ MBIM_CONTEXT_TYPE_INVALID = 0,
+ MBIM_CONTEXT_TYPE_NONE = 1,
+ MBIM_CONTEXT_TYPE_INTERNET = 2,
+ MBIM_CONTEXT_TYPE_VPN = 3,
+ MBIM_CONTEXT_TYPE_VOICE = 4,
+ MBIM_CONTEXT_TYPE_VIDEO_SHARE = 5,
+ MBIM_CONTEXT_TYPE_PURCHASE = 6,
+ MBIM_CONTEXT_TYPE_IMS = 7,
+ MBIM_CONTEXT_TYPE_MMS = 8,
+ MBIM_CONTEXT_TYPE_LOCAL = 9,
+} MbimContextType;
+
+/* To/From context type */
+const MbimUuid *mbim_uuid_from_context_type (MbimContextType context_type);
+MbimContextType mbim_uuid_to_context_type (const MbimUuid *uuid);
+
+G_END_DECLS
+
+#endif /* _LIBMBIM_GLIB_MBIM_UUID_H_ */
diff --git a/libmbim-glib/mbim-version.h.in b/libmbim-glib/mbim-version.h.in
new file mode 100644
index 0000000..23debda
--- /dev/null
+++ b/libmbim-glib/mbim-version.h.in
@@ -0,0 +1,69 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2013 Lanedo GmbH
+ */
+
+#ifndef _MBIM_VERSION_H_
+#define _MBIM_VERSION_H_
+
+/**
+ * SECTION:mbim-version
+ * @short_description: Version information in the API.
+ *
+ * This section defines types that are used to identify the libmbim-glib version.
+ **/
+
+/**
+ * MBIM_MAJOR_VERSION:
+ *
+ * Evaluates to the major version number of libmbim-glib which this source
+ * is compiled against.
+ */
+#define MBIM_MAJOR_VERSION (@MBIM_MAJOR_VERSION@)
+
+/**
+ * MBIM_MINOR_VERSION:
+ *
+ * Evaluates to the minor version number of libmbim-glib which this source
+ * is compiled against.
+ */
+#define MBIM_MINOR_VERSION (@MBIM_MINOR_VERSION@)
+
+/**
+ * MBIM_MICRO_VERSION:
+ *
+ * Evaluates to the micro version number of libmbim-glib which this source
+ * compiled against.
+ */
+#define MBIM_MICRO_VERSION (@MBIM_MICRO_VERSION@)
+
+/**
+ * MBIM_CHECK_VERSION:
+ * @major: major version (e.g. 1 for version 1.2.5)
+ * @minor: minor version (e.g. 2 for version 1.2.5)
+ * @micro: micro version (e.g. 5 for version 1.2.5)
+ *
+ * Returns: %TRUE if the version of the libmbim-glib header files
+ * is the same as or newer than the passed-in version.
+ */
+#define MBIM_CHECK_VERSION(major,minor,micro) \
+ (MBIM_MAJOR_VERSION > (major) || \
+ (MBIM_MAJOR_VERSION == (major) && MBIM_MINOR_VERSION > (minor)) || \
+ (MBIM_MAJOR_VERSION == (major) && MBIM_MINOR_VERSION == (minor) && MBIM_MICRO_VERSION >= (micro)))
+
+#endif /* _MBIM_VERSION_H_ */
diff --git a/libmbim-glib/test/Makefile.am b/libmbim-glib/test/Makefile.am
new file mode 100644
index 0000000..4177491
--- /dev/null
+++ b/libmbim-glib/test/Makefile.am
@@ -0,0 +1,86 @@
+include $(top_srcdir)/gtester.make
+
+noinst_PROGRAMS = \
+ test-uuid \
+ test-cid \
+ test-message \
+ test-fragment \
+ test-message-parser \
+ test-message-builder
+
+TEST_PROGS += $(noinst_PROGRAMS)
+
+
+test_uuid_SOURCES = \
+ test-uuid.c
+test_uuid_CPPFLAGS = \
+ $(LIBMBIM_GLIB_CFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libmbim-glib \
+ -I$(top_builddir)/libmbim-glib \
+ -DLIBMBIM_GLIB_COMPILATION
+test_uuid_LDADD = \
+ $(top_builddir)/libmbim-glib/libmbim-glib.la \
+ $(LIBMBIM_GLIB_LIBS)
+
+test_cid_SOURCES = \
+ test-cid.c
+test_cid_CPPFLAGS = \
+ $(LIBMBIM_GLIB_CFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libmbim-glib \
+ -I$(top_builddir)/libmbim-glib \
+ -DLIBMBIM_GLIB_COMPILATION
+test_cid_LDADD = \
+ $(top_builddir)/libmbim-glib/libmbim-glib.la \
+ $(LIBMBIM_GLIB_LIBS)
+
+test_message_SOURCES = \
+ test-message.c
+test_message_CPPFLAGS = \
+ $(LIBMBIM_GLIB_CFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libmbim-glib \
+ -I$(top_builddir)/libmbim-glib \
+ -DLIBMBIM_GLIB_COMPILATION
+test_message_LDADD = \
+ $(top_builddir)/libmbim-glib/libmbim-glib.la \
+ $(LIBMBIM_GLIB_LIBS)
+
+test_fragment_SOURCES = \
+ test-fragment.c
+test_fragment_CPPFLAGS = \
+ $(LIBMBIM_GLIB_CFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libmbim-glib \
+ -I$(top_builddir)/libmbim-glib \
+ -DLIBMBIM_GLIB_COMPILATION
+test_fragment_LDADD = \
+ $(top_builddir)/libmbim-glib/libmbim-glib.la \
+ $(LIBMBIM_GLIB_LIBS)
+
+test_message_parser_SOURCES = \
+ test-message-parser.c
+test_message_parser_CPPFLAGS = \
+ $(LIBMBIM_GLIB_CFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libmbim-glib \
+ -I$(top_builddir)/libmbim-glib \
+ -I$(top_builddir)/libmbim-glib/generated \
+ -DLIBMBIM_GLIB_COMPILATION
+test_message_parser_LDADD = \
+ $(top_builddir)/libmbim-glib/libmbim-glib.la \
+ $(LIBMBIM_GLIB_LIBS)
+
+test_message_builder_SOURCES = \
+ test-message-builder.c
+test_message_builder_CPPFLAGS = \
+ $(LIBMBIM_GLIB_CFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libmbim-glib \
+ -I$(top_builddir)/libmbim-glib \
+ -I$(top_builddir)/libmbim-glib/generated \
+ -DLIBMBIM_GLIB_COMPILATION
+test_message_builder_LDADD = \
+ $(top_builddir)/libmbim-glib/libmbim-glib.la \
+ $(LIBMBIM_GLIB_LIBS)
diff --git a/libmbim-glib/test/test-cid.c b/libmbim-glib/test/test-cid.c
new file mode 100644
index 0000000..ffb6837
--- /dev/null
+++ b/libmbim-glib/test/test-cid.c
@@ -0,0 +1,121 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#include <config.h>
+
+#include "mbim-cid.h"
+
+static void
+test_common (MbimService service,
+ guint cid,
+ gboolean can_set,
+ gboolean can_query,
+ gboolean can_notify)
+{
+ g_assert (mbim_cid_can_set (service, cid) == can_set);
+ g_assert (mbim_cid_can_query (service, cid) == can_query);
+ g_assert (mbim_cid_can_notify (service, cid) == can_notify);
+}
+
+static void
+test_cid_basic_connect (void)
+{
+ test_common (MBIM_SERVICE_BASIC_CONNECT,
+ MBIM_CID_BASIC_CONNECT_DEVICE_CAPS,
+ FALSE, TRUE, FALSE);
+
+ test_common (MBIM_SERVICE_BASIC_CONNECT,
+ MBIM_CID_BASIC_CONNECT_MULTICARRIER_PROVIDERS,
+ TRUE, TRUE, TRUE);
+}
+
+static void
+test_cid_sms (void)
+{
+ test_common (MBIM_SERVICE_SMS,
+ MBIM_CID_SMS_CONFIGURATION,
+ TRUE, TRUE, TRUE);
+
+ test_common (MBIM_SERVICE_SMS,
+ MBIM_CID_SMS_MESSAGE_STORE_STATUS,
+ FALSE, TRUE, TRUE);
+}
+
+static void
+test_cid_ussd (void)
+{
+ test_common (MBIM_SERVICE_USSD,
+ MBIM_CID_USSD,
+ TRUE, FALSE, TRUE);
+}
+
+static void
+test_cid_phonebook (void)
+{
+ test_common (MBIM_SERVICE_PHONEBOOK,
+ MBIM_CID_PHONEBOOK_CONFIGURATION,
+ FALSE, TRUE, TRUE);
+
+ test_common (MBIM_SERVICE_PHONEBOOK,
+ MBIM_CID_PHONEBOOK_WRITE,
+ TRUE, FALSE, FALSE);
+}
+
+static void
+test_cid_stk (void)
+{
+ test_common (MBIM_SERVICE_STK,
+ MBIM_CID_STK_PAC,
+ TRUE, TRUE, TRUE);
+
+ test_common (MBIM_SERVICE_STK,
+ MBIM_CID_STK_ENVELOPE,
+ TRUE, TRUE, FALSE);
+}
+
+static void
+test_cid_auth (void)
+{
+ test_common (MBIM_SERVICE_AUTH,
+ MBIM_CID_AUTH_AKA,
+ FALSE, TRUE, FALSE);
+
+ test_common (MBIM_SERVICE_AUTH,
+ MBIM_CID_AUTH_SIM,
+ FALSE, TRUE, FALSE);
+}
+
+static void
+test_cid_dss (void)
+{
+ test_common (MBIM_SERVICE_DSS,
+ MBIM_CID_DSS_CONNECT,
+ TRUE, FALSE, FALSE);
+}
+
+int main (int argc, char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/libmbim-glib/cid/basic-connect", test_cid_basic_connect);
+ g_test_add_func ("/libmbim-glib/cid/sms", test_cid_sms);
+ g_test_add_func ("/libmbim-glib/cid/ussd", test_cid_ussd);
+ g_test_add_func ("/libmbim-glib/cid/phonebook", test_cid_phonebook);
+ g_test_add_func ("/libmbim-glib/cid/stk", test_cid_stk);
+ g_test_add_func ("/libmbim-glib/cid/auth", test_cid_auth);
+ g_test_add_func ("/libmbim-glib/cid/dss", test_cid_dss);
+
+ return g_test_run ();
+}
diff --git a/libmbim-glib/test/test-fragment.c b/libmbim-glib/test/test-fragment.c
new file mode 100644
index 0000000..15f9df9
--- /dev/null
+++ b/libmbim-glib/test/test-fragment.c
@@ -0,0 +1,331 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#include <config.h>
+#include <string.h>
+
+#include "mbim-message.h"
+#include "mbim-message-private.h"
+
+static void
+test_fragment_receive_single (void)
+{
+ MbimMessage *message;
+ const guint8 *fragment_information_buffer;
+ guint32 fragment_information_buffer_length;
+
+ /* This buffer contains a single message composed of a single fragment.
+ * We don't really care about the actual data included within the fragment. */
+ const guint8 buffer [] = {
+ 0x07, 0x00, 0x00, 0x80, /* indications have fragments */
+ 0x1C, 0x00, 0x00, 0x00, /* length of this fragment */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ 0x01, 0x00, 0x00, 0x00, /* total fragments */
+ 0x00, 0x00, 0x00, 0x00, /* current fragment */
+ 0x01, 0x02, 0x03, 0x04, /* frament data */
+ 0x05, 0x06, 0x07, 0x08 };
+
+ const guint8 data [] = {
+ 0x01, 0x02, 0x03, 0x04, /* same data as in the fragment */
+ 0x05, 0x06, 0x07, 0x08
+ };
+
+ message = mbim_message_new (buffer, sizeof (buffer));
+ g_assert (_mbim_message_is_fragment (message));
+ g_assert_cmpuint (_mbim_message_fragment_get_total (message), ==, 1);
+ g_assert_cmpuint (_mbim_message_fragment_get_current (message), ==, 0);
+
+ fragment_information_buffer = (_mbim_message_fragment_get_payload (
+ message,
+ &fragment_information_buffer_length));
+
+ g_assert_cmpuint (fragment_information_buffer_length, ==, sizeof (data));
+ g_assert (memcmp (fragment_information_buffer, data, fragment_information_buffer_length) == 0);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_fragment_receive_multiple (void)
+{
+ GByteArray *bytearray;
+ MbimMessage *message;
+ GError *error = NULL;
+ const guint8 *fragment_information_buffer;
+ guint32 fragment_information_buffer_length;
+
+ /* This buffer contains several fragments of a single message.
+ * We don't really care about the actual data included within the fragments. */
+ const guint8 buffer [] = {
+ /* First fragment */
+ 0x07, 0x00, 0x00, 0x80, /* indications have fragments */
+ 0x1C, 0x00, 0x00, 0x00, /* length of this fragment */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ 0x04, 0x00, 0x00, 0x00, /* total fragments */
+ 0x00, 0x00, 0x00, 0x00, /* current fragment */
+ 0x00, 0x01, 0x02, 0x03, /* frament data */
+ 0x04, 0x05, 0x06, 0x07,
+ /* Second fragment */
+ 0x07, 0x00, 0x00, 0x80, /* indications have fragments */
+ 0x1C, 0x00, 0x00, 0x00, /* length of this fragment */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ 0x04, 0x00, 0x00, 0x00, /* total fragments */
+ 0x01, 0x00, 0x00, 0x00, /* current fragment */
+ 0x08, 0x09, 0x0A, 0x0B, /* frament data */
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ /* Third fragment */
+ 0x07, 0x00, 0x00, 0x80, /* indications have fragments */
+ 0x1C, 0x00, 0x00, 0x00, /* length of this fragment */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ 0x04, 0x00, 0x00, 0x00, /* total fragments */
+ 0x02, 0x00, 0x00, 0x00, /* current fragment */
+ 0x10, 0x11, 0x12, 0x13, /* frament data */
+ 0x14, 0x15, 0x16, 0x17,
+ /* Fourth fragment */
+ 0x07, 0x00, 0x00, 0x80, /* indications have fragments */
+ 0x18, 0x00, 0x00, 0x00, /* length of this fragment */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ 0x04, 0x00, 0x00, 0x00, /* total fragments */
+ 0x03, 0x00, 0x00, 0x00, /* current fragment */
+ 0x18, 0x19, 0x1A, 0x1B /* frament data */
+ };
+
+ const guint8 data [] = {
+ 0x00, 0x01, 0x02, 0x03, /* same data as in the fragments */
+ 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13,
+ 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B
+ };
+
+ bytearray = g_byte_array_new ();
+ g_byte_array_append (bytearray, buffer, sizeof (buffer));
+
+ /* First fragment creates the message */
+ message = _mbim_message_fragment_collector_init ((const MbimMessage *)bytearray, &error);
+ g_assert_no_error (error);
+ g_assert_cmpuint (_mbim_message_fragment_get_total (message), ==, 4);
+ g_assert_cmpuint (_mbim_message_fragment_get_current (message), ==, 0);
+ g_assert (_mbim_message_fragment_collector_complete (message) == FALSE);
+ g_byte_array_remove_range (bytearray, 0, mbim_message_get_message_length ((const MbimMessage *)bytearray));
+
+
+ /* Add second fragment */
+ g_assert (_mbim_message_fragment_collector_add (message, (const MbimMessage *)bytearray, &error));
+ g_assert_no_error (error);
+ g_assert_cmpuint (_mbim_message_fragment_get_total (message), ==, 4);
+ g_assert_cmpuint (_mbim_message_fragment_get_current (message), ==, 1);
+ g_assert (_mbim_message_fragment_collector_complete (message) == FALSE);
+ g_byte_array_remove_range (bytearray, 0, mbim_message_get_message_length ((const MbimMessage *)bytearray));
+
+ /* Add third fragment */
+ g_assert (_mbim_message_fragment_collector_add (message, (const MbimMessage *)bytearray, &error));
+ g_assert_no_error (error);
+ g_assert_cmpuint (_mbim_message_fragment_get_total (message), ==, 4);
+ g_assert_cmpuint (_mbim_message_fragment_get_current (message), ==, 2);
+ g_assert (_mbim_message_fragment_collector_complete (message) == FALSE);
+ g_byte_array_remove_range (bytearray, 0, mbim_message_get_message_length ((const MbimMessage *)bytearray));
+
+ /* Add fourth fragment */
+ g_assert (_mbim_message_fragment_collector_add (message, (const MbimMessage *)bytearray, &error));
+ g_assert_no_error (error);
+ g_assert_cmpuint (_mbim_message_fragment_get_total (message), ==, 4);
+ g_assert_cmpuint (_mbim_message_fragment_get_current (message), ==, 3);
+ g_assert (_mbim_message_fragment_collector_complete (message) == TRUE);
+ g_assert_cmpuint (_mbim_message_fragment_get_total (message), ==, 1);
+ g_assert_cmpuint (_mbim_message_fragment_get_current (message), ==, 0);
+ g_byte_array_remove_range (bytearray, 0, mbim_message_get_message_length ((const MbimMessage *)bytearray));
+
+ /* Compare all compiled data */
+ fragment_information_buffer = (_mbim_message_fragment_get_payload (
+ message,
+ &fragment_information_buffer_length));
+ g_assert_cmpuint (fragment_information_buffer_length, ==, sizeof (data));
+ g_assert (memcmp (fragment_information_buffer, data, fragment_information_buffer_length) == 0);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_fragment_send_multiple_common (guint32 max_fragment_size,
+ const guint8 *buffer,
+ gsize buffer_length,
+ const guint8 *expected_buffer,
+ gsize expected_buffer_length)
+{
+ GByteArray *bytearray;
+ struct fragment_info *fragments;
+ guint n_fragments;
+ guint i;
+ GByteArray *output_bytearray;
+
+ /* Setup message and split it into fragments */
+ bytearray = g_byte_array_new ();
+ g_byte_array_append (bytearray, buffer, buffer_length);
+ fragments = _mbim_message_split_fragments ((const MbimMessage *)bytearray,
+ max_fragment_size,
+ &n_fragments);
+ g_assert (fragments != NULL);
+
+ /* Simulate that we write the fragments */
+ output_bytearray = g_byte_array_new ();
+ for (i = 0; i < n_fragments; i++) {
+ /* Header */
+ g_byte_array_append (output_bytearray,
+ (guint8 *)&fragments[i].header,
+ sizeof (fragments[i].header));
+ /* Fragment header */
+ g_byte_array_append (output_bytearray,
+ (guint8 *)&fragments[i].fragment_header,
+ sizeof (fragments[i].fragment_header));
+ /* Data */
+ g_byte_array_append (output_bytearray,
+ fragments[i].data,
+ fragments[i].data_length);
+ }
+ g_free (fragments);
+
+ /* Compare with the expected buffer */
+ g_assert_cmpuint (expected_buffer_length, == , output_bytearray->len);
+ g_assert (memcmp (output_bytearray->data, expected_buffer, output_bytearray->len) == 0);
+
+ g_byte_array_unref (output_bytearray);
+}
+
+static void
+test_fragment_send_multiple_1 (void)
+{
+ const guint8 buffer [] = {
+ 0x07, 0x00, 0x00, 0x80, /* indications have fragments */
+ 0x30, 0x00, 0x00, 0x00, /* length of this fragment */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ 0x01, 0x00, 0x00, 0x00, /* total fragments */
+ 0x00, 0x00, 0x00, 0x00, /* current fragment */
+ 0x00, 0x01, 0x02, 0x03, /* same data as in the fragments */
+ 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13,
+ 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B
+ };
+
+ /* This buffer contains several fragments of a single message.
+ * We don't really care about the actual data included within the fragments. */
+ const guint8 expected_buffer [] = {
+ /* First fragment */
+ 0x07, 0x00, 0x00, 0x80, /* indications have fragments */
+ 0x1C, 0x00, 0x00, 0x00, /* length of this fragment */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ 0x04, 0x00, 0x00, 0x00, /* total fragments */
+ 0x00, 0x00, 0x00, 0x00, /* current fragment */
+ 0x00, 0x01, 0x02, 0x03, /* frament data */
+ 0x04, 0x05, 0x06, 0x07,
+ /* Second fragment */
+ 0x07, 0x00, 0x00, 0x80, /* indications have fragments */
+ 0x1C, 0x00, 0x00, 0x00, /* length of this fragment */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ 0x04, 0x00, 0x00, 0x00, /* total fragments */
+ 0x01, 0x00, 0x00, 0x00, /* current fragment */
+ 0x08, 0x09, 0x0A, 0x0B, /* frament data */
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ /* Third fragment */
+ 0x07, 0x00, 0x00, 0x80, /* indications have fragments */
+ 0x1C, 0x00, 0x00, 0x00, /* length of this fragment */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ 0x04, 0x00, 0x00, 0x00, /* total fragments */
+ 0x02, 0x00, 0x00, 0x00, /* current fragment */
+ 0x10, 0x11, 0x12, 0x13, /* frament data */
+ 0x14, 0x15, 0x16, 0x17,
+ /* Fourth fragment */
+ 0x07, 0x00, 0x00, 0x80, /* indications have fragments */
+ 0x18, 0x00, 0x00, 0x00, /* length of this fragment */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ 0x04, 0x00, 0x00, 0x00, /* total fragments */
+ 0x03, 0x00, 0x00, 0x00, /* current fragment */
+ 0x18, 0x19, 0x1A, 0x1B /* frament data */
+ };
+
+ test_fragment_send_multiple_common (
+ 28,
+ buffer, sizeof (buffer),
+ expected_buffer, sizeof (expected_buffer));
+}
+
+static void
+test_fragment_send_multiple_2 (void)
+{
+ const guint8 buffer [] = {
+ 0x07, 0x00, 0x00, 0x80, /* indications have fragments */
+ 0x2C, 0x00, 0x00, 0x00, /* length of this fragment */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ 0x01, 0x00, 0x00, 0x00, /* total fragments */
+ 0x00, 0x00, 0x00, 0x00, /* current fragment */
+ 0x00, 0x01, 0x02, 0x03, /* same data as in the fragments */
+ 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13,
+ 0x14, 0x15, 0x16, 0x17
+ };
+
+ /* This buffer contains several fragments of a single message.
+ * We don't really care about the actual data included within the fragments. */
+ const guint8 expected_buffer [] = {
+ /* First fragment */
+ 0x07, 0x00, 0x00, 0x80, /* indications have fragments */
+ 0x1C, 0x00, 0x00, 0x00, /* length of this fragment */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ 0x03, 0x00, 0x00, 0x00, /* total fragments */
+ 0x00, 0x00, 0x00, 0x00, /* current fragment */
+ 0x00, 0x01, 0x02, 0x03, /* frament data */
+ 0x04, 0x05, 0x06, 0x07,
+ /* Second fragment */
+ 0x07, 0x00, 0x00, 0x80, /* indications have fragments */
+ 0x1C, 0x00, 0x00, 0x00, /* length of this fragment */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ 0x03, 0x00, 0x00, 0x00, /* total fragments */
+ 0x01, 0x00, 0x00, 0x00, /* current fragment */
+ 0x08, 0x09, 0x0A, 0x0B, /* frament data */
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ /* Third fragment */
+ 0x07, 0x00, 0x00, 0x80, /* indications have fragments */
+ 0x1C, 0x00, 0x00, 0x00, /* length of this fragment */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ 0x03, 0x00, 0x00, 0x00, /* total fragments */
+ 0x02, 0x00, 0x00, 0x00, /* current fragment */
+ 0x10, 0x11, 0x12, 0x13, /* frament data */
+ 0x14, 0x15, 0x16, 0x17
+ };
+
+ test_fragment_send_multiple_common (
+ 28,
+ buffer, sizeof (buffer),
+ expected_buffer, sizeof (expected_buffer));
+}
+
+int main (int argc, char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/libmbim-glib/fragment/receive/single", test_fragment_receive_single);
+ g_test_add_func ("/libmbim-glib/fragment/receive/multiple", test_fragment_receive_multiple);
+ g_test_add_func ("/libmbim-glib/fragment/send/multiple-1", test_fragment_send_multiple_1);
+ g_test_add_func ("/libmbim-glib/fragment/send/multiple-2", test_fragment_send_multiple_2);
+
+ return g_test_run ();
+}
diff --git a/libmbim-glib/test/test-message-builder.c b/libmbim-glib/test/test-message-builder.c
new file mode 100644
index 0000000..239a8bf
--- /dev/null
+++ b/libmbim-glib/test/test-message-builder.c
@@ -0,0 +1,1321 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#include <config.h>
+#include <string.h>
+
+#include "mbim-message.h"
+#include "mbim-message-private.h"
+#include "mbim-cid.h"
+#include "mbim-enums.h"
+#include "mbim-utils.h"
+#include "mbim-basic-connect.h"
+#include "mbim-ussd.h"
+#include "mbim-auth.h"
+#include "mbim-stk.h"
+#include "mbim-dss.h"
+
+#if defined ENABLE_TEST_MESSAGE_TRACES
+static void
+test_message_trace (const guint8 *computed,
+ guint32 computed_size,
+ const guint8 *expected,
+ guint32 expected_size)
+{
+ gchar *message_str;
+ gchar *expected_str;
+
+ message_str = __mbim_utils_str_hex (computed, computed_size, ':');
+ expected_str = __mbim_utils_str_hex (expected, expected_size, ':');
+
+ /* Dump all message contents */
+ g_print ("\n"
+ "Message str:\n"
+ "'%s'\n"
+ "Expected str:\n"
+ "'%s'\n",
+ message_str,
+ expected_str);
+
+ /* If they are different, tell which are the different bytes */
+ if (computed_size != expected_size ||
+ memcmp (computed, expected, expected_size)) {
+ guint32 i;
+
+ for (i = 0; i < MIN (computed_size, expected_size); i++) {
+ if (computed[i] != expected[i])
+ g_print ("Byte [%u] is different (computed: 0x%02X vs expected: 0x%02x)\n", i, computed[i], expected[i]);
+ }
+ }
+
+ g_free (message_str);
+ g_free (expected_str);
+}
+#else
+#define test_message_trace(...)
+#endif
+
+static void
+test_message_builder_basic_connect_pin_set_raw (void)
+{
+ MbimMessage *message;
+ MbimMessageCommandBuilder *builder;
+ const guint8 expected_message [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x00, /* type */
+ 0x50, 0x00, 0x00, 0x00, /* length */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_message */
+ 0xa2, 0x89, 0xcc, 0x33, /* service id */
+ 0xbc, 0xbb, 0x8b, 0x4f,
+ 0xb6, 0xb0, 0x13, 0x3e,
+ 0xc2, 0xaa, 0xe6, 0xdf,
+ 0x04, 0x00, 0x00, 0x00, /* command id */
+ 0x01, 0x00, 0x00, 0x00, /* command_type */
+ 0x20, 0x00, 0x00, 0x00, /* buffer_length */
+ /* information buffer */
+ 0x02, 0x00, 0x00, 0x00, /* pin type */
+ 0x00, 0x00, 0x00, 0x00, /* pin operation */
+ 0x18, 0x00, 0x00, 0x00, /* pin offset */
+ 0x08, 0x00, 0x00, 0x00, /* pin size */
+ 0x00, 0x00, 0x00, 0x00, /* new pin offset */
+ 0x00, 0x00, 0x00, 0x00, /* new pin size */
+ 0x31, 0x00, 0x31, 0x00, /* pin string */
+ 0x31, 0x00, 0x31, 0x00
+ };
+
+ /* PIN set message */
+ builder = _mbim_message_command_builder_new (1,
+ MBIM_SERVICE_BASIC_CONNECT,
+ MBIM_CID_BASIC_CONNECT_PIN,
+ MBIM_MESSAGE_COMMAND_TYPE_SET);
+ _mbim_message_command_builder_append_guint32 (builder, (guint32)MBIM_PIN_TYPE_PIN1);
+ _mbim_message_command_builder_append_guint32 (builder, (guint32)MBIM_PIN_OPERATION_ENTER);
+ _mbim_message_command_builder_append_string (builder, "1111");
+ _mbim_message_command_builder_append_string (builder, "");
+ message = _mbim_message_command_builder_complete (builder);
+
+ g_assert (message != NULL);
+
+ test_message_trace ((const guint8 *)((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ expected_message,
+ sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_BASIC_CONNECT);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_BASIC_CONNECT_PIN);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_SET);
+
+ g_assert_cmpuint (((GByteArray *)message)->len, ==, sizeof (expected_message));
+ g_assert (memcmp (((GByteArray *)message)->data, expected_message, sizeof (expected_message)) == 0);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_message_builder_basic_connect_pin_set (void)
+{
+ GError *error = NULL;
+ MbimMessage *message;
+ const guint8 expected_message [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x00, /* type */
+ 0x50, 0x00, 0x00, 0x00, /* length */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_message */
+ 0xa2, 0x89, 0xcc, 0x33, /* service id */
+ 0xbc, 0xbb, 0x8b, 0x4f,
+ 0xb6, 0xb0, 0x13, 0x3e,
+ 0xc2, 0xaa, 0xe6, 0xdf,
+ 0x04, 0x00, 0x00, 0x00, /* command id */
+ 0x01, 0x00, 0x00, 0x00, /* command_type */
+ 0x20, 0x00, 0x00, 0x00, /* buffer_length */
+ /* information buffer */
+ 0x02, 0x00, 0x00, 0x00, /* pin type */
+ 0x00, 0x00, 0x00, 0x00, /* pin operation */
+ 0x18, 0x00, 0x00, 0x00, /* pin offset */
+ 0x08, 0x00, 0x00, 0x00, /* pin size */
+ 0x00, 0x00, 0x00, 0x00, /* new pin offset */
+ 0x00, 0x00, 0x00, 0x00, /* new pin size */
+ 0x31, 0x00, 0x31, 0x00, /* pin string */
+ 0x31, 0x00, 0x31, 0x00
+ };
+
+ /* PIN set message */
+ message = mbim_message_pin_set_new (MBIM_PIN_TYPE_PIN1,
+ MBIM_PIN_OPERATION_ENTER,
+ "1111",
+ "",
+ &error);
+ g_assert_no_error (error);
+ g_assert (message != NULL);
+ mbim_message_set_transaction_id (message, 1);
+
+ test_message_trace ((const guint8 *)((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ expected_message,
+ sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_BASIC_CONNECT);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_BASIC_CONNECT_PIN);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_SET);
+
+ g_assert_cmpuint (((GByteArray *)message)->len, ==, sizeof (expected_message));
+ g_assert (memcmp (((GByteArray *)message)->data, expected_message, sizeof (expected_message)) == 0);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_message_builder_basic_connect_connect_set_raw (void)
+{
+ MbimMessage *message;
+ MbimMessageCommandBuilder *builder;
+ const guint8 expected_message [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x00, /* type */
+ 0x7C, 0x00, 0x00, 0x00, /* length */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_message */
+ 0xA2, 0x89, 0xCC, 0x33, /* service id */
+ 0xBC, 0xBB, 0x8B, 0x4F,
+ 0xB6, 0xB0, 0x13, 0x3E,
+ 0xC2, 0xAA, 0xE6, 0xDF,
+ 0x0C, 0x00, 0x00, 0x00, /* command id */
+ 0x01, 0x00, 0x00, 0x00, /* command_type */
+ 0x4C, 0x00, 0x00, 0x00, /* buffer_length */
+ /* information buffer */
+ 0x01, 0x00, 0x00, 0x00, /* session id */
+ 0x01, 0x00, 0x00, 0x00, /* activation command */
+ 0x3C, 0x00, 0x00, 0x00, /* access string offset */
+ 0x10, 0x00, 0x00, 0x00, /* access string size */
+ 0x00, 0x00, 0x00, 0x00, /* username offset */
+ 0x00, 0x00, 0x00, 0x00, /* username size */
+ 0x00, 0x00, 0x00, 0x00, /* password offset */
+ 0x00, 0x00, 0x00, 0x00, /* password size */
+ 0x00, 0x00, 0x00, 0x00, /* compression */
+ 0x01, 0x00, 0x00, 0x00, /* auth protocol */
+ 0x01, 0x00, 0x00, 0x00, /* ip type */
+ 0x7E, 0x5E, 0x2A, 0x7E, /* context type */
+ 0x4E, 0x6F, 0x72, 0x72,
+ 0x73, 0x6B, 0x65, 0x6E,
+ 0x7E, 0x5E, 0x2A, 0x7E,
+ /* data buffer */
+ 0x69, 0x00, 0x6E, 0x00, /* access string */
+ 0x74, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x6E, 0x00,
+ 0x65, 0x00, 0x74, 0x00
+ };
+
+ /* CONNECT set message */
+ builder = _mbim_message_command_builder_new (1,
+ MBIM_SERVICE_BASIC_CONNECT,
+ MBIM_CID_BASIC_CONNECT_CONNECT,
+ MBIM_MESSAGE_COMMAND_TYPE_SET);
+ _mbim_message_command_builder_append_guint32 (builder, 0x01);
+ _mbim_message_command_builder_append_guint32 (builder, (guint32)MBIM_ACTIVATION_COMMAND_ACTIVATE);
+ _mbim_message_command_builder_append_string (builder, "internet");
+ _mbim_message_command_builder_append_string (builder, "");
+ _mbim_message_command_builder_append_string (builder, "");
+ _mbim_message_command_builder_append_guint32 (builder, (guint32)MBIM_COMPRESSION_NONE);
+ _mbim_message_command_builder_append_guint32 (builder, (guint32)MBIM_AUTH_PROTOCOL_PAP);
+ _mbim_message_command_builder_append_guint32 (builder, (guint32)MBIM_CONTEXT_IP_TYPE_IPV4);
+ _mbim_message_command_builder_append_uuid (builder, mbim_uuid_from_context_type (MBIM_CONTEXT_TYPE_INTERNET));
+ message = _mbim_message_command_builder_complete (builder);
+
+ g_assert (message != NULL);
+
+ test_message_trace ((const guint8 *)((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ expected_message,
+ sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_BASIC_CONNECT);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_BASIC_CONNECT_CONNECT);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_SET);
+
+ g_assert_cmpuint (((GByteArray *)message)->len, ==, sizeof (expected_message));
+ g_assert (memcmp (((GByteArray *)message)->data, expected_message, sizeof (expected_message)) == 0);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_message_builder_basic_connect_connect_set (void)
+{
+ GError *error = NULL;
+ MbimMessage *message;
+ const guint8 expected_message [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x00, /* type */
+ 0x7C, 0x00, 0x00, 0x00, /* length */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_message */
+ 0xA2, 0x89, 0xCC, 0x33, /* service id */
+ 0xBC, 0xBB, 0x8B, 0x4F,
+ 0xB6, 0xB0, 0x13, 0x3E,
+ 0xC2, 0xAA, 0xE6, 0xDF,
+ 0x0C, 0x00, 0x00, 0x00, /* command id */
+ 0x01, 0x00, 0x00, 0x00, /* command_type */
+ 0x4C, 0x00, 0x00, 0x00, /* buffer_length */
+ /* information buffer */
+ 0x01, 0x00, 0x00, 0x00, /* session id */
+ 0x01, 0x00, 0x00, 0x00, /* activation command */
+ 0x3C, 0x00, 0x00, 0x00, /* access string offset */
+ 0x10, 0x00, 0x00, 0x00, /* access string size */
+ 0x00, 0x00, 0x00, 0x00, /* username offset */
+ 0x00, 0x00, 0x00, 0x00, /* username size */
+ 0x00, 0x00, 0x00, 0x00, /* password offset */
+ 0x00, 0x00, 0x00, 0x00, /* password size */
+ 0x00, 0x00, 0x00, 0x00, /* compression */
+ 0x01, 0x00, 0x00, 0x00, /* auth protocol */
+ 0x01, 0x00, 0x00, 0x00, /* ip type */
+ 0x7E, 0x5E, 0x2A, 0x7E, /* context type */
+ 0x4E, 0x6F, 0x72, 0x72,
+ 0x73, 0x6B, 0x65, 0x6E,
+ 0x7E, 0x5E, 0x2A, 0x7E,
+ /* data buffer */
+ 0x69, 0x00, 0x6E, 0x00, /* access string */
+ 0x74, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x6E, 0x00,
+ 0x65, 0x00, 0x74, 0x00
+ };
+
+ /* CONNECT set message */
+ message = (mbim_message_connect_set_new (
+ 0x01,
+ MBIM_ACTIVATION_COMMAND_ACTIVATE,
+ "internet",
+ "",
+ "",
+ MBIM_COMPRESSION_NONE,
+ MBIM_AUTH_PROTOCOL_PAP,
+ MBIM_CONTEXT_IP_TYPE_IPV4,
+ mbim_uuid_from_context_type (MBIM_CONTEXT_TYPE_INTERNET),
+ &error));
+ g_assert_no_error (error);
+ g_assert (message != NULL);
+ mbim_message_set_transaction_id (message, 1);
+
+ test_message_trace ((const guint8 *)((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ expected_message,
+ sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_BASIC_CONNECT);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_BASIC_CONNECT_CONNECT);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_SET);
+
+ g_assert_cmpuint (((GByteArray *)message)->len, ==, sizeof (expected_message));
+ g_assert (memcmp (((GByteArray *)message)->data, expected_message, sizeof (expected_message)) == 0);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_message_builder_basic_connect_service_activation_set (void)
+{
+ GError *error = NULL;
+ MbimMessage *message;
+ const guint8 buffer [] = {
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08
+ };
+ const guint8 expected_message [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x00, /* type */
+ 0x38, 0x00, 0x00, 0x00, /* length */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_message */
+ 0xA2, 0x89, 0xCC, 0x33, /* service id */
+ 0xBC, 0xBB, 0x8B, 0x4F,
+ 0xB6, 0xB0, 0x13, 0x3E,
+ 0xC2, 0xAA, 0xE6, 0xDF,
+ 0x0E, 0x00, 0x00, 0x00, /* command id */
+ 0x01, 0x00, 0x00, 0x00, /* command_type */
+ 0x08, 0x00, 0x00, 0x00, /* buffer_length */
+ /* information buffer */
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08 };
+
+ /* CONNECT set message */
+ message = (mbim_message_service_activation_set_new (
+ sizeof (buffer),
+ buffer,
+ &error));
+ g_assert_no_error (error);
+ g_assert (message != NULL);
+ mbim_message_set_transaction_id (message, 1);
+
+ test_message_trace ((const guint8 *)((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ expected_message,
+ sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_BASIC_CONNECT);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_BASIC_CONNECT_SERVICE_ACTIVATION);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_SET);
+
+ g_assert_cmpuint (((GByteArray *)message)->len, ==, sizeof (expected_message));
+ g_assert (memcmp (((GByteArray *)message)->data, expected_message, sizeof (expected_message)) == 0);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_message_builder_basic_connect_device_service_subscriber_list_set (void)
+{
+ GError *error = NULL;
+ MbimEventEntry **entries;
+ MbimMessage *message;
+ const guint8 expected_message [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x00, /* type */
+ 0x78, 0x00, 0x00, 0x00, /* length */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_message */
+ 0xA2, 0x89, 0xCC, 0x33, /* service id */
+ 0xBC, 0xBB, 0x8B, 0x4F,
+ 0xB6, 0xB0, 0x13, 0x3E,
+ 0xC2, 0xAA, 0xE6, 0xDF,
+ 0x13, 0x00, 0x00, 0x00, /* command id */
+ 0x01, 0x00, 0x00, 0x00, /* command_type */
+ 0x48, 0x00, 0x00, 0x00, /* buffer_length */
+ /* information buffer */
+ 0x02, 0x00, 0x00, 0x00, /* 0x00 Events count */
+ 0x14, 0x00, 0x00, 0x00, /* 0x04 Event 1 offset */
+ 0x1C, 0x00, 0x00, 0x00, /* 0x08 Event 1 length */
+ 0x30, 0x00, 0x00, 0x00, /* 0x0C Event 2 offset */
+ 0x18, 0x00, 0x00, 0x00, /* 0x10 Event 2 length */
+ /* data buffer, event 1 */
+ 0xA2, 0x89, 0xCC, 0x33, /* 0x14 Event 1, service id */
+ 0xBC, 0xBB, 0x8B, 0x4F,
+ 0xB6, 0xB0, 0x13, 0x3E,
+ 0xC2, 0xAA, 0xE6, 0xDF,
+ 0x02, 0x00, 0x00, 0x00, /* 0x24 Event 1, cid count */
+ 0x0B, 0x00, 0x00, 0x00, /* 0x28 Event 1, cid 1 */
+ 0x09, 0x00, 0x00, 0x00, /* 0x2C Event 1, cid 2 */
+ /* data buffer, event 2 */
+ 0x53, 0x3F, 0xBE, 0xEB, /* 0x30 Event 1, service id */
+ 0x14, 0xFE, 0x44, 0x67,
+ 0x9F, 0x90, 0x33, 0xA2,
+ 0x23, 0xE5, 0x6C, 0x3F,
+ 0x01, 0x00, 0x00, 0x00, /* 0x40 Event 2, cid count */
+ 0x02, 0x00, 0x00, 0x00, /* 0x44 Event 2, cid 1 */
+ };
+
+ /* Device Service Subscribe List set message */
+ entries = g_new0 (MbimEventEntry *, 3);
+
+ entries[0] = g_new (MbimEventEntry, 1);
+ memcpy (&(entries[0]->device_service_id), MBIM_UUID_BASIC_CONNECT, sizeof (MbimUuid));
+ entries[0]->cids_count = 2;
+ entries[0]->cids = g_new0 (guint32, 2);
+ entries[0]->cids[0] = MBIM_CID_BASIC_CONNECT_SIGNAL_STATE;
+ entries[0]->cids[1] = MBIM_CID_BASIC_CONNECT_REGISTER_STATE;
+
+ entries[1] = g_new (MbimEventEntry, 1);
+ memcpy (&(entries[1]->device_service_id), MBIM_UUID_SMS, sizeof (MbimUuid));
+ entries[1]->cids_count = 1;
+ entries[1]->cids = g_new0 (guint32, 1);
+ entries[1]->cids[0] = MBIM_CID_SMS_READ;
+
+ message = (mbim_message_device_service_subscriber_list_set_new (
+ 2,
+ (const MbimEventEntry *const *)entries,
+ &error));
+ mbim_event_entry_array_free (entries);
+
+ g_assert_no_error (error);
+ g_assert (message != NULL);
+ mbim_message_set_transaction_id (message, 1);
+
+ test_message_trace ((const guint8 *)((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ expected_message,
+ sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_BASIC_CONNECT);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_BASIC_CONNECT_DEVICE_SERVICE_SUBSCRIBER_LIST);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_SET);
+
+ g_assert_cmpuint (((GByteArray *)message)->len, ==, sizeof (expected_message));
+ g_assert (memcmp (((GByteArray *)message)->data, expected_message, sizeof (expected_message)) == 0);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_message_builder_ussd_set (void)
+{
+ GError *error = NULL;
+ MbimMessage *message;
+ const guint8 expected_message [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x00, /* type */
+ 0x50, 0x00, 0x00, 0x00, /* length */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_message */
+ 0xE5, 0x50, 0xA0, 0xC8, /* service id */
+ 0x5E, 0x82, 0x47, 0x9E,
+ 0x82, 0xF7, 0x10, 0xAB,
+ 0xF4, 0xC3, 0x35, 0x1F,
+ 0x01, 0x00, 0x00, 0x00, /* command id */
+ 0x01, 0x00, 0x00, 0x00, /* command_type */
+ 0x20, 0x00, 0x00, 0x00, /* buffer_length */
+ /* information buffer */
+ 0x01, 0x00, 0x00, 0x00, /* 0x00 Action */
+ 0x01, 0x00, 0x00, 0x00, /* 0x04 Data coding scheme */
+ 0x10, 0x00, 0x00, 0x00, /* 0x08 Payload offset */
+ 0x10, 0x00, 0x00, 0x00, /* 0x0C Payload length */
+ /* data buffer, payload */
+ 0x01, 0x02, 0x03, 0x04, /* 0x10 Payload */
+ 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C,
+ 0x0D, 0x0E, 0x0F, 0x00
+ };
+ const guint8 payload [] = {
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C,
+ 0x0D, 0x0E, 0x0F, 0x00
+ };
+
+ /* USSD set message */
+ message = (mbim_message_ussd_set_new (
+ MBIM_USSD_ACTION_CONTINUE,
+ 1, /* dcs */
+ sizeof (payload),
+ payload,
+ &error));
+
+ g_assert_no_error (error);
+ g_assert (message != NULL);
+ mbim_message_set_transaction_id (message, 1);
+
+ test_message_trace ((const guint8 *)((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ expected_message,
+ sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_USSD);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_USSD);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_SET);
+
+ g_assert_cmpuint (((GByteArray *)message)->len, ==, sizeof (expected_message));
+ g_assert (memcmp (((GByteArray *)message)->data, expected_message, sizeof (expected_message)) == 0);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_message_builder_auth_akap_query (void)
+{
+ GError *error = NULL;
+ MbimMessage *message;
+ const guint8 expected_message [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x00, /* type */
+ 0x60, 0x00, 0x00, 0x00, /* length */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_message */
+ 0x1D, 0x2B, 0x5F, 0xF7, /* service id */
+ 0x0A, 0xA1, 0x48, 0xB2,
+ 0xAA, 0x52, 0x50, 0xF1,
+ 0x57, 0x67, 0x17, 0x4E,
+ 0x02, 0x00, 0x00, 0x00, /* command id */
+ 0x00, 0x00, 0x00, 0x00, /* command_type */
+ 0x30, 0x00, 0x00, 0x00, /* buffer_length */
+ /* information buffer */
+ 0x00, 0x01, 0x02, 0x03, /* 0x00 Rand */
+ 0x04, 0x05, 0x06, 0x07, /* 0x04 */
+ 0x08, 0x09, 0x0A, 0x0B, /* 0x08 */
+ 0x0C, 0x0D, 0x0E, 0x0F, /* 0x0C */
+ 0xFF, 0xFE, 0xFD, 0xFC, /* 0x10 Autn */
+ 0xFB, 0xFA, 0xF9, 0xF8, /* 0x14 */
+ 0xF7, 0xF6, 0xF5, 0xF4, /* 0x18 */
+ 0xF3, 0xF2, 0xF1, 0xF0, /* 0x1C */
+ 0x28, 0x00, 0x00, 0x00, /* 0x20 Network name (offset) */
+ 0x08, 0x00, 0x00, 0x00, /* 0x24 Network name (length) */
+ /* data buffer */
+ 0x31, 0x00, 0x31, 0x00, /* 0x28 Network name */
+ 0x31, 0x00, 0x31, 0x00
+ };
+
+ const guint8 rand [] = {
+ 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F
+ };
+ const guint8 autn [] = {
+ 0xFF, 0xFE, 0xFD, 0xFC,
+ 0xFB, 0xFA, 0xF9, 0xF8,
+ 0xF7, 0xF6, 0xF5, 0xF4,
+ 0xF3, 0xF2, 0xF1, 0xF0
+ };
+
+ /* AKAP Auth message */
+ message = (mbim_message_auth_akap_query_new (
+ rand,
+ autn,
+ "1111",
+ &error));
+
+ g_assert_no_error (error);
+ g_assert (message != NULL);
+ mbim_message_set_transaction_id (message, 1);
+
+ test_message_trace ((const guint8 *)((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ expected_message,
+ sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_AUTH);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_AUTH_AKAP);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_QUERY);
+
+ g_assert_cmpuint (((GByteArray *)message)->len, ==, sizeof (expected_message));
+ g_assert (memcmp (((GByteArray *)message)->data, expected_message, sizeof (expected_message)) == 0);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_message_builder_stk_pac_set (void)
+{
+ GError *error = NULL;
+ MbimMessage *message;
+ const guint8 expected_message [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x00, /* type */
+ 0x50, 0x00, 0x00, 0x00, /* length */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_message */
+ 0xD8, 0xF2, 0x01, 0x31, /* service id */
+ 0xFC, 0xB5, 0x4E, 0x17,
+ 0x86, 0x02, 0xD6, 0xED,
+ 0x38, 0x16, 0x16, 0x4C,
+ 0x01, 0x00, 0x00, 0x00, /* command id */
+ 0x01, 0x00, 0x00, 0x00, /* command_type */
+ 0x20, 0x00, 0x00, 0x00, /* buffer_length */
+ /* information buffer */
+ 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ 0xFF, 0xFE, 0xFD, 0xFC,
+ 0xFB, 0xFA, 0xF9, 0xF8,
+ 0xF7, 0xF6, 0xF5, 0xF4,
+ 0xF3, 0xF2, 0xF1, 0xF0
+ };
+
+ const guint8 pac_host_control [] = {
+ 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ 0xFF, 0xFE, 0xFD, 0xFC,
+ 0xFB, 0xFA, 0xF9, 0xF8,
+ 0xF7, 0xF6, 0xF5, 0xF4,
+ 0xF3, 0xF2, 0xF1, 0xF0
+ };
+
+ /* STK PAC set message */
+ message = (mbim_message_stk_pac_set_new (
+ pac_host_control,
+ &error));
+
+ g_assert_no_error (error);
+ g_assert (message != NULL);
+ mbim_message_set_transaction_id (message, 1);
+
+ test_message_trace ((const guint8 *)((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ expected_message,
+ sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_STK);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_STK_PAC);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_SET);
+
+ g_assert_cmpuint (((GByteArray *)message)->len, ==, sizeof (expected_message));
+ g_assert (memcmp (((GByteArray *)message)->data, expected_message, sizeof (expected_message)) == 0);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_message_builder_stk_terminal_response_set (void)
+{
+ GError *error = NULL;
+ MbimMessage *message;
+ const guint8 expected_message [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x00, /* type */
+ 0x50, 0x00, 0x00, 0x00, /* length */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_message */
+ 0xD8, 0xF2, 0x01, 0x31, /* service id */
+ 0xFC, 0xB5, 0x4E, 0x17,
+ 0x86, 0x02, 0xD6, 0xED,
+ 0x38, 0x16, 0x16, 0x4C,
+ 0x02, 0x00, 0x00, 0x00, /* command id */
+ 0x01, 0x00, 0x00, 0x00, /* command_type */
+ 0x20, 0x00, 0x00, 0x00, /* buffer_length */
+ /* information buffer */
+ 0x1C, 0x00, 0x00, 0x00, /* 0x00 Response length */
+ 0x04, 0x05, 0x06, 0x07, /* 0x04 Response */
+ 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ 0xFF, 0xFE, 0xFD, 0xFC,
+ 0xFB, 0xFA, 0xF9, 0xF8,
+ 0xF7, 0xF6, 0xF5, 0xF4,
+ 0xF3, 0xF2, 0xF1, 0xF0
+ };
+
+ const guint8 response [] = {
+ 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ 0xFF, 0xFE, 0xFD, 0xFC,
+ 0xFB, 0xFA, 0xF9, 0xF8,
+ 0xF7, 0xF6, 0xF5, 0xF4,
+ 0xF3, 0xF2, 0xF1, 0xF0
+ };
+
+ /* STK Terminal Response set message */
+ message = (mbim_message_stk_terminal_response_set_new (
+ sizeof (response),
+ response,
+ &error));
+
+ g_assert_no_error (error);
+ g_assert (message != NULL);
+ mbim_message_set_transaction_id (message, 1);
+
+ test_message_trace ((const guint8 *)((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ expected_message,
+ sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_STK);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_STK_TERMINAL_RESPONSE);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_SET);
+
+ g_assert_cmpuint (((GByteArray *)message)->len, ==, sizeof (expected_message));
+ g_assert (memcmp (((GByteArray *)message)->data, expected_message, sizeof (expected_message)) == 0);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_message_builder_stk_envelope_set (void)
+{
+ GError *error = NULL;
+ MbimMessage *message;
+ const guint8 expected_message [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x00, /* type */
+ 0x58, 0x00, 0x00, 0x00, /* length */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_message */
+ 0xD8, 0xF2, 0x01, 0x31, /* service id */
+ 0xFC, 0xB5, 0x4E, 0x17,
+ 0x86, 0x02, 0xD6, 0xED,
+ 0x38, 0x16, 0x16, 0x4C,
+ 0x03, 0x00, 0x00, 0x00, /* command id */
+ 0x01, 0x00, 0x00, 0x00, /* command_type */
+ 0x28, 0x00, 0x00, 0x00, /* buffer_length */
+ /* information buffer */
+ 0x1C, 0x00, 0x00, 0x00,
+ 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ 0xFF, 0xFE, 0xFD, 0xFC,
+ 0xFB, 0xFA, 0xF9, 0xF8,
+ 0xF7, 0xF6, 0xF5, 0xF4,
+ 0xF3, 0xF2, 0xF1, 0xF0,
+ 0xFF, 0xFE, 0xFD, 0xFC,
+ 0xFB, 0xFA, 0xF9, 0xF8
+ };
+
+ const guint8 databuffer [] = {
+ 0x1C, 0x00, 0x00, 0x00,
+ 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ 0xFF, 0xFE, 0xFD, 0xFC,
+ 0xFB, 0xFA, 0xF9, 0xF8,
+ 0xF7, 0xF6, 0xF5, 0xF4,
+ 0xF3, 0xF2, 0xF1, 0xF0,
+ 0xFF, 0xFE, 0xFD, 0xFC,
+ 0xFB, 0xFA, 0xF9, 0xF8
+ };
+
+ /* STK Envelop set message */
+ message = (mbim_message_stk_envelope_set_new (
+ sizeof (databuffer),
+ databuffer,
+ &error));
+
+ g_assert_no_error (error);
+ g_assert (message != NULL);
+ mbim_message_set_transaction_id (message, 1);
+
+ test_message_trace ((const guint8 *)((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ expected_message,
+ sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_STK);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_STK_ENVELOPE);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_SET);
+
+ g_assert_cmpuint (((GByteArray *)message)->len, ==, sizeof (expected_message));
+ g_assert (memcmp (((GByteArray *)message)->data, expected_message, sizeof (expected_message)) == 0);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_message_builder_basic_connect_ip_packet_filters_set_none (void)
+{
+ GError *error = NULL;
+ MbimMessage *message;
+ const guint8 expected_message [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x00, /* type */
+ 0x38, 0x00, 0x00, 0x00, /* length */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_message */
+ 0xA2, 0x89, 0xCC, 0x33, /* service id */
+ 0xBC, 0xBB, 0x8B, 0x4F,
+ 0xB6, 0xB0, 0x13, 0x3E,
+ 0xC2, 0xAA, 0xE6, 0xDF,
+ 0x17, 0x00, 0x00, 0x00, /* command id */
+ 0x01, 0x00, 0x00, 0x00, /* command_type */
+ 0x08, 0x00, 0x00, 0x00, /* buffer_length */
+ /* information buffer */
+ 0x01, 0x00, 0x00, 0x00, /* 0x00 session id */
+ 0x00, 0x00, 0x00, 0x00 /* 0x04 packet filters count */
+ };
+
+ /* IP packet filters set message */
+ message = mbim_message_ip_packet_filters_set_new (1, 0, NULL, &error);
+
+ g_assert_no_error (error);
+ g_assert (message != NULL);
+ mbim_message_set_transaction_id (message, 1);
+
+ test_message_trace ((const guint8 *)((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ expected_message,
+ sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_BASIC_CONNECT);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_BASIC_CONNECT_IP_PACKET_FILTERS);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_SET);
+
+ g_assert_cmpuint (((GByteArray *)message)->len, ==, sizeof (expected_message));
+ g_assert (memcmp (((GByteArray *)message)->data, expected_message, sizeof (expected_message)) == 0);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_message_builder_basic_connect_ip_packet_filters_set_one (void)
+{
+ GError *error = NULL;
+ MbimMessage *message;
+ MbimPacketFilter **filters;
+ const guint8 expected_message [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x00, /* type */
+ 0x5C, 0x00, 0x00, 0x00, /* length */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_message */
+ 0xA2, 0x89, 0xCC, 0x33, /* service id */
+ 0xBC, 0xBB, 0x8B, 0x4F,
+ 0xB6, 0xB0, 0x13, 0x3E,
+ 0xC2, 0xAA, 0xE6, 0xDF,
+ 0x17, 0x00, 0x00, 0x00, /* command id */
+ 0x01, 0x00, 0x00, 0x00, /* command_type */
+ 0x2C, 0x00, 0x00, 0x00, /* buffer_length */
+ /* information buffer */
+ 0x01, 0x00, 0x00, 0x00, /* 0x00 session id */
+ 0x01, 0x00, 0x00, 0x00, /* 0x04 packet filters count */
+ 0x10, 0x00, 0x00, 0x00, /* 0x08 packet filter 1 offset */
+ 0x1C, 0x00, 0x00, 0x00, /* 0x0C packet filter 1 length */
+ /* databuffer, packet filter 1 */
+ 0x07, 0x00, 0x00, 0x00, /* 0x10 0x00 filter size */
+ 0x0C, 0x00, 0x00, 0x00, /* 0x14 0x04 filter offset (from beginning of struct) */
+ 0x14, 0x00, 0x00, 0x00, /* 0x18 0x08 mask offset (from beginning of struct) */
+ 0x01, 0x02, 0x03, 0x04, /* 0x1C 0x0C filter (padding 1) */
+ 0x05, 0x06, 0x07, 0x00,
+ 0xF1, 0xF2, 0xF3, 0xF4, /* 0x24 0x14 mask (padding 1) */
+ 0xF5, 0xF6, 0xF7, 0x00,
+ };
+
+ const guint8 filter[] = {
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07,
+ };
+ const guint8 mask[] = {
+ 0xF1, 0xF2, 0xF3, 0xF4,
+ 0xF5, 0xF6, 0xF7,
+ };
+
+
+ filters = g_new0 (MbimPacketFilter *, 2);
+ filters[0] = g_new (MbimPacketFilter, 1);
+ filters[0]->filter_size = 7;
+ filters[0]->packet_filter = g_new (guint8, 7);
+ memcpy (filters[0]->packet_filter, filter, 7);
+ filters[0]->packet_mask = g_new (guint8, 7);
+ memcpy (filters[0]->packet_mask, mask, 7);
+
+ /* IP packet filters set message */
+ message = (mbim_message_ip_packet_filters_set_new (
+ 1,
+ 1,
+ (const MbimPacketFilter * const*)filters,
+ &error));
+
+ g_assert_no_error (error);
+ g_assert (message != NULL);
+ mbim_message_set_transaction_id (message, 1);
+
+ test_message_trace ((const guint8 *)((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ expected_message,
+ sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_BASIC_CONNECT);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_BASIC_CONNECT_IP_PACKET_FILTERS);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_SET);
+
+ g_assert_cmpuint (((GByteArray *)message)->len, ==, sizeof (expected_message));
+ g_assert (memcmp (((GByteArray *)message)->data, expected_message, sizeof (expected_message)) == 0);
+
+ mbim_message_unref (message);
+
+ mbim_packet_filter_array_free (filters);
+}
+
+static void
+test_message_builder_basic_connect_ip_packet_filters_set_two (void)
+{
+ GError *error = NULL;
+ MbimMessage *message;
+ MbimPacketFilter **filters;
+ const guint8 expected_message [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x00, /* type */
+ 0x88, 0x00, 0x00, 0x00, /* length */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_message */
+ 0xA2, 0x89, 0xCC, 0x33, /* service id */
+ 0xBC, 0xBB, 0x8B, 0x4F,
+ 0xB6, 0xB0, 0x13, 0x3E,
+ 0xC2, 0xAA, 0xE6, 0xDF,
+ 0x17, 0x00, 0x00, 0x00, /* command id */
+ 0x01, 0x00, 0x00, 0x00, /* command_type */
+ 0x58, 0x00, 0x00, 0x00, /* buffer_length */
+ /* information buffer */
+ 0x01, 0x00, 0x00, 0x00, /* 0x00 session id */
+ 0x02, 0x00, 0x00, 0x00, /* 0x04 packet filters count */
+ 0x18, 0x00, 0x00, 0x00, /* 0x08 packet filter 1 offset */
+ 0x1C, 0x00, 0x00, 0x00, /* 0x0C packet filter 1 length */
+ 0x34, 0x00, 0x00, 0x00, /* 0x10 packet filter 2 offset */
+ 0x24, 0x00, 0x00, 0x00, /* 0x14 packet filter 2 length */
+ /* databuffer, packet filter 2 */
+ 0x08, 0x00, 0x00, 0x00, /* 0x18 0x00 filter size */
+ 0x0C, 0x00, 0x00, 0x00, /* 0x1C 0x04 filter offset (from beginning of struct) */
+ 0x14, 0x00, 0x00, 0x00, /* 0x20 0x08 mask offset (from beginning of struct) */
+ 0x01, 0x02, 0x03, 0x04, /* 0x24 0x0C filter */
+ 0x05, 0x06, 0x07, 0x08,
+ 0xF1, 0xF2, 0xF3, 0xF4, /* 0x2C 0x14 mask */
+ 0xF5, 0xF6, 0xF7, 0xF8,
+ /* databuffer, packet filter 2 */
+ 0x0C, 0x00, 0x00, 0x00, /* 0x34 0x00 filter size */
+ 0x0C, 0x00, 0x00, 0x00, /* 0x38 0x04 filter offset (from beginning of struct) */
+ 0x18, 0x00, 0x00, 0x00, /* 0x3C 0x08 mask offset (from beginning of struct) */
+ 0x01, 0x02, 0x03, 0x04, /* 0x40 0x0C filter */
+ 0x05, 0x06, 0x07, 0x08,
+ 0x05, 0x06, 0x07, 0x08,
+ 0xF1, 0xF2, 0xF3, 0xF4, /* 0x4C 0x18 mask */
+ 0xF5, 0xF6, 0xF7, 0xF8,
+ 0xF5, 0xF6, 0xF7, 0xF8,
+ };
+
+ const guint8 filter1[] = {
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08,
+ };
+ const guint8 mask1[] = {
+ 0xF1, 0xF2, 0xF3, 0xF4,
+ 0xF5, 0xF6, 0xF7, 0xF8,
+ };
+ const guint8 filter2[] = {
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08,
+ 0x05, 0x06, 0x07, 0x08,
+ };
+ const guint8 mask2[] = {
+ 0xF1, 0xF2, 0xF3, 0xF4,
+ 0xF5, 0xF6, 0xF7, 0xF8,
+ 0xF5, 0xF6, 0xF7, 0xF8,
+ };
+
+ filters = g_new0 (MbimPacketFilter *, 3);
+ filters[0] = g_new (MbimPacketFilter, 1);
+ filters[0]->filter_size = 8;
+ filters[0]->packet_filter = g_new (guint8, 8);
+ memcpy (filters[0]->packet_filter, filter1, 8);
+ filters[0]->packet_mask = g_new (guint8, 8);
+ memcpy (filters[0]->packet_mask, mask1, 8);
+ filters[1] = g_new (MbimPacketFilter, 1);
+ filters[1]->filter_size = 12;
+ filters[1]->packet_filter = g_new (guint8, 12);
+ memcpy (filters[1]->packet_filter, filter2, 12);
+ filters[1]->packet_mask = g_new (guint8, 12);
+ memcpy (filters[1]->packet_mask, mask2, 12);
+
+ /* IP packet filters set message */
+ message = (mbim_message_ip_packet_filters_set_new (
+ 1,
+ 2,
+ (const MbimPacketFilter * const*)filters,
+ &error));
+
+ g_assert_no_error (error);
+ g_assert (message != NULL);
+ mbim_message_set_transaction_id (message, 1);
+
+ test_message_trace ((const guint8 *)((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ expected_message,
+ sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_BASIC_CONNECT);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_BASIC_CONNECT_IP_PACKET_FILTERS);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_SET);
+
+ g_assert_cmpuint (((GByteArray *)message)->len, ==, sizeof (expected_message));
+ g_assert (memcmp (((GByteArray *)message)->data, expected_message, sizeof (expected_message)) == 0);
+
+ mbim_message_unref (message);
+
+ mbim_packet_filter_array_free (filters);
+}
+
+static void
+test_message_builder_dss_connect_set (void)
+{
+ GError *error = NULL;
+ MbimMessage *message;
+ const guint8 expected_message [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x00, /* type */
+ 0x48, 0x00, 0x00, 0x00, /* length */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_message */
+ 0xC0, 0x8A, 0x26, 0xDD, /* service id */
+ 0x77, 0x18, 0x43, 0x82,
+ 0x84, 0x82, 0x6E, 0x0D,
+ 0x58, 0x3C, 0x4D, 0x0E,
+ 0x01, 0x00, 0x00, 0x00, /* command id */
+ 0x01, 0x00, 0x00, 0x00, /* command_type */
+ 0x18, 0x00, 0x00, 0x00, /* buffer_length */
+ /* information buffer */
+ 0x01, 0x02, 0x03, 0x04, /* service id */
+ 0xFF, 0xFF, 0xBB, 0xBB,
+ 0xFF, 0xCC, 0xF0, 0xF1,
+ 0xF2, 0xF3, 0xF4, 0xF5,
+ 0xFF, 0x00, 0x00, 0x00, /* dss session id */
+ 0x01, 0x00, 0x00, 0x00 /* dss link state */
+ };
+
+ static const MbimUuid another_uuid = {
+ .a = { 0x01, 0x02, 0x03, 0x04 },
+ .b = { 0xFF, 0xFF },
+ .c = { 0xBB, 0xBB },
+ .d = { 0xFF, 0xCC },
+ .e = { 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5 }
+ };
+
+ /* IP packet filters set message */
+ message = (mbim_message_dss_connect_set_new (
+ &another_uuid,
+ 255,
+ MBIM_DSS_LINK_STATE_ACTIVATE,
+ &error));
+
+ g_assert_no_error (error);
+ g_assert (message != NULL);
+ mbim_message_set_transaction_id (message, 1);
+
+ test_message_trace ((const guint8 *)((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ expected_message,
+ sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_DSS);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_DSS_CONNECT);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_SET);
+
+ g_assert_cmpuint (((GByteArray *)message)->len, ==, sizeof (expected_message));
+ g_assert (memcmp (((GByteArray *)message)->data, expected_message, sizeof (expected_message)) == 0);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_message_builder_basic_connect_multicarrier_providers_set (void)
+{
+ GError *error = NULL;
+ MbimMessage *message;
+ MbimProvider **providers;
+ const guint8 expected_message [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x00, /* type */
+ 0xB4, 0x00, 0x00, 0x00, /* length */
+ 0x01, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_message */
+ 0xA2, 0x89, 0xCC, 0x33, /* service id */
+ 0xBC, 0xBB, 0x8B, 0x4F,
+ 0xB6, 0xB0, 0x13, 0x3E,
+ 0xC2, 0xAA, 0xE6, 0xDF,
+ 0x18, 0x00, 0x00, 0x00, /* command id */
+ 0x01, 0x00, 0x00, 0x00, /* command_type */
+ 0x84, 0x00, 0x00, 0x00, /* buffer_length */
+ /* information buffer */
+ 0x02, 0x00, 0x00, 0x00, /* 0x00 providers count */
+ 0x14, 0x00, 0x00, 0x00, /* 0x04 provider 0 offset */
+ 0x38, 0x00, 0x00, 0x00, /* 0x08 provider 0 length */
+ 0x4C, 0x00, 0x00, 0x00, /* 0x0C provider 1 offset */
+ 0x38, 0x00, 0x00, 0x00, /* 0x10 provider 1 length */
+ /* data buffer... struct provider 0 */
+ 0x20, 0x00, 0x00, 0x00, /* 0x14 [0x00] id offset */
+ 0x0A, 0x00, 0x00, 0x00, /* 0x18 [0x04] id length */
+ 0x08, 0x00, 0x00, 0x00, /* 0x1C [0x08] state */
+ 0x2C, 0x00, 0x00, 0x00, /* 0x20 [0x0C] name offset */
+ 0x0C, 0x00, 0x00, 0x00, /* 0x24 [0x10] name length */
+ 0x01, 0x00, 0x00, 0x00, /* 0x28 [0x14] cellular class */
+ 0x0B, 0x00, 0x00, 0x00, /* 0x2C [0x18] rssi */
+ 0x00, 0x00, 0x00, 0x00, /* 0x30 [0x1C] error rate */
+ 0x32, 0x00, 0x31, 0x00, /* 0x34 [0x20] id string (10 bytes) */
+ 0x34, 0x00, 0x30, 0x00,
+ 0x33, 0x00, 0x00, 0x00,
+ 0x4F, 0x00, 0x72, 0x00, /* 0x40 [0x2C] name string (12 bytes) */
+ 0x61, 0x00, 0x6E, 0x00,
+ 0x67, 0x00, 0x65, 0x00,
+ /* data buffer... struct provider 1 */
+ 0x20, 0x00, 0x00, 0x00, /* 0x4C [0x00] id offset */
+ 0x0A, 0x00, 0x00, 0x00, /* 0x50 [0x04] id length */
+ 0x19, 0x00, 0x00, 0x00, /* 0x51 [0x08] state */
+ 0x2C, 0x00, 0x00, 0x00, /* 0x54 [0x0C] name offset */
+ 0x0C, 0x00, 0x00, 0x00, /* 0x58 [0x10] name length */
+ 0x01, 0x00, 0x00, 0x00, /* 0x5C [0x14] cellular class */
+ 0x0B, 0x00, 0x00, 0x00, /* 0x60 [0x18] rssi */
+ 0x00, 0x00, 0x00, 0x00, /* 0x64 [0x1C] error rate */
+ 0x32, 0x00, 0x31, 0x00, /* 0x68 [0x20] id string (10 bytes) */
+ 0x34, 0x00, 0x30, 0x00,
+ 0x33, 0x00, 0x00, 0x00,
+ 0x4F, 0x00, 0x72, 0x00, /* 0x74 [0x2C] name string (12 bytes) */
+ 0x61, 0x00, 0x6E, 0x00,
+ 0x67, 0x00, 0x65, 0x00
+ };
+
+ providers = g_new0 (MbimProvider *, 3);
+ providers[0] = g_new0 (MbimProvider, 1);
+ providers[0]->provider_id = g_strdup ("21403");
+ providers[0]->provider_name = g_strdup ("Orange");
+ providers[0]->provider_state = MBIM_PROVIDER_STATE_VISIBLE;
+ providers[0]->cellular_class = MBIM_CELLULAR_CLASS_GSM;
+ providers[0]->rssi = 11;
+ providers[0]->error_rate = 0;
+ providers[1] = g_new0 (MbimProvider, 1);
+ providers[1]->provider_id = g_strdup ("21403");
+ providers[1]->provider_name = g_strdup ("Orange");
+ providers[1]->provider_state = (MBIM_PROVIDER_STATE_HOME |
+ MBIM_PROVIDER_STATE_VISIBLE |
+ MBIM_PROVIDER_STATE_REGISTERED);
+ providers[1]->cellular_class = MBIM_CELLULAR_CLASS_GSM;
+ providers[1]->rssi = 11;
+ providers[1]->error_rate = 0;
+
+ /* Multicarrier providers set message */
+ message = (mbim_message_multicarrier_providers_set_new (
+ 2,
+ (const MbimProvider *const *)providers,
+ &error));
+
+ g_assert_no_error (error);
+ g_assert (message != NULL);
+ mbim_message_set_transaction_id (message, 1);
+
+ test_message_trace ((const guint8 *)((GByteArray *)message)->data,
+ ((GByteArray *)message)->len,
+ expected_message,
+ sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, sizeof (expected_message));
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_BASIC_CONNECT);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_BASIC_CONNECT_MULTICARRIER_PROVIDERS);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_SET);
+
+ g_assert_cmpuint (((GByteArray *)message)->len, ==, sizeof (expected_message));
+ g_assert (memcmp (((GByteArray *)message)->data, expected_message, sizeof (expected_message)) == 0);
+
+ mbim_message_unref (message);
+ mbim_provider_array_free (providers);
+}
+
+int main (int argc, char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/libmbim-glib/message/builder/basic-connect/pin/set/raw", test_message_builder_basic_connect_pin_set_raw);
+ g_test_add_func ("/libmbim-glib/message/builder/basic-connect/pin/set", test_message_builder_basic_connect_pin_set);
+ g_test_add_func ("/libmbim-glib/message/builder/basic-connect/connect/set/raw", test_message_builder_basic_connect_connect_set_raw);
+ g_test_add_func ("/libmbim-glib/message/builder/basic-connect/connect/set", test_message_builder_basic_connect_connect_set);
+ g_test_add_func ("/libmbim-glib/message/builder/basic-connect/service-activation/set", test_message_builder_basic_connect_service_activation_set);
+ g_test_add_func ("/libmbim-glib/message/builder/basic-connect/device-service-subscriber-list/set", test_message_builder_basic_connect_device_service_subscriber_list_set);
+ g_test_add_func ("/libmbim-glib/message/builder/ussd/set", test_message_builder_ussd_set);
+ g_test_add_func ("/libmbim-glib/message/builder/auth/akap/query", test_message_builder_auth_akap_query);
+ g_test_add_func ("/libmbim-glib/message/builder/stk/pac/set", test_message_builder_stk_pac_set);
+ g_test_add_func ("/libmbim-glib/message/builder/stk/terminal-response/set", test_message_builder_stk_terminal_response_set);
+ g_test_add_func ("/libmbim-glib/message/builder/stk/envelope/set", test_message_builder_stk_envelope_set);
+ g_test_add_func ("/libmbim-glib/message/builder/basic-connect/ip-packet-filters/set/none", test_message_builder_basic_connect_ip_packet_filters_set_none);
+ g_test_add_func ("/libmbim-glib/message/builder/basic-connect/ip-packet-filters/set/one", test_message_builder_basic_connect_ip_packet_filters_set_one);
+ g_test_add_func ("/libmbim-glib/message/builder/basic-connect/ip-packet-filters/set/two", test_message_builder_basic_connect_ip_packet_filters_set_two);
+ g_test_add_func ("/libmbim-glib/message/builder/dss/connect/set", test_message_builder_dss_connect_set);
+ g_test_add_func ("/libmbim-glib/message/builder/basic-connect/multicarrier-providers/set", test_message_builder_basic_connect_multicarrier_providers_set);
+
+ return g_test_run ();
+}
diff --git a/libmbim-glib/test/test-message-parser.c b/libmbim-glib/test/test-message-parser.c
new file mode 100644
index 0000000..1f33805
--- /dev/null
+++ b/libmbim-glib/test/test-message-parser.c
@@ -0,0 +1,1587 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#include <config.h>
+#include <string.h>
+
+#include "mbim-basic-connect.h"
+#include "mbim-sms.h"
+#include "mbim-ussd.h"
+#include "mbim-auth.h"
+#include "mbim-stk.h"
+#include "mbim-message.h"
+#include "mbim-cid.h"
+#include "mbim-utils.h"
+
+#if defined ENABLE_TEST_MESSAGE_TRACES
+static void
+test_message_trace (const guint8 *computed,
+ guint32 computed_size,
+ const guint8 *expected,
+ guint32 expected_size)
+{
+ gchar *message_str;
+ gchar *expected_str;
+
+ message_str = __mbim_utils_str_hex (computed, computed_size, ':');
+ expected_str = __mbim_utils_str_hex (expected, expected_size, ':');
+
+ /* Dump all message contents */
+ g_print ("\n"
+ "Message str:\n"
+ "'%s'\n"
+ "Expected str:\n"
+ "'%s'\n",
+ message_str,
+ expected_str);
+
+ /* If they are different, tell which are the different bytes */
+ if (computed_size != expected_size ||
+ memcmp (computed, expected, expected_size)) {
+ guint32 i;
+
+ for (i = 0; i < MIN (computed_size, expected_size); i++) {
+ if (computed[i] != expected[i])
+ g_print ("Byte [%u] is different (computed: 0x%02X vs expected: 0x%02x)\n", i, computed[i], expected[i]);
+ }
+ }
+
+ g_free (message_str);
+ g_free (expected_str);
+}
+#else
+#define test_message_trace(...)
+#endif
+
+static void
+test_message_parser_basic_connect_visible_providers (void)
+{
+ MbimProvider **providers;
+ guint32 n_providers;
+ MbimMessage *response;
+ GError *error = NULL;
+ const guint8 buffer [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x80, /* type */
+ 0xB4, 0x00, 0x00, 0x00, /* length */
+ 0x02, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_done_message */
+ 0xA2, 0x89, 0xCC, 0x33, /* service id */
+ 0xBC, 0xBB, 0x8B, 0x4F,
+ 0xB6, 0xB0, 0x13, 0x3E,
+ 0xC2, 0xAA, 0xE6, 0xDF,
+ 0x08, 0x00, 0x00, 0x00, /* command id */
+ 0x00, 0x00, 0x00, 0x00, /* status code */
+ 0x84, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x02, 0x00, 0x00, 0x00, /* 0x00 providers count */
+ 0x14, 0x00, 0x00, 0x00, /* 0x04 provider 0 offset */
+ 0x38, 0x00, 0x00, 0x00, /* 0x08 provider 0 length */
+ 0x4C, 0x00, 0x00, 0x00, /* 0x0C provider 1 offset */
+ 0x38, 0x00, 0x00, 0x00, /* 0x10 provider 1 length */
+ /* data buffer... struct provider 0 */
+ 0x20, 0x00, 0x00, 0x00, /* 0x14 [0x00] id offset */
+ 0x0A, 0x00, 0x00, 0x00, /* 0x18 [0x04] id length */
+ 0x08, 0x00, 0x00, 0x00, /* 0x1C [0x08] state */
+ 0x2C, 0x00, 0x00, 0x00, /* 0x20 [0x0C] name offset */
+ 0x0C, 0x00, 0x00, 0x00, /* 0x24 [0x10] name length */
+ 0x01, 0x00, 0x00, 0x00, /* 0x28 [0x14] cellular class */
+ 0x0B, 0x00, 0x00, 0x00, /* 0x2C [0x18] rssi */
+ 0x00, 0x00, 0x00, 0x00, /* 0x30 [0x1C] error rate */
+ 0x32, 0x00, 0x31, 0x00, /* 0x34 [0x20] id string (10 bytes) */
+ 0x34, 0x00, 0x30, 0x00,
+ 0x33, 0x00, 0x00, 0x00,
+ 0x4F, 0x00, 0x72, 0x00, /* 0x40 [0x2C] name string (12 bytes) */
+ 0x61, 0x00, 0x6E, 0x00,
+ 0x67, 0x00, 0x65, 0x00,
+ /* data buffer... struct provider 1 */
+ 0x20, 0x00, 0x00, 0x00, /* 0x4C [0x00] id offset */
+ 0x0A, 0x00, 0x00, 0x00, /* 0x50 [0x04] id length */
+ 0x19, 0x00, 0x00, 0x00, /* 0x51 [0x08] state */
+ 0x2C, 0x00, 0x00, 0x00, /* 0x54 [0x0C] name offset */
+ 0x0C, 0x00, 0x00, 0x00, /* 0x58 [0x10] name length */
+ 0x01, 0x00, 0x00, 0x00, /* 0x5C [0x14] cellular class */
+ 0x0B, 0x00, 0x00, 0x00, /* 0x60 [0x18] rssi */
+ 0x00, 0x00, 0x00, 0x00, /* 0x64 [0x1C] error rate */
+ 0x32, 0x00, 0x31, 0x00, /* 0x68 [0x20] id string (10 bytes) */
+ 0x34, 0x00, 0x30, 0x00,
+ 0x33, 0x00, 0x00, 0x00,
+ 0x4F, 0x00, 0x72, 0x00, /* 0x74 [0x2C] name string (12 bytes) */
+ 0x61, 0x00, 0x6E, 0x00,
+ 0x67, 0x00, 0x65, 0x00 };
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert (mbim_message_visible_providers_response_parse (
+ response,
+ &n_providers,
+ &providers,
+ &error));
+
+ g_assert_no_error (error);
+
+ g_assert_cmpuint (n_providers, ==, 2);
+
+ /* Provider [0]
+ * Provider ID: '21403'
+ * Provider Name: 'Orange'
+ * State: 'visible'
+ * Cellular class: 'gsm'
+ * RSSI: '11'
+ * Error rate: '0'
+ */
+ g_assert_cmpstr (providers[0]->provider_id, ==, "21403");
+ g_assert_cmpstr (providers[0]->provider_name, ==, "Orange");
+ g_assert_cmpuint (providers[0]->provider_state, ==, MBIM_PROVIDER_STATE_VISIBLE);
+ g_assert_cmpuint (providers[0]->cellular_class, ==, MBIM_CELLULAR_CLASS_GSM);
+ g_assert_cmpuint (providers[0]->rssi, ==, 11);
+ g_assert_cmpuint (providers[0]->error_rate, ==, 0);
+
+ /* Provider [1]:
+ * Provider ID: '21403'
+ * Provider Name: 'Orange'
+ * State: 'home, visible, registered'
+ * Cellular class: 'gsm'
+ * RSSI: '11'
+ * Error rate: '0'
+ */
+ g_assert_cmpstr (providers[1]->provider_id, ==, "21403");
+ g_assert_cmpstr (providers[1]->provider_name, ==, "Orange");
+ g_assert_cmpuint (providers[1]->provider_state, ==, (MBIM_PROVIDER_STATE_HOME |
+ MBIM_PROVIDER_STATE_VISIBLE |
+ MBIM_PROVIDER_STATE_REGISTERED));
+ g_assert_cmpuint (providers[1]->cellular_class, ==, MBIM_CELLULAR_CLASS_GSM);
+ g_assert_cmpuint (providers[1]->rssi, ==, 11);
+ g_assert_cmpuint (providers[1]->error_rate, ==, 0);
+
+ mbim_provider_array_free (providers);
+ mbim_message_unref (response);
+}
+
+static void
+test_message_parser_basic_connect_subscriber_ready_status (void)
+{
+ MbimSubscriberReadyState ready_state;
+ gchar *subscriber_id;
+ gchar *sim_iccid;
+ MbimReadyInfoFlag ready_info;
+ guint32 telephone_numbers_count;
+ gchar **telephone_numbers;
+ MbimMessage *response;
+ GError *error = NULL;
+ const guint8 buffer [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x80, /* type */
+ 0xB4, 0x00, 0x00, 0x00, /* length */
+ 0x02, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_message */
+ 0xA2, 0x89, 0xCC, 0x33, /* service id */
+ 0xBC, 0xBB, 0x8B, 0x4F,
+ 0xB6, 0xB0, 0x13, 0x3E,
+ 0xC2, 0xAA, 0xE6, 0xDF,
+ 0x02, 0x00, 0x00, 0x00, /* command id */
+ 0x00, 0x00, 0x00, 0x00, /* status code */
+ 0x84, 0x00, 0x00, 0x00, /* buffer_length */
+ /* information buffer */
+ 0x01, 0x00, 0x00, 0x00, /* 0x00 ready state */
+ 0x5C, 0x00, 0x00, 0x00, /* 0x04 subscriber id (offset) */
+ 0x1E, 0x00, 0x00, 0x00, /* 0x08 subscriber id (size) */
+ 0x7C, 0x00, 0x00, 0x00, /* 0x0C sim iccid (offset) */
+ 0x28, 0x00, 0x00, 0x00, /* 0x10 sim iccid (size) */
+ 0x00, 0x00, 0x00, 0x00, /* 0x14 ready info */
+ 0x02, 0x00, 0x00, 0x00, /* 0x18 telephone numbers count */
+ 0x2C, 0x00, 0x00, 0x00, /* 0x1C telephone number #1 (offset) */
+ 0x16, 0x00, 0x00, 0x00, /* 0x20 telephone number #1 (size) */
+ 0x44, 0x00, 0x00, 0x00, /* 0x24 telephone number #2 (offset) */
+ 0x16, 0x00, 0x00, 0x00, /* 0x28 telephone number #2 (size) */
+ /* data buffer */
+ 0x31, 0x00, 0x31, 0x00, /* 0x2C telephone number #1 (data) */
+ 0x31, 0x00, 0x31, 0x00,
+ 0x31, 0x00, 0x31, 0x00,
+ 0x31, 0x00, 0x31, 0x00,
+ 0x31, 0x00, 0x31, 0x00,
+ 0x31, 0x00, 0x00, 0x00, /* last 2 bytes are padding */
+ 0x30, 0x00, 0x30, 0x00, /* 0x44 telephone number #2 (data) */
+ 0x30, 0x00, 0x30, 0x00,
+ 0x30, 0x00, 0x30, 0x00,
+ 0x30, 0x00, 0x30, 0x00,
+ 0x30, 0x00, 0x30, 0x00,
+ 0x30, 0x00, 0x00, 0x00, /* last 2 bytes are padding */
+ 0x33, 0x00, 0x31, 0x00, /* 0x5C subscriber id (data) */
+ 0x30, 0x00, 0x34, 0x00,
+ 0x31, 0x00, 0x30, 0x00,
+ 0x30, 0x00, 0x30, 0x00,
+ 0x30, 0x00, 0x31, 0x00,
+ 0x31, 0x00, 0x30, 0x00,
+ 0x37, 0x00, 0x36, 0x00,
+ 0x31, 0x00, 0x00, 0x00, /* last 2 bytes are padding */
+ 0x38, 0x00, 0x39, 0x00, /* 0x7C sim iccid (data) */
+ 0x30, 0x00, 0x31, 0x00,
+ 0x30, 0x00, 0x31, 0x00,
+ 0x30, 0x00, 0x34, 0x00,
+ 0x30, 0x00, 0x35, 0x00,
+ 0x34, 0x00, 0x36, 0x00,
+ 0x30, 0x00, 0x31, 0x00,
+ 0x31, 0x00, 0x30, 0x00,
+ 0x30, 0x00, 0x36, 0x00,
+ 0x31, 0x00, 0x32, 0x00 };
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert (mbim_message_subscriber_ready_status_response_parse (
+ response,
+ &ready_state,
+ &subscriber_id,
+ &sim_iccid,
+ &ready_info,
+ &telephone_numbers_count,
+ &telephone_numbers,
+ &error));
+
+ g_assert_no_error (error);
+
+ g_assert_cmpuint (ready_state, ==, MBIM_SUBSCRIBER_READY_STATE_INITIALIZED);
+ g_assert_cmpstr (subscriber_id, ==, "310410000110761");
+ g_assert_cmpstr (sim_iccid, ==, "89010104054601100612");
+ g_assert_cmpuint (ready_info, ==, 0);
+ g_assert_cmpuint (telephone_numbers_count, ==, 2);
+ g_assert_cmpstr (telephone_numbers[0], ==, "11111111111");
+ g_assert_cmpstr (telephone_numbers[1], ==, "00000000000");
+ g_assert (telephone_numbers[2] == NULL);
+
+ g_free (subscriber_id);
+ g_free (sim_iccid);
+ g_strfreev (telephone_numbers);
+
+ mbim_message_unref (response);
+}
+
+static void
+test_message_parser_basic_connect_device_caps (void)
+{
+ MbimMessage *response;
+ MbimDeviceType device_type;
+ MbimCellularClass cellular_class;
+ MbimVoiceClass voice_class;
+ MbimSimClass sim_class;
+ MbimDataClass data_class;
+ MbimSmsCaps sms_caps;
+ MbimCtrlCaps ctrl_caps;
+ guint32 max_sessions;
+ gchar *custom_data_class;
+ gchar *device_id;
+ gchar *firmware_info;
+ gchar *hardware_info;
+ GError *error = NULL;
+ const guint8 buffer [] = { 0x03, 0x00, 0x00, 0x80,
+ 0xD0, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xA2, 0x89, 0xCC, 0x33,
+ 0xBC, 0xBB, 0x8B, 0x4F,
+ 0xB6, 0xB0, 0x13, 0x3E,
+ 0xC2, 0xAA, 0xE6, 0xDF,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xA0, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x1F, 0x00, 0x00, 0x80,
+ 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x40, 0x00, 0x00, 0x00,
+ 0x0A, 0x00, 0x00, 0x00,
+ 0x4C, 0x00, 0x00, 0x00,
+ 0x1E, 0x00, 0x00, 0x00,
+ 0x6C, 0x00, 0x00, 0x00,
+ 0x1E, 0x00, 0x00, 0x00,
+ 0x8C, 0x00, 0x00, 0x00,
+ 0x12, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x53, 0x00,
+ 0x50, 0x00, 0x41, 0x00,
+ 0x2B, 0x00, 0x00, 0x00,
+ 0x33, 0x00, 0x35, 0x00,
+ 0x33, 0x00, 0x36, 0x00,
+ 0x31, 0x00, 0x33, 0x00,
+ 0x30, 0x00, 0x34, 0x00,
+ 0x38, 0x00, 0x38, 0x00,
+ 0x30, 0x00, 0x34, 0x00,
+ 0x36, 0x00, 0x32, 0x00,
+ 0x32, 0x00, 0x00, 0x00,
+ 0x31, 0x00, 0x31, 0x00,
+ 0x2E, 0x00, 0x38, 0x00,
+ 0x31, 0x00, 0x30, 0x00,
+ 0x2E, 0x00, 0x30, 0x00,
+ 0x39, 0x00, 0x2E, 0x00,
+ 0x30, 0x00, 0x30, 0x00,
+ 0x2E, 0x00, 0x30, 0x00,
+ 0x30, 0x00, 0x00, 0x00,
+ 0x43, 0x00, 0x50, 0x00,
+ 0x31, 0x00, 0x45, 0x00,
+ 0x33, 0x00, 0x36, 0x00,
+ 0x37, 0x00, 0x55, 0x00,
+ 0x4D, 0x00, 0x00, 0x00 };
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert (mbim_message_device_caps_response_parse (
+ response,
+ &device_type,
+ &cellular_class,
+ &voice_class,
+ &sim_class,
+ &data_class,
+ &sms_caps,
+ &ctrl_caps,
+ &max_sessions,
+ &custom_data_class,
+ &device_id,
+ &firmware_info,
+ &hardware_info,
+ &error));
+
+ g_assert_no_error (error);
+
+ g_assert_cmpuint (device_type, ==, MBIM_DEVICE_TYPE_REMOVABLE);
+ g_assert_cmpuint (cellular_class, ==, MBIM_CELLULAR_CLASS_GSM);
+ g_assert_cmpuint (sim_class, ==, MBIM_SIM_CLASS_REMOVABLE);
+ g_assert_cmpuint (data_class, ==, (MBIM_DATA_CLASS_GPRS |
+ MBIM_DATA_CLASS_EDGE |
+ MBIM_DATA_CLASS_UMTS |
+ MBIM_DATA_CLASS_HSDPA |
+ MBIM_DATA_CLASS_HSUPA |
+ MBIM_DATA_CLASS_CUSTOM));
+ g_assert_cmpuint (sms_caps, ==, (MBIM_SMS_CAPS_PDU_RECEIVE | MBIM_SMS_CAPS_PDU_SEND));
+ g_assert_cmpuint (ctrl_caps, ==, MBIM_CTRL_CAPS_REG_MANUAL);
+ g_assert_cmpuint (max_sessions, ==, 1);
+ g_assert_cmpstr (custom_data_class, ==, "HSPA+");
+ g_assert_cmpstr (device_id, ==, "353613048804622");
+ g_assert_cmpstr (firmware_info, ==, "11.810.09.00.00");
+ g_assert_cmpstr (hardware_info, ==, "CP1E367UM");
+
+ g_free (custom_data_class);
+ g_free (device_id);
+ g_free (firmware_info);
+ g_free (hardware_info);
+
+ mbim_message_unref (response);
+}
+
+static void
+test_message_parser_basic_connect_ip_configuration (void)
+{
+ MbimMessage *response;
+ guint32 session_id;
+ MbimIPConfigurationAvailableFlag ipv4configurationavailable;
+ MbimIPConfigurationAvailableFlag ipv6configurationavailable;
+ guint32 ipv4addresscount;
+ MbimIPv4Element **ipv4address;
+ guint32 ipv6addresscount;
+ MbimIPv6Element **ipv6address;
+ const MbimIPv4 *ipv4gateway;
+ const MbimIPv6 *ipv6gateway;
+ guint32 ipv4dnsservercount;
+ MbimIPv4 *ipv4dnsserver;
+ guint32 ipv6dnsservercount;
+ MbimIPv6 *ipv6dnsserver;
+ guint32 ipv4mtu;
+ guint32 ipv6mtu;
+ GError *error = NULL;
+ const guint8 buffer [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x80, /* type */
+ 0x80, 0x00, 0x00, 0x00, /* length */
+ 0x1A, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_done_message */
+ 0xA2, 0x89, 0xCC, 0x33, /* service id */
+ 0xBC, 0xBB, 0x8B, 0x4F,
+ 0xB6, 0xB0, 0x13, 0x3E,
+ 0xC2, 0xAA, 0xE6, 0xDF,
+ 0x0F, 0x00, 0x00, 0x00, /* command id */
+ 0x00, 0x00, 0x00, 0x00, /* status code */
+ 0x50, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x00, 0x00, 0x00, 0x00, /* session id */
+ 0x0F, 0x00, 0x00, 0x00, /* IPv4ConfigurationAvailable */
+ 0x00, 0x00, 0x00, 0x00, /* IPv6ConfigurationAvailable */
+ 0x01, 0x00, 0x00, 0x00, /* IPv4 element count */
+ 0x3C, 0x00, 0x00, 0x00, /* IPv4 element offset */
+ 0x00, 0x00, 0x00, 0x00, /* IPv6 element count */
+ 0x00, 0x00, 0x00, 0x00, /* IPv6 element offset */
+ 0x44, 0x00, 0x00, 0x00, /* IPv4 gateway offset */
+ 0x00, 0x00, 0x00, 0x00, /* IPv6 gateway offset */
+ 0x02, 0x00, 0x00, 0x00, /* IPv4 DNS count */
+ 0x48, 0x00, 0x00, 0x00, /* IPv4 DNS offset */
+ 0x00, 0x00, 0x00, 0x00, /* IPv6 DNS count */
+ 0x00, 0x00, 0x00, 0x00, /* IPv6 DNS offset */
+ 0xDC, 0x05, 0x00, 0x00, /* IPv4 MTU */
+ 0x00, 0x00, 0x00, 0x00, /* IPv6 MTU */
+ /* data buffer */
+ 0x1C, 0x00, 0x00, 0x00, /* IPv4 element (netmask) */
+ 0xD4, 0x49, 0x22, 0xF8, /* IPv4 element (address) */
+ 0xD4, 0x49, 0x22, 0xF1, /* IPv4 gateway */
+ 0xD4, 0xA6, 0xD2, 0x50, /* IPv4 DNS1 */
+ 0xD4, 0x49, 0x20, 0x43 /* IPv4 DNS2 */
+ };
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert (mbim_message_ip_configuration_response_parse (
+ response,
+ &session_id,
+ &ipv4configurationavailable,
+ &ipv6configurationavailable,
+ &ipv4addresscount,
+ &ipv4address,
+ &ipv6addresscount,
+ &ipv6address,
+ &ipv4gateway,
+ &ipv6gateway,
+ &ipv4dnsservercount,
+ &ipv4dnsserver,
+ &ipv6dnsservercount,
+ &ipv6dnsserver,
+ &ipv4mtu,
+ &ipv6mtu,
+ &error));
+
+ /*
+ * IPv4 configuration available: 'address, gateway, dns, mtu'
+ * IP addresses (1)
+ * IP [0]: '212.166.228.25/28'
+ * Gateway: '212.166.228.26'
+ * DNS addresses (2)
+ * DNS [0]: '212.166.210.80'
+ * DNS [1]: '212.73.32.67'
+ * MTU: '1500'
+ */
+
+ g_assert_cmpuint (session_id, ==, 0);
+ g_assert_cmpuint (ipv4configurationavailable, ==, (MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_ADDRESS |
+ MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_GATEWAY |
+ MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_DNS |
+ MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_MTU));
+ g_assert_cmpuint (ipv6configurationavailable, ==, MBIM_IP_CONFIGURATION_AVAILABLE_FLAG_NONE);
+
+ {
+ MbimIPv4 addr = { .addr = { 0xD4, 0x49, 0x22, 0xF8 } };
+
+ g_assert_cmpuint (ipv4addresscount, ==, 1);
+ g_assert_cmpuint (ipv4address[0]->on_link_prefix_length, ==, 28);
+ g_assert (memcmp (&addr, &(ipv4address[0]->ipv4_address), 4) == 0);
+ }
+
+ {
+ MbimIPv4 gateway_addr = { .addr = { 0xD4, 0x49, 0x22, 0xF1 } };
+
+ g_assert (memcmp (&gateway_addr, ipv4gateway, 4) == 0);
+ }
+
+ {
+ MbimIPv4 dns_addr_1 = { .addr = { 0xD4, 0xA6, 0xD2, 0x50 } };
+ MbimIPv4 dns_addr_2 = { .addr = { 0xD4, 0x49, 0x20, 0x43 } };
+
+ g_assert_cmpuint (ipv4dnsservercount, ==, 2);
+ g_assert (memcmp (&dns_addr_1, &ipv4dnsserver[0], 4) == 0);
+ g_assert (memcmp (&dns_addr_2, &ipv4dnsserver[1], 4) == 0);
+ }
+
+ g_assert_cmpuint (ipv4mtu, ==, 1500);
+
+ g_assert_cmpuint (ipv6addresscount, ==, 0);
+ g_assert (ipv6address == NULL);
+ g_assert (ipv6gateway == NULL);
+ g_assert_cmpuint (ipv6dnsservercount, ==, 0);
+ g_assert (ipv6dnsserver == NULL);
+
+ mbim_ipv4_element_array_free (ipv4address);
+ mbim_ipv6_element_array_free (ipv6address);
+ g_free (ipv4dnsserver);
+ g_free (ipv6dnsserver);
+
+ mbim_message_unref (response);
+}
+
+static void
+test_message_parser_basic_connect_service_activation (void)
+{
+ MbimMessage *response;
+ GError *error = NULL;
+ guint32 nw_error;
+ const guint8 *databuffer;
+ guint32 databuffer_size;
+ const guint8 expected_databuffer [] = {
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08
+ };
+ const guint8 buffer [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x80, /* type */
+ 0x3C, 0x00, 0x00, 0x00, /* length */
+ 0x02, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_done_message */
+ 0xA2, 0x89, 0xCC, 0x33, /* service id */
+ 0xBC, 0xBB, 0x8B, 0x4F,
+ 0xB6, 0xB0, 0x13, 0x3E,
+ 0xC2, 0xAA, 0xE6, 0xDF,
+ 0x0E, 0x00, 0x00, 0x00, /* command id */
+ 0x00, 0x00, 0x00, 0x00, /* status code */
+ 0x0C, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x06, 0x00, 0x00, 0x00, /* nw error */
+ 0x01, 0x02, 0x03, 0x04, /* buffer */
+ 0x05, 0x06, 0x07, 0x08 };
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert (mbim_message_service_activation_response_parse (
+ response,
+ &nw_error,
+ &databuffer_size,
+ &databuffer,
+ &error));
+
+ g_assert_no_error (error);
+
+ g_assert_cmpuint (nw_error, ==, MBIM_NW_ERROR_ILLEGAL_ME);
+ g_assert_cmpuint (databuffer_size, ==, sizeof (expected_databuffer));
+ g_assert (memcmp (databuffer, expected_databuffer, databuffer_size) == 0);
+
+ mbim_message_unref (response);
+}
+
+static void
+test_message_parser_sms_read_zero_pdu (void)
+{
+ MbimSmsFormat format;
+ guint32 messages_count;
+ MbimSmsPduReadRecord **pdu_messages;
+ MbimSmsCdmaReadRecord **cdma_messages;
+ MbimMessage *response;
+ GError *error = NULL;
+ const guint8 buffer [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x80, /* type */
+ 0xB0, 0x00, 0x00, 0x00, /* length */
+ 0x02, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_done_message */
+ 0x53, 0x3F, 0xBE, 0xEB, /* service id */
+ 0x14, 0xFE, 0x44, 0x67,
+ 0x9F, 0x90, 0x33, 0xA2,
+ 0x23, 0xE5, 0x6C, 0x3F,
+ 0x02, 0x00, 0x00, 0x00, /* command id */
+ 0x00, 0x00, 0x00, 0x00, /* status code */
+ 0x38, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x00, 0x00, 0x00, 0x00, /* 0x00 format */
+ 0x00, 0x00, 0x00, 0x00, /* 0x04 messages count */
+ };
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert (mbim_message_sms_read_response_parse (
+ response,
+ &format,
+ &messages_count,
+ &pdu_messages,
+ &cdma_messages,
+ &error));
+ g_assert_no_error (error);
+
+ g_assert_cmpuint (format, ==, MBIM_SMS_FORMAT_PDU);
+ g_assert_cmpuint (messages_count, ==, 0);
+ g_assert (pdu_messages == NULL);
+ g_assert (cdma_messages == NULL);
+
+ mbim_message_unref (response);
+}
+
+static void
+test_message_parser_sms_read_single_pdu (void)
+{
+ MbimSmsFormat format;
+ guint32 messages_count;
+ MbimSmsPduReadRecord **pdu_messages;
+ MbimSmsCdmaReadRecord **cdma_messages;
+ MbimMessage *response;
+ GError *error = NULL;
+ const guint8 buffer [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x80, /* type */
+ 0xB0, 0x00, 0x00, 0x00, /* length */
+ 0x02, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_done_message */
+ 0x53, 0x3F, 0xBE, 0xEB, /* service id */
+ 0x14, 0xFE, 0x44, 0x67,
+ 0x9F, 0x90, 0x33, 0xA2,
+ 0x23, 0xE5, 0x6C, 0x3F,
+ 0x02, 0x00, 0x00, 0x00, /* command id */
+ 0x00, 0x00, 0x00, 0x00, /* status code */
+ 0x60, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x00, 0x00, 0x00, 0x00, /* 0x00 format */
+ 0x01, 0x00, 0x00, 0x00, /* 0x04 messages count */
+ 0x10, 0x00, 0x00, 0x00, /* 0x08 message 1 offset */
+ 0x20, 0x00, 0x00, 0x00, /* 0x0C message 1 length */
+ /* data buffer... message 1 */
+ 0x07, 0x00, 0x00, 0x00, /* 0x10 0x00 message index */
+ 0x03, 0x00, 0x00, 0x00, /* 0x14 0x04 message status */
+ 0x10, 0x00, 0x00, 0x00, /* 0x18 0x08 pdu data offset (w.r.t. pdu start */
+ 0x10, 0x00, 0x00, 0x00, /* 0x1C 0x0C pdu data length */
+ /* pdu data... */
+ 0x01, 0x02, 0x03, 0x04, /* 0x20 0x10 */
+ 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C,
+ 0x0D, 0x0E, 0x0F, 0x00
+ };
+
+ const guint8 expected_pdu [] = {
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C,
+ 0x0D, 0x0E, 0x0F, 0x00
+ };
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert (mbim_message_sms_read_response_parse (
+ response,
+ &format,
+ &messages_count,
+ &pdu_messages,
+ &cdma_messages,
+ &error));
+ g_assert_no_error (error);
+
+ g_assert_cmpuint (format, ==, MBIM_SMS_FORMAT_PDU);
+ g_assert_cmpuint (messages_count, ==, 1);
+ g_assert (pdu_messages != NULL);
+ g_assert (cdma_messages == NULL);
+
+ g_assert_cmpuint (pdu_messages[0]->message_index, ==, 7);
+ g_assert_cmpuint (pdu_messages[0]->message_status, ==, MBIM_SMS_STATUS_SENT);
+ test_message_trace (pdu_messages[0]->pdu_data,
+ pdu_messages[0]->pdu_data_size,
+ expected_pdu,
+ sizeof (expected_pdu));
+ g_assert_cmpuint (pdu_messages[0]->pdu_data_size, ==, sizeof (expected_pdu));
+ g_assert (memcmp (pdu_messages[0]->pdu_data, expected_pdu, sizeof (expected_pdu)) == 0);
+
+ mbim_sms_pdu_read_record_array_free (pdu_messages);
+ mbim_message_unref (response);
+}
+
+static void
+test_message_parser_sms_read_multiple_pdu (void)
+{
+ guint32 idx;
+ MbimSmsFormat format;
+ guint32 messages_count;
+ MbimSmsPduReadRecord **pdu_messages;
+ MbimSmsCdmaReadRecord **cdma_messages;
+ MbimMessage *response;
+ GError *error = NULL;
+ const guint8 buffer [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x80, /* type */
+ 0xB0, 0x00, 0x00, 0x00, /* length */
+ 0x02, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_done_message */
+ 0x53, 0x3F, 0xBE, 0xEB, /* service id */
+ 0x14, 0xFE, 0x44, 0x67,
+ 0x9F, 0x90, 0x33, 0xA2,
+ 0x23, 0xE5, 0x6C, 0x3F,
+ 0x02, 0x00, 0x00, 0x00, /* command id */
+ 0x00, 0x00, 0x00, 0x00, /* status code */
+ 0x60, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x00, 0x00, 0x00, 0x00, /* 0x00 format */
+ 0x02, 0x00, 0x00, 0x00, /* 0x04 messages count */
+ 0x18, 0x00, 0x00, 0x00, /* 0x08 message 1 offset */
+ 0x20, 0x00, 0x00, 0x00, /* 0x0C message 1 length */
+ 0x38, 0x00, 0x00, 0x00, /* 0x10 message 2 offset */
+ 0x24, 0x00, 0x00, 0x00, /* 0x14 message 2 length */
+ /* data buffer... message 1 */
+ 0x06, 0x00, 0x00, 0x00, /* 0x18 0x00 message index */
+ 0x03, 0x00, 0x00, 0x00, /* 0x1C 0x04 message status */
+ 0x10, 0x00, 0x00, 0x00, /* 0x20 0x08 pdu data offset (w.r.t. pdu start */
+ 0x10, 0x00, 0x00, 0x00, /* 0x24 0x0C pdu data length */
+ /* pdu data... */
+ 0x01, 0x02, 0x03, 0x04, /* 0x28 0x10 */
+ 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C,
+ 0x0D, 0x0E, 0x0F, 0x00,
+ /* data buffer... message 2 */
+ 0x07, 0x00, 0x00, 0x00, /* 0x38 0x00 message index */
+ 0x03, 0x00, 0x00, 0x00, /* 0x3C 0x04 message status */
+ 0x10, 0x00, 0x00, 0x00, /* 0x40 0x08 pdu data offset (w.r.t. pdu start */
+ 0x10, 0x00, 0x00, 0x00, /* 0x44 0x0C pdu data length */
+ /* pdu data... */
+ 0x00, 0x01, 0x02, 0x03, /* 0x48 0x10 */
+ 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F
+ };
+
+ const guint8 expected_pdu_idx6 [] = {
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C,
+ 0x0D, 0x0E, 0x0F, 0x00
+ };
+
+ const guint8 expected_pdu_idx7 [] = {
+ 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F
+ };
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert (mbim_message_sms_read_response_parse (
+ response,
+ &format,
+ &messages_count,
+ &pdu_messages,
+ &cdma_messages,
+ &error));
+ g_assert_no_error (error);
+
+ g_assert_cmpuint (format, ==, MBIM_SMS_FORMAT_PDU);
+ g_assert_cmpuint (messages_count, ==, 2);
+ g_assert (pdu_messages != NULL);
+ g_assert (cdma_messages == NULL);
+
+ /* First message with index 6 */
+ if (pdu_messages[0]->message_index == 6)
+ idx = 0;
+ else if (pdu_messages[1]->message_index == 6)
+ idx = 1;
+ else
+ g_assert_not_reached ();
+ g_assert_cmpuint (pdu_messages[idx]->message_index, ==, 6);
+ g_assert_cmpuint (pdu_messages[idx]->message_status, ==, MBIM_SMS_STATUS_SENT);
+ test_message_trace (pdu_messages[idx]->pdu_data,
+ pdu_messages[idx]->pdu_data_size,
+ expected_pdu_idx6,
+ sizeof (expected_pdu_idx6));
+ g_assert_cmpuint (pdu_messages[idx]->pdu_data_size, ==, sizeof (expected_pdu_idx6));
+ g_assert (memcmp (pdu_messages[idx]->pdu_data, expected_pdu_idx6, sizeof (expected_pdu_idx6)) == 0);
+
+ /* Second message with index 7 */
+ if (pdu_messages[0]->message_index == 7)
+ idx = 0;
+ else if (pdu_messages[1]->message_index == 7)
+ idx = 1;
+ else
+ g_assert_not_reached ();
+ g_assert_cmpuint (pdu_messages[idx]->message_index, ==, 7);
+ g_assert_cmpuint (pdu_messages[idx]->message_status, ==, MBIM_SMS_STATUS_SENT);
+ test_message_trace (pdu_messages[idx]->pdu_data,
+ pdu_messages[idx]->pdu_data_size,
+ expected_pdu_idx7,
+ sizeof (expected_pdu_idx7));
+ g_assert_cmpuint (pdu_messages[idx]->pdu_data_size, ==, sizeof (expected_pdu_idx7));
+ g_assert (memcmp (pdu_messages[idx]->pdu_data, expected_pdu_idx7, sizeof (expected_pdu_idx7)) == 0);
+
+ mbim_sms_pdu_read_record_array_free (pdu_messages);
+ mbim_message_unref (response);
+}
+
+static void
+test_message_parser_ussd (void)
+{
+ MbimUssdResponse ussd_response;
+ MbimUssdSessionState ussd_session_state;
+ const guint8 *ussd_payload;
+ guint32 ussd_payload_size;
+ guint32 ussd_dcs;
+ MbimMessage *response;
+ GError *error = NULL;
+ const guint8 buffer [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x80, /* type */
+ 0x54, 0x00, 0x00, 0x00, /* length */
+ 0x02, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_done_message */
+ 0xE5, 0x50, 0xA0, 0xC8, /* service id */
+ 0x5E, 0x82, 0x47, 0x9E,
+ 0x82, 0xF7, 0x10, 0xAB,
+ 0xF4, 0xC3, 0x35, 0x1F,
+ 0x01, 0x00, 0x00, 0x00, /* command id */
+ 0x00, 0x00, 0x00, 0x00, /* status code */
+ 0x24, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x05, 0x00, 0x00, 0x00, /* 0x00 response */
+ 0x01, 0x00, 0x00, 0x00, /* 0x04 sesstion state */
+ 0x01, 0x00, 0x00, 0x00, /* 0x08 coding scheme */
+ 0x14, 0x00, 0x00, 0x00, /* 0x0C payload offset */
+ 0x10, 0x00, 0x00, 0x00, /* 0x10 payload length */
+ /* data buffer... payload */
+ 0x01, 0x02, 0x03, 0x04, /* 0x14 payload */
+ 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C,
+ 0x0D, 0x0E, 0x0F, 0x00
+ };
+
+ const guint8 expected_payload [] = {
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C,
+ 0x0D, 0x0E, 0x0F, 0x00
+ };
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert (mbim_message_ussd_response_parse (
+ response,
+ &ussd_response,
+ &ussd_session_state,
+ &ussd_dcs,
+ &ussd_payload_size,
+ &ussd_payload,
+ &error));
+ g_assert_no_error (error);
+
+ g_assert_cmpuint (ussd_response, ==, MBIM_USSD_RESPONSE_NETWORK_TIMEOUT);
+ g_assert_cmpuint (ussd_session_state, ==, MBIM_USSD_SESSION_STATE_EXISTING_SESSION);
+ g_assert_cmpuint (ussd_dcs, ==, 0x01);
+
+ test_message_trace (ussd_payload,
+ ussd_payload_size,
+ expected_payload,
+ sizeof (expected_payload));
+ g_assert_cmpuint (ussd_payload_size, ==, sizeof (expected_payload));
+ g_assert (memcmp (ussd_payload, expected_payload, sizeof (expected_payload)) == 0);
+
+ mbim_message_unref (response);
+}
+
+static void
+test_message_parser_auth_akap (void)
+{
+ const guint8 *res;
+ guint32 res_len;
+ const guint8 *ik;
+ const guint8 *ck;
+ const guint8 *auts;
+ MbimMessage *response;
+ GError *error = NULL;
+ const guint8 buffer [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x80, /* type */
+ 0x74, 0x00, 0x00, 0x00, /* length */
+ 0x02, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* command_done_message */
+ 0x1D, 0x2B, 0x5F, 0xF7, /* service id */
+ 0x0A, 0xA1, 0x48, 0xB2,
+ 0xAA, 0x52, 0x50, 0xF1,
+ 0x57, 0x67, 0x17, 0x4E,
+ 0x02, 0x00, 0x00, 0x00, /* command id */
+ 0x00, 0x00, 0x00, 0x00, /* status code */
+ 0x44, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x00, 0x01, 0x02, 0x03, /* 0x00 Res */
+ 0x04, 0x05, 0x06, 0x07, /* 0x04 */
+ 0x08, 0x09, 0x0A, 0x0B, /* 0x08 */
+ 0x0C, 0x0D, 0x0E, 0x0F, /* 0x0C */
+ 0x05, 0x00, 0x00, 0x00, /* 0x10 Reslen */
+ 0xFF, 0xFE, 0xFD, 0xFC, /* 0x14 IK */
+ 0xFB, 0xFA, 0xF9, 0xF8, /* 0x18 */
+ 0xF7, 0xF6, 0xF5, 0xF4, /* 0x1C */
+ 0xF3, 0xF2, 0xF1, 0xF0, /* 0x20 */
+ 0xAF, 0xAE, 0xAD, 0xAC, /* 0x24 CK */
+ 0xAB, 0xAA, 0xA9, 0xA8, /* 0x28 */
+ 0xA7, 0xA6, 0xA5, 0xA4, /* 0x2C */
+ 0xA3, 0xA2, 0xA1, 0xA0, /* 0x30 */
+ 0x7F, 0x7E, 0x7D, 0x7C, /* 0x34 Auts */
+ 0x7B, 0x7A, 0x79, 0x78, /* 0x38 */
+ 0x77, 0x76, 0x75, 0x74, /* 0x3C */
+ 0x73, 0x72, 0x00, 0x00, /* 0x40 */
+ };
+
+ const guint8 expected_res [] = {
+ 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ };
+ const guint8 expected_ik [] = {
+ 0xFF, 0xFE, 0xFD, 0xFC,
+ 0xFB, 0xFA, 0xF9, 0xF8,
+ 0xF7, 0xF6, 0xF5, 0xF4,
+ 0xF3, 0xF2, 0xF1, 0xF0,
+ };
+ const guint8 expected_ck [] = {
+ 0xAF, 0xAE, 0xAD, 0xAC,
+ 0xAB, 0xAA, 0xA9, 0xA8,
+ 0xA7, 0xA6, 0xA5, 0xA4,
+ 0xA3, 0xA2, 0xA1, 0xA0,
+ };
+ const guint8 expected_auts [] = {
+ 0x7F, 0x7E, 0x7D, 0x7C,
+ 0x7B, 0x7A, 0x79, 0x78,
+ 0x77, 0x76, 0x75, 0x74,
+ 0x73, 0x72
+ };
+
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert (mbim_message_auth_akap_response_parse (
+ response,
+ &res,
+ &res_len,
+ &ik,
+ &ck,
+ &auts,
+ &error));
+ g_assert_no_error (error);
+
+ test_message_trace (res,
+ sizeof (expected_res),
+ expected_res,
+ sizeof (expected_res));
+ g_assert (memcmp (res, expected_res, sizeof (expected_res)) == 0);
+
+ g_assert_cmpuint (res_len, ==, 5);
+
+ test_message_trace (ik,
+ sizeof (expected_ik),
+ expected_ik,
+ sizeof (expected_ik));
+ g_assert (memcmp (ik, expected_ik, sizeof (expected_ik)) == 0);
+
+ test_message_trace (ck,
+ sizeof (expected_ck),
+ expected_ck,
+ sizeof (expected_ck));
+ g_assert (memcmp (ck, expected_ck, sizeof (expected_ck)) == 0);
+
+ test_message_trace (auts,
+ sizeof (expected_auts),
+ expected_auts,
+ sizeof (expected_auts));
+ g_assert (memcmp (auts, expected_auts, sizeof (expected_auts)) == 0);
+
+ mbim_message_unref (response);
+}
+
+static void
+test_message_parser_stk_pac_notification (void)
+{
+ const guint8 *databuffer;
+ guint32 databuffer_len;
+ guint32 pac_type;
+ MbimMessage *response;
+ GError *error = NULL;
+ const guint8 buffer [] = {
+ /* header */
+ 0x07, 0x00, 0x00, 0x80, /* type */
+ 0x54, 0x00, 0x00, 0x00, /* length */
+ 0x02, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* indicate_status_message */
+ 0xD8, 0xF2, 0x01, 0x31, /* service id */
+ 0xFC, 0xB5, 0x4E, 0x17,
+ 0x86, 0x02, 0xD6, 0xED,
+ 0x38, 0x16, 0x16, 0x4C,
+ 0x01, 0x00, 0x00, 0x00, /* command id */
+ 0x28, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x01, 0x00, 0x00, 0x00, /* 0x00 Pac Type */
+ 0x04, 0x05, 0x06, 0x07, /* 0x04 Data buffer */
+ 0xAF, 0xAE, 0xAD, 0xAC,
+ 0xAB, 0xAA, 0xA9, 0xA8,
+ 0xA7, 0xA6, 0xA5, 0xA4,
+ 0xA3, 0xA2, 0xA1, 0xA0,
+ 0x7F, 0x7E, 0x7D, 0x7C,
+ 0x7B, 0x7A, 0x79, 0x78,
+ 0x77, 0x76, 0x75, 0x74,
+ 0x73, 0x72, 0x00, 0x00
+ };
+
+ const guint8 expected_databuffer [] = {
+ 0x04, 0x05, 0x06, 0x07,
+ 0xAF, 0xAE, 0xAD, 0xAC,
+ 0xAB, 0xAA, 0xA9, 0xA8,
+ 0xA7, 0xA6, 0xA5, 0xA4,
+ 0xA3, 0xA2, 0xA1, 0xA0,
+ 0x7F, 0x7E, 0x7D, 0x7C,
+ 0x7B, 0x7A, 0x79, 0x78,
+ 0x77, 0x76, 0x75, 0x74,
+ 0x73, 0x72, 0x00, 0x00
+ };
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert (mbim_message_stk_pac_notification_parse (
+ response,
+ &pac_type,
+ &databuffer_len,
+ &databuffer,
+ &error));
+ g_assert_no_error (error);
+
+ g_assert_cmpuint (pac_type, ==, MBIM_STK_PAC_TYPE_NOTIFICATION);
+
+ test_message_trace (databuffer,
+ sizeof (databuffer_len),
+ expected_databuffer,
+ sizeof (expected_databuffer));
+ g_assert_cmpuint (databuffer_len, ==, sizeof (expected_databuffer));
+ g_assert (memcmp (databuffer, expected_databuffer, sizeof (expected_databuffer)) == 0);
+
+ mbim_message_unref (response);
+}
+
+static void
+test_message_parser_stk_pac_response (void)
+{
+ const guint8 *databuffer;
+ MbimMessage *response;
+ GError *error = NULL;
+ const guint8 buffer [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x80, /* type */
+ 0x2C, 0x01, 0x00, 0x00, /* length */
+ 0x02, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* indicate_status_message */
+ 0xD8, 0xF2, 0x01, 0x31, /* service id */
+ 0xFC, 0xB5, 0x4E, 0x17,
+ 0x86, 0x02, 0xD6, 0xED,
+ 0x38, 0x16, 0x16, 0x4C,
+ 0x01, 0x00, 0x00, 0x00, /* command id */
+ 0x00, 0x00, 0x00, 0x00, /* status code */
+ 0x00, 0x01, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x04, 0x05, 0x06, 0x07,
+ 0xAF, 0xAE, 0xAD, 0xAC,
+ 0xAB, 0xAA, 0xA9, 0xA8,
+ 0xA7, 0xA6, 0xA5, 0xA4,
+ 0xA3, 0xA2, 0xA1, 0xA0,
+ 0x7F, 0x7E, 0x7D, 0x7C,
+ 0x7B, 0x7A, 0x79, 0x78,
+ 0x77, 0x76, 0x75, 0x74,
+ 0x73, 0x72, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x04, 0x05, 0x06, 0x07,
+ 0xAF, 0xAE, 0xAD, 0xAC,
+ 0xAB, 0xAA, 0xA9, 0xA8,
+ 0xA7, 0xA6, 0xA5, 0xA4,
+ 0xA3, 0xA2, 0xA1, 0xA0,
+ 0x7F, 0x7E, 0x7D, 0x7C,
+ 0x7B, 0x7A, 0x79, 0x78,
+ 0x77, 0x76, 0x75, 0x74,
+ 0x73, 0x72, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x04, 0x05, 0x06, 0x07,
+ 0xAF, 0xAE, 0xAD, 0xAC,
+ 0xAB, 0xAA, 0xA9, 0xA8,
+ 0xA7, 0xA6, 0xA5, 0xA4,
+ 0xA3, 0xA2, 0xA1, 0xA0,
+ 0x7F, 0x7E, 0x7D, 0x7C,
+ 0x7B, 0x7A, 0x79, 0x78,
+ 0x77, 0x76, 0x75, 0x74,
+ 0x73, 0x72, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x04, 0x05, 0x06, 0x07,
+ 0xAF, 0xAE, 0xAD, 0xAC,
+ 0xAB, 0xAA, 0xA9, 0xA8,
+ 0xA7, 0xA6, 0xA5, 0xA4,
+ 0xA3, 0xA2, 0xA1, 0xA0,
+ 0x7F, 0x7E, 0x7D, 0x7C,
+ 0x7B, 0x7A, 0x79, 0x78,
+ 0x77, 0x76, 0x75, 0x74,
+ 0x73, 0x72, 0x00, 0x00,
+ };
+
+ const guint8 expected_databuffer [] = {
+ 0x04, 0x05, 0x06, 0x07,
+ 0xAF, 0xAE, 0xAD, 0xAC,
+ 0xAB, 0xAA, 0xA9, 0xA8,
+ 0xA7, 0xA6, 0xA5, 0xA4,
+ 0xA3, 0xA2, 0xA1, 0xA0,
+ 0x7F, 0x7E, 0x7D, 0x7C,
+ 0x7B, 0x7A, 0x79, 0x78,
+ 0x77, 0x76, 0x75, 0x74,
+ 0x73, 0x72, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x04, 0x05, 0x06, 0x07,
+ 0xAF, 0xAE, 0xAD, 0xAC,
+ 0xAB, 0xAA, 0xA9, 0xA8,
+ 0xA7, 0xA6, 0xA5, 0xA4,
+ 0xA3, 0xA2, 0xA1, 0xA0,
+ 0x7F, 0x7E, 0x7D, 0x7C,
+ 0x7B, 0x7A, 0x79, 0x78,
+ 0x77, 0x76, 0x75, 0x74,
+ 0x73, 0x72, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x04, 0x05, 0x06, 0x07,
+ 0xAF, 0xAE, 0xAD, 0xAC,
+ 0xAB, 0xAA, 0xA9, 0xA8,
+ 0xA7, 0xA6, 0xA5, 0xA4,
+ 0xA3, 0xA2, 0xA1, 0xA0,
+ 0x7F, 0x7E, 0x7D, 0x7C,
+ 0x7B, 0x7A, 0x79, 0x78,
+ 0x77, 0x76, 0x75, 0x74,
+ 0x73, 0x72, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x04, 0x05, 0x06, 0x07,
+ 0xAF, 0xAE, 0xAD, 0xAC,
+ 0xAB, 0xAA, 0xA9, 0xA8,
+ 0xA7, 0xA6, 0xA5, 0xA4,
+ 0xA3, 0xA2, 0xA1, 0xA0,
+ 0x7F, 0x7E, 0x7D, 0x7C,
+ 0x7B, 0x7A, 0x79, 0x78,
+ 0x77, 0x76, 0x75, 0x74,
+ 0x73, 0x72, 0x00, 0x00
+ };
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert (mbim_message_stk_pac_response_parse (
+ response,
+ &databuffer,
+ &error));
+ g_assert_no_error (error);
+
+ test_message_trace (databuffer,
+ sizeof (expected_databuffer),
+ expected_databuffer,
+ sizeof (expected_databuffer));
+ g_assert (memcmp (databuffer, expected_databuffer, sizeof (expected_databuffer)) == 0);
+
+ mbim_message_unref (response);
+}
+
+static void
+test_message_parser_stk_terminal_response (void)
+{
+ const guint8 *databuffer;
+ guint32 databuffer_len;
+ guint32 status_words;
+ MbimMessage *response;
+ GError *error = NULL;
+ const guint8 buffer [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x80, /* type */
+ 0x48, 0x01, 0x00, 0x00, /* length */
+ 0x02, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* indicate_status_message */
+ 0xD8, 0xF2, 0x01, 0x31, /* service id */
+ 0xFC, 0xB5, 0x4E, 0x17,
+ 0x86, 0x02, 0xD6, 0xED,
+ 0x38, 0x16, 0x16, 0x4C,
+ 0x02, 0x00, 0x00, 0x00, /* command id */
+ 0x00, 0x00, 0x00, 0x00, /* status code */
+ 0x18, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x0C, 0x00, 0x00, 0x00, /* 0x00 ResultData offset */
+ 0x0C, 0x00, 0x00, 0x00, /* 0x04 ResultData length */
+ 0xCC, 0x00, 0x00, 0x00, /* 0x08 StatusWords */
+ /* databuffer */
+ 0x00, 0x00, 0x00, 0x00, /* 0x0C ResultData */
+ 0x04, 0x05, 0x06, 0x07,
+ 0xAF, 0xAE, 0xAD, 0xAC
+ };
+
+ const guint8 expected_databuffer [] = {
+ 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x05, 0x06, 0x07,
+ 0xAF, 0xAE, 0xAD, 0xAC
+ };
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert (mbim_message_stk_terminal_response_response_parse (
+ response,
+ &databuffer_len,
+ &databuffer,
+ &status_words,
+ &error));
+ g_assert_no_error (error);
+
+ g_assert_cmpuint (status_words, ==, 204);
+
+ test_message_trace (databuffer,
+ databuffer_len,
+ expected_databuffer,
+ sizeof (expected_databuffer));
+ g_assert_cmpuint (databuffer_len, ==, sizeof (expected_databuffer));
+ g_assert (memcmp (databuffer, expected_databuffer, sizeof (expected_databuffer)) == 0);
+
+ mbim_message_unref (response);
+}
+
+static void
+test_message_parser_stk_envelope_response (void)
+{
+ const guint8 *databuffer;
+ MbimMessage *response;
+ GError *error = NULL;
+ const guint8 buffer [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x80, /* type */
+ 0x50, 0x01, 0x00, 0x00, /* length */
+ 0x02, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* indicate_status_message */
+ 0xD8, 0xF2, 0x01, 0x31, /* service id */
+ 0xFC, 0xB5, 0x4E, 0x17,
+ 0x86, 0x02, 0xD6, 0xED,
+ 0x38, 0x16, 0x16, 0x4C,
+ 0x03, 0x00, 0x00, 0x00, /* command id */
+ 0x00, 0x00, 0x00, 0x00, /* status code */
+ 0x20, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x0C, 0x00, 0x00, 0x00,
+ 0x0C, 0x00, 0x00, 0x00,
+ 0xCC, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x0C, 0x00, 0x00, 0x00,
+ 0x0C, 0x00, 0x00, 0x00,
+ 0xCC, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+
+ const guint8 expected_databuffer [] = {
+ 0x0C, 0x00, 0x00, 0x00,
+ 0x0C, 0x00, 0x00, 0x00,
+ 0xCC, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x0C, 0x00, 0x00, 0x00,
+ 0x0C, 0x00, 0x00, 0x00,
+ 0xCC, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert (mbim_message_stk_envelope_response_parse (
+ response,
+ &databuffer,
+ &error));
+ g_assert_no_error (error);
+
+ test_message_trace (databuffer,
+ sizeof (expected_databuffer),
+ expected_databuffer,
+ sizeof (expected_databuffer));
+ g_assert (memcmp (databuffer, expected_databuffer, sizeof (expected_databuffer)) == 0);
+
+ mbim_message_unref (response);
+}
+
+static void
+test_message_parser_basic_connect_ip_packet_filters_none (void)
+{
+ MbimPacketFilter **filters = NULL;
+ guint32 n_filters;
+ guint32 session_id;
+ MbimMessage *response;
+ GError *error = NULL;
+ const guint8 buffer [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x80, /* type */
+ 0x38, 0x01, 0x00, 0x00, /* length */
+ 0x02, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* indicate_status_message */
+ 0xA2, 0x89, 0xCC, 0x33, /* service id */
+ 0xBC, 0xBB, 0x8B, 0x4F,
+ 0xB6, 0xB0, 0x13, 0x3E,
+ 0xC2, 0xAA, 0xE6, 0xDF,
+ 0x17, 0x00, 0x00, 0x00, /* command id */
+ 0x00, 0x00, 0x00, 0x00, /* status code */
+ 0x08, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x01, 0x00, 0x00, 0x00, /* session id */
+ 0x00, 0x00, 0x00, 0x00 /* packet filters count */
+ };
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert (mbim_message_ip_packet_filters_response_parse (
+ response,
+ &session_id,
+ &n_filters,
+ &filters,
+ &error));
+ g_assert_no_error (error);
+
+ g_assert_cmpuint (session_id, ==, 1);
+ g_assert_cmpuint (n_filters, ==, 0);
+ g_assert (filters == NULL);
+
+ mbim_message_unref (response);
+}
+
+static void
+test_message_parser_basic_connect_ip_packet_filters_one (void)
+{
+ MbimPacketFilter **filters = NULL;
+ guint32 n_filters;
+ guint32 session_id;
+ MbimMessage *response;
+ GError *error = NULL;
+ const guint8 buffer [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x80, /* type */
+ 0x5C, 0x01, 0x00, 0x00, /* length */
+ 0x02, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* indicate_status_message */
+ 0xA2, 0x89, 0xCC, 0x33, /* service id */
+ 0xBC, 0xBB, 0x8B, 0x4F,
+ 0xB6, 0xB0, 0x13, 0x3E,
+ 0xC2, 0xAA, 0xE6, 0xDF,
+ 0x17, 0x00, 0x00, 0x00, /* command id */
+ 0x00, 0x00, 0x00, 0x00, /* status code */
+ 0x2C, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x01, 0x00, 0x00, 0x00, /* 0x00 session id */
+ 0x01, 0x00, 0x00, 0x00, /* 0x04 packet filters count */
+ 0x10, 0x00, 0x00, 0x00, /* 0x08 packet filter 1 offset */
+ 0x1C, 0x00, 0x00, 0x00, /* 0x0C packet filter 1 length */
+ /* databuffer, packet filter 1 */
+ 0x08, 0x00, 0x00, 0x00, /* 0x10 0x00 filter size */
+ 0x0C, 0x00, 0x00, 0x00, /* 0x14 0x04 filter offset (from beginning of struct) */
+ 0x14, 0x00, 0x00, 0x00, /* 0x18 0x08 mask offset (from beginning of struct) */
+ 0x01, 0x02, 0x03, 0x04, /* 0x1C 0x0C filter */
+ 0x05, 0x06, 0x07, 0x08,
+ 0xF1, 0xF2, 0xF3, 0xF4, /* 0x24 0x14 mask */
+ 0xF5, 0xF6, 0xF7, 0xF8,
+ };
+
+ const guint8 expected_filter[] = {
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08,
+ };
+ const guint8 expected_mask[] = {
+ 0xF1, 0xF2, 0xF3, 0xF4,
+ 0xF5, 0xF6, 0xF7, 0xF8,
+ };
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert (mbim_message_ip_packet_filters_response_parse (
+ response,
+ &session_id,
+ &n_filters,
+ &filters,
+ &error));
+ g_assert_no_error (error);
+
+ g_assert_cmpuint (session_id, ==, 1);
+ g_assert_cmpuint (n_filters, ==, 1);
+ g_assert (filters != NULL);
+
+ g_assert_cmpuint (filters[0]->filter_size, ==, 8);
+
+ test_message_trace (filters[0]->packet_filter, 8,
+ expected_filter,
+ sizeof (expected_filter));
+ g_assert (memcmp (filters[0]->packet_filter, expected_filter, sizeof (expected_filter)) == 0);
+
+ test_message_trace (filters[0]->packet_mask, 8,
+ expected_mask,
+ sizeof (expected_mask));
+ g_assert (memcmp (filters[0]->packet_mask, expected_mask, sizeof (expected_mask)) == 0);
+
+ mbim_packet_filter_array_free (filters);
+
+ mbim_message_unref (response);
+}
+
+static void
+test_message_parser_basic_connect_ip_packet_filters_two (void)
+{
+ MbimPacketFilter **filters = NULL;
+ guint32 n_filters;
+ guint32 session_id;
+ MbimMessage *response;
+ GError *error = NULL;
+ const guint8 buffer [] = {
+ /* header */
+ 0x03, 0x00, 0x00, 0x80, /* type */
+ 0x88, 0x01, 0x00, 0x00, /* length */
+ 0x02, 0x00, 0x00, 0x00, /* transaction id */
+ /* fragment header */
+ 0x01, 0x00, 0x00, 0x00, /* total */
+ 0x00, 0x00, 0x00, 0x00, /* current */
+ /* indicate_status_message */
+ 0xA2, 0x89, 0xCC, 0x33, /* service id */
+ 0xBC, 0xBB, 0x8B, 0x4F,
+ 0xB6, 0xB0, 0x13, 0x3E,
+ 0xC2, 0xAA, 0xE6, 0xDF,
+ 0x17, 0x00, 0x00, 0x00, /* command id */
+ 0x00, 0x00, 0x00, 0x00, /* status code */
+ 0x58, 0x00, 0x00, 0x00, /* buffer length */
+ /* information buffer */
+ 0x01, 0x00, 0x00, 0x00, /* 0x00 session id */
+ 0x02, 0x00, 0x00, 0x00, /* 0x04 packet filters count */
+ 0x18, 0x00, 0x00, 0x00, /* 0x08 packet filter 1 offset */
+ 0x1C, 0x00, 0x00, 0x00, /* 0x0C packet filter 1 length */
+ 0x34, 0x00, 0x00, 0x00, /* 0x10 packet filter 2 offset */
+ 0x24, 0x00, 0x00, 0x00, /* 0x14 packet filter 2 length */
+ /* databuffer, packet filter 2 */
+ 0x08, 0x00, 0x00, 0x00, /* 0x18 0x00 filter size */
+ 0x0C, 0x00, 0x00, 0x00, /* 0x1C 0x04 filter offset (from beginning of struct) */
+ 0x14, 0x00, 0x00, 0x00, /* 0x20 0x08 mask offset (from beginning of struct) */
+ 0x01, 0x02, 0x03, 0x04, /* 0x24 0x0C filter */
+ 0x05, 0x06, 0x07, 0x08,
+ 0xF1, 0xF2, 0xF3, 0xF4, /* 0x2C 0x14 mask */
+ 0xF5, 0xF6, 0xF7, 0xF8,
+ /* databuffer, packet filter 2 */
+ 0x0C, 0x00, 0x00, 0x00, /* 0x34 0x00 filter size */
+ 0x0C, 0x00, 0x00, 0x00, /* 0x38 0x04 filter offset (from beginning of struct) */
+ 0x18, 0x00, 0x00, 0x00, /* 0x3C 0x08 mask offset (from beginning of struct) */
+ 0x01, 0x02, 0x03, 0x04, /* 0x40 0x0C filter */
+ 0x05, 0x06, 0x07, 0x08,
+ 0x05, 0x06, 0x07, 0x08,
+ 0xF1, 0xF2, 0xF3, 0xF4, /* 0x4C 0x18 mask */
+ 0xF5, 0xF6, 0xF7, 0xF8,
+ 0xF5, 0xF6, 0xF7, 0xF8,
+ };
+
+ const guint8 expected_filter1[] = {
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08,
+ };
+ const guint8 expected_mask1[] = {
+ 0xF1, 0xF2, 0xF3, 0xF4,
+ 0xF5, 0xF6, 0xF7, 0xF8,
+ };
+ const guint8 expected_filter2[] = {
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08,
+ 0x05, 0x06, 0x07, 0x08,
+ };
+ const guint8 expected_mask2[] = {
+ 0xF1, 0xF2, 0xF3, 0xF4,
+ 0xF5, 0xF6, 0xF7, 0xF8,
+ 0xF5, 0xF6, 0xF7, 0xF8,
+ };
+
+ response = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert (mbim_message_ip_packet_filters_response_parse (
+ response,
+ &session_id,
+ &n_filters,
+ &filters,
+ &error));
+ g_assert_no_error (error);
+
+ g_assert_cmpuint (session_id, ==, 1);
+ g_assert_cmpuint (n_filters, ==, 2);
+ g_assert (filters != NULL);
+
+ g_assert_cmpuint (filters[0]->filter_size, ==, 8);
+ test_message_trace (filters[0]->packet_filter, 8,
+ expected_filter1,
+ sizeof (expected_filter1));
+ g_assert (memcmp (filters[0]->packet_filter, expected_filter1, sizeof (expected_filter1)) == 0);
+ test_message_trace (filters[0]->packet_mask, 8,
+ expected_mask1,
+ sizeof (expected_mask1));
+ g_assert (memcmp (filters[0]->packet_mask, expected_mask1, sizeof (expected_mask1)) == 0);
+
+ g_assert_cmpuint (filters[1]->filter_size, ==, 12);
+ test_message_trace (filters[1]->packet_filter, 12,
+ expected_filter2,
+ sizeof (expected_filter2));
+ g_assert (memcmp (filters[1]->packet_filter, expected_filter2, sizeof (expected_filter2)) == 0);
+ test_message_trace (filters[1]->packet_mask, 12,
+ expected_mask2,
+ sizeof (expected_mask2));
+ g_assert (memcmp (filters[1]->packet_mask, expected_mask2, sizeof (expected_mask2)) == 0);
+
+ mbim_packet_filter_array_free (filters);
+
+ mbim_message_unref (response);
+}
+
+int main (int argc, char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/libmbim-glib/message/parser/basic-connect/visible-providers", test_message_parser_basic_connect_visible_providers);
+ g_test_add_func ("/libmbim-glib/message/parser/basic-connect/subscriber-ready-status", test_message_parser_basic_connect_subscriber_ready_status);
+ g_test_add_func ("/libmbim-glib/message/parser/basic-connect/device-caps", test_message_parser_basic_connect_device_caps);
+ g_test_add_func ("/libmbim-glib/message/parser/basic-connect/ip-configuration", test_message_parser_basic_connect_ip_configuration);
+ g_test_add_func ("/libmbim-glib/message/parser/basic-connect/service-activation", test_message_parser_basic_connect_service_activation);
+ g_test_add_func ("/libmbim-glib/message/parser/sms/read/zero-pdu", test_message_parser_sms_read_zero_pdu);
+ g_test_add_func ("/libmbim-glib/message/parser/sms/read/single-pdu", test_message_parser_sms_read_single_pdu);
+ g_test_add_func ("/libmbim-glib/message/parser/sms/read/multiple-pdu", test_message_parser_sms_read_multiple_pdu);
+ g_test_add_func ("/libmbim-glib/message/parser/ussd", test_message_parser_ussd);
+ g_test_add_func ("/libmbim-glib/message/parser/auth/akap", test_message_parser_auth_akap);
+ g_test_add_func ("/libmbim-glib/message/parser/stk/pac/notification", test_message_parser_stk_pac_notification);
+ g_test_add_func ("/libmbim-glib/message/parser/stk/pac/response", test_message_parser_stk_pac_response);
+ g_test_add_func ("/libmbim-glib/message/parser/stk/terminal/response", test_message_parser_stk_terminal_response);
+ g_test_add_func ("/libmbim-glib/message/parser/stk/envelope/response", test_message_parser_stk_envelope_response);
+ g_test_add_func ("/libmbim-glib/message/parser/basic-connect/ip-packet-filters/none", test_message_parser_basic_connect_ip_packet_filters_none);
+ g_test_add_func ("/libmbim-glib/message/parser/basic-connect/ip-packet-filters/one", test_message_parser_basic_connect_ip_packet_filters_one);
+ g_test_add_func ("/libmbim-glib/message/parser/basic-connect/ip-packet-filters/two", test_message_parser_basic_connect_ip_packet_filters_two);
+
+ return g_test_run ();
+}
diff --git a/libmbim-glib/test/test-message.c b/libmbim-glib/test/test-message.c
new file mode 100644
index 0000000..399ff52
--- /dev/null
+++ b/libmbim-glib/test/test-message.c
@@ -0,0 +1,207 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#include <config.h>
+#include <string.h>
+
+#include "mbim-message.h"
+#include "mbim-cid.h"
+
+static void
+test_message_open (void)
+{
+ MbimMessage *message;
+
+ message = mbim_message_open_new (12345, 4096);
+ g_assert (message != NULL);
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 12345);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_OPEN);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, 16);
+ g_assert_cmpuint (mbim_message_open_get_max_control_transfer (message), ==, 4096);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_message_open_done (void)
+{
+ MbimMessage *message;
+ const guint8 buffer [] = { 0x01, 0x00, 0x00, 0x80,
+ 0x10, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+
+ message = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_OPEN_DONE);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, 16);
+ g_assert_cmpuint (mbim_message_open_done_get_status_code (message), ==, MBIM_STATUS_ERROR_NONE);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_message_close (void)
+{
+ MbimMessage *message;
+
+ message = mbim_message_close_new (12345);
+ g_assert (message != NULL);
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 12345);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_CLOSE);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, 12);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_message_close_done (void)
+{
+ MbimMessage *message;
+ const guint8 buffer [] = { 0x02, 0x00, 0x00, 0x80,
+ 0x10, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+
+ message = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_CLOSE_DONE);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, 16);
+ g_assert_cmpuint (mbim_message_close_done_get_status_code (message), ==, MBIM_STATUS_ERROR_NONE);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_message_command_empty (void)
+{
+ MbimMessage *message;
+ guint32 len;
+
+ message = mbim_message_command_new (12345,
+ MBIM_SERVICE_BASIC_CONNECT,
+ MBIM_CID_BASIC_CONNECT_DEVICE_CAPS,
+ MBIM_MESSAGE_COMMAND_TYPE_QUERY);
+ g_assert (message != NULL);
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 12345);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, 48);
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_BASIC_CONNECT);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_BASIC_CONNECT_DEVICE_CAPS);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_QUERY);
+
+ g_assert (mbim_message_command_get_raw_information_buffer (message, &len) == NULL);
+ g_assert_cmpuint (len, ==, 0);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_message_command_not_empty (void)
+{
+ MbimMessage *message;
+ const guint8 *buffer;
+ guint32 len;
+ const guint8 information_buffer [] = {
+ 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07
+ };
+
+ message = mbim_message_command_new (12345,
+ MBIM_SERVICE_BASIC_CONNECT,
+ MBIM_CID_BASIC_CONNECT_DEVICE_CAPS,
+ MBIM_MESSAGE_COMMAND_TYPE_QUERY);
+ g_assert (message != NULL);
+ mbim_message_command_append (message, information_buffer, sizeof (information_buffer));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 12345);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, 56);
+
+ g_assert_cmpuint (mbim_message_command_get_service (message), ==, MBIM_SERVICE_BASIC_CONNECT);
+ g_assert_cmpuint (mbim_message_command_get_cid (message), ==, MBIM_CID_BASIC_CONNECT_DEVICE_CAPS);
+ g_assert_cmpuint (mbim_message_command_get_command_type (message), ==, MBIM_MESSAGE_COMMAND_TYPE_QUERY);
+
+ buffer = mbim_message_command_get_raw_information_buffer (message, &len);
+ g_assert (buffer != NULL);
+ g_assert_cmpuint (len, ==, sizeof (information_buffer));
+ g_assert (memcmp (&information_buffer, buffer, sizeof (information_buffer)) == 0);
+
+ mbim_message_unref (message);
+}
+
+static void
+test_message_command_done (void)
+{
+ MbimMessage *message;
+ const guint8 buffer [] = { 0x03, 0x00, 0x00, 0x80,
+ 0x3c, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xa2, 0x89, 0xcc, 0x33,
+ 0xbc, 0xbb, 0x8b, 0x4f,
+ 0xb6, 0xb0, 0x13, 0x3e,
+ 0xc2, 0xaa, 0xe6, 0xdf,
+ 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+ const guint8 expected_information_buffer [] = { 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+ const guint8 *out_information_buffer;
+ guint32 len;
+
+ message = mbim_message_new (buffer, sizeof (buffer));
+
+ g_assert_cmpuint (mbim_message_get_transaction_id (message), ==, 1);
+ g_assert_cmpuint (mbim_message_get_message_type (message), ==, MBIM_MESSAGE_TYPE_COMMAND_DONE);
+ g_assert_cmpuint (mbim_message_get_message_length (message), ==, 60);
+
+ g_assert_cmpuint (mbim_message_command_done_get_service (message), ==, MBIM_SERVICE_BASIC_CONNECT);
+ g_assert_cmpuint (mbim_message_command_done_get_cid (message), ==, MBIM_CID_BASIC_CONNECT_PIN);
+ g_assert_cmpuint (mbim_message_command_done_get_status_code (message), ==, MBIM_STATUS_ERROR_NONE);
+
+ out_information_buffer = mbim_message_command_done_get_raw_information_buffer (message, &len);
+ g_assert (buffer != NULL);
+ g_assert_cmpuint (len, ==, sizeof (expected_information_buffer));
+ g_assert (memcmp (&expected_information_buffer, out_information_buffer, sizeof (expected_information_buffer)) == 0);
+
+ mbim_message_unref (message);
+}
+
+int main (int argc, char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/libmbim-glib/message/open", test_message_open);
+ g_test_add_func ("/libmbim-glib/message/open-done", test_message_open_done);
+ g_test_add_func ("/libmbim-glib/message/close", test_message_close);
+ g_test_add_func ("/libmbim-glib/message/close-done", test_message_close_done);
+ g_test_add_func ("/libmbim-glib/message/command/empty", test_message_command_empty);
+ g_test_add_func ("/libmbim-glib/message/command/not-empty", test_message_command_not_empty);
+ g_test_add_func ("/libmbim-glib/message/command-done", test_message_command_done);
+
+ return g_test_run ();
+}
diff --git a/libmbim-glib/test/test-uuid.c b/libmbim-glib/test/test-uuid.c
new file mode 100644
index 0000000..010b0e9
--- /dev/null
+++ b/libmbim-glib/test/test-uuid.c
@@ -0,0 +1,93 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org>
+ */
+
+#include <config.h>
+
+#include "mbim-uuid.h"
+
+static void
+compare_uuid_strings (const MbimUuid *uuid,
+ const gchar *other_uuid_str)
+{
+ gchar *uuid_str;
+
+ uuid_str = mbim_uuid_get_printable (uuid);
+ g_assert_cmpstr (uuid_str, ==, other_uuid_str);
+ g_free (uuid_str);
+}
+
+static void
+test_uuid_basic_connect (void)
+{
+ compare_uuid_strings (MBIM_UUID_BASIC_CONNECT,
+ "a289cc33-bcbb-8b4f-b6b0-133ec2aae6df");
+}
+
+static void
+test_uuid_sms (void)
+{
+ compare_uuid_strings (MBIM_UUID_SMS,
+ "533fbeeb-14fe-4467-9f90-33a223e56c3f");
+}
+
+static void
+test_uuid_ussd (void)
+{
+ compare_uuid_strings (MBIM_UUID_USSD,
+ "e550a0c8-5e82-479e-82f7-10abf4c3351f");
+}
+
+static void
+test_uuid_phonebook (void)
+{
+ compare_uuid_strings (MBIM_UUID_PHONEBOOK,
+ "4bf38476-1e6a-41db-b1d8-bed289c25bdb");
+}
+
+static void
+test_uuid_stk (void)
+{
+ compare_uuid_strings (MBIM_UUID_STK,
+ "d8f20131-fcb5-4e17-8602-d6ed3816164c");
+}
+
+static void
+test_uuid_auth (void)
+{
+ compare_uuid_strings (MBIM_UUID_AUTH,
+ "1d2b5ff7-0aa1-48b2-aa52-50f15767174e");
+}
+
+static void
+test_uuid_dss (void)
+{
+ compare_uuid_strings (MBIM_UUID_DSS,
+ "c08a26dd-7718-4382-8482-6e0d583c4d0e");
+}
+
+int main (int argc, char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/libmbim-glib/uuid/basic-connect", test_uuid_basic_connect);
+ g_test_add_func ("/libmbim-glib/uuid/sms", test_uuid_sms);
+ g_test_add_func ("/libmbim-glib/uuid/ussd", test_uuid_ussd);
+ g_test_add_func ("/libmbim-glib/uuid/phonebook", test_uuid_phonebook);
+ g_test_add_func ("/libmbim-glib/uuid/stk", test_uuid_stk);
+ g_test_add_func ("/libmbim-glib/uuid/auth", test_uuid_auth);
+ g_test_add_func ("/libmbim-glib/uuid/dss", test_uuid_dss);
+
+ return g_test_run ();
+}
diff --git a/m4/compiler-warnings.m4 b/m4/compiler-warnings.m4
new file mode 100644
index 0000000..eb78503
--- /dev/null
+++ b/m4/compiler-warnings.m4
@@ -0,0 +1,39 @@
+AC_DEFUN([LIBMBIM_COMPILER_WARNINGS],
+[AC_ARG_ENABLE(more-warnings,
+ AS_HELP_STRING([--enable-more-warnings], [Possible values: no/yes/error]),
+ set_more_warnings="$enableval",set_more_warnings=error)
+AC_MSG_CHECKING(for more warnings)
+if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then
+ AC_MSG_RESULT(yes)
+ CFLAGS="-Wall -std=gnu89 $CFLAGS"
+
+ for option in -Wmissing-declarations -Wmissing-prototypes \
+ -Wdeclaration-after-statement -Wstrict-prototypes \
+ -fno-strict-aliasing -Wno-deprecated-declarations \
+ -Wint-to-pointer-cast -Wfloat-equal -Wno-unused-parameter \
+ -Wno-sign-compare -Wunused-but-set-variable \
+ -Wundef -Wimplicit-function-declaration \
+ -Wpointer-arith -Winit-self -Wshadow \
+ -Wmissing-include-dirs -Waggregate-return \
+ -Wformat-security; do
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $option"
+ AC_MSG_CHECKING([whether gcc understands $option])
+ AC_TRY_COMPILE([], [],
+ has_option=yes,
+ has_option=no,)
+ if test $has_option = no; then
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ AC_MSG_RESULT($has_option)
+ unset has_option
+ unset SAVE_CFLAGS
+ done
+ unset option
+ if test "x$set_more_warnings" = xerror; then
+ CFLAGS="$CFLAGS -Werror"
+ fi
+else
+ AC_MSG_RESULT(no)
+fi
+])
diff --git a/utils/Makefile.am b/utils/Makefile.am
new file mode 100644
index 0000000..bdf3437
--- /dev/null
+++ b/utils/Makefile.am
@@ -0,0 +1,2 @@
+
+dist_bin_SCRIPTS = mbim-network
diff --git a/utils/mbim-network b/utils/mbim-network
new file mode 100755
index 0000000..404d511
--- /dev/null
+++ b/utils/mbim-network
@@ -0,0 +1,259 @@
+#!/bin/sh
+
+# 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, version 2.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
+#
+# Based on libqmi's qmi-network script
+#
+
+print_usage ()
+{
+ echo "usage: $0 [DEVICE] [COMMAND]"
+}
+
+if [ $# -ne 2 ]; then
+ echo "error: missing arguments" 1>&2
+ print_usage
+ exit 255
+fi
+
+DEVICE=$1
+COMMAND=$2
+STATE_FILE=/tmp/mbim-network-state
+PROFILE_FILE=/etc/mbim-network.conf
+
+load_profile ()
+{
+ if [ -f $PROFILE_FILE ]; then
+ echo "Loading profile..."
+ source $PROFILE_FILE
+
+ if [ "x$APN" != "x" ]; then
+ echo " APN: $APN"
+ fi
+ fi
+}
+
+save_state ()
+{
+ KEY=$1
+ VAL=$2
+
+ echo "Saving state... ($KEY: $VAL)"
+
+ if [ -f $STATE_FILE ]; then
+ PREVIOUS=`cat $STATE_FILE`
+ PREVIOUS=`echo "$PREVIOUS" | grep -v $KEY`
+ if [ "x$PREVIOUS" != "x" ]; then
+ echo $PREVIOUS > $STATE_FILE
+ else
+ rm $STATE_FILE
+ fi
+ fi
+
+ if [ "x$VAL" != "x" ]; then
+ echo "$KEY=\"$VAL\"" >> $STATE_FILE
+ fi
+}
+
+load_state ()
+{
+ if [ -f $STATE_FILE ]; then
+ echo "Loading previous state..."
+ source $STATE_FILE
+
+ if [ "x$TRID" != "x" ]; then
+ echo " Previous Transaction ID: $TRID"
+ fi
+ fi
+}
+
+clear_state ()
+{
+ echo "Clearing state..."
+ rm -f $STATE_FILE
+}
+
+#
+# $ sudo mbimcli -d /dev/cdc-wdm0 --connect="Internet" --no-close
+# [/dev/cdc-wdm0] Successfully connected
+# [/dev/cdc-wdm0] Connection status:
+# Session ID: '0'
+# Activation state: 'activated'
+# Voice call state: 'none'
+# IP type: 'ipv4'
+# Context type: 'internet'
+# Network error: 'unknown'
+#
+connect ()
+{
+ # Always try to connect using a fresh session
+ if [ "x$TRID" != "x" ]; then
+ mbimcli -d $DEVICE --no-open=$TRID
+ clear_state
+ fi
+
+ SUBSCRIBER_READY_CMD="mbimcli -d $DEVICE --query-subscriber-ready-status --no-close"
+ echo "Querying subscriber ready status '$SUBSCRIBER_READY_CMD'..."
+
+ SUBSCRIBER_READY_OUT=`$SUBSCRIBER_READY_CMD`
+ echo $SUBSCRIBER_READY_OUT
+
+ # Save the new TRID
+ TRID=`echo "$SUBSCRIBER_READY_OUT" | sed -n "s/.*TRID.*'\(.*\)'.*/\1/p"`
+ if [ "x$TRID" != "x" ]; then
+ save_state "TRID" $TRID
+ fi
+
+
+ REGISTRATION_STATE_CMD="mbimcli -d $DEVICE --query-registration-state --no-open=$TRID --no-close"
+ echo "Querying registration state '$REGISTRATION_STATE_CMD'..."
+
+ REGISTRATION_STATE_OUT=`$REGISTRATION_STATE_CMD`
+ echo $REGISTRATION_STATE_OUT
+
+ # Save the new TRID
+ TRID=`echo "$REGISTRATION_STATE_OUT" | sed -n "s/.*TRID.*'\(.*\)'.*/\1/p"`
+ if [ "x$TRID" != "x" ]; then
+ save_state "TRID" $TRID
+ fi
+
+ ATTACH_CMD="mbimcli -d $DEVICE --attach-packet-service --no-open=$TRID --no-close"
+ echo "Attaching to packet service with '$ATTACH_CMD'..."
+
+ ATTACH_OUT=`$ATTACH_CMD`
+
+ # Save the new TRID
+ TRID=`echo "$ATTACH_OUT" | sed -n "s/.*TRID.*'\(.*\)'.*/\1/p"`
+ if [ "x$TRID" != "x" ]; then
+ save_state "TRID" $TRID
+ fi
+
+ CONNECT_CMD="mbimcli -d $DEVICE --connect=$APN --no-open=$TRID --no-close"
+ echo "Starting network with '$CONNECT_CMD'..."
+
+ CONNECT_OUT=`$CONNECT_CMD`
+ if [ $? -eq 0 ]; then
+ echo "Network started successfully"
+ else
+ echo "Network start failed"
+ echo $CONNECT_OUT
+ fi
+
+ # Save the new TRID
+ TRID=`echo "$CONNECT_OUT" | sed -n "s/.*TRID.*'\(.*\)'.*/\1/p"`
+ if [ "x$TRID" != "x" ]; then
+ save_state "TRID" $TRID
+ fi
+}
+
+#
+# $ sudo mbimcli -d /dev/cdc-wdm0 --disconnect="0"
+# [/dev/cdc-wdm0] Successfully disconnected
+# [/dev/cdc-wdm0] Connection status:
+# Session ID: '0'
+# Activation state: 'deactivated'
+# Voice call state: 'none'
+# IP type: 'default'
+# Context type: 'internet'
+# Network error: 'unknown'
+#
+disconnect ()
+{
+ # Always close the session when disconnecting
+ if [ "x$TRID" != "x" ]; then
+ DISCONNECT_CMD="mbimcli -d $DEVICE --disconnect --no-open=$TRID"
+ else
+ DISCONNECT_CMD="mbimcli -d $DEVICE --disconnect"
+ fi
+ echo "Stopping network with '$DISCONNECT_CMD'..."
+
+ DISCONNECT_OUT=`$DISCONNECT_CMD`
+ if [ $? -eq 0 ]; then
+ echo "Network stopped successfully"
+ else
+ echo "Network stop failed"
+ echo $DISCONNECT_OUT
+ fi
+
+ clear_state
+}
+
+#
+# $ sudo mbimcli -d /dev/cdc-wdm0 --query-connection-state --no-close
+# [/dev/cdc-wdm0] Connection status:
+# Session ID: '0'
+# Activation state: 'deactivated'
+# Voice call state: 'none'
+# IP type: 'default'
+# Context type: 'none'
+# Network error: 'unknown'
+#
+status ()
+{
+ if [ "x$TRID" != "x" ]; then
+ STATUS_CMD="mbimcli -d $DEVICE --query-connection-state --no-close --no-open=$TRID"
+ else
+ STATUS_CMD="mbimcli -d $DEVICE --query-connection-state"
+ fi
+ echo "Getting status with '$STATUS_CMD'..."
+
+ STATUS_OUT=`$STATUS_CMD`
+
+ # Save the new TRID
+ TRID=`echo "$STATUS_OUT" | sed -n "s/.*TRID.*'\(.*\)'.*/\1/p"`
+ if [ "x$TRID" != "x" ]; then
+ save_state "TRID" $TRID
+ fi
+
+ CONN=`echo "$STATUS_OUT" | sed -n "s/.*Activation state:.*'\(.*\)'.*/\1/p"`
+ if [ "x$CONN" = "x" ]; then
+ echo "error: couldn't get connection status" 1>&2
+ exit 2
+ else
+ echo "Status: $CONN"
+ if [ "x$CONN" != "xconnected" ]; then
+ exit 64
+ fi
+ fi
+}
+
+# Main
+
+# Load profile, if any
+load_profile
+
+# Load previous state, if any
+load_state
+
+# Process commands
+case $COMMAND in
+ "start")
+ connect
+ ;;
+ "stop")
+ disconnect
+ ;;
+ "status")
+ status
+ ;;
+ *)
+ echo "error: unexpected command '$COMMAND'" 1>&2
+ print_usage
+ exit 255
+ ;;
+esac
+
+exit 0