[Pkg-voip-commits] r3756 - / misdn-user misdn-user/trunk misdn-user/trunk/bridge misdn-user/trunk/debian misdn-user/trunk/debugtool misdn-user/trunk/doc misdn-user/trunk/example misdn-user/trunk/i4lnet misdn-user/trunk/include misdn-user/trunk/lib misdn-user/trunk/suppserv misdn-user/trunk/tenovis misdn-user/trunk/tenovis/lib misdn-user/trunk/voip misdn-user/trunk/voip/example

bradley-guest at alioth.debian.org bradley-guest at alioth.debian.org
Tue Jul 17 16:40:33 UTC 2007


Author: bradley-guest
Date: 2007-07-17 16:40:33 +0000 (Tue, 17 Jul 2007)
New Revision: 3756

Added:
   misdn-user/
   misdn-user/trunk/
   misdn-user/trunk/CHANGES
   misdn-user/trunk/COPYING.LIB
   misdn-user/trunk/LICENSE
   misdn-user/trunk/Makefile
   misdn-user/trunk/VERSION
   misdn-user/trunk/bridge/
   misdn-user/trunk/bridge/isdnbridge
   misdn-user/trunk/debian/
   misdn-user/trunk/debian/changelog
   misdn-user/trunk/debian/compat
   misdn-user/trunk/debian/control
   misdn-user/trunk/debian/copyright
   misdn-user/trunk/debian/libisdnnet-dev.install
   misdn-user/trunk/debian/libisdnnet.install
   misdn-user/trunk/debian/libmisdn-dev.install
   misdn-user/trunk/debian/libmisdn.install
   misdn-user/trunk/debian/misdn-utils.install
   misdn-user/trunk/debian/misdn-utils.links
   misdn-user/trunk/debian/rules
   misdn-user/trunk/debugtool/
   misdn-user/trunk/debugtool/Makefile
   misdn-user/trunk/debugtool/mISDNdebugtool.c
   misdn-user/trunk/doc/
   misdn-user/trunk/doc/README.debugtool
   misdn-user/trunk/example/
   misdn-user/trunk/example/.cvsignore
   misdn-user/trunk/example/Makefile
   misdn-user/trunk/example/loadfirm.c
   misdn-user/trunk/example/logger.c
   misdn-user/trunk/example/misdnportinfo.c
   misdn-user/trunk/example/sendhwctrl.c
   misdn-user/trunk/example/test_file
   misdn-user/trunk/example/test_file.in
   misdn-user/trunk/example/test_file.out
   misdn-user/trunk/example/test_x75.in
   misdn-user/trunk/example/test_x75.out
   misdn-user/trunk/example/testcon.c
   misdn-user/trunk/example/testcon.in
   misdn-user/trunk/example/testcon_l2.c
   misdn-user/trunk/example/testlayer1.c
   misdn-user/trunk/example/testlayer3.c
   misdn-user/trunk/example/testnet.c
   misdn-user/trunk/i4lnet/
   misdn-user/trunk/i4lnet/Makefile
   misdn-user/trunk/i4lnet/bchannel.c
   misdn-user/trunk/i4lnet/fsm.c
   misdn-user/trunk/i4lnet/fsm.h
   misdn-user/trunk/i4lnet/g711.c
   misdn-user/trunk/i4lnet/isdn_debug.c
   misdn-user/trunk/i4lnet/isdn_msg.c
   misdn-user/trunk/i4lnet/manager.c
   misdn-user/trunk/i4lnet/net_if.c
   misdn-user/trunk/i4lnet/net_l2.c
   misdn-user/trunk/i4lnet/net_l2.h
   misdn-user/trunk/i4lnet/net_l3.c
   misdn-user/trunk/i4lnet/net_l3.h
   misdn-user/trunk/i4lnet/nettst.c
   misdn-user/trunk/i4lnet/sndloop.c
   misdn-user/trunk/i4lnet/sndloop2.c
   misdn-user/trunk/i4lnet/tei.c
   misdn-user/trunk/i4lnet/tone.c
   misdn-user/trunk/include/
   misdn-user/trunk/include/bchannel.h
   misdn-user/trunk/include/g711.h
   misdn-user/trunk/include/helper.h
   misdn-user/trunk/include/ibuffer.h
   misdn-user/trunk/include/isdn_debug.h
   misdn-user/trunk/include/isdn_msg.h
   misdn-user/trunk/include/isdn_net.h
   misdn-user/trunk/include/isound.h
   misdn-user/trunk/include/l3dss1.h
   misdn-user/trunk/include/mISDNlib.h
   misdn-user/trunk/include/tone.h
   misdn-user/trunk/lib/
   misdn-user/trunk/lib/Makefile
   misdn-user/trunk/lib/device.c
   misdn-user/trunk/lib/layer.c
   misdn-user/trunk/lib/stack.c
   misdn-user/trunk/lib/status.c
   misdn-user/trunk/suppserv/
   misdn-user/trunk/suppserv/Makefile
   misdn-user/trunk/suppserv/asn1.c
   misdn-user/trunk/suppserv/asn1.h
   misdn-user/trunk/suppserv/asn1_address.c
   misdn-user/trunk/suppserv/asn1_aoc.c
   misdn-user/trunk/suppserv/asn1_basic_service.c
   misdn-user/trunk/suppserv/asn1_comp.c
   misdn-user/trunk/suppserv/asn1_diversion.c
   misdn-user/trunk/suppserv/asn1_diversion.h
   misdn-user/trunk/suppserv/asn1_enc.c
   misdn-user/trunk/suppserv/asn1_generic.c
   misdn-user/trunk/suppserv/fac.c
   misdn-user/trunk/suppserv/suppserv.h
   misdn-user/trunk/tenovis/
   misdn-user/trunk/tenovis/Makefile
   misdn-user/trunk/tenovis/lib/
   misdn-user/trunk/tenovis/lib/Makefile
   misdn-user/trunk/tenovis/lib/tenovis.h
   misdn-user/trunk/tenovis/lib/tenovis_device.c
   misdn-user/trunk/tenovis/lib/tenovis_int.h
   misdn-user/trunk/tenovis/lib/tenovis_intern.c
   misdn-user/trunk/tenovis/testlib.c
   misdn-user/trunk/tenovis/tstlib.c
   misdn-user/trunk/voip/
   misdn-user/trunk/voip/Makefile
   misdn-user/trunk/voip/Makefile.org
   misdn-user/trunk/voip/cfg.lex
   misdn-user/trunk/voip/example/
   misdn-user/trunk/voip/example/pingi2.voip.cfg
   misdn-user/trunk/voip/example/rec_ctrl.sample
   misdn-user/trunk/voip/globals.h
   misdn-user/trunk/voip/iapplication.h
   misdn-user/trunk/voip/options.h
   misdn-user/trunk/voip/prep.conf
   misdn-user/trunk/voip/read_cfg.c
   misdn-user/trunk/voip/rtp.h
   misdn-user/trunk/voip/rtpacket.c
   misdn-user/trunk/voip/rtpacket.h
   misdn-user/trunk/voip/testlog
   misdn-user/trunk/voip/tstcfg
   misdn-user/trunk/voip/tstparse.c
   misdn-user/trunk/voip/vitimer.h
   misdn-user/trunk/voip/voip_appl.c
   misdn-user/trunk/voip/voip_isdn.c
   misdn-user/trunk/voip/voip_isdn_app.c
   misdn-user/trunk/voip/voip_timer.c
   misdn-user/trunk/voip/voipisdn.spec
Log:
Added initial version of misdn-user to repository

Added: misdn-user/trunk/CHANGES
===================================================================
--- misdn-user/trunk/CHANGES	                        (rev 0)
+++ misdn-user/trunk/CHANGES	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,2 @@
+mISDNuser-1-1-2:
+	- nothin changed

Added: misdn-user/trunk/COPYING.LIB
===================================================================
--- misdn-user/trunk/COPYING.LIB	                        (rev 0)
+++ misdn-user/trunk/COPYING.LIB	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,481 @@
+		  GNU LIBRARY GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+                    675 Mass Ave, Cambridge, MA 02139, 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
+
+     Appendix: 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., 675 Mass Ave, Cambridge, MA 02139, 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!

Added: misdn-user/trunk/LICENSE
===================================================================
--- misdn-user/trunk/LICENSE	                        (rev 0)
+++ misdn-user/trunk/LICENSE	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,7 @@
+This project is Opensource distributed under the
+GNU LIBRARY GENERAL PUBLIC LICENSE (see COPYING.LIB).
+
+So it's allowed to link and use this stuff together with
+proprietary software, but any modifications and extensions
+to the libraries itself have to be Opensource under the
+GNU LIBRARY GENERAL PUBLIC LICENSE again.

Added: misdn-user/trunk/Makefile
===================================================================
--- misdn-user/trunk/Makefile	                        (rev 0)
+++ misdn-user/trunk/Makefile	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,133 @@
+
+MAJOR=1
+MINOR=1
+SUBMINOR=5
+
+#
+# Set this to your local copy of mISDN
+#
+MISDNDIR := /usr/src/mqueue/mISDN
+
+PWD=$(shell pwd)
+#
+# Change this to create an install prefix for the shared libs, programms and
+# includes
+#
+INSTALL_PREFIX := /
+export INSTALL_PREFIX
+
+MISDNINCLUDEDIR := $(MISDNDIR)/include
+export MISDNINCLUDEDIR
+
+mISDN_DIR := $(PWD)
+export mISDN_DIR
+
+INCLUDEDIR := $(mISDN_DIR)/include
+export INCLUDEDIR
+
+LIBDIR=/usr/lib
+export LIBDIR
+
+CFLAGS:= -g -Wall -I $(INCLUDEDIR) -I $(MISDNINCLUDEDIR)
+CFLAGS+= -D CLOSE_REPORT=1
+
+#disable this if your system does not support PIC (position independent code)
+ifeq ($(shell uname -m),x86_64)
+CFLAGS         += -fPIC
+endif
+
+export CFLAGS
+
+mISDNLIB	:= $(PWD)/lib/libmISDN.a
+mISDNNETLIB	:= $(PWD)/i4lnet/libmisdnnet.a
+export mISDNLIB
+export mISDNNETLIB
+
+SUBDIRS := lib example
+
+SUBDIRS += $(shell if test -d i4lnet ; then echo i4lnet; fi)
+SUBDIRS += $(shell if test -d tenovis ; then echo tenovis; fi)
+SUBDIRS += $(shell if test -d voip ; then echo voip; fi)
+SUBDIRS += $(shell if test -d suppserv ; then echo suppserv; fi)
+SUBDIRS += $(shell if test -d debugtool ; then echo debugtool; fi)
+
+LIBS := lib/libmISDN.a
+
+all: test_misdn_includes
+	$(MAKE) TARGET=$@ subdirs
+
+
+install_path:
+	mkdir -p $(INSTALL_PREFIX)/usr/bin/
+	mkdir -p $(INSTALL_PREFIX)/usr/include/mISDNuser/
+	mkdir -p $(INSTALL_PREFIX)/$(LIBDIR)
+
+
+install: install_path all
+	$(MAKE) TARGET=install subdirs
+	cp include/*.h $(INSTALL_PREFIX)/usr/include/mISDNuser/
+
+
+subdirs:
+	set -e; for i in $(SUBDIRS) ; do $(MAKE) -C $$i $(TARGET); done
+
+clean:  
+	$(MAKE) TARGET=$@ subdirs
+	rm -f *.o *~ DEADJOE $(INCLUDEDIR)/*~ $(INCLUDEDIR)/DEADJOE
+
+distclean: clean
+	$(MAKE) TARGET=$@ subdirs
+	rm -f *.o *~ testlog
+
+MAINDIR := $(shell basename $(PWD))
+ARCHIVDIR = /usr/src/packages/SOURCES
+ARCHIVOPT := -v
+# VERSION := $(shell date +"%Y%m%d")
+VERSION := 20030423
+
+ARCHIVNAME := $(ARCHIVDIR)/$(MAINDIR)-$(VERSION).tar.bz2
+
+archiv: distclean
+	cd ../; tar c $(ARCHIVOPT) -f - $(MAINDIR) | bzip2 > $(ARCHIVNAME)
+
+basearchiv: ARCHIVOPT += --exclude i4lnet --exclude voip --exclude tenovis
+basearchiv: ARCHIVNAME := $(ARCHIVDIR)/$(MAINDIR)_base-$(VERSION).tar.bz2
+basearchiv: archiv
+
+mainarchiv: ARCHIVOPT += --exclude voip --exclude tenovis
+mainarchiv: ARCHIVNAME := $(ARCHIVDIR)/$(MAINDIR)_main-$(VERSION).tar.bz2
+mainarchiv: archiv
+
+tenovisarchiv: ARCHIVOPT += --exclude voip --exclude i4lnet
+tenovisarchiv: ARCHIVNAME := $(ARCHIVDIR)/$(MAINDIR)_tenovis-$(VERSION).tar.bz2
+tenovisarchiv: archiv
+
+voiparchiv: ARCHIVOPT += --exclude tenovis
+voiparchiv: ARCHIVNAME := $(ARCHIVDIR)/$(MAINDIR)_voip-$(VERSION).tar.bz2
+voiparchiv: archiv
+
+
+test_misdn_includes:
+	@if ! echo "#include <linux/mISDNif.h>" | gcc -I$(MISDNINCLUDEDIR) -C -E - >/dev/null ; then echo -e "\n\nYou either don't seem to have installed mISDN properly\nor you haven't set the MISDNDIR variable in this very Makefile.\n\nPlease either install mISDN or set the MISDNDIR properly\n"; exit 1; fi
+
+
+VERSION:
+	echo $(MAJOR)_$(MINOR)_$(SUBMINOR) > VERSION
+
+snapshot: clean
+	DIR=mISDNuser-$$(date +"20%y_%m_%d") ; \
+	echo $$(date +"20%y_%m_%d" | sed -e "s/\//_/g") > VERSION ; \
+	mkdir -p /tmp/$$DIR ; \
+	cp -a * /tmp/$$DIR ; \
+	cd /tmp/; \
+	tar czf $$DIR.tar.gz $$DIR
+
+release: clean
+	DIR=mISDNuser-$(MAJOR)_$(MINOR)_$(SUBMINOR) ; \
+	echo $(MAJOR)_$(MINOR)_$(SUBMINOR) > VERSION ; \
+	mkdir -p /tmp/$$DIR ; \
+	cp -a * /tmp/$$DIR ; \
+	cd /tmp/; \
+	tar czf $$DIR.tar.gz $$DIR
+
+.PHONY: VERSION clean

Added: misdn-user/trunk/VERSION
===================================================================
--- misdn-user/trunk/VERSION	                        (rev 0)
+++ misdn-user/trunk/VERSION	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1 @@
+1_1_5

Added: misdn-user/trunk/bridge/isdnbridge
===================================================================
(Binary files differ)


Property changes on: misdn-user/trunk/bridge/isdnbridge
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:mime-type
   + application/octet-stream

Added: misdn-user/trunk/debian/changelog
===================================================================
--- misdn-user/trunk/debian/changelog	                        (rev 0)
+++ misdn-user/trunk/debian/changelog	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,64 @@
+misdn-user (1.1.5-1) stable; urgency=low
+
+  * New upstream release.
+  * Changed dependancy from linux-headers-misdn to misdn-headers.
+  * Changed install files so that libsuppserv libraries are also
+    packaged up.
+  * Package dynamic libraries as well as static ones.
+  * Added more of the example programs to the misdn-utils package.
+
+ -- Dermot Bradley <dermot.bradley at sla-networks.com>  Thu,  5 Jul 2007 16:24:52 +0100
+
+misdn-user (1.1.2-1) unstable; urgency=low
+
+  * New upstream release.
+  * Removing all patches to source for the sake of simplicity.
+  * Installing headers to /usr/include/mISDNuser , as this is where 
+    upstream installs to and this is where Asterisk looks at.
+
+ -- Tzafrir Cohen <tzafrir.cohen at xorcom.com>  Sun,  8 Apr 2007 20:28:30 +0300
+
+misdn-user (0.0.0+cvs20060214-2) unstable; urgency=low
+
+  * Fix a few instances of broken bitops
+
+ -- Simon Richter <sjr at debian.org>  Wed,  5 Jul 2006 12:50:20 +0200
+
+misdn-user (0.0.0+cvs20060214-1) unstable; urgency=low
+
+  * New upstream release
+
+ -- Simon Richter <sjr at debian.org>  Thu, 16 Feb 2006 14:33:07 +0100
+
+misdn-user (0.0.0+cvs20041018-5) unstable; urgency=low
+
+  * Added forceful usage of -fPIC.
+  * Removed duplicate definition of strL2Status (Closes: #287655).
+
+ -- Simon Richter <sjr at debian.org>  Fri, 11 Mar 2005 02:35:28 +0100
+
+misdn-user (0.0.0+cvs20041018-4) unstable; urgency=low
+
+  * Added missing header file bitops.h
+
+ -- Simon Richter <sjr at debian.org>  Tue,  7 Dec 2004 12:23:23 +0100
+
+misdn-user (0.0.0+cvs20041018-3) unstable; urgency=low
+
+  * Removed dependency on kernel headers, fixing HPPA and possibly
+    others (Closes: #283046)
+
+ -- Simon Richter <sjr at debian.org>  Fri, 26 Nov 2004 15:13:52 +0000
+
+misdn-user (0.0.0+cvs20041018-2) unstable; urgency=low
+
+  * Fixed descriptions (Closes: #281177, #281178)
+  * Fixed build-dependencies (Closes: #281272)
+
+ -- Simon Richter <sjr at debian.org>  Tue, 16 Nov 2004 15:46:20 +0100
+
+misdn-user (0.0.0+cvs20041018-1) unstable; urgency=low
+
+  * Initial Release (Closes: #263096).
+
+ -- Simon Richter <sjr at debian.org>  Mon, 18 Oct 2004 16:25:38 +0200

Added: misdn-user/trunk/debian/compat
===================================================================
--- misdn-user/trunk/debian/compat	                        (rev 0)
+++ misdn-user/trunk/debian/compat	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1 @@
+4

Added: misdn-user/trunk/debian/control
===================================================================
--- misdn-user/trunk/debian/control	                        (rev 0)
+++ misdn-user/trunk/debian/control	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,56 @@
+Source: misdn-user
+Section: comm
+Priority: extra
+Maintainer: Dermot Bradley <dermot.bradley at sla-networks.com>
+Build-Depends: debhelper (>= 4.0.0), misdn-headers
+Standards-Version: 3.7.2
+
+Package: misdn-utils
+Section: comm
+Architecture: any
+Depends: ${shlibs:Depends}
+Description: mISDN userspace utilities
+ This package contains the userspace binaries that come with mISDN. At
+ present, the only probably sensible tool is the "loadfirm" utility.
+ .
+ It is highly unlikely that you need this package, but it is included
+ for completeness.
+
+Package: libmisdn
+Section: libs
+Architecture: any
+Description: mISDN interface library
+ This is the mISDN TE mode library, used by applications that want to call
+ out into an ISDN network while not going through a higher-level stack like
+ CAPI.
+
+Package: libmisdn-dev
+Section: libdevel
+Architecture: any
+Depends: libmisdn (= ${Source-Version})
+Description: mISDN interface library development
+ This is the mISDN TE mode library, used by applications that want to call
+ out into an ISDN network while not going through a higher-level stack like
+ CAPI.
+ .
+ This package contains the static library and header files used in
+ development.
+
+Package: libisdnnet
+Section: libs
+Architecture: any
+Depends: libmisdn (= ${Source-Version})
+Description: ISDN networking library
+ This is the mISDN NT mode library, used by applications that want to emulate
+ an ISDN network.
+
+Package: libisdnnet-dev
+Section: libdevel
+Architecture: any
+Depends: libmisdn-dev (= ${Source-Version})
+Description: ISDN networking library development
+ This is the mISDN NT mode library, used by applications that want to emulate
+ an ISDN network.
+ .
+ This package contains the static library and header files used in
+ development.

Added: misdn-user/trunk/debian/copyright
===================================================================
--- misdn-user/trunk/debian/copyright	                        (rev 0)
+++ misdn-user/trunk/debian/copyright	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,24 @@
+This package was debianized by Simon Richter <sjr at debian.org> on
+Tue,  3 Aug 2004 11:11:56 +0200.
+
+It was downloaded from http://www.misdn.org/downloads/releases/
+
+Upstream Author: Karsten Keil <kkeil at suse.de>
+
+Copyright:
+
+   This package 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 dated June, 1991.
+
+   This package is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+On Debian systems, the complete text of the GNU General
+Public License can be found in `/usr/share/common-licenses/GPL'.

Added: misdn-user/trunk/debian/libisdnnet-dev.install
===================================================================
--- misdn-user/trunk/debian/libisdnnet-dev.install	                        (rev 0)
+++ misdn-user/trunk/debian/libisdnnet-dev.install	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,13 @@
+i4lnet/libisdnnet.a usr/lib
+i4lnet/libisdnnet_pic.a usr/lib
+i4lnet/*.h usr/include/mISDNuser
+include/bchannel.h usr/include/mISDNuser
+include/g711.h usr/include/mISDNuser
+include/helper.h usr/include/mISDNuser
+include/ibuffer.h usr/include/mISDNuser
+include/isdn_debug.h usr/include/mISDNuser
+include/isdn_msg.h usr/include/mISDNuser
+include/isdn_net.h usr/include/mISDNuser
+include/isound.h usr/include/mISDNuser
+include/l3dss1.h usr/include/mISDNuser
+include/tone.h usr/include/mISDNuser

Added: misdn-user/trunk/debian/libisdnnet.install
===================================================================
--- misdn-user/trunk/debian/libisdnnet.install	                        (rev 0)
+++ misdn-user/trunk/debian/libisdnnet.install	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1 @@
+i4lnet/libisdnnet.so usr/lib

Added: misdn-user/trunk/debian/libmisdn-dev.install
===================================================================
--- misdn-user/trunk/debian/libmisdn-dev.install	                        (rev 0)
+++ misdn-user/trunk/debian/libmisdn-dev.install	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,6 @@
+lib/libmISDN.a usr/lib
+lib/libmISDN_pic.a usr/lib
+suppserv/libsuppserv.a usr/lib
+suppserv/libsuppserv_pic.a usr/lib
+include/mISDNlib.h usr/include/mISDNuser
+suppserv/suppserv.h usr/include/mISDNuser

Added: misdn-user/trunk/debian/libmisdn.install
===================================================================
--- misdn-user/trunk/debian/libmisdn.install	                        (rev 0)
+++ misdn-user/trunk/debian/libmisdn.install	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,2 @@
+lib/libmISDN.so usr/lib
+suppserv/libsuppserv.so usr/lib

Added: misdn-user/trunk/debian/misdn-utils.install
===================================================================
--- misdn-user/trunk/debian/misdn-utils.install	                        (rev 0)
+++ misdn-user/trunk/debian/misdn-utils.install	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,8 @@
+debugtool/mISDNdebugtool usr/sbin/
+example/loadfirm usr/sbin/
+example/misdnportinfo usr/sbin/
+example/sendhwctrl usr/sbin/
+example/testcon usr/sbin/
+example/testcon_l2 usr/sbin/
+example/testlayer1 usr/sbin/
+example/testlayer3 usr/sbin/

Added: misdn-user/trunk/debian/misdn-utils.links
===================================================================
--- misdn-user/trunk/debian/misdn-utils.links	                        (rev 0)
+++ misdn-user/trunk/debian/misdn-utils.links	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1 @@
+usr/share/man/man7/undocumented.7.gz usr/share/man/man8/loadfirm.8.gz

Added: misdn-user/trunk/debian/rules
===================================================================
--- misdn-user/trunk/debian/rules	                        (rev 0)
+++ misdn-user/trunk/debian/rules	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,96 @@
+#!/usr/bin/make -f
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+CFLAGS = -Wall -Werror -g
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+	CFLAGS += -O0
+else
+	CFLAGS += -O2
+endif
+ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
+	INSTALL_PROGRAM += -s
+endif
+
+DEBVERSION:=$(shell head -n 1 debian/changelog \
+                    | sed -e 's/^[^(]*(\([^)]*\)).*/\1/')
+ORIGVERSION:=$(shell echo $(DEBVERSION) | sed -e 's/^.*://' -e 's/-[0-9.]*$$//')
+UPVERSION:=$(shell echo $(ORIGVERSION) | sed -e's/\./_/g')
+
+FILENAME := misdn-user_$(ORIGVERSION).orig.tar.gz
+URL :=
+http://www.misdn.org/downloads/releases/mISDNuser-$(UPVERSION).tar.gz
+
+
+build: build-stamp
+build-stamp:
+	dh_testdir
+	$(MAKE)
+	touch build-stamp
+
+clean:
+	dh_testdir
+	dh_testroot
+	rm -f build-stamp configure-stamp
+	$(MAKE) clean
+	$(RM) -f example/loadfirm
+	$(RM) -f example/misdnportinfo
+	$(RM) -f example/sendhwctrl
+	$(RM) -f example/testcon
+	$(RM) -f example/testcon_l2
+	$(RM) -f example/testlayer1
+	$(RM) -f example/testlayer3
+	$(RM) -f lib/libmISDN_pic.a
+	dh_clean 
+
+install: build
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+	dh_testdir
+	dh_testroot
+	dh_installchangelogs 
+	dh_installdocs
+	dh_installexamples
+	dh_install
+#	dh_installmenu
+#	dh_installdebconf	
+#	dh_installlogrotate
+#	dh_installemacsen
+#	dh_installpam
+#	dh_installmime
+#	dh_installinit
+#	dh_installcron
+#	dh_installinfo
+	dh_installman
+	dh_link
+	dh_strip
+	dh_compress
+	dh_fixperms
+#	dh_perl
+#	dh_python
+#	dh_makeshlibs
+	dh_installdeb
+	dh_shlibdeps
+	dh_gencontrol
+	dh_md5sums
+	dh_builddeb
+
+print-version:
+	@echo Version: $(DEBVERSION)
+	@echo Source: $(URL)
+	@echo Local: $(FILENAME)
+
+get-orig-source:
+	@dh_testdir
+	@echo Downloading $(FILENAME) from $(URL) ...
+	@wget -N -nv -T10 -t3 -O ../$(FILENAME) $(URL)
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure


Property changes on: misdn-user/trunk/debian/rules
___________________________________________________________________
Name: svn:executable
   + *

Added: misdn-user/trunk/debugtool/Makefile
===================================================================
--- misdn-user/trunk/debugtool/Makefile	                        (rev 0)
+++ misdn-user/trunk/debugtool/Makefile	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,14 @@
+CC = gcc
+
+CFLAGS += -Wall
+
+all: mISDNdebugtool
+
+install: mISDNdebugtool
+	install -m 755 mISDNdebugtool $(INSTALL_PREFIX)/usr/bin
+
+clean:
+	rm -f mISDNdebugtool *.o
+
+distclean: clean
+

Added: misdn-user/trunk/debugtool/mISDNdebugtool.c
===================================================================
--- misdn-user/trunk/debugtool/mISDNdebugtool.c	                        (rev 0)
+++ misdn-user/trunk/debugtool/mISDNdebugtool.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,487 @@
+/*
+ * mISDNdebugtool: Userspace counterpart of the mISDN_debugtool kernel module.
+ *
+ * Copyright (C) 2007, Nadi Sarrar
+ *
+ * Nadi Sarrar <nadi at beronet.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ */
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <linux/mISDNdebugtool.h>
+
+#define BUFLEN 1024
+
+static int arg_daemon = 0;
+static int arg_verbose = 0;
+static int arg_udp_port = 50501;
+static int arg_dontenable = 0;
+static char *arg_ports = NULL;
+static char *arg_dfile = NULL;
+static char *arg_lfile = NULL;
+
+static char usage[] =
+"Usage: %s [-p <mISDN-port>,..] [-f <prefix>] [-l <prefix>] [-b <UDP-port>] [-d] [-n] [-v] [-h]\n"
+"\n"
+"Arguments:\n"
+"  -p <mISDN-port>,..  mISDN ports to care for, default: care for all\n"
+"  -f <prefix>         enable dumpfile mode, use this prefix for filenames\n"
+"  -l <prefix>         enable logfile mode, use this prefix for filenames\n"
+"  -b <UDP-port>       UDP port to bind to, default: 50501\n"
+"  -d                  daemon mode\n"
+"  -n                  do not enable mISDN_debugtool kernel module\n"
+"  -v                  print packets to stdout\n"
+"  -h                  print this help text and exit\n";
+
+static char *self;
+
+static int disable_kernel_debugtool = 0;
+
+static void fail (char *err)
+{
+	fprintf(stderr, "ERROR: %s\n", err);
+	exit(1);
+}
+
+static void fail_perr (char *err)
+{
+	perror(err);
+	exit(1);
+}
+
+/* file helper */
+static void _init_file (FILE **file, char *fn)
+{
+	*file = fopen(fn, "w");
+	if (!*file || ferror(*file)) {
+		fprintf(stderr, "ERROR: failed to open %s for writing!\n", fn);
+		exit(1);
+	}
+}
+
+static void init_dfile (FILE **file, char *fn)
+{
+	_init_file(file, fn);
+	fprintf(*file, "EyeSDN");
+}
+
+static void init_lfile (FILE **file, char *fn)
+{
+	_init_file(file, fn);
+}
+
+/* port filter */
+struct port {
+	int pnum;
+	FILE *df;
+	FILE *lf;
+	struct port *next;
+};
+struct port *ports = NULL;
+
+static inline struct port* _get_port (int pnum)
+{
+	struct port *p = ports;
+
+	for (; p; p = p->next)
+		if (p->pnum == pnum)
+			return p;
+
+	return NULL;
+}
+
+static struct port* new_port (int pnum)
+{
+	struct port *p;
+	char fn[256];
+
+	if ((p = _get_port(pnum)))
+		return p;
+
+	p = calloc(1, sizeof(struct port));
+	if (!p)
+		fail_perr("calloc()");
+	if (arg_dfile) {
+		if (snprintf(fn, sizeof(fn), "%s-%d", arg_dfile, pnum) >= sizeof(fn))
+			fail("dumpfile prefix too long");
+		init_dfile(&p->df, fn);
+	}
+
+	if (arg_lfile) {
+		if (snprintf(fn, sizeof(fn), "%s-%d", arg_lfile, pnum) >= sizeof(fn))
+			fail("logfile prefix too long");
+		init_lfile(&p->lf, fn);
+	}
+
+	p->pnum = pnum;
+	p->next = ports;
+	ports = p;
+
+	return p;
+}
+
+static void init_ports (void)
+{
+	char *tok, *dup;
+	int pnum;
+
+	if (!arg_ports)
+		return;
+
+	dup = strdup(arg_ports);
+	if (!dup)
+		fail_perr("strdup()");
+	
+	while ((tok = strsep(&dup, ","))) {
+		if (sscanf(tok, "%d", &pnum) == 1 && pnum > 0)
+			new_port(pnum);
+		else
+			fail("port value incorrect");
+	}
+}
+
+static struct port* get_port (int pnum)
+{
+	struct port *p = ports;
+
+	p = _get_port(pnum);
+	if (p)
+		return p;
+
+	if (!arg_ports)
+		return new_port(pnum);
+	
+	return NULL;
+}
+
+static char *typestr (unsigned char type)
+{
+	static char *str[] = {
+		"??",
+		"D_RX",
+		"D_TX",
+		"L1_UP",
+		"L1_DOWN",
+		"CRC_ERR",
+		"NEWSTATE",
+	};
+
+	if (type <= NEWSTATE)
+		return str[type];
+	return str[0];
+}
+
+static void write_esc (FILE *file, unsigned char *buf, int len)
+{
+    int i, byte;
+    
+    for (i = 0; i < len; ++i) {
+		byte = buf[i];
+		if (byte == 0xff || byte == 0xfe) {
+			fputc(0xfe, file);
+			byte -= 2;
+		}
+		fputc(byte, file);
+	}
+
+	if (ferror(file)) {
+		fprintf(stderr, "Error on writing to file!\nAborting...");
+		exit(1);
+	}
+}
+
+static void write_header (FILE *file, mISDN_dt_header_t *hdr)
+{
+    unsigned char buf[12];
+	int usecs;
+	unsigned long secs;
+	int origin;
+	
+	if (hdr->stack_protocol & 0x10)
+		origin = hdr->type == D_TX ? 0 : 1;
+	else
+		origin = hdr->type == D_TX ? 1 : 0;
+	secs = hdr->time.tv_sec;
+	usecs = hdr->time.tv_nsec / 1000;
+
+    buf[0] = (unsigned char)(0xff & (usecs >> 16));
+    buf[1] = (unsigned char)(0xff & (usecs >> 8));
+    buf[2] = (unsigned char)(0xff & (usecs >> 0));
+    buf[3] = (unsigned char)0;
+    buf[4] = (unsigned char)(0xff & (secs >> 24));
+    buf[5] = (unsigned char)(0xff & (secs >> 16));
+    buf[6] = (unsigned char)(0xff & (secs >> 8));
+    buf[7] = (unsigned char)(0xff & (secs >> 0));
+    buf[8] = (unsigned char) 0;
+    buf[9] = (unsigned char) origin;
+    buf[10]= (unsigned char)(0xff & (hdr->plength >> 8));
+    buf[11]= (unsigned char)(0xff & (hdr->plength >> 0));
+    
+    return write_esc(file, buf, 12);
+}
+
+static void log_packet (FILE *file, struct sockaddr_in *sock_client, mISDN_dt_header_t *hdr, unsigned char *buf)
+{
+	int i;
+
+	fprintf(file, "Received packet from %s:%d (vers:%d protocol:%s type:%s id:%08x plen:%d)\n%ld.%ld: ", 
+		   inet_ntoa(sock_client->sin_addr),
+		   ntohs(sock_client->sin_port),
+		   hdr->version, hdr->stack_protocol & 0x10 ? "NT" : "TE",
+		   typestr(hdr->type),
+		   hdr->stack_id,
+		   hdr->plength,
+		   hdr->time.tv_sec,
+		   hdr->time.tv_nsec);
+
+	switch (hdr->type) {
+	case D_RX:
+	case D_TX:
+		for (i = 0; i < hdr->plength; ++i)
+			fprintf(file, "%.2hhx ", *(buf + i));
+		break;
+	case NEWSTATE:
+		fprintf(file, "%u %s", *(unsigned int *)buf, buf + 4);
+		break;
+	default:
+		break;
+	}
+	
+	fprintf(file, "\n\n");
+}
+
+static inline void handle_packet (struct sockaddr_in *sock_client, mISDN_dt_header_t *hdr, unsigned char *buf)
+{
+	struct port *p = get_port(hdr->stack_id >> 8); 
+
+	if (!p)
+		return;
+
+	if (arg_verbose)
+		log_packet(stdout, sock_client, hdr, buf);
+
+	if (p->lf) {
+		log_packet(p->lf, sock_client, hdr, buf);
+		fflush(p->lf);
+	}
+
+	if (p->df && (hdr->type == D_RX || hdr->type == D_TX)) {
+		fputc(0xff, p->df);
+		write_header(p->df, hdr);
+		write_esc(p->df, buf, hdr->plength);
+		fflush(p->df);
+	}
+}
+
+static int kernel_debugtool_disabled (void)
+{
+	int e;
+
+	FILE *enabled = fopen("/sys/class/mISDN-debugtool/enabled", "r");
+	if (!enabled)
+		fail_perr("fopen(\"/sys/class/mISDN-debugtool/enabled\")");
+
+	if (fscanf(enabled, "%d", &e) != 1)
+		fail("Could not get enabled status");
+
+	fclose(enabled);
+
+	return !e;
+}
+
+static void kernel_debugtool_echo (char *str)
+{
+	FILE *enabled = fopen("/sys/class/mISDN-debugtool/enabled", "w");
+	if (!enabled)
+		fail_perr("fopen(\"/sys/class/mISDN-debugtool/enabled\")");
+	fprintf(enabled, str);
+	fclose(enabled);
+}
+
+static void kernel_debugtool_enable (void)
+{
+	if (kernel_debugtool_disabled()) {
+		disable_kernel_debugtool = 1;
+		kernel_debugtool_echo("1");
+	}
+}
+
+static void kernel_debugtool_disable (void)
+{
+	if (disable_kernel_debugtool)
+		kernel_debugtool_echo("0");
+}
+
+static void sighandler (int signo)
+{
+	struct port* p;
+
+	printf("Exiting ...\n");
+
+	for (p = ports; p; p = p->next) {
+		if (p->df) {
+			fflush(p->df);
+			fclose(p->df);
+		}
+		if (p->lf) {
+			fflush(p->lf);
+			fclose(p->lf);
+		}
+	}
+
+	kernel_debugtool_disable();
+
+	exit(0);
+}
+
+int main (int argc, char *argv[])
+{
+	struct sockaddr_in sock_server;
+	struct sockaddr_in sock_client;
+	int s;
+	socklen_t socklen = sizeof(struct sockaddr_in);
+	char buf[BUFLEN];
+	size_t size;
+	int c;
+	int failed = 0;
+	int noargs = 1;
+
+	self = argv[0];
+
+	signal(SIGINT, sighandler);
+	signal(SIGKILL, sighandler);
+	signal(SIGTERM, sighandler);
+
+	/* parse args */
+	while ((c = getopt(argc, argv, "p:f:l:b:dnvh")) != -1) {
+		noargs = 0;
+		switch (c) {
+		case 'p':
+			if (!arg_ports)
+				arg_ports = optarg;
+			else {
+				fprintf(stderr, "%s: argument given more than once -- p\n", self);
+				failed = 1;
+			}
+			break;
+		case 'f':
+			if (!arg_dfile)
+				arg_dfile = optarg;
+			else {
+				fprintf(stderr, "%s: argument given more than once -- f\n", self);
+				failed = 1;
+			}
+			break;
+		case 'l':
+			if (!arg_lfile)
+				arg_lfile = optarg;
+			else {
+				fprintf(stderr, "%s: argument given more than once -- l\n", self);
+				failed = 1;
+			}
+			break;
+		case 'b':
+			if (!optarg || sscanf(optarg, "%d", &arg_udp_port) != 1 || arg_udp_port < 1)
+				fail("UDP port value incorrect");
+			break;
+		case 'd':
+			arg_daemon = 1;
+			break;
+		case 'v':
+			arg_verbose = 1;
+			break;
+		case 'n':
+			arg_dontenable = 1;
+			break;
+		case 'h':
+			printf(usage, self);
+			exit(0);
+			break;
+		default:
+			failed = 1;
+		}
+	}
+
+	if (noargs || failed) {
+		if (failed)
+			fprintf(stderr, "\n");
+		fprintf(failed ? stderr : stdout, usage, self);
+		exit(failed ? -1 : 0);
+	}
+
+	if (!arg_verbose && !arg_dfile && !arg_lfile) {
+		fprintf(stderr, "I ain't got things to do!\nPlease give me a job with -f, -l or -v.\n");
+		exit(1);
+	}
+
+	if (arg_daemon && arg_verbose) {
+		fprintf(stderr, "Option -v in combination with -d makes no sense.\n");
+		exit(1);
+	}
+
+	if (!arg_dontenable)
+		kernel_debugtool_enable();
+
+	if (arg_daemon && daemon(1, 0))
+		fail("daemon()");
+
+	init_ports();
+
+	if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+		fail_perr("socket()");
+
+	sock_server.sin_family = AF_INET;
+	sock_server.sin_port = htons(arg_udp_port);
+	sock_server.sin_addr.s_addr = htonl(INADDR_ANY);
+
+	if (bind(s, (struct sockaddr *) &sock_server, socklen) < 0)
+		fail_perr("bind()");
+
+	for (;;) {
+		size = recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &sock_client, &socklen);
+		if (size < 0)
+			fail_perr("recvfrom()");
+		if (size < sizeof(mISDN_dt_header_t)) {
+			printf("Invalid Packet! (size(%d) < %d)\n", size, sizeof(mISDN_dt_header_t));
+			continue;
+		}
+		
+		mISDN_dt_header_t *hdr = (mISDN_dt_header_t *)buf;
+		if (hdr->plength + sizeof(mISDN_dt_header_t) != size) {
+			printf("Invalid Packet! (plen:%d, but size:%d)\n", hdr->plength, size);
+			continue;
+		}
+
+		handle_packet(&sock_client, hdr, buf + sizeof(mISDN_dt_header_t));
+	}
+
+	printf("\nFailed!\n");
+
+	return 0;
+}

Added: misdn-user/trunk/doc/README.debugtool
===================================================================
--- misdn-user/trunk/doc/README.debugtool	                        (rev 0)
+++ misdn-user/trunk/doc/README.debugtool	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,87 @@
+mISDNdebugtool
+==============
+
+I.   Intro
+II.  Setup
+III. Changing the UDP port
+IV.  Usage of mISDNdebugtool
+
+
+I. Intro
+--------
+
+mISDNdebugtool consists of a kernel module (mISDN_debugtool) and a user space tool
+(mISDNdebugtool).
+
+The kernel modules takes care of transmitting a UDP packet for each ISDN dchannel
+frame, and for events like layer 1 up/down. For hfc_multi, it also transmits packets
+on state changes and CRC errors.
+
+The mISDNdebugtool program is the counterpart to the kernel module. It captures the
+UDP packets, does some parsing and writes them to stdout, to a logfile, and/or to a
+wireshark compatible dumpfile. It also can work as a daemon, see section IV.
+
+
+II. Setup
+---------
+
+1. Install the latest mISDN and mISDNuser. On how to obtain the sources, read:
+
+     http://www.misdn.org/index.php/GIT
+
+2. Configure the mISDN kernel modules. On how to do that, read:
+
+     http://www.misdn.org/index.php/Installing_mISDN
+     http://www.misdn.org/index.php/Configuring_mISDN
+
+3. Add the following line to you /etc/mISDN.conf:
+
+     <module>mISDN_debugtool</module>
+
+4. Load the mISDN kernel modules via:
+
+     mISDN start
+
+5. Enable the debugging facility:
+
+     echo 1 > /sys/class/mISDN-debugtool/enabled
+
+6. Validate your setup by running the mISDNdebugtool user space program to capture
+   all packets transmitted by the mISDNdebugtool kernel module and log them to stdout:
+
+     mISDNdebugtool -v
+
+   Now let something happen on your ISDN lines, i.e. by plugging in a phone. You should
+   now see debugging messages.
+
+
+III. Changing the UDP port
+--------------------------
+
+1. Edit /etc/mISDN.conf. In this example, we use UDP port 12345:
+
+     <module port="12345">mISDN_debugtool</module>
+
+2. Reload your mISDN kernel modules:
+
+     mISDN restart
+
+3. Use the UDP port parameter of mISDNdebugtool:
+
+     mISDNdebugtool -b 12345
+
+
+IV. Usage of mISDNdebugtool
+---------------------------
+
+mISDNdebugtool [-p <mISDN-port>,..] [-f <prefix>] [-l <prefix>] [-b <UDP-port>] [-d] [-v] [-h]
+
+Arguments:
+  -p <mISDN-port>,..  mISDN ports to care for, default: care for all
+  -f <prefix>         enable dumpfile mode, use this prefix for filenames
+  -l <prefix>         enable logfile mode, use this prefix for filenames
+  -b <UDP-port>       UDP port to bind to, default: 50501
+  -d                  daemon mode
+  -v                  print packets to stdout
+  -h                  print this help text and exit
+

Added: misdn-user/trunk/example/.cvsignore
===================================================================
--- misdn-user/trunk/example/.cvsignore	                        (rev 0)
+++ misdn-user/trunk/example/.cvsignore	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,7 @@
+testcon
+testlayer3
+testnet
+testcon_l2
+loadfirm
+sendhwctrl
+logger

Added: misdn-user/trunk/example/Makefile
===================================================================
--- misdn-user/trunk/example/Makefile	                        (rev 0)
+++ misdn-user/trunk/example/Makefile	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,52 @@
+LIBINCL	:= $(INCLUDEDIR)/mISDNlib.h
+PROGS	:= testcon testcon_l2 testlayer3 loadfirm sendhwctrl testlayer1 misdnportinfo
+# PROGS   := testcon testnet loadfirm logger
+
+all: $(PROGS)
+
+install:
+	for i in $(PROGS) ; do \
+		install -m 755 $$i $(INSTALL_PREFIX)/usr/bin ;\
+	done
+
+misdnportinfo: misdnportinfo.o $(mISDNLIB)
+
+testcon: testcon.o $(mISDNLIB)
+
+testlayer3: testlayer3.o $(mISDNLIB)
+
+testnet: testnet.o $(mISDNLIB)
+
+testcon_l2: testcon_l2.o $(mISDNLIB)
+
+loadfirm: loadfirm.o $(mISDNLIB)
+
+sendhwctrl: sendhwctrl.o $(mISDNLIB)
+
+testlayer1: testlayer1.o $(mISDNLIB)
+
+logger: logger.o $(mISDNLIB)
+
+misdnportinfo.o : misdnportinfo.c $(LIBINCL)
+
+
+testcon.o : testcon.c ../include/l3dss1.h $(LIBINCL)
+
+testlayer3.o : testlayer3.c ../include/l3dss1.h $(LIBINCL)
+
+testnet.o : testnet.c ../include/l3dss1.h $(LIBINCL)
+
+testcon_l2.o : testcon_l2.c ../include/l3dss1.h $(LIBINCL)
+
+loadfirm.o: loadfirm.c $(LIBINCL)
+
+sendhwctrl.o: sendhwctrl.c $(LIBINCL)
+
+logger.o: logger.c $(LIBINCL)
+
+
+clean:
+	rm -f *.o *~ DEADJOE
+
+distclean: clean
+	rm -f *.a $(PROGS)

Added: misdn-user/trunk/example/loadfirm.c
===================================================================
--- misdn-user/trunk/example/loadfirm.c	                        (rev 0)
+++ misdn-user/trunk/example/loadfirm.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,301 @@
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include "mISDNlib.h"
+
+void usage(pname) 
+char *pname;
+{
+	fprintf(stderr,"Call with %s [options] [firmware filename]\n",pname);
+	fprintf(stderr,"\n     Valid options are:\n");
+	fprintf(stderr,"\n");
+	fprintf(stderr,"  -?               Usage ; printout this information\n");
+	fprintf(stderr,"  -c<n>            use card number n (default 1)\n"); 
+	fprintf(stderr,"  -v<n>            Printing debug info level n\n");
+	fprintf(stderr,"        0          only received messages are printed\n");
+	fprintf(stderr,"        1          send count\n");
+	fprintf(stderr,"        2          send status\n");
+	fprintf(stderr,"        3          send contens\n");
+	fprintf(stderr,"        4          device read count\n");
+	fprintf(stderr,"        5          stdin line parsing\n");
+	fprintf(stderr,"        6          stdin line raw contens\n");
+	fprintf(stderr,"        7          filenumber/select status\n");
+	fprintf(stderr,"\n");
+}
+
+typedef struct _devinfo {
+	int  device;
+	int  mode;
+	int  d_stid;
+	int  d_adress;
+	int  b_stid[2];
+	int  b_adress[2];
+	int  used_bchannel;
+} devinfo_t;
+
+#define MAX_SIZE 0x10000
+
+static int VerifyOn=0;
+unsigned char *firmware;
+
+int download_firmware(devinfo_t *di, int size) {
+	unsigned char *p, buf[2048], rbuf[128];
+	iframe_t *frm = (iframe_t *)buf;
+	//iframe_t *rfrm = (iframe_t *)rbuf;
+	int cnt, ret = 0;
+	int *adr, l;
+
+	frm->prim = PH_CONTROL | REQUEST;
+	frm->dinfo = HW_FIRM_START;
+	frm->addr = di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN;
+	frm->len = 4;
+	adr = (int *)&frm->data.i;
+//	*adr++ = HW_FIRM_START;
+	*adr++ = size;
+
+	ret = mISDN_write(di->device, buf, frm->len+mISDN_HEADER_LEN, 100000);
+	if (ret < 0)
+		fprintf(stdout,"send_data write error %d %s\n", errno,
+			strerror(errno));
+	else if (VerifyOn>3)
+		fprintf(stdout,"send_data write ret=%d\n", ret);
+
+	ret = mISDN_read(di->device, rbuf, 128, TIMEOUT_10SEC); 	
+	if (VerifyOn>3)
+		fprintf(stdout,"read ret=%d\n", ret);
+	cnt = 0;
+	p = firmware;
+	while (cnt<size) {
+		l = 1024;
+		if (l+cnt >=size)
+			l = size - cnt;
+		frm->prim = PH_CONTROL | REQUEST;
+		frm->dinfo = HW_FIRM_DATA;
+		frm->addr = di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN;
+		frm->len = l + 4;
+		adr = (int *)&frm->data.i;
+//		*adr++ = HW_FIRM_DATA;
+		*adr++ = l;
+		memcpy(adr, firmware + cnt, l);
+		ret = mISDN_write(di->device, buf, frm->len+mISDN_HEADER_LEN, 100000);
+		if (ret < 0)
+			fprintf(stdout,"send_data write error %d %s\n", errno,
+				strerror(errno));
+		else if (VerifyOn>3)
+			fprintf(stdout,"send_data write ret=%d\n", ret);
+		ret = mISDN_read(di->device, rbuf, 128, TIMEOUT_10SEC);
+		if (VerifyOn>3)
+			fprintf(stdout,"read ret=%d\n", ret);
+		cnt += l;
+	}
+	frm->prim = PH_CONTROL | REQUEST;
+	frm->dinfo = HW_FIRM_END;
+	frm->addr = di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN;
+	frm->len = 0;
+//	adr = (int *)&frm->data.i;
+//	*adr++ = HW_FIRM_END;
+	ret = mISDN_write(di->device, buf, frm->len+mISDN_HEADER_LEN, 100000);
+	if (ret < 0)
+		fprintf(stdout,"send_data write error %d %s\n", errno,
+			strerror(errno));
+	else if (VerifyOn>3)
+		fprintf(stdout,"send_data write ret=%d\n", ret);
+	ret = mISDN_read(di->device, rbuf, 128, TIMEOUT_10SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"read ret=%d\n", ret);
+	
+	ret = mISDN_clear_stack(di->device, di->b_stid[di->used_bchannel]);
+	if (VerifyOn>3)
+		fprintf(stdout,"clear_stack ret=%d\n", ret);
+	return(0);
+}
+
+int do_setup(devinfo_t *di, int cardnr) {
+	unsigned char buf[2048];
+	iframe_t *frm = (iframe_t *)buf;
+	int ret = 0;
+	int i;
+	stack_info_t *stinf;
+	mISDN_pid_t pid;
+	layer_info_t li;
+
+	ret = mISDN_get_stack_count(di->device);
+	if (VerifyOn>1)
+		fprintf(stdout,"%d stacks found(%d)\n", ret, cardnr);
+	if (ret < cardnr) {
+		fprintf(stdout,"cannot config card nr %d only %d cards\n",
+			cardnr, ret);
+		return(2);
+	}
+	ret = mISDN_get_stack_info(di->device, cardnr, buf, 1024);
+	if (ret<=0) {
+		fprintf(stdout,"cannot get stackinfo err: %d\n", ret);
+		return(3);
+	}
+	stinf = (stack_info_t *)&frm->data.p;
+	if (VerifyOn>1)
+		mISDNprint_stack_info(stdout, stinf);
+	di->d_stid = stinf->id;
+	fprintf(stdout,"stid(%08x) childcnt(%d)\n", stinf->id, stinf->childcnt);
+	for (i=0;i<2;i++) {
+		if (stinf->childcnt>i)
+			di->b_stid[i] = stinf->child[i];
+		else
+			di->b_stid[i] = 0;
+	}
+
+	di->used_bchannel = 0;
+
+	memset(&li, 0, sizeof(layer_info_t));
+	strcpy(&li.name[0], "B L3");
+	li.object_id = -1;
+	li.extentions = 0;
+	li.pid.protocol[3] = ISDN_PID_L3_B_TRANS;
+	li.pid.layermask = ISDN_LAYER(3);
+	li.st = di->b_stid[di->used_bchannel];
+	ret = mISDN_new_layer(di->device, &li);
+	if (ret) {
+		fprintf(stdout, "new_layer ret(%d)\n", ret);
+		return(4);
+	}
+	di->b_adress[di->used_bchannel] = li.id;
+	if (VerifyOn>2)
+		fprintf(stdout,"b_adress%d %08x\n",
+			di->used_bchannel+1, ret);
+#if 0
+	ret = mISDN_preregister_layer(di->device, di->b_stid[di->used_bchannel], di->b_adress[di->used_bchannel]);
+	if (ret < 0) {
+		fprintf(stdout, "preregister_layer ret(%d)\n", ret);
+		return(5);
+	}
+#endif
+	memset(&pid, 0, sizeof(mISDN_pid_t));
+	pid.protocol[1] = ISDN_PID_L1_B_64TRANS;
+	pid.protocol[2] = ISDN_PID_L2_B_TRANS;
+	pid.protocol[3] = ISDN_PID_L3_B_TRANS;
+	pid.layermask = ISDN_LAYER(1) | ISDN_LAYER(2)| ISDN_LAYER(3);
+	ret = mISDN_set_stack(di->device,
+		di->b_stid[di->used_bchannel], &pid);
+	if (ret) {
+		fprintf(stdout, "set_stack ret(%d)\n", ret);
+		return(6);
+	}
+	ret = mISDN_get_setstack_ind(di->device, di->b_adress[di->used_bchannel]);
+	if (ret) {
+		fprintf(stdout, "get_setstack_ind ret(%d)\n", ret);
+		return(7);
+	}
+	return(0);
+}
+
+int
+read_firmware(unsigned char *fname)
+{
+	FILE *infile;
+	int  cnt;
+	
+	if (!(infile = fopen(fname, "rb"))) {
+		fprintf(stderr, "cannot open file %s\n", fname);
+		exit(-1);
+	}
+	firmware = (unsigned char *) malloc(MAX_SIZE);
+	if (!firmware) {
+		fprintf(stderr, "cannot get %d byte memory\n", MAX_SIZE+4);
+		exit(-1);
+	}
+	cnt = fread(firmware, 1, MAX_SIZE, infile);
+	fclose(infile);
+	if (cnt==MAX_SIZE) {
+		fprintf(stderr, "wrong filesize\n");
+		exit(-1);
+	}
+	return(cnt);
+}
+
+int main(argc,argv)
+int argc;
+char *argv[];
+
+{
+	char FileName[200];
+	int aidx=1,para=1;
+	char sw;
+	int len,err;
+	devinfo_t mISDN;
+	int cardnr =1;
+
+	fprintf(stderr,"loadfirm 1.0\n");
+	strcpy(FileName,"ISAR.BIN");
+	if (argc<1) {
+		fprintf(stderr,"Error: Not enough arguments please check\n");
+		usage(argv[0]);
+		exit(1);
+	} else {
+		do {
+			if (argv[aidx] && argv[aidx][0]=='-') {
+				sw=argv[aidx][1];
+				switch (sw) {
+					case 'v':
+					case 'V':
+						VerifyOn=1;
+						if (argv[aidx][2]) {
+							VerifyOn=atol(&argv[aidx][2]);
+						}
+						break;
+					case 'c':
+						if (argv[aidx][2]) {
+							cardnr=atol(&argv[aidx][2]);
+						}
+						break;
+					case '?' :
+						usage(argv[0]);
+						exit(1);
+						break;
+					default  : fprintf(stderr,"Unknown Switch %c\n",sw);
+						usage(argv[0]);
+						exit(1);
+						break;
+				}
+			}  else {
+				if (para==1) {
+					if (argc > 1)
+						strcpy(FileName,argv[aidx]);
+					para++;
+				} else {
+					fprintf(stderr,"Undefined argument %s\n",argv[aidx]);
+					usage(argv[0]);
+					exit(1);
+				}
+			}
+                                   aidx++;
+		} while (aidx<argc);
+	}
+	memset(&mISDN, 0, sizeof(mISDN));
+	if (0>(mISDN.device = mISDN_open())) {
+		printf("TestmISDN cannot open mISDN due to %s\n",
+			strerror(errno));
+		return(1);
+	}
+
+	len = read_firmware(FileName);
+	if (VerifyOn)
+		fprintf(stdout,"read firmware from %s %d bytes\n", FileName, len);
+	err = do_setup(&mISDN, cardnr);
+	if (err)
+		fprintf(stdout,"do_setup error %d\n", err);
+	else
+		download_firmware(&mISDN, len);
+	free(firmware);
+	err=mISDN_close(mISDN.device);
+	if (err)
+		fprintf(stdout,"mISDN_close: error(%d): %s\n", err,
+			strerror(err));
+	
+	return(0);
+}

Added: misdn-user/trunk/example/logger.c
===================================================================
--- misdn-user/trunk/example/logger.c	                        (rev 0)
+++ misdn-user/trunk/example/logger.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,475 @@
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include "mISDNlib.h"
+#include "l3dss1.h"
+
+void usage(pname) 
+char *pname;
+{
+	fprintf(stderr,"Call with %s [options] [filename]\n",pname);
+	fprintf(stderr,"\n");
+	fprintf(stderr,"\n     Valid options are:\n");
+	fprintf(stderr,"\n");
+	fprintf(stderr,"  -?              Usage ; printout this information\n");
+	fprintf(stderr,"  -c<n>           use card number n (default 1)\n"); 
+	fprintf(stderr,"  -F<n>           use function n (default 0)\n"); 
+	fprintf(stderr,"                    0 normal logging\n"); 
+	fprintf(stderr,"\n");
+}
+
+typedef struct _devinfo {
+	int	device;
+	int	cardnr;
+	int	func;
+	char	phonenr[32];
+	int	d_stid;
+	int	layer1;
+	int	layer2;
+	int	layer3;
+	int	b_stid[2];
+	int	b_adress[2];
+	int	used_bchannel;
+	int	save;
+	int	flag;
+	int	val;
+	int	cr;
+	int	si;
+	int	bl1_prot;
+	int	bl2_prot;
+	int	bl3_prot;
+} devinfo_t;
+
+#define FLG_SEND_TONE		0x0001
+#define FLG_SEND_DATA		0x0002
+#define FLG_BCHANNEL_SETUP	0x0010
+#define FLG_BCHANNEL_DOACTIVE	0x0020
+#define FLG_BCHANNEL_ACTIVE	0x0040
+#define FLG_BCHANNEL_ACTDELAYED	0x0080
+#define FLG_CALL_ORGINATE	0x0100
+#define FLG_BCHANNEL_EARLY	0x0200
+
+
+#define MAX_REC_BUF		4000
+#define MAX_DATA_BUF		1024
+
+static int VerifyOn=0;
+
+static devinfo_t *init_di = NULL;
+
+#define	MsgHead(ptr, cref, mty) \
+	*ptr++ = 0x8; \
+	if (cref == -1) { \
+		*ptr++ = 0x0; \
+	} else { \
+		*ptr++ = 0x1; \
+		*ptr++ = cref^0x80; \
+	} \
+	*ptr++ = mty
+	
+int printhexdata(FILE *f, int len, u_char *p)
+{
+	while(len--) {
+		fprintf(f, "%02x", *p++);
+		if (len)
+			fprintf(f, " ");
+	}
+	fprintf(f, "\n");
+	return(0);
+}
+
+int process_dchannel(devinfo_t *di, int len, iframe_t *frm)
+{
+	write(di->save, frm, len);
+	if (frm->prim == (PH_DATA | INDICATION) && (frm->len >0)) {
+		if (VerifyOn>5)
+			printhexdata(stdout, frm->len, (void *)&frm->data.i);
+	} 
+	return(0);
+}
+
+int setup_bchannel(devinfo_t *di) {
+	mISDN_pid_t pid;
+	int ret;
+	layer_info_t li;
+
+
+	if ((di->used_bchannel<0) || (di->used_bchannel>1)) {
+		fprintf(stdout, "wrong channel %d\n", di->used_bchannel);
+		return(0);
+	}
+	memset(&li, 0, sizeof(layer_info_t));
+	strcpy(&li.name[0], "B L3");
+	li.object_id = -1;
+	li.extentions = 0;
+	li.pid.protocol[3] = di->bl3_prot;
+	li.pid.layermask = ISDN_LAYER(3);
+	li.st = di->b_stid[di->used_bchannel];
+	ret = mISDN_new_layer(di->device, &li);
+	if (ret<0) {
+		fprintf(stdout, "new_layer ret(%d)\n", ret);
+		return(0);
+	}
+	if (ret) {
+		di->b_adress[di->used_bchannel] = ret;
+		if (VerifyOn>2)
+			fprintf(stdout,"b_adress%d %08x\n",
+				di->used_bchannel+1, ret);
+		memset(&pid, 0, sizeof(mISDN_pid_t));
+		pid.protocol[1] = di->bl1_prot;
+		pid.protocol[2] = di->bl2_prot;
+		pid.protocol[3] = di->bl3_prot;
+		pid.layermask = ISDN_LAYER(1) | ISDN_LAYER(2)| ISDN_LAYER(3);
+		if (di->flag & FLG_CALL_ORGINATE)
+			pid.global = 1;
+		ret = mISDN_set_stack(di->device,
+			di->b_stid[di->used_bchannel], &pid);
+		if (ret) {
+			fprintf(stdout, "set_stack ret(%d)\n", ret);
+			return(0);
+		}
+		ret = di->b_adress[di->used_bchannel];
+	}
+	return(ret);
+}
+
+int activate_bchan(devinfo_t *di) {
+	unsigned char buf[128];
+	iframe_t *rfrm;
+	int ret;
+
+	ret = mISDN_write_frame(di->device, buf,
+		di->b_adress[di->used_bchannel] | IF_DOWN,
+		DL_ESTABLISH | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"DL_ESTABLISH write ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 128, TIMEOUT_10SEC); 	
+	if (VerifyOn>3)
+		fprintf(stdout,"DL_ESTABLISH read ret=%d\n", ret);
+	rfrm = (iframe_t *)buf;
+	if (ret>0) {
+		if (rfrm->prim == (DL_ESTABLISH | CONFIRM)) {
+			di->flag |= FLG_BCHANNEL_ACTIVE;
+		}
+	}
+	return(ret);
+}
+
+int deactivate_bchan(devinfo_t *di) {
+	unsigned char buf[128];
+	int ret;
+
+	ret = mISDN_write_frame(di->device, buf,
+		di->b_adress[di->used_bchannel] | IF_DOWN,
+		DL_RELEASE | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"DL_RELEASE write ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 128, TIMEOUT_10SEC); 	
+	if (VerifyOn>3)
+		fprintf(stdout,"DL_RELEASE read ret=%d\n", ret);
+	di->flag &= ~FLG_BCHANNEL_ACTIVE;
+	di->flag &= ~FLG_BCHANNEL_SETUP;
+	ret = mISDN_clear_stack(di->device, di->b_stid[di->used_bchannel]);
+	if (VerifyOn>3)
+		fprintf(stdout,"clear_stack ret=%d\n", ret);
+	return(ret);
+}
+
+int read_mutiplexer(devinfo_t *di) {
+	unsigned char	buf[MAX_REC_BUF];
+	iframe_t	*rfrm;
+	int		timeout = TIMEOUT_10SEC;
+	int		ret = 0;
+
+	rfrm = (iframe_t *)buf;
+	/* Main loop */
+	while (1){
+		ret = mISDN_read(di->device, buf, MAX_REC_BUF, timeout);
+		if (VerifyOn>3)
+			fprintf(stdout,"readloop ret=%d\n", ret);
+		if (ret == -1) {
+			fprintf(stdout,"readloop read error\n");
+			break;
+		}
+		if (ret >= 16) {
+			if (VerifyOn>4)
+				fprintf(stdout,"readloop addr(%x) prim(%x) len(%d)\n",
+					rfrm->addr, rfrm->prim, rfrm->len);
+			if (rfrm->addr == (di->b_adress[di->used_bchannel] | IF_DOWN)) {
+				/* B-Channel related messages */
+				if (rfrm->prim == (DL_DATA | INDICATION)) {
+					/* received data, save it */
+					write(di->save, &rfrm->data.i, rfrm->len);
+				} 
+			/* D-Channel related messages */  
+			} else if (rfrm->addr == (di->layer2 | IF_DOWN)) {
+				if (VerifyOn>4)
+					fprintf(stdout,"readloop addr(%x) prim(%x)len(%d)\n",
+						rfrm->addr, rfrm->prim, rfrm->len);
+				process_dchannel(di, ret, rfrm);
+			} else {
+				if (VerifyOn)
+					fprintf(stdout,"readloop unknown addr(%x) prim((%x)len(%d)\n",
+						rfrm->addr, rfrm->prim, rfrm->len);
+			}
+		}
+	}
+	return(0);
+}
+
+
+int
+add_dlayer2(devinfo_t *di, int prot)
+{
+	layer_info_t li;
+	interface_info_t ii;
+	int lid, ret;
+
+	memset(&li, 0, sizeof(layer_info_t));
+	strcpy(&li.name[0], "user L2");
+	li.object_id = -1;
+	li.extentions = 0;
+	li.pid.protocol[2] = prot;
+	li.pid.layermask = ISDN_LAYER(2);
+	li.st = di->d_stid;
+	lid = mISDN_new_layer(di->device, &li);
+	if (lid<0)
+		return(12);
+	di->layer2 = lid;
+	if (!di->layer2)
+		return(13);
+	
+	/* 
+	 * EXT_IF_CREATE | EXT_IF_EXCLUSIV sorgen dafuer, das wenn die L3
+	 * Schnittstelle schon benutzt ist, eine neue L2 Instanz erzeugt
+	 * wird
+	 */
+   	
+	ii.extentions = EXT_IF_CREATE | EXT_IF_EXCLUSIV;
+	ii.owner = di->layer2;
+	ii.peer = di->layer1;
+	ii.stat = IF_DOWN;
+	ret = mISDN_connect(di->device, &ii);
+	if (ret)
+		return(13);
+	ii.owner = di->layer2;
+	ii.stat = IF_DOWN;
+	ret = mISDN_get_interface_info(di->device, &ii);
+	if (ret != 0)
+		return(14);
+	if (ii.peer == di->layer1)
+		fprintf(stdout, "Layer 1 not cloned\n");
+	else
+		fprintf(stdout, "Layer 1 %08x cloned from %08x\n",
+			ii.peer, di->layer1);
+	return(0);
+}
+
+int do_setup(devinfo_t *di) {
+	unsigned char buf[1024];
+	iframe_t *frm = (iframe_t *)buf;
+	int i, ret = 0;
+	stack_info_t *stinf;
+	status_info_t *si;
+
+	di->bl2_prot = ISDN_PID_L2_B_TRANS;
+	di->bl3_prot = ISDN_PID_L3_B_TRANS;
+	switch (di->func) {
+		case 0:
+			di->bl1_prot = ISDN_PID_L1_B_64TRANS;
+			di->si = 1;
+			break;
+		default:
+			fprintf(stdout,"unknown program function %d\n",
+				di->func);
+			return(1);
+	}
+	ret = mISDN_get_stack_count(di->device);
+	if (VerifyOn>1)
+		fprintf(stdout,"%d stacks found\n", ret);
+	if (ret < di->cardnr) {
+		fprintf(stdout,"cannot config card nr %d only %d cards\n",
+			di->cardnr, ret);
+		return(2);
+	}
+	ret = mISDN_get_stack_info(di->device, di->cardnr, buf, 1024);
+	if (ret<=0) {
+		fprintf(stdout,"cannot get stackinfo err: %d\n", ret);
+		return(3);
+	}
+	stinf = (stack_info_t *)&frm->data.p;
+	if (VerifyOn>1)
+		mISDNprint_stack_info(stdout, stinf);
+	di->d_stid = stinf->id;
+	for (i=0;i<2;i++) {
+		if (stinf->childcnt>i)
+			di->b_stid[i] = stinf->child[i];
+		else
+			di->b_stid[i] = 0;
+	}
+
+	di->layer1 = mISDN_get_layerid(di->device, di->d_stid, 1);
+	if (di->layer1<0) {
+		fprintf(stdout,"cannot get layer1\n");
+		return(4);
+	}
+	if (VerifyOn>1)
+		fprintf(stdout,"layer1 id %08x\n", di->layer1);
+
+	di->layer2 = mISDN_get_layerid(di->device, di->d_stid, 2);
+	if (VerifyOn>1)
+		fprintf(stdout,"layer2 id %08x\n", di->layer2);
+
+	if (di->layer2) {
+		fprintf(stdout,"layer 2 allready present\n");
+		return(5);
+	}
+
+	ret = add_dlayer2(di, ISDN_PID_L2_LAPD);
+	if (ret)
+		return(ret);
+
+	ret = mISDN_get_status_info(di->device, di->layer1, buf, 1024);
+	if (ret > mISDN_HEADER_LEN) {
+		si = (status_info_t *)&frm->data.p;
+		mISDNprint_status(stdout, si);
+	} else
+		fprintf(stdout,"mISDN_get_status_info ret(%d)\n", ret);
+	ret = mISDN_get_status_info(di->device, di->layer2, buf, 1024);
+	if (ret > mISDN_HEADER_LEN) {
+		si = (status_info_t *)&frm->data.p;
+		mISDNprint_status(stdout, si);
+	} else
+		fprintf(stdout,"mISDN_get_status_info ret(%d)\n", ret);
+	sleep(1);
+	init_di = di;
+	return(0);
+}
+
+void
+close_di(devinfo_t *di) {
+	unsigned char buf[1024];
+	int ret = 0;
+
+	init_di = NULL;
+	ret = mISDN_write_frame(di->device, buf, di->layer3 | IF_DOWN,
+		MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"read ret=%d\n", ret);
+}
+
+static void
+term_handler(int sig)
+{
+	if (init_di)
+		close_di(init_di);
+}
+
+int main(argc,argv)
+int argc;
+char *argv[];
+
+{
+	char FileName[200],FileNameOut[200];
+	int aidx=1,para=1;
+	char sw;
+	devinfo_t mISDN;
+	int err;
+
+	fprintf(stderr,"TestmISDN 1.0\n");
+	strcpy(FileName, "test_file");
+	memset(&mISDN, 0, sizeof(mISDN));
+	mISDN.cardnr = 1;
+	mISDN.func = 0;
+	mISDN.phonenr[0] = 0;
+
+	signal(SIGTERM, term_handler);
+	signal(SIGINT, term_handler);
+	signal(SIGPIPE, term_handler);
+
+	if (argc<1) {
+		fprintf(stderr,"Error: Not enough arguments please check\n");
+		usage(argv[0]);
+		exit(1);
+	} else {
+		do {
+			if (argv[aidx] && argv[aidx][0]=='-') {
+				sw=argv[aidx][1];
+				switch (sw) {
+					 case 'v':
+					 case 'V':
+						VerifyOn=1;
+						if (argv[aidx][2]) {
+							VerifyOn=atol(&argv[aidx][2]);
+						}
+						break;
+					case 'c':
+						if (argv[aidx][2]) {
+							mISDN.cardnr=atol(&argv[aidx][2]);
+						}
+						break;
+					case 'F':
+						if (argv[aidx][2]) {
+							mISDN.func=atol(&argv[aidx][2]);
+						}
+						break;
+					case '?' :
+						usage(argv[0]);
+						exit(1);
+						break;
+					default  : fprintf(stderr,"Unknown Switch %c\n",sw);
+						usage(argv[0]);
+						exit(1);
+						break;
+				}
+			}  else {
+				if (para==1) {
+					if (argc > 1)
+						strcpy(FileName,argv[aidx]);
+					para++;
+				} else {
+					fprintf(stderr,"Undefined argument %s\n",argv[aidx]);
+					usage(argv[0]);
+					exit(1);
+				}
+			}
+                                   aidx++;
+		} while (aidx<argc);
+	}
+	if (0>(mISDN.device = mISDN_open())) {
+		printf("TestmISDN cannot open mISDN due to %s\n",
+			strerror(errno));
+		return(1);
+	}
+	sprintf(FileNameOut,"%s",FileName);
+	if (0>(mISDN.save = open(FileName, O_WRONLY|O_CREAT|O_TRUNC,S_IRWXU))) {
+		printf("TestmISDN cannot open %s due to %s\n",FileName,
+			strerror(errno));
+		close(mISDN.device);
+		return(1);
+	}
+	if (VerifyOn>8)
+		fprintf(stdout,"fileno %d/%d\n",mISDN.save, mISDN.device);
+	err = do_setup(&mISDN);
+	if (err)
+		fprintf(stdout,"do_setup error %d\n", err);
+	else
+		read_mutiplexer(&mISDN);
+	close(mISDN.save);
+	err=mISDN_close(mISDN.device);
+	if (err)
+		fprintf(stdout,"mISDN_close: error(%d): %s\n", err,
+			strerror(err));
+	
+	return(0);
+}

Added: misdn-user/trunk/example/misdnportinfo.c
===================================================================
--- misdn-user/trunk/example/misdnportinfo.c	                        (rev 0)
+++ misdn-user/trunk/example/misdnportinfo.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,199 @@
+
+
+#include "mISDNlib.h"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/*
+ * global function to show all available isdn ports
+ */
+void isdn_port_info(void)
+{
+	int err;
+	int i, ii, p;
+	int useable, nt, pri;
+	unsigned char buff[1025];
+	iframe_t *frm = (iframe_t *)buff;
+	stack_info_t *stinf;
+	int device;
+
+	/* open mISDN */
+	if ((device = mISDN_open()) < 0)
+	{
+		fprintf(stderr, "mISDN_open() failed: ret=%d errno=%d (%s) Check for mISDN modules and device.\n", device, errno, strerror(errno));
+		exit(-1);
+	}
+
+	/* get number of stacks */
+	i = 1;
+	ii = mISDN_get_stack_count(device);
+	printf("\n");
+	if (ii <= 0)
+	{
+		printf("Found no card. Please be sure to load card drivers.\n");
+	}
+
+	/* loop the number of cards and get their info */
+	while(i <= ii)
+	{
+		err = mISDN_get_stack_info(device, i, buff, sizeof(buff));
+		if (err <= 0)
+		{
+			fprintf(stderr, "mISDN_get_stack_info() failed: port=%d err=%d\n", i, err);
+			break;
+		}
+		stinf = (stack_info_t *)&frm->data.p;
+
+		nt = pri = 0;
+		useable = 1;
+
+		/* output the port info */
+		printf("Port %2d: ", i);
+		switch(stinf->pid.protocol[0] & ~ISDN_PID_FEATURE_MASK)
+		{
+			case ISDN_PID_L0_TE_S0:
+			printf("TE-mode BRI S/T interface line (for phone lines)");
+#if 0
+			if (stinf->pid.protocol[0] & ISDN_PID_L0_TE_S0_HFC & ISDN_PID_FEATURE_MASK)
+				printf(" HFC multiport card");
+#endif
+			break;
+			case ISDN_PID_L0_NT_S0:
+			nt = 1;
+			printf("NT-mode BRI S/T interface port (for phones)");
+#if 0
+			if (stinf->pid.protocol[0] & ISDN_PID_L0_NT_S0_HFC & ISDN_PID_FEATURE_MASK)
+				printf(" HFC multiport card");
+#endif
+			break;
+			case ISDN_PID_L0_TE_U:
+			printf("TE-mode BRI U   interface line");
+			break;
+			case ISDN_PID_L0_NT_U:
+			nt = 1;
+			printf("NT-mode BRI U   interface port");
+			break;
+			case ISDN_PID_L0_TE_UP2:
+			printf("TE-mode BRI Up2 interface line");
+			break;
+			case ISDN_PID_L0_NT_UP2:
+			nt = 1;
+			printf("NT-mode BRI Up2 interface port");
+			break;
+			case ISDN_PID_L0_TE_E1:
+			pri = 1;
+			printf("TE-mode PRI E1  interface line (for phone lines)");
+#if 0
+			if (stinf->pid.protocol[0] & ISDN_PID_L0_TE_E1_HFC & ISDN_PID_FEATURE_MASK)
+				printf(" HFC-E1 card");
+#endif
+			break;
+			case ISDN_PID_L0_NT_E1:
+			nt = 1;
+			pri = 1;
+			printf("NT-mode PRI E1  interface port (for phones)");
+#if 0
+			if (stinf->pid.protocol[0] & ISDN_PID_L0_NT_E1_HFC & ISDN_PID_FEATURE_MASK)
+				printf(" HFC-E1 card");
+#endif
+			break;
+			default:
+			useable = 0;
+			printf("unknown type 0x%08x",stinf->pid.protocol[0]);
+		}
+		printf("\n");
+
+		if (nt)
+		{
+			if (stinf->pid.protocol[1] == 0)
+			{
+				useable = 0;
+				printf(" -> Missing layer 1 NT-mode protocol.\n");
+			}
+			p = 2;
+			while(p <= MAX_LAYER_NR) {
+				if (stinf->pid.protocol[p])
+				{
+					useable = 0;
+					printf(" -> Layer %d protocol 0x%08x is detected, but not allowed for NT lib.\n", p, stinf->pid.protocol[p]);
+				}
+				p++;
+			}
+			if (useable)
+			{
+				if (pri)
+					printf(" -> Interface is Point-To-Point (PRI).\n");
+				else
+					printf(" -> Interface can be Poin-To-Point/Multipoint.\n");
+			}
+		} else
+		{
+			if (stinf->pid.protocol[1] == 0)
+			{
+				useable = 0;
+				printf(" -> Missing layer 1 protocol.\n");
+			}
+			if (stinf->pid.protocol[2] == 0)
+			{
+				useable = 0;
+				printf(" -> Missing layer 2 protocol.\n");
+			}
+			if (stinf->pid.protocol[2] & ISDN_PID_L2_DF_PTP)
+			{
+				printf(" -> Interface is Poin-To-Point.\n");
+			}
+			if (stinf->pid.protocol[3] == 0)
+			{
+				useable = 0;
+				printf(" -> Missing layer 3 protocol.\n");
+			} else
+			{
+				printf(" -> Protocol: ");
+				switch(stinf->pid.protocol[3] & ~ISDN_PID_FEATURE_MASK)
+				{
+					case ISDN_PID_L3_DSS1USER:
+					printf("DSS1 (Euro ISDN)");
+					break;
+
+					default:
+					useable = 0;
+					printf("unknown protocol 0x%08x",stinf->pid.protocol[3]);
+				}
+				printf("\n");
+			}
+			p = 4;
+			while(p <= MAX_LAYER_NR) {
+				if (stinf->pid.protocol[p])
+				{
+					useable = 0;
+					printf(" -> Layer %d protocol 0x%08x is detected, but not allowed for TE lib.\n", p, stinf->pid.protocol[p]);
+				}
+				p++;
+			}
+			printf(" -> childcnt: %d\n",stinf->childcnt);
+		}
+
+		if (!useable)
+			printf(" * Port NOT useable for PBX (maybe there is already a PBX running?)\n");
+
+		printf("--------\n");
+
+		i++;
+	}
+	printf("\n");
+
+	/* close mISDN */
+	if ((err = mISDN_close(device)))
+	{
+		fprintf(stderr, "mISDN_close() failed: err=%d '%s'\n", err, strerror(err));
+		exit(-1);
+	}
+}
+
+
+int main()
+{
+  isdn_port_info();
+  return 0;
+}

Added: misdn-user/trunk/example/sendhwctrl.c
===================================================================
--- misdn-user/trunk/example/sendhwctrl.c	                        (rev 0)
+++ misdn-user/trunk/example/sendhwctrl.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,199 @@
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include "mISDNlib.h"
+
+void usage(pname) 
+char *pname;
+{
+	fprintf(stderr,"Call with %s [options] <prim> <dinfo>\n",pname);
+	fprintf(stderr,"\n     Valid options are:\n");
+	fprintf(stderr,"\n");
+	fprintf(stderr,"  -?               Usage ; printout this information\n");
+	fprintf(stderr,"  -c<n>            use card number n (default 1)\n"); 
+	fprintf(stderr,"  -v<n>            Printing debug info level n\n");
+	fprintf(stderr,"        0          only received messages are printed\n");
+	fprintf(stderr,"        1          send count\n");
+	fprintf(stderr,"        2          send status\n");
+	fprintf(stderr,"        3          send contens\n");
+	fprintf(stderr,"        4          device read count\n");
+	fprintf(stderr,"        5          stdin line parsing\n");
+	fprintf(stderr,"        6          stdin line raw contens\n");
+	fprintf(stderr,"        7          filenumber/select status\n");
+	fprintf(stderr,"\n");
+	fprintf(stderr,"<prim>             primitiv code e.g. 0x000280 PH_CONTROL REQUEST\n");
+	fprintf(stderr,"<dinfo>            dinfo code e.g. 0xFF01 to loop B1\n");
+	fprintf(stderr,"\n");
+}
+
+typedef struct _devinfo {
+	int 		device;
+	unsigned int  d_stid;
+	unsigned int  d_adress;
+} devinfo_t;
+
+
+static int VerifyOn=0;
+
+int send_primitiv(devinfo_t *di, unsigned int prim, unsigned int dinfo) {
+	unsigned char *p, buf[2048], rbuf[128];
+	iframe_t *frm = (iframe_t *)buf;
+	int ret = 0;
+
+	frm->prim = prim;
+	frm->dinfo = dinfo;
+	frm->addr = di->d_adress | FLG_MSG_TARGET | FLG_MSG_DOWN;
+	frm->len = 0;
+
+	ret = mISDN_write(di->device, buf, frm->len+mISDN_HEADER_LEN, 100000);
+	if (ret < 0)
+		fprintf(stdout,"send_data write error %d %s\n", errno,
+			strerror(errno));
+	else if (VerifyOn>3)
+		fprintf(stdout,"send_data write ret=%d\n", ret);
+
+	ret = mISDN_read(di->device, rbuf, 128, TIMEOUT_1SEC); 	
+	if (VerifyOn>3)
+		fprintf(stdout,"read ret=%d\n", ret);
+	return(0);
+}
+
+int do_setup(devinfo_t *di, int cardnr) {
+	unsigned char buf[2048];
+	iframe_t *frm = (iframe_t *)buf;
+	int ret = 0;
+	stack_info_t *stinf;
+
+	ret = mISDN_get_stack_count(di->device);
+	if (VerifyOn>1)
+		fprintf(stdout,"%d stacks found(%d)\n", ret, cardnr);
+	if (ret < cardnr) {
+		fprintf(stdout,"cannot config card nr %d only %d cards\n",
+			cardnr, ret);
+		return(2);
+	}
+	ret = mISDN_get_stack_info(di->device, cardnr, buf, 1024);
+	if (ret<=0) {
+		fprintf(stdout,"cannot get stackinfo err: %d\n", ret);
+		return(3);
+	}
+	stinf = (stack_info_t *)&frm->data.p;
+	if (VerifyOn>1)
+		mISDNprint_stack_info(stdout, stinf);
+	di->d_stid = stinf->id;
+	if (!stinf->inst[0]) {
+		fprintf(stdout,"cannot get hw d-channel address\n");
+		return(4);
+	}
+	di->d_adress = stinf->inst[0];
+	return(0);
+}
+
+unsigned int
+get_value(char *s)
+{
+	unsigned int v;
+	
+	if (strlen(s) >2) {
+		if (s[0] == '0') {
+			if ((s[1] == 'x') || (s[1] == 'X')) {
+				sscanf(s, "%x", &v);
+				return(v);
+			}
+		}
+	}
+	v = atol(s);
+	return(v);
+}
+
+int main(argc,argv)
+int argc;
+char *argv[];
+
+{
+	int aidx=1,para=1;
+	char sw;
+	int err;
+	devinfo_t mISDN;
+	int cardnr =1;
+	unsigned int prim = 0;
+	unsigned int dinfo = 0;
+
+	fprintf(stderr,"sendhwctrl 1.0\n");
+	if (argc<1) {
+		fprintf(stderr,"Error: Not enough arguments please check\n");
+		usage(argv[0]);
+		exit(1);
+	} else {
+		do {
+			if (argv[aidx] && argv[aidx][0]=='-') {
+				sw=argv[aidx][1];
+				switch (sw) {
+					case 'v':
+					case 'V':
+						VerifyOn=1;
+						if (argv[aidx][2]) {
+							VerifyOn=atol(&argv[aidx][2]);
+						}
+						break;
+					case 'c':
+						if (argv[aidx][2]) {
+							cardnr=atol(&argv[aidx][2]);
+						}
+						break;
+					case '?' :
+						usage(argv[0]);
+						exit(1);
+						break;
+					default  : fprintf(stderr,"Unknown Switch %c\n",sw);
+						usage(argv[0]);
+						exit(1);
+						break;
+				}
+			}  else {
+				if (para==1) {
+					if (argc > 1)
+						prim = get_value(argv[aidx]);
+					para++;
+				} else if (para==2) {
+					if (argc > 1)
+						dinfo = get_value(argv[aidx]);
+					para++;
+				} else {
+					fprintf(stderr,"Undefined argument %s\n",argv[aidx]);
+					usage(argv[0]);
+					exit(1);
+				}
+			}
+                                   aidx++;
+		} while (aidx<argc);
+	}
+	if (para < 3) {
+		fprintf(stderr,"Error: Not enough arguments please check\n");
+		usage(argv[0]);
+		exit(1);
+	}
+	memset(&mISDN, 0, sizeof(mISDN));
+	if (0>(mISDN.device = mISDN_open())) {
+		printf("TestmISDN cannot open mISDN due to %s\n",
+			strerror(errno));
+		return(1);
+	}
+
+	err = do_setup(&mISDN, cardnr);
+	if (err)
+		fprintf(stdout,"do_setup error %d\n", err);
+	else
+		send_primitiv(&mISDN, prim, dinfo);
+	if (err)
+		fprintf(stdout,"mISDN_close: error(%d): %s\n", err,
+			strerror(err));
+	
+	return(0);
+}

Added: misdn-user/trunk/example/test_file
===================================================================
(Binary files differ)


Property changes on: misdn-user/trunk/example/test_file
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:mime-type
   + application/octet-stream

Added: misdn-user/trunk/example/test_file.in
===================================================================


Property changes on: misdn-user/trunk/example/test_file.in
___________________________________________________________________
Name: svn:executable
   + *

Added: misdn-user/trunk/example/test_file.out
===================================================================
--- misdn-user/trunk/example/test_file.out	                        (rev 0)
+++ misdn-user/trunk/example/test_file.out	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,38 @@
+ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ||qsóóñóñýüþñðòórrróóòsròr~~òþðÿòòóóòssqsósòññòòóñðñðórqpppqróóósróqròóóòòóðüÿðòrqpqpprósòðñòòóqrqqqrrrðñóñòòòòóqqpóñrsòórsóóóòòòsóñórssròòòórqpqpròðñòÿñóòsssrssssósprsqpròsóññòòssñósñóòðñósñññóððòòsqpqqqpqrqqp~qsqrrsñññòòsòñññýýòòòósóòósrprrprsssssòq~rrsñóññòòòñòñòrósssqròóóósòsrsóðòóssòqqrpqprrsòsòòsòsqòñsóóñÿòsóñòóòóróóprrñòÿðóóqspqppqprpqóóðððñðòóóòñòsròóqòòòòðòqs}qpqrróòñÿórsññsòðÿÿñññóqqrrsòrpqqrsòÿñrrósrssððsòóprrqqssóòññóóóñóóòrsrpsssññòòòssòòóòóqpqpqórsòððsóósqrrqðñóÿðÿñósrsp~pròòsóórssórròórrsòósÿðóòósqqsrsórsòrñÿóórqprssþýððòp~qqrsrqrórròððòÿðóññsqððóòóórrsqqpqqrssóñòsósóñsñðssrqsrsóqsóqsóòñòþðòrpòrsÿðòòðòrpqpr~~òóóóðñqóðòóóópósòòÿþòñòrqsssóqqqpsóóñòðróþsórróprqqrrrprsróòòòÿñòñòsqñòrðÿñósóórróósppq}rrrðñòñòòsórñòsósòsññðñsòssrqppsrprróòrsóñòðÿòòóósróspóòòq~ssqsóórsóóóóòòsñÿñsòñòsrñs~}~~qrððÿþÿòññóòqròrqóñópprsópóðòñsqsñqrsóóóñññóñórspróóñÿñòòsqprsrròsósrsqòòsóòññÿòròsrróñòñsòñòssòqp~prqóóñóqóppssòssóóñróþssósrqsòòssssrpqsòóóðððÿñññrpórròóóòrpqqróòsóssrsósòðñòñòòòqsrrðósssóóòrrsqrrqóñÿÿñsssqrórsòòñòòóqpssppqóspòññðòóòñósósssóòðóqssósósssrqqqqóðÿÿÿñòrqrpróóòñðsòñssóòòññññrsòpqñspóòrpssrsqróóòsrrsqqsññðóqóqpqsñòÿññÿñðópórrrprqrqqpprssòýÿññssqssóñþþÿòòr}ppqpssññóòóóqsñóðñðÿsòòósóòrróqròssðórrórpqsññóðññðññòóssrp~psróñðñóórppprqqrròrsðòñsprrqpróssðþÿñòðñsrqpqsññòññóóðsrórrrqrsñòñññóòðssróòsñðÿðòóqqq~pqsósÿÿñòsrr}qóóqsÿòóssòsóòrqróósòðþþðñòòsrqqrqróòòòóq~pqqròsóóóòòñòòðñrsópsòóóóðòrrqòóóñÿñòòósrssspqóñðóññòñsssqqrsqróssrqrrqrsqqrsññþþñóósqróòsròÿÿòóòóssssqròrsóóòóòóóósspqssòrrsrósróñòóòñssÿñðñðÿòòqrrqspsòr~p~qqsòssósóðññÿññóprqróòórrrsrqóórqssròððòòsssrósòðósqppsrqsñðñróòsqpppqqròðýË÷ööÍÉýñsss}KMMOvOKMI~próóÿÿýÏ÷Ï÷ÏËýÿòr~p}~p~KKKKI|qóÿððÿþüÿþýýýðññòñsòòñþñósrq}~~|}qsrsósrqqssróññðððþýþñóòòòòrsór~}~qqròrp~rórsóÿüððþÿÿòórròq~qrsróðñòqrsprrrsrñòsñðñssòqprqqsóròñròsqòsóòòóóÿðñññsrqpqqsóóòòóÿñóóóspsóqrsóòóòðrqórprsqròòñðððòòssrqóqrñòssórsqrqpsróñòòóðÿórrpqrðñòòóòóÿòòòròrqqqósñðsóóqòsqrpsrqsññsrrsòðòqrpòññðñðñqròqqóóóñþóóñóóppòrprrpqrròòðÿòòsspsóñðóòsqòñññósqrrrróðòòósòq}~sq}óòñþðñðððsrqrsróòsóòóqqqsòñòróóòòsssñóqrsóqrósósòòsòórrqórsñóòñóòòrqrsppròósýÿÿððñsÿññórórrqrrpsqppqsòññòósórqórssóósòññóóðòsrós~rssóðñóÿÿðórsrssrqósrsrsqsqqrpóóòóòòðþòóòñòóròðòÿòóñrsqró~qrrqqsqòòðñóóqóñòóòóòóróóróssñrròòðýðsssqsqróqròsóòòññósóóóóóòsrssòssòsrsóqqòóóññòòòsprqpsrsrprsóðÿñðññðððññsrórqrqrrpq~qrsóósòóóòòòñòñðsñññðòñsóñrr}s~qqsórósórpqrsósssñÿþòqòòssòñrsóósóòóòòsrpóssððÿóóòpqqqpqóprsqsrðñóðòóòòòÿòòñòðóòósóprqrqqqqssóòsqsòsñÿróòssòssñsòòrsrsóññrspsqóñÿòóòròssóqqrrqrsósòòóóssròðòòqsòsñósóóórpqqqppsñrñÿÿÉýýÿòòrqpsppqprssññrrñòñÿñÿòsñsróspqqsñòðòóðòòòóóròòssqòósóqórqspsrrósóñòsóòqpróòòòòòñòòósòrpqrssóòóòrrñssssóóòsòñsóqqrñÿ}ór|qÍóMÿöÉ}íñcr÷ð~q}þýq}óqqÿð~Kòþðòÿüóòòqrpsròðòòppóð~}ÿÿóqñóòróÿòóòòsóñðópqÿÿpsósrqrrqsóóòðó~ñþòòrqðsóüòóññòpprppqòñrðòóðòòóñrqòrpprðòòòsòssrrróòpsròòsóññròòrrsròþórsóóqqóòsrðòrpòó~òñósrórðñróññòsròósrròsssqòssr~qqpóòñsðýóòrsssóróppsssqòñðòóþñróóòòsòópróórsrpspsòñññsòòrññòòóósòrrórñsrrpqsspsósrósróñòóñÿñóòñòñósrrórsósóssqsqrssòsrpóñóòóòppòsòòñórñósqsósspòósòòòòñòsóòóqrrqróssñòssññóòósósssrròsrópqqsqpòsòòòñòòòñósòqrñòóòòóóòqrrprqqssrqsóóósssqsssssóñþÿýüðóóóórssssróqpqppssrrsòóóñórssrrórróññòÿýÿððÿórsqqqqqqsssórrróópqóórñðòóòsprrsóÿþòðñsóósqrrqrrrròñòðóssqppqróòóòðþðñóss~rspròÿðòñòóqprqqrqóóóñññrrrprqòòsðòñòsÿsrssrpspsòññÿñòòósqsrpqprñòósrssrpsñròñòðññòóósrrrrpròróòqsórqsssóróñññòòòòòsòósñórrsqprrpróòssòóòñòòòþðóórqprsprrróóñòròsqróqsñòñsððñðòóqqq~pósrsrósqórrrróròñóññòññóòñóòósóóqrsqqppssrñðssóòssòrsqqópqóòòÿðòñósróósòòsóòòóóórrrsrqrqsóóòòòppsqòñððÿþðóòósóóóósqrrqsrsóóñòqrrqróññòññórrórrósóssósóqqóóññòòòñòórprrrsòórsóñósòsrsòóprssòðÿÿòqósrqrósssóórrsrqrsqsósðósòóóóñòñósòóóóósóòssqprppóqóðóòóóssòssssrósòðñðñóóóórrqrsqsòòðññðòpq}rrsòòòòòÿðsòósósssssssñóóÿóqsósrróóñòòópppsssóñðñðóóòrpqqóòðòñóòòssssósóòððóóóóòórrqqróðñðÿñóqqrp~rqsñðþðñóòsppqpqqòñòðññòòòñóóórñsóñsòññrqqrssróóòrsñrrsóòóñÿÿÿðñòqróóóóóñóóòós}}I||òóÿÉüÿðòqrqróqppsòðýþðòrórprpprñññþñóòóssrppqsrsòsqssóóòÿýþþÿññòrsrrpósóóóòssrpqórsÿÿðñðþñórrpprsóòðòòòósqpqsqrðòrqròòñòóòsrssóssñññÿórrpqsrqóñòñrósqsrósóñrsòsrsssssòòóóssóssðñððrsrrrqsqróqròðsqrrsròþññòòñósóòósóqpqqsssòòòrqr~qóssóñòòñðñrsqqsqrssóóññòóòóóñsssqrqóðóðÿórqq~~róóóðssÿþüñóórrsòsóðñsrórrrqpqqprqsóñòsòóòròñqsqròssðÿósssóósòððósñópsrqòòqóóprrrpqòrsóóóqóÿÿòròñsñÿsprsrppqqòsòÿóróóqsrrÿòsòñssðrpòñósðsrrqssórrsrrróqrñsóósòððóòðqsssóñòóñqrðsssÿñ~sròórñðóòñrqqprórqsðósñòóóðósssÿñrÿòòñsòóópóðprñr}pr|rñrsóóqóórñüÿòðòòññsóðpsýópóqpspqrqsrrrpqððqÿÿpóòóòòqqóóóðñsñðñrrq~~qórññòñÿòsñsspqrpóóóssòðòssssróðñðððñssrsqqqqqqrqñppó~póórððñÿðÿýÿýñóqpòssòóórrq}rqsòqòqsðÿÿòósrqóprñóòqÿðñÿññqqpqssósòñósóópqspprròòòþñðòòò~rqròróòòÿþÿþðórp~|ppsóòðprórsprròsòòòÉðññóñsqq~prsòòóñðñróòqrròrrÿñòñósóórps~rþsññóÿóóspp|póròóñòqòññòóðórqprqsòñðsqsóòsòÿsóñóòsñóqqqrpsñðñòðsqò~~qpssþþÿÿñðspqróòprssrqðóóñsñsqòspqsrrñðòsósrsrsðñróÿðóóÿqpòsórsòròrrsqp~sp}qpqÉãäùãrohKðËót{``yMróýüý÷ìíåáççùïËóp}|OuchoolO}qðþsóþÿðÉËýýórp~~~rróósóþËüÉÍþòñðòq}}}~sósssrsópqròññrÿýððñýóòþsòrqpp~}qpprrq~sórðñþððþðþspóòòóóssqrópprsqpñþññÿñqsq~ññsrspòqpqsòrqòñsòñðsðÉðóssrrprósósòòrp~q~ròsÿóóðñòòñóqssqsññóòsròÿópóq~óóq~ððóñðñóór~qrrórsòðòrsññóñÿòsóòsñòpóóssrp}|~qróþþñðþòrq}qrsÿñÿþðñsòsqñq~spqñòóóppòqqórsróýüËþòññrssprssòðþñsó~~~pqqsðÉýñðòq~q~K~óþñðÉüüðòóp}~rsrrüþóññI~~qòðóÿÉÿýððñsr~qqsñðþñsóó}Ip~}qqóððÿþðòrpsrqssòòòðññðósóssq~prqóòðÿsðsprqósqsòñòñòróóóñqsqqðóòòñþðñrppqpqsóqsÿðórrpp|sðòòòórsñðsòðóóqòñrsññóÿñóspqqs}sóqòýþrsórprrpróþñóñóñrÿüssqrq~pñóqÿÿqqqsqrðóññòðÿñrñspsqqóòóròñqòñsÿó|sñóðóðórósópqórrsññsóñòórrrrsññqsórqqòóóòðópórrrpsðÿñðþñpóÿòrrrqpsóóòðñórsò~}sòsðñsrsqóòñðòòòóóñðÿÿrsòópsóróñrrpqòrððòspsspqòrqòóórsÿÿÿüðòóÿÿqròó}qsr}rspqÿÿóòóósssqòðññòòÿñòrps~ss~sýñsñórñòsðñósqssóòðópssppsñrpóóqpñòrñòrsósòsósóÿrsððórqrpqòsóóññsóóñðóppssqñÿssósr~qósòÿòqór~òþðrñýñòòñósròs~~qópóðq÷ý|sqrpðòðþóñróq~rpp~órpóòÿòÿñðþòprýp|rñòóþððssópp|~òóósòñqóðòssrósòòrÿóóòsðrqr|óóÿýþòóspórrórpsðÿÿñðòqrqq}ñðsñðóqsqpp|óssòóñýüÿýýrsðóróqsóqóórpóqK}rspqòróÉýòñróñórqññòòññpqrrr~pqqqòÿÿýÿðñòqqrðòósÿópsprqpóós~qñóñýüüÿññppqsrrþñóñs}M~pssòüþðÿñspqqpqòòÿðòÿþñpprqpqósðþñóóðq~ppqóññsòÿsròrprsðñóññòróòðÿñýór|}srpñò}}}}sòñþðððòñþÿòóóròòróòñórópppss~prq~sðòþÉþóqsñrsrqóññòrsórqòóòðqssññsþÉñrrrsrrósóósó}sðsròþñsñósróòòróspqòórðÿðsóóssrqqóp~òòðòsórsóssrsòðòñÿsòÿrrð~~ñssÿsqsqòqqþòróóqrñspprsòóÿÿòñóòñóróðs~psrqrsqqqóspspsóróðþñýüüüñððp~órps~}~rósóssróþòrsñòóþþñóóóósóóqrqrp|~pqsóÿÉÍÿóñòqqssqrðñròòrrrsórrpqóóóprósòñýÿñòrsórsórñó~rñr~pssqrrqróðñýÉóòþqqsqqóòrrsósrñòqrsóssññññpsðsóñóqqóñr~qssòðsrsqròðòóþýþñóppóqrq|~óÿòqrrrrðÿðþþððóðÿòòróqqò}}~spqsÿrròòsðþòsóòsòòþòpsrsrqòrsñòñññq}rqqòððòÿýórrpr|psóóñýññòrñrrsóñòÿÿñsrrqòròÿqsòr~òqqppspròòðòòððñóÿürqpóñ~ósóòòñòrròsprprsóñósóñðóqñsqóòqrÿðppñòpsððssóqóósÿñqrósp|~qp~ñüòòüÉÿósñs}pòr~óÿòsrpsp~ssóprññññüpqðqqsrpsóüÍýýsrs~rq}qsróðòòòqróqóðñðþüÿsqñò~qrp}}qqrðüðòÿðñsñòsðós~}~|rr}|ròñÿþüÿòòsóórróòrÿðsòóòsqóq||~sòñÿþÿñþóqsñprþróñpsqròóóóñprÿrrñððssðóqsñòpqspqrròòòðòñòósòòpóðrpóðsqssqsñ~pòqòñssñðpsòósñþóóñþÿpsròósrròrrpprpqósóñòòòðqóqòñÿÿsòsòrsqsrÿýòÿðÿñpsspp~~ó}óóóppóòrpðññðððsórsñðÿñspqpróróósÿýðóððppór~qñórqrp}qsrqsòñóóÿÿÿóðýórsñ}ròòqsóqqóñsssqqòòòó~÷ýIöóþOð~qñqÿssrrsqrrrsñþÿñòósòóssóòsrpóósóqñrqðñòðþñòÿssóqpp~psqqòñòñsqròóòþòrññóÿÿóñðsqsrpqqpsññðóòr}p~rpròròóðþðñþòppqñóqsñðñÿðòññssr}r~sóñÿssr~qrpóòsqsÿðqsðòqóñsròþðóýÿóóqrp}}}sróÿÿþñÿñóssñsóðóqóòrrss~qqsòóòóññòðóróróñóóñssðÿòsòq~~qqóóóóððóñórsq~pórsóðñsòsrsóóóññòñüðssósqsq~~psrÿósòóspprsñósóóÿòòðóòðýþrrssóòrp~qspsssòñððÿr~pòósòrq~sssñÉðòýñóórqspóspòÿqrðspñðòòóósñþðòòòsqpq~~ròqsñqósððqñðòrsñòòpsrrròs}qóósðýòsðñòrqðrrsóÿòóqòóóðòòprpqróðýþñññsróssóòñóssòóòóqspóñóqóòs}rò~psñòðþòópsórsòñrqpqróñòÿñóòñÿppþñrsós}~òòsñòqqppóñr~pórpòóróðÿñÿþðórþñssqòòÿðsp|pqqrrrqsòrósqrqsðÿòüÉòsós~qsðñòñrqóÿrpñÿòspsrrròòqsòò~~òóóòþþðþòñórqsósrrrppspñóóóþüqròòsqÿðpsóp}qsqðñsñÿórñsp~qñóóñòrsòrqsÿñóóðópqsròüüòòÿóssqqq~pósqóÿðsqòó~póp|rróðssññóóÿÿsðÉýÿÿóóq~rq}ssppppóòÿósspþñrñòsòþóóòòppòóssòñðñóñðspprrpòóqóòñ~qópqqsóóórpññsóððóñòqpóðÿþþÿórqrp}pqsóqsòñópós~pðòrñðóñýòrósqsqqòóóüþsòÿðpprqpqòrpòððòþðspr~~rróñóóóòñóñðspsðòsòòòsÿýóssp~~rs~|rñsrññrsñsòüðñþðqñþrñs~rqsñsqðýópqñrqññòòþñóÿórrKOq~ñýÿÿðñssñðòsððþüòóðó~p~q~~òñrrñòóñòósróþýðñðñóp}psrsñüñóýðqqsòrrñrqròÿññòñó~}I|ýËsñðóðópKmó÷róÍõÍËÉ}~rpulIPQìû|ÍàÐípöÉüñq|MqKbhMpO|p}ósósþýþËðüðÉðqñÿþþþrópsþIIþð}MË}}ñsÍÿrñÏr}ËóòIsrKò|ò|}óO}pðpðÍrsýõññðÉÍKÿñ~þqòr}ópò~qò~sqñsrñòÿññpóñóppsssòñ|qñóóóðÿÉÿqqñÿrrüó|sóssÿr~ÿñÿðrsqrprp|ñÿsrÿÉpMðÿ|rÿórðþóòóÿ~qýqp|rñqrròñópñðÿñ~þrIÉqcýÿ~Ipürðÿðððò~ÿËòpðÉ~ÿñspòÿp~~sr~pqÿsqüÉs~pròrqssòssòrprðððòòðñsðÉËspópqprr~òñÿóMðppsrssÿÿýüðÿsqóóðñ~pþò}ñýó}ÿÿKMsÉòM~ðóMpËürüöòüÏsIqòppóÿòòÿrqq~sññò~òðrssñóróòIóüýÿóýðsòÉ}wpþóòòrqó}Irpqýs~ÿüñrü÷òòðrsðqóðóqsqqsóüñqÿÍrM}ðþqððpþñIs~sñðÍüsòóðñqqòÉñpqðòKIsþqMqóprñòÿþrsóñññÿsrrpsòpqrpqsðÿóþËÿsòr~qóórq~rsðþòÿr}rós~qñrþýÿþppòrÿðrsóýðr~òórñròñsqðÉñóqòóppóòósI~òrròýðrsqIIqssrñÿñÿýðrsòssðórþñsóòò~rþñpsp~sssñðñòrqrpprqròsrñýñóýþñòóq|pòðÿrròqqóó~qðrqqrrrñòñóñðrñÉþórqsrórsóqrpóp~ósóqpsqðþñÿþýñpròòsqñÿrrssòòóqóÿððòrsrqròóóñðr}~póñrrðÉñppsspñþóqòññrrñóòýññòrqðþqqrpq}ps}}qòóóðóqðþüÏÿÿñqp~òópóñsòÿó}qprsósÿþÿòòòrósrósóñðpsþþrsó|pñsóÿóqórsËÉñsóðóp~sðóór~qr~}sðrrqqóòðÿÉüñrprrqóÉÉòððr~M|sr|òòqqþÿóóssqpròðÿÿÿÿrrqqòññqprp}qðóñÿòòóòóðýýs}òó|qórrrrpròrsssñòsóñórsýüósñòqssrópsó}pññrsóòýòóþðÿþñs~pp~pq~pðq|óÿññþþñròÉðrðýòrsrpprróó}Issóðóòÿÿòóñrsóòòóÿüò}~qp~ssóÿýÿsóðýÿ}r}ðððÿñòððqp|pòrñþüÿqrpñðòsóñq~~qòòñðòrrÿÿsòüþðñssqrpóp}rñòrrrqrpròpròñðüþóðòññÿüsrrrópqÿs~qq~I~òüüòýþrqsðÿðòpsóqòñòqñòp}prpóòüýóósrqqqsósróýñqpóñór}óñqsrþüróðüýór|}rròðòrsòòñspprþñq~qÿÿððòrq|w|rq}~þÏÍüÿÿðóp~òòppsñòñòñÿópIIsòqqóþÿóssñsrðssÿýüüðqpr}|qssrròÿÿòóóòþór}MqsóóñÉòqsóópqðòòóóòóðÿðòrppKwpòróÿÿýðrqqqrórsñòòðÿÉÉñr~~sóóñr}|}qqñþðÿóppóýþñþür}òÿñrpsprq~òòróðròñrðüòðüñqrðòqòsqrróñó~rqpqsòòòññpIrðsñþÿðòó|Oqñýþððððqrðòrrsp}I~sóòñòóòñsñÿþÿssssrppóòpp}sðñðÿþÿòòñðòðñóÿÿI~rròsròqsósssññÿññÿqrsprrs~qsòrrðÿsòórñóñÿñòðþóòñðósp~}rñqsrqóòspppróñðòñðñòððsróóq}qóðòrñsrðórrqssqpòñqrssóóñðñrprñðððñrqóróqqñóòsq|Kpñþóððórróóòòððòóróp~sróóósqóóòòóòpóó}~ððpòüóòþñrppp~qòóññóðþÿòññsqqrrqròrprqórqóóñòóòóñóóóròðñsppqp~sñññòþðqrsrsñðóppqqsóòóóÿóppprsòñÿðsssrsóròðsóòs~òsòósóqrssóóòñòóòóóórsòq~óòqsñðñóòñrssqsròrññÿþósóòqpq~~sòssrsròðsòósòÿòsñðÿðósrqqpóññòòóqórpsrrsróòðÿðÿsróórrsqsòÿðòòróðprp}rñrñÿñðrñs~rrqqóñòòðÿðòrrsrsóñòssññqsssr|ró~qòñóòñrssqósóÿþþÿññðósðó~~~sóóòsqróp~ðòróñðòþÿðþñðóqqI||pðÿppÿñsñüðpsòórróñsrróóqròrqòñqqssssóððÿðórpóósósóðÿñqssqssspqñòqòòóñðþó~róqððsqrñrqñssóòósòóóÿñsñðsprs|rñóóþðpsqqqsóóñÿðñþðqòñrqpr~~ssóóÿðqòñsrrsqqòðóqsòñòórqòóóóñóqñsrróðrpóÿóòñsqóò~róròñòñòsóÿsrðòssóòðópòqsspsqppqsrðòsñóðòñÿòñòòòsóðr|òñqssrpsssqqóòsssðóqþÿrrðñqrssqrñòñssòrñósqóóóòsòñrppqqqòþññññòqrssósòósðÉð~qrp~}qqpsþðñÿóóósrñüòqòñrpòòpqñòpqrqpòsrrññòðssÿñóòðñssòòpqòópópqòñqrñòÿýüòprqòsqsórqppóòñrqróórr~ÿâÉMpõËðqwIsñpw~þýÿýþròs|}qr~róóósòòðýñqòðq|pòðñþòóýòóòrpqrqóþÿóÿó}|~rqrðÿòñóssrórsrqsóòòóòñòÿþððñqppqsrpñðssòs}qrqóóñòÿýñòór~qóppóòóqsòñróðpqóóròþsñÿssòñrrp}óðsóýðqsòr~qòóòsóòòòñðsqqó}}pððÿüñòpsñrrqóqqþðòòòóóñórqq}óòqðÿóóñsqppóssÿÿsñþðrrsppqqróssñýñróprqðrqñðòóÿÿñórpq~óòqqÿüñóðÿrrópqðòròðssòórpòòpqròòððóðòrppsqòòsqðòqòóóósòòróññòóòòsrpppsrrqpðñòsós}ñüñòññððsss~rñróðssópqóóróqñÿþñsñòsóþðqrñòqsñsqòòqq~psqpóóqðþñòóÿóprqósÿÿóòsðñòóqs}sñròþðópóqqñróóqpqòórrsrsòòññðññðñòqsòsóqqqsrsòòsðñrsqsòqqñósñóqsÿsqðòqsñòññsròñóóòòp~rrrsðþòðý÷ùÓ95<ò¿¹¿A6=PyCVcÆ¿¾ÐA]QçòRFEhƺ°¦œ¤¬·T**?ǹ½çD;,%#+@Ø®«¯¾ÔmÕTÔ§˜¡Â,)=ÐÁîîÖÏ:*#(Z¿®®·¾¿ÝÅ´’““ž²'/E¿³·õ(k2ت£œ ¤®ù>?Æ®¬¬°ÞW9/++4WþyB;00\Ä·±³½ÞÀÀ¹°¬œ•“™¯&1TØ´°Ý.4±¡’’Ÿ£­ÔyæWb·®¯ß>50,39;D~U>9<|Û»´¶º¶¹¿¾·¯²·©˜›¢Ek'2@¯°À/#Õ¯¥ Ÿ’œ¬Ûº¼8&.í¯·ðA9484,3oÓíuѾ¼ÂÄ¿²¬®»Ø²²éW®›’³3'6ߪ²è1$!*EÚ®¥£³Ö¾¦§\_¶ÚB>RvA/%)[ÆÅƾ¯¯ÙæÕ¹­¯Øô¿ӽœ•¨#
+)F¨Ÿ§I"'>¿©—™¡Â;5Á ˜¬+-V>,0ѵÅ7%%6OI𹨧µÔÓÚ¸¶¿×Ù´Âu¨–œ+5­˜¢Ã(#.@±Ÿ•ë’´h=_·¬§¯{///+/8óÝá;022<Zp¸ª©¯¼Ãس³ÛÖÓÕ×Ы”ž£¼$,礥´|-'1Ôª˜”›¢²à:_µŸ§Õ:.;.'*@ÛÁÕ//:;2=Ä®§­·Ù¼º½º¸¼×þQ°™™«¾y$k$;À®¶¸q,"-Z¼¨’›˜¤¯ÀWI¹¬»Ö×F.)*19XVQE?<46GÁ¼·±¯®´»¼¼ÞÆÄÐ×¢Ÿ½»B );»¶¹X)!*._¿¨’˜’¨­»Ä㶱SÓ¹ß0"+7808D~{;07lÄÂÛ´­«¯¿½·¿Órÿ¶”«·°7)Zܺ­Ç/'',,Z¼¢’˜œ¦«·ÇDU¼œ£R8?-)?PÓÉ@?\2-_¿±±®«ª°½ÃÞ¼ßb­–—³¶À-k*gÓ½®G-(,,._±œŸ’œ£«·Õѽ´ßF׿F%!/6--?óýA9=eâéƶ¬­³²¯¹ÃÆÐÖ¡œ»¬Ý'(`Ô¸¾:0/0*/Q«¡¢œœ¡¬»ÅÚ»²ºFVÖB% -=2-<a[9<fÔÅÞ¶¬¬³»¶±»ÄÆ®™›¶¯³:4hÒ¾\346-.]¼¦¥£œœ§°·°²öA|Ù×?1/2.(+5CFZ]OÐfmź´³´¯®µ¿ÞÙµŸ›¬°¯G"k+SPÐB;;6//\Ç­ª§¡Ÿ¥®°²±¶ÇDüÔE3+06,*2X\Z?BýOuÖ¿¶°´²¬®»Þ¿¬’œ±­¹82TRQYZ;4/8R¿®«¥œœ¨¬µ¿Ùß®¦K*9Y(%?Q75TQ>87Õ¿½¾®ª­³¼´®¿×©žœ·®¼8/=@V>=;72=P¿®«¦œœ¦­³µ½±­P;îA+%+61,3T];XYWåÐõ¯¯®²·²ºß³¢’¤¬¬Ð+"3=\Y?<855]÷¾°©¤ ¡¨®­®°»éÑä?1/20++3;57ZBESïÜ»º¶°±··¶µ³«œœ©¬·<%)659X<797=aÕ½­§¤£¦©©¯¼·¨ªV0_\( )<<.0CC54Xn×Á¾®«³»µ°±·²¡’§¬°l.$#-//:<7;;=TÑÁµª§¦¥¦©¬­ª¯ÆáÏ?1..//-2:54:=^aèÁ¸µ·µ³µµ´²«¢¤«¬·S2*%!  %+-.259==\uÔÁº¯¬ª©ª©«®«ª¸IWWY1,0:9128<=;]ÍÁßÜ»¸¸»½»¹»º·ºØÁÓm\<<934622:97>A at Fy~àÅÀݾ½¼¹¸¹¶³¸ßÃÀáSRU at BA<9>><>[AQMuíÇÃÁÜÚ¿¸µº»¶»ÆÇÕSAA:155/0458>?\QÏû×ßغ¶µ±®²»¸ºÆÑÑbWT^9;=:;==\WWUðÓ×ÀÚÙ»¶¹»¶·ÙÃÅõTV[7683/245:=>BOìÑß¿½·´¶¸´µ»¾ÙÄÒîoD_[==>>?]@CW`éÓÆÁÛ¿¾½»¹½ÞÂÕrSE?:;93268:>X]RÿíÓß¾¹¶¹»··¼¿ÚÃ×ÒbFDBZ?YX[ABDSOsíÓÖÆÀÞÞÚ¾¿ÙÜÅÒåhF_X;98669<=XAWdìÔÁ¿¼¼ºº»»¼¾ÜÁÖâKRGD@]^__BEWRhséÑÕ×ÆÆÃÁÀÃÃÀÂÒÍr`FB\=<=;9<X\CUR~ÓÇÅÞÙؾ½¿Ø¿ÛÃ×ÓíInRÕVFDEGWTPdwýôâàÑÒÒÒÑÐÐùîàéòKt`RTFCEC_ at BCWfltüÐÑÒÖÇÇÃÃÅÆÇ×ÕÓÑäâü~ulngPgfPeK|}óñsrq~qqqs|}p}MOMuuwcmwtOKM}òðòþþððÿÍöÍÉÍ÷ÏÍíö÷íãôÏöËÍËðüþñòpq|mvvbcmbbluMK|óðñýÿóþýòþÏÍËÏÏÉðsròpó}K~p~psóñssðýÿòñóqqðÿÿþþþsprq|q}|ròóòóròrñÿþðÿýòrsñspóòssóñòq}qp~róqóñòròñòóÿýòñðsqssqóòpsòòóñðóóòrqsðòqqósròóqpðrpsrsðó~ór~ssóórsòðòÿþðñÿþóròÿrqðñññóñs~}~}rqsóóññrrñðóòñsqpððpròsqòòròòsqpòòròþóqóóóppððòòðñðýñqsqròqóñróþþñóórq~~~}qrrqpppróqóþñþñðþsóqñÿóÿððpsðqrssórsòrpsórqóqpórsòòóñÿóóòsrsrsrrqrñòpóòqósóròòñðñðóórp~rrsññósòóóËÔÓBGÑPtËòíòçòýöqÏsÿósqqþrýâÉQS~lop|qþ÷ýþíÏüÉÍÉËýsòðqÿÉKpñqó|~~MK|}|ÿÿqÿÿóñs}óËrpÿþsrÏs}Íðñðq}rr|ññþòqr|pó}vðÏÿÉÿóÿý~pñÿòÿó|ññðqMüþÿIKÍ}pÿIÏðÿËwÿðqüò}qs~÷íqýIðKþÉ}q}Mpþrpñórrp}~ýr}ýþóñüüÉÿýÿIòssó}ÿ÷rÉKKýsýspqýIò÷iþü|qtrqpìqOürÿ~pü|ËpwòþôþrþñþòKÿòOpòý~tÉÏmpíKüýiÏÏ~wþõvr÷|Ïèy}ðIðs}õö{|û|ríiMsMýötðçñmýsËåöhQãñhþKÏíqqqôviÏð|IóÏýmÿïsv}ÉuÍÏpOðèÍ}ðËomóóõ~IõrtÏÑþPOìqbðôÏqavÿrrõüntðñåïrólðÿð}åÿls|}ÿMK÷Ííö|yhËíórwcüñò÷psèËI}|ìËo}}ÍõwüÿOr}ðüórs÷vcüóüüðwOÏn|ÏpËüýIüÏwKÿòIÉpqsâìuþKÿütþôËc}ìvMñ~~}plråsIÿþ÷ÍOppcðspíöéÿwrpròÍqhsqOýþÉÿwòÏñIsòc}òüìürðOKéònõùvsipüËOwöqIsìÏðõiËíQtüÍpuIq÷ÿOÿ÷òþñqüó}ññvsôÿóËiþþ~w~òËýIþòpOåpÏrðÉýc|þIÿûæQTõwhõþý÷Ï~|âóqìóIýñMóËóO~IððsýõpKM~ÿríþrÏ}ñòprsðýsecõìMqÉ~ñí|vÏóuòòËpIðòã~ìþbÏÏdþíltìñvþó}ÉéutîèIhÿËñwqûïeQÿè`bÒýPüícwõsãüìM`éÍËãPdÉcOõþÿËóÿlõÍwóõèí|mytïËM|ËÍsIiÉîým}ãsiwrmýücðöÏòÍMåñeòËñ÷üÍrÿígwÏOOòívMð}Ë|rñuüþósÿðsïñ~övOñisíü}päMOþtssÏö|KcóáülüíðswcñÍMþóf}ñ}óüüüâýÿòhñÉMõãOpÉuIìómþKyôâtqíó}Íüc~ôwñèobåítþéIIÉ÷uirvMÍíþKqóÏüttÏölñìMröp}îþbË÷IKýbýõqIþ÷|ð÷mIËMuóq~ôqMüísmõówq}óíròéüóýðIr}ñññÿ|ðrrI~tñqwõý|qóÏrñôKpñI~ð÷tpâðÉÿòþÏpur~OñõñwsrMòóòwKþýpOöó}íssð|sðÉIËsðþñrsÉqpòsI}üóËIsrqËIrð}rpósóðqþËsñsÉspòIrñòppËýsþr~ð|~ý|pò}rpÿÿIqsþÉ~}þüróËÿ~þÉóñò~prp|ðñKópüñoòÿóðqþ~~ÏðípqðOóþKññóòsöÿIqýóqñqqòòrÉÿ~óòòtsðqò~üórÏ~ýóqq~ÍMðËpÉó~qÿpKÿ÷ð|róqwsüwsðòÿsÿrqqðñópóËsñËKKÉqðÍK~óór~I|üþóýÍòòñsñspòpKòýËpMðð}ðr|ðsðõO÷ðcð÷wKÿópüsIþósqòÿrñpÍËrñÿ}q÷ñ}rññ~þó|ì}asñqKsñ|ÏIwÏÏývþôwÉôIððp}wðÏðrI}üqKópÿór~õÏuÏíoKöðqqÉ|côýsüMKóþó~Éð}Ï~rÿMþMüîu~qKqsó|ròËþKr|ÿÉqüòsltíâüKâì}öbwütö|h÷þôwpáauô~Muñ~vrýüöãOÉÏ`h÷ö|þðsððýIïåcuþÏwbóþóOÿìsððss~IOðwsåIÿ~RIãösñ÷usáüèða}p~MðãIiräËpqðírp~òtKìüw`IpôôñË|KãûMsvb÷íöoKòuIöh|Ë}ÍñôÓÐÓþdGBüPtöîâÑþqíæÓãuSSìùMÉòPÉüPi|ObÒçR{ËåÿñËèîòrðMaòôËäûübìûöûrÕ_BSPsOoçÓÐÐÐðãÔéËûíÕVFSÐ{í×É×Õñ}éÇÔÐ|WeþIPPnPPppPcWAKpqâÍåÐÓÕdVõïäÑôþKÐÒõáP|ÖåKMâobÓr_WýDSçQüæO×ÁÒÓÕòwîaWufFVIìcVSo|ËòuýÿfÐÃíIÛ¿ÐÞÂPTüS\eQVÐsÕöÿPÏÖKËÕWFË~QQoâÍòcTTE{|QPöÔÐùùÀäbÞÅÇÄôÑÄÂÔÖÞÒnZ\T:]~>?PBÃ^WÝpR×Òý¿»ÖÛÚobsGPdTGfèýÓÂÜÀÆÕãtPäçÔÀgZEFX?\7,*+.;]d¼¸¹··¸½¸³µ½ÅÔÖÄÅß¾ÄC98BÑÒqZ?ïçâ}B[>DW[[CCmÂÆÚºÃ×ÅÑMQrrÒÙÂÔÔÐËeD>@ïsFS]<FR`ÅÆíÝÜrhcQhÐõ~ÒpQàÔKPgUS~gtûuQ|ÐísàÕÙºÝqRbptyhrÓÕõdSWFUhìûpTWPÍáòdRiîôòîÒÓÕÔuGGECaò{}åéè×ÖÆÀÄÄÂÅîàÇÑçÒpfKQ]^G_CiVASPSãÇÕÂØß×àW:6539\_CyüÍÐÇÅÂؽ¾½¿À×ÖÔÔÃÂÄÃÃÅÆÇífQevó~wÓ¹ª«»S.#!! !%+;Ѻ±­­¬ª¨ª³ÜýWVrÄ»ºÐ>747Addbõ~TDAEyÔܺ·¹¿×Ém|ߪë™§ñ(-Я¦¡¡¡¢£ª¹Í<//7?SçÁ¼®¨¨¦¤­A%&7CǼÙÚ¿ÜÔÖÇÅ¿½×B=T¬ë‚‚—³)&Фž”›œ¦­¸×[+" '7Ô¯©§¦§¨©©¬Ù;'*>À·°®µÄaC>[PçÔ×îPÚ’‚‰Ž“ºk3®”ŒŒ—¢Ü]5+% .Æ¥›—™Ÿ¨¸æV?-"$6Ѽ¹¹Ãíþa^;63=RÒݽ¾ÁÀß³’Œˆ—Ú/Ä¡•Œ“·2"!'.?½£™•¬t-%&**+-7ð´«­¼W2.2:]ECDvÇÛÙÀÆÃÁÆ׸œ–ˆ”Ó .|¬›–Œ”«7-Aï ™•´6*\ðß¿¼·¸Ä_0)+9aÆßÓÕAFr×ÅÆÆÃÇàuÔ¨‹ŽŒ®
+$:Ø£—Œ›Þ k"^º¨Ÿ”“™¬5k5ܧž–žº'%Þ¡Ÿ©¼Q3-.2@½«¦«Â<3ÉŸ‡Ž”8	,Q¨”™½k#D¶¦’—–“›»''Ò§˜’©O),æ­¨°Æ_749Y|½±¯ºí[\Pݨ›‘‚<	"쬝됔©86²Ÿžëë—œØ)k+קŸž“žoY¦Ÿ¯|7((,6骠¤·X-5춬¨œë‚‚1
+;ºª’”ž¸!+·œ˜ž——ž¬6)Û¥ŸœŸ¢ZÚ’˜¥Ä<3..0=Ī¢ªÄ:2^Àµ°ªŒ‹‚§!E·¦™–“œ5
+K©Ÿ›—“•œWk"ñ«£¡¢¢œ£:&´œ¤±ÇSE8+*:ܨ¥³Q6>IJ¸ÅÞ¦“‰‹”)
+(_±ž˜;
+?»«Ÿ•ŒV'R¸­¥Ÿ’¢±á(/Ù¬¬²¹ÓX/(/h·®µ×RdǼ¿çϲ˜‚„‚¨	 &÷¡‘“­#k#=À¨”‚ë®*-B­Ÿž˜¤Ø+(aµ¬¬²ÆX-(/e¹°¶ÇE[Oß¾½Ø¾¯Ÿ–‹ˆ£"V¦‚«(k"4í¬™Œ—®. +9ñ¯œ˜’­Äó*k.¾©ª¯»h;/+5K¼µ»ÇþôúºÝ®˜ŽŒÒ	#Ó’›õ$/I£“‚ŒŸá) "%'/䨝˜£³ºTkD®©¬¯¿P7));Õ¶²½ÅÅÕÇÂ×Þ¬˜ŒŽ¯	ktŸŒ‚—¾#&A¥“‚˜½2$ )m¨› ¯»Æ)0·©®¯³Ä]-%-q¹·¾Ä¼¼ÄçÓºœ“œ&
+1¦•ª6!.´”ŒŒ™©Ð5&":³Ÿ™’¯Ç:!#Xµ¬¯¸ä\:11EÝ»¼Å{rÀÀÆÄÀ³ —‚.
+*¬—Œ•¤F))Ù˜––”¢¸T,0Ý©¡Ÿž’g9Ñ»©£¬Ö1"'XÑÛ»¼¼ºÜèsqÔ²¢™Œ‚›X
+
+%¸ž‘œÄ3$#˜듗’ªÁ4*ó©Ÿ¡¨°R+ #;Çع»ÄþA76FÑÁÛÄÆ¿ØÓr×°œ”ŒŒœ1k
+)®™–—¢Û?(&ל™—”¤¾5*G®¡¤¦¯S-# '<m×¼»ÞÐD8;VõÆÀÂÙºØíTvÚ«ë‘•­)
+
+6©™•ž£¾\&,ߢ›””˜£¿2 !*V¸¯¦¥¹T5*'/9XöÜÝÁàAZUwÍÑ׿µºÑWWൡ™––’S
+ÄŸ—”¨Ú: :·£˜”—˜¨÷-#"0F쨱Üg:0215CþÓ×ÒfRcy}Ñ»³¹û@VÖº©’—ž»";©ž™˜¢¯Ð-,ö®¡˜™™œµ_+$(*+^ø³¹ÕOd?44;AwãOuãåìÒú³¿ÿMÏìƳ¡™”¬/)»Ÿ˜˜’¤´?#&:Ö­Ÿ™”¨Þ?-)$".Eº¸¼ÛÂS926<^SdòÑÕÑÇØ·¶ÛÕàoRr¹¡™•žª<k&Ò¥’˜˜Ÿ¬T*#.B¹¢›™˜¢±÷7,%'8Q»¶¹½éX66;=]U|äÇÄÁ¿¼»¾ÝÓìæÓ»¥›’©Gk Y®¡Ÿ’œ©Ä9("%-=Õ¬œœ«ÛD:."$-=n׿»·Øl=9=>>YGMÇÞÃÞ¹´¼ÞÅÒïÒ¹¥˜œ®<#B°¥Ÿ’œ¨Á;+'&+9þ¯¢ŸŸœ§·}Z/#%+4^ñÞº¶¿àWXX=:>DQûÀÁܹ¶¼ÛÁÇÕÕ¼§’’ ®?"!?½«œ’Ÿ¤¸D3-'(1E½©¡œœ£¯Ð;/8D/#+TÒuDÏ·´Ò\=^Õ>1?Á¹¹º¼¶°ºÕîdz¢Ÿ£§µ6!#XÚ«œœ¡§·Q:.(+6GÛ­¥ œ¦²½Á<&#'.6=i½²¹ÂMR`\57^gíûÔ¾´¶½¿½»ÜĹª££¦º1#$?dz¥¡œ¤µÉD;.-1YDZª¥¥¨¦¯V5.((*.\ÇÛÙ¾ÅÇÑC>@A^SasĽ¿¿º·µ¼ÆÁ´«¨«¬¹5##<Óµ¨¥£¤¯Çf[424>춯¯­¬­³³µB"#-,*/Q¶­»ÇÕÑM<0>ÓÖâÔݼ¹¾Ü»¸·²ª¥¨©·2!k!;㺩¥¡¡­Å~G7/0:u»²°®«©§©ý*,/*%'=¿¶ÆÆ¿ÝÇC2<ÓïBR×¼»Áǹ±µ»Ù·©¨±¯Þ-$&=u¼ª§£¥¯ßÇ{848YsÝÚ¸¯­¬¦¨v-/.*&(?Ø»ÇÄÀÞÆ^4DÂËUv׿ÚÐÒ»´´¹¹«£ª¬²<&"/FÔ¯§£¡¨¹ÀÕZ327AÐÃÚ³­«¨¥±Z//-&$-SÚÁÖÝÙÚõ>?çÇSFÿÀÙÅÐܵ³·º¯¥¥©­E)&k+>Õ¹©¢ ¤°¼¿P705=`îÒ¼¯«¬¨¥¾4/1+&%2ô¿ÓÔÛØÜi=DÂÒWTçÂÂÓÔ½µµ¸²©¦§¨¾/("!5[籦  ©µ¸ÜC527\PgÓº¯¬§¡±Y9:.'$,GÃËËÝØ¿à_WÜÂUÕçÃÖòmß·¸¼¶©¥¦¦²>,&,7V¹ª¢œ¥®°·ó;57<^]y»¬­¯®·ÆT:1222;@Sç×ÐÔ×ùåÕäKõæâòwüÄØ¿½·¬¦©¨ªù1)!$2XÓ²¨¡¡©®¯¿S?:8;>\iÝ·« ©RýX.(*<õF?~ÁÙÇQa¼¸÷RûÇÐóVlݾÞÚ´­«¨©¿Y2+"!+3ZÕ±§¤©««®¿MBYX>;<UÖº«ªÁñÁäX109VÕ<[òÅÔsuŸ¿ììÃ×çKQóÅÂèÕ¾¸·µ¶¾ì>4,(##&)2<SÔ»±¯­¯¯´»ÁûpVCCniPýÐÐõümdiVSQQggrþÑáè×ÑÐìáÐþâösýsrmqñvÏpÿIÿáÍrfSGEDABFTPmIýéÑÑäàæÐÓÔÔÓÓÑÐáèìí÷ÿr|tmwceyeioouIp~qþñÿýÉËÍõ÷Í÷ööõËþüÿpIOOwOK|IMI}KtuIKwOMO~ñþÉõöÏ÷ËÉÏýqòñsüöÉÉËüòós|}p~|pòrrðñóòqqp}~qqñüñqòÿórrsòrróórqrpqppñópðüÿñòsóñósñópsñsóòòsròórrs~~rrsróòññóÿþñsóssñq|qsrððóóòòòðó~Mórp}sñòòÉãÿ{uìíìöòpðýpq}~ppððüËóII}IMtw~psÿüÍÍÍËÉþóòñsprsrssòqrñp|~sósóòññððñññsrrqpóóróððsq}pqpqrrpòóóþÿþòððsðððÿÿðñóóssrqs|Ippòñrrñóròÿñóóññsòñóÿñrÿðsqsòqóñsqssprórqóósóssòñróþqñýó~ññqóððqsðqròñòrsspññ|O~óqóýüsrðñqóþr~sðrpòüüðñórq|òsðòñ~rÉ}vqòËñÿõüórüôpQSaMîÇ~]QÐÓ×ÞÕ@ÁµÔY+8ÇÁ]9GĸßáWiÁÁÒWQoüÔÒ|TéÕÅÕtShéãMUWPñü`TSuöýhuÐÕçtuþñ~}}diÏ÷|`Po|Ï~obpÒÂÁÆÇÇÅÆÑòeyK÷ùûàÕÃÛßÿ^:642214>PæÔÖÆÞ¿¼½ÁÕùyC_BPÐÒùÑÖÖÖÕépw{QgedtüäÐ׿­¢¡¦§­×=-!".YÒ²©§¦§­ºÅT800/3Xn׸«¦¦ª²ßT:-))-5YUIù×ÃÇÒÐÑÐûýeIââèÒÅß¹© œ¢¨·D-#&7O»«£¡¡¦­¼é_5/.1<WÖ¼²­¬­°²µÅ4%$&*1>GÕº¹ÜÓÉuMôéòwsËÐÇÇÇÁ¿¼·®©§¨¬¾>+%)?Ò¼®¨¦§ª³Á`@:57:[uܸ²®®°ºÞèEYFv<))/<SÒÑÐß¾ßöV^B~ÇÅÔÒÇÀÜÝÇïèÇܺ¯®°¬²S1)! !'9õ¼°ª©«¬±Øo@=8=^G}Á¹´°±¸Ü×õW^B@;765:DrùÓ×ÕÐìrPSlïÇÁÂ×ÒÕÆÆÓâòÿÓºª¦§¨ºX-%!,VÚ´«¦©ª­¼sZ;46YFKÁ¶¯®­´¿Ô~C;;>?^VD\^FQKäùööìònPRmÒÀÛÞÂÕçÓÒöiRQѵ§¢¡¥Ø7)"7Ôµ©¥¥«®¶ÐA6//;R迵°­¬¯½ÓQ=558[ñ×ôcT@]ESVOáâìó`VPå×ÜÙÁÖÐäìèñREEp¿ªœ’’¦÷,+a¼©¡¢¨¯¼OY8..6VÇ·¬¬«­²½ÐE6/18@á¿¿ÃíDY>ZAVt~â÷meQwåÁØÜÄöbyvùÔæQBCý¯Ÿž™’º-)Tº§Ÿœ¦³×]60,/:P¾®§¦¨®»ÇT>3/2<RÕ¾¸¹ÜÏX216\qÖÇéfDVMÐÂÞßÇîyGUeÒÁÄâVCѪ˜ëë’þ k(;À­œœ«ô5((,5Cþ¼­¤ £«ÛV7245<\PÔ¿¹½Þ×ÔT;1+.?нºÙu_[WÔÛÙ×òTES~ÖÃÅäW^ä«›–‘žÁ5ñ´¨’˜œ®?$)^½¯¨¥¢¡¦³y/&'1TÛ»¼ØÂÅÔþCXZBQgC;69GÁ¹·Ým\XFpÕÖÐre}ÔÞßÑWCÝ¥—Œ‘’:	4Á¯¨¢’œªt#<± ’Ÿ£¨­¼S-#!,y¯¥§±ÖD<;<<]eÓÂÅG3,-ZÚ­¬·i618Rݺ½Å~WQów{o©™ë×	 	?©œŸ ¡¥±B>£ë™£·ä]3)##1Â¥§Ö1%$+6FѺ­®½B'!7·¡œ®S*#-R·«®½}X;\ÕPâØ­ŒŒ¦ /¤””’¦®Æ7: ‘“ Ô0'%'+1R± ˜’©õ+$5Æ´®«¬»C&*ØŸ›£Ð'!?´£¥³r;36?SÔÙ®¡žŒ”½	W•ëŸ¯Ñ6#%¹™™±4 "-^į£Ÿœªî+&õ­®³ÇGÆÔ;+!!=®¡œ±4#"2¼§©·p:?WShMwí ”Œ‘˜ïk	Õ˜•—œ·V*k;¦–ŸÕ(&8Õ±¦œœ¦¼9".½¢¥²×>_Z,'&.Ш£«Ñ*#-h®¦¯ÕC<BÍÍvPgÒ°¡ž‘Œ™¼	 T˜“•’µD(k:¤“‚‘Ÿü$'>Û¬£Ÿœ¨Â1%:À¯­°³´À18©›˜­8-׬©¯¿ÉG\==GÓº°´®¤žŒŒ¢"Ež‘—¢¼G2$+¨ŒŒœB-Eö¨œ’£Ý,$?»®®®­°h#k ݝ™œÖ'&X»­¯·¿Ço</3P¶¨©¹Ø°Ÿ‘Œœ'W—¨¸ÇC*.£Œ‚¨>%$*3=VÛ§’¥ÿ&!,GÚ¿»­£ªY-ªž˜ª['&/WÆÚº°°¹m/(1ת£¬ÜÛ¬—–½"­›¥­°¿=»ŒŸÃ1,--,/F­˜”’½+.TÑÖû¾£’¼#¸˜ž¤,,0>gbÆ®§«Ù2")V¯¥ª¿Ðµ’Œ‚˜//® ¡¤£©ß)0¢–Œ”§Á@6,#".Ûœ”ž©F'!&4R}c´§œ³$kÖœŸ§¿X9915[©Ù:%*U¼®¬ºº¤—‘©	\¬¡ ¡¡«A嘖“ªØU0$ =«›”’¸;)&)-:nÁ¬’œÞ&k!쪣ª½É^2,.;Ý©¤«Ã6*.ZÀ²³¸®¤••¢ZC®£œŸ¨Ä++µ”ž’©Ú[) .£’©ÞY/*')?²¨­¶V-((-[Á»´¸ûD80:¿²¯¾ûT?=YDÑ·¯¬¦¤’”˜¯0
+%릠¢®ò&k=ª˜› ­ß>&$:·¡Ÿ¤¯×^5+&+YDZ£’ª.9²¦¦©¶ü9$".㪠¦¼U2.;U¯¦Ÿ™•™¦C
+9´£Ÿ¥Ø.'Ç¢˜ž›œ®e*)b« œ¤®À].()/DÁº¸ÝV834>SÉÆÝÁàg@\RÐÂÝÀ×áPAEdǺ¯ªœ›”˜¯-
+
+?¹¥’¥Ò(4Þ©œ˜˜Ÿ®C'#3㳩¥¥ª»W3+*/>WÔÛÄéS[X[[WÉáÑÓí~ÿñþæÒÑÒõaOÕÁÛ¾µ¦˜——¤:%E«ž’·3&8Ǩ˜”ž£ß6(%(/@¾© ¡ªß]3+),d¨­=.+/WR[Pµ°¹ó//]èÆÚÞ¿µÜoEfù½±®¥””«.=¬™’¹;' "*E«”›¢¶r9)$%1Э¥¥¨¬²ò.# '3]{Á´±ØS74;_Rÿ׿¼ÀòTVPíÅؼ½¾Þ׺¥›”’¾+\ªŸ¢¯Ã=)'_´¥Ÿ’’£²R.''-;p½­¦¤¬ÁñÔ: .ÓºÙ¼¬¯}6)/VÓû×¼º¹ÆFV½ÚÛçÒ°œžëß.<¯¢’’¡­í,#/Q·¥ž¦»S4*&&.G¾¬¢¡«¹t4&&<Ñ¿·¶¶ÞT;7XTþåÖÀÂÔqïÞ¸¸¾ÞÞ³¤›™œÀ4"-î¡’’£¸@+&$(.Dµ¥Ÿ’œ¦¯Å;+&(-:w´¤¥«·Ð>)!!(7@ìÛµ´ÚûTRSWGVýÒÑ࿲¯¹Û¼¨’›Ÿ±P4kk,F¶¡’¦²Æ\.$$+?з¨ ’œ§´×^.(%*:î½³¯¯²î<0-.,.7lÀÀÝÀ½ÙÓnVyTDAüܼ¸¼º¯¤˜—˜¯ÿ9"5¼¢˜›Ÿ£­Æ5%!$+1V¶¥Ÿ’Ÿ¢ª¾\,&%'.9P»¯®³ÙÕQ:.-.1>CoÄ¿»½ÚÁÆþEEÕgÉÆÂßµ¤™•›©º|%%r©Ÿ˜˜˜Ÿ¬c/)$"!*Gºª£’’¦¹~:,$$(+6PÚ³µ¹¶¿pZ;3/36?ÕäÞ¿¾¾»ÝÐïõIfoKŸ¦›”’©¯Í'"A¼§Ÿ˜ž¦ºö;*$!'2CÖ¯¤œŸ¡§¯ßA5.&$(.:Apܶµ¼¿ÃlB<67;>EIÓݾ¿¾¹½ÂÓîן¥’œ«®º=#+]¬¢’œ¦¯ÚC3+(+.9P¾¯©¥¥§¬¸Åq:+***+.?Åݹµ¼ßà{AX;<\@TËÅÜ»¹º»½½¿²£Ÿ¥´±¾6!,=ô°¤ŸŸ ¤ª¹d=3,*,4_羯¨§§ª®¶Ý@2/+''*3ZPѼ¶¸»ÙÄðF??X=ZGpÔÛ½º·¸º»·« £°´µñ* ".<ô®¤œœ¡£©¸O at 9/+,4YvÇ·­ª©©©°ßK\/)&%(-6^ãÞ¼¶·º¿ÅþS@?Y]EyÔßݼ´°®¥’Ÿ¨¯³`'kk+8Ó­¢’’’œ¤±ÖU8,'),3Xò»®ª§££«¸ÂÕ4)##$',9QÕ½¶±±·¾ÃáWZ>?^CRîÙ¼ºµ­£’Ÿ§«­ç+!k%-D´¦œ’œ¨ºÇG3)(*,0<þ½°«£¡§¬µÃ_.(%$#%,;vÕ½´°°µ¹ÜÓPCA@]@aËÖܾ³¥’Ÿ¥¥©Õ1&k '=Ø«¢Ÿ˜˜¡¬¸Ó?-*()*/>¿´©Ÿ¡¶¯«R/,,&#$'>_]䮶±´³»åP{}>>ÕóÍûÙµ¦œ¡¦§®ÿ;( (:Ò°§œ’œ§°¾n</,++/9ÕìÀ´°¯²µ¼Çm=51/-.7?UýÆ¿º¹¼½¾ÚÂÓÑöcQOìâÕ¾°¯­­ÙÐõ?*"$!#*3DíÛ­¨¦¦¥¦«¯¾ÇóW92;=;;DMéÔÒÃßÅþyqU_Z_CERPì×ÁÁÁÚÝÝÁÄÇÑûó~vK}n~ÓÚ¼¾Ñ|Ðf<001--,/8ZGRÅ»µ´²¯²´ºÙÁÕÓölUVSVEETSR`cfP}IcfoöéüOrÐÓäýåÇÕèèæÓåÿþòþKnRQPalMËíÐÐðhf{U@@DDFVSQuôãîÓ×ÇÄÄÇÇÖÓÐéËþòðwOËMoi|qqÉ|OÿIQyr}Mò|O}qÉïãüãï}ýÿswu~ñþ~O|spMOM~tcuñö}Ký÷}isÏôãüñÏËþò|qÏîýlt~óóþÏËåàíýKóôqe{vvw~|uvüñocóqvñ÷òÏåí÷þýõüs|wr~MþÉíôI|sþþòrrËrpq}}ñctvluMrþüñôõüüËü~wOòKýòðÍõÿöÿ~èöþòþ÷ò~}ðþóuat}h}s~ñIõsiðþÍüqKóðIK~ýéíK|ýþncâìþérpýrIusËðÿþäñOý}|óbvüpPh÷Éq~óèÐÐÍuöòã}KpèÉ{OpÿuvKó~sñpmðòMþtõÐ~óÐÑõspKooahquýËiÉð}÷åíMü}õ÷ðmMK}P{íËýOðÑÏlÿÐÓðýâûôgwírctlóþfnrñssMw}KbðüýñKáÿKÿòñsõóü÷ró}qI|sn|ïËÏõôôpbiqMmpìÐÍKñâvbsËâ|ðõIusñqbtÍMv}ipÿIýòòîðO|òóóöËÏÐ}bÍôs}çóiýñomöulýöñ÷õMIÍdPovâéqrÉì÷rñpâætg~çûgtõñ}ooþçüKh|õMþããücrm}É{÷þÿõðõóýMsübpâsyõâon÷âhýéÍËfbr÷÷noùácpó}Kqsgðíâ~cÐóQmöýðÍÏõüõrI÷àbc÷hvüÿcÿ÷tþòýsrbMólIòìôËûñþíõITââQRuäèétKÑûRSåÏsvsÿaÉäËKàÔíaarOófsðiîÏò}éði{QËÐûRmÓÐPSÓæðuñùÿöówhòsSKÅáQÑÐPhènÕòuvbýËQéÐeFMÐlpóûÅÑdfÐá}ìçwòåTW|áÍéçôísbSüÑ}ThïñlPsmiyM|ÒõvîÔéttwÐòlìôå{gËäôlåÐþhuÿ`pümoý÷mueõïÓÅvcã`E`ádQÑÓÑÐðüþíqVÏÑeÕàoOwFQÐQB|õòäàåÓÄËVðíÑPGõóÍSÏÞÐQSäfKÔP{Âß[R»é_àÚaaÕTDSpB\ÕÒGQÃËAÔàPÆç}ÖüoüID}×óürÇcÉÐYÔÔÉâÇÐWæ@QOWrtÑFÒÙR|ÀÒTÑE=ÅÒCIÀK{ÕAUÆ`PÙÑ\Ôö?|ÂÍýÖGËÝFQÝÐ{ÆÄåóBRðVWlÓlShR~fmÇÒQéÇË}àwËüQbF\fhGÐÑ~ÓÒÖÔsçÅÖÑprÄðgÄäíÒòäèQVÐC=|@[V@]åFXäQcWVpîuPÙÞºººµ¿½ÞÇÕ@][cRÇ¿èöpVDW at yãoþRïôVRRR at QVQãUo÷wQiVVTGôé÷ÆÃ×ÜØ»·ºº×õfEZ:Z];DEBTd|süc××Ç¿ÜØÂÖÔ÷üçpSWCWESuèÕÕÔÕÅÕÓæí|hWQRPQWaslPfGFC@ÕGTéôõÑÖÄÆÃÞßÖÓçð~PMKgllQPQÕbRQwdulMlìKóÕõ×ÕÒÖûæîKÿîlót|}SqnPobMd~p}|Éýòõôöõõïíôùõõ÷óðpm|qllmbmnvKrsMrr~óóìþôâùÐõîâöðñIKh|výÍËÐûæÐÒùéìÉ}{PTVDDEACFVTQMÏùÓÖÄÄÅÃÇÕÓÒùýöpwruwwaOtPMÿåéÐÅÅÀÔÖÂððfÕE<[>9::?>YWQiÍÕÞÞÛ»ºº»¹ºØÛÜÀÖäöKVB at Y><=>=?[_BGQirûÕÅÃßÝßßÀÄÇÖÔÒÒÓ×ÖÆÄÆÀÖèÑmSDZ]889574;=<@UiþÒÞؾ¹·µ¶·¶º½¿ÛÀçðqTD[X>8;:;;<^\CQl÷î×ÂÃÞÚÚÛÝÚßÅÄÇÇÖÆÁÄ×ÂÇäãoPB?Y87536269<\ByöÑÀ¿¼¹·³´µµ·º¾ÜÁÕùOPG][=<:8;:>X\EFaKüÑÓÅÂÂÞÞÝÝÀßÂÅ×ÕÕÖÅÄÇÆÃÆùíþRDZX;574436;;YEfræÁؽ¹¶´´µ´·»½ÙÂÔæwRW]\<<<8<;>?ZGFf|ÉÐÓÄÁÂÝÛÜÝÁÞÂÇÖÕÔÓÇÄÅÇÄÃàÍpRD??;453434;<YEdéÒÀ½»¸µ³³µ´¶»¿ÜÁÔñuQA\><;7:9<=?BASoÿçÑÄÁÁßÛÚÝÀÞÁÆ×ÖÕÓÖÅÅÅÄÃ×âöKF@?=7251226<;_RqÐľº¹µ±²³´´¸¾ÙßÆÿcfAZ<<:5:9:=>DBTpðçÒÅßÂÝÙÜÜÀÞÁ××ÕÓÒÖÀÄÇÞÀÖìû~B[=;203///7:<AhîÕÛº··±¯°²²³¹¿ÞÄÐäR>S=3<2>13F5@]QÍEÆÅÕÂÛ¿ÙÁ¼ÚÆß×ÃäÐÄÇÀÀÝØßÒÕìÕ@=<4.0...088>UrÒÀ»´³°­­®¯°´½ÜÅÑmCBZ896865>;?_WiQìÔÔÕÄßÁÅÀÝÅÆÆÂÔá×ÕÖ¾¾Ü¼½ÅÓãa]882,+,,+-5:>WÐÞ¾·®¬­«ª«¯³¶¾ÔýbG>9<6356;7>BESeÑÐæ×Ã×ÕÇÆÓé×ÔîîÓÇàÑÄÁݹ¶¼µ¶ØÃím^42/)''())09?RÖ½µ¯ª§¨¨¨ª®µ»À|EZ=8/29/6:>B?}âñÑÆÙÕÕÄÆqOÐ|PQû÷OäÄÃÐÿ»³¯´®®¿ÜÐT?--*"!#$%'0>AË»°¬©¥¢¥§§«³¾Æó]7530,095=@dèrÝÚÁÀßÀù}n{_[FDCFÏÑùÆ¿¾Ýؼ·±­¯¯­¹ÅïA7,%%  "&)1_ËÁ´©§¤£ £¨«¯»ÒP[9/,--.1<i½ÑGª²R½Ç¾W2Ö@.1C?2=ìÚFÛ®¶»º¯·ÅÜ«®·±±­ÑCw9+"#$!)(-@Ô¾ºª££¥£¡¨¯¹»æX;82+,2:=YèÝÞ¿¹¶¸ÞÄ×Q?=:303;<>TÓÅÁ¼µµº¹¸ÚÀݸ¯¯®±¯¶mm=-(!"*,?u¼°¬¢¡ ££§®¹ÇöX5/..,19GðÕ½³²µ¶»½õCB:/-.//3?QhÓ¼µ¸¶¯µ½ØÝ×㲯­­®©ÜQn/*'*3IÛª©¡Ÿ’Ÿ¤¤­ºãB>.+),-/<ÕÚ¶¸®¥®¸ºÂÑ3/2*&%227_Ѻ߸®­µ¼µ¿ÖPOàôº­¦¦¬¦¯æV.),:Õ»¥Ÿ’˜¢ª¶ÖF/+('&)3?vÁ¯¦¨¨¦ªºÿE8(#!$&&2CÉĹ­­®°°¶ÅïOR][RÀ¬£Ÿœ¡Ÿ¯y=&%;ï­£ž””™˜Ÿ®ÁB/(!(-:Öµª¥¡œ ’œE*í$%!&W¯ªÔ¥œ®³À¹ÔG78Ë7=и ›—›˜›¯?*k
+/¿¨›—––•›¦°T+ *^½®¡˜›˜’œ°l9%'5DZ¬¦§§®¿á@>/.6={Æ»³ª¢žŒ“’¦¦}
+/^¸•Œ”›¡¸/% &>Ý­£ž”ž’¦¯ÿ/ $/&-Üw9R­ªºá¼ä0+5GY[ï°¤¬³ª§ª¡ë—ª¿»9k~²¦Ÿž•ž µÕQ+#-5{»¤Ÿ¡¤°y1&# "8Ùï0ÿ®ã4;û`Y6{ÄC6[À¾Ú½µ«­³¾Ä²˜Œ”ºÚ±8kk#¹œ’Ÿ™ë›§P4.)%?Ú®¨Ÿ›™Ÿ°ÞR4$/F98Dz±ÁPVóí5+2CQ?Aã¼µÚÅØ®®ÂÔÃß½¤–’·À<
+k"e¦™—”™œ©Ã0" ([Ù§’žž¡¯÷5%'Y±œœÞ}¿Y(!'-7Óa{À½¼æÚÞÒ½º¸Öüշ’‚’¹D'
+$Y¼¢”•–”¨Ö8,4Ù¦Ÿ˜™ž§Ö4$$+/G¿´²´·Ð]>3--2:\õÄܾ»»ÞÞÙØ¿ÀÖðЮ™‚Œ¢û/
+	
+2ݬŸžë–ž¬B+% #5¾ ˜ž›Ÿ¢¬Ä5"$+9ؤ¤¸Äo6../,3RðÔÆÄÕÖ½ÙßÚ»¹¿¼ÄÕ÷¨–ë­; 
+\²£ŸŸ™ëž§Q+ &),0q¬Ÿž˜œªµÙM=,#!&.6_e÷žºß÷V[X\@]_Rï¿»º¶¯°¹ÂÐѶ˜“™®\%(S®¤¦£Ÿœ©¾>,,266<CÖ°¥¡¥ª±º¿ã?+##'-5=CM¼¹½Çã}É÷MdIÐÙ··º¿ß×ÔÕÖ»©¡¥·S."%6ã¹°®«¨¦§ª³ÄpdfRSRWT㿾ØÂáþiA;679>DyòìÑÐÐÔÖÓÑÔÅÃÇÇÕÕÓåôôãIiPSGOܶ²»Ð^6421.,-/9DñÔÃÙ½·µµ¶»¾ÜÂÇÕÖÑîóniyREDTWÕRSQGV{~Ëw|ìâûÐöïáÑÑÇÇyéKbÐuâKðq`mSttpsmncñÍèqmQSVERO}hIKýÐñûïûÕæ×ÑôöÍÑ÷ÍÉqèlmôýwSmïMiéiPýþôðûpPèróåÿKPlÉmce~áOòèË}|~ñÑbQðIÉôþñobwÍ÷hËñýìËÿËüv~èþh`qãËÏbM÷ÑáiòuÉÐl}mKÉOÍpiÉq~ÿö÷PÉã|poÿy~ïðíóËÏôþ~ñ~òKO÷qlýqóÍlþóoÿp~~qíÿpñËóOsðóqpsþÏòýóÿËÏiÍòóisrñô~rý}ðIqòMpÿýMrîsuïþsð}õwññumÍóíOóK}ðqtüññÍÉüpËüMÉþKq}ü}óÏ~ü~ððws~wrËsKwñüòýËö}üÿòmIs}ñsÿðpðþËðrÍÏprv~ËðKIóþtrÏqÿp}ÿ}s~qöròüósÿýýópÿM~öóOrñ}ñqKó~qròüðóóþÿñóòð|üóòþsspÿËMsòvóóóþñIðÏóIOÍÿu~Éñiýíòrý~}ÿòróÍþK~ñÍò}ÍòspývsÉÿMpóÿ}IÏÏÒÇS_aPwöÿàöÏÒqóäuüí~ïðfvÍÏOqvsù`hÏý}c÷ìOvÿþO|}qññõórôÿüüu~ËMIþüËdMí~r|ËÏ}ÿlqõKþðÿôÍqòñMüaþö{âOñódíËí~iã|eqlçËbÔvIõ`Ï÷ì}ménaMöìñïþóvKrllËöpphåâ~öò~ñÿssö÷nnòîsdéîKOqËOtèÉpð`cíöõÿûPRMlÿÉeòùwsâôñ÷ûa~rPíÍòKãüiÑuåÉRþqÐI`ÒáõÉfûïroEÿõQyòÒìnæráÐSw`ýTDPPãmèÇí÷bsÑéÕÍüÐPbõqâöe|vnÏæöüðñIPs|õÒíðþâqhmaDehFiRsËqåmÃÇdÔýqÅÇÉWWPRb×ÐPyçÅÿþMvòýÓVo÷Qöìd{îõõ}whVüËMÑàtiËÔîdPPËvöÓ{óqKr|Õß¿W=K=ZåÔ×ËÃÄôPRÐáÐwPTRðyÒËP}ùùUûíÑwPlSÑÒdÍÉÕqñÖ÷ÙÂöcT÷StÏp~RD[A?ZRÉôPftÐäËàÒÔÓÄÔÐÖÖÕæÒàvÕÂöoaSVfPRASÏçËGQVèûóÇnòåãâmSRûÐgA|ÑÓÒhÔûvSVîÐ×ÔÅQEPYMpËòhÆ|}ÏFCmïÿÉÓÞÞÞ½ºÛûÿgFTaDA^==?iÉíÔFBÅÚæîÄÁÑOÕASeËIãÔnàaóÕbÑðbPeÓwfìÖÚÒõçSýaC_ at QUèÖÔÑÐÑÒÝÕ^[TVIgqÔÅÔcÝÞÔËqÄÇÅåPohST?669QF=?=<<˹¯°³­®²¶·½ÄÐD8//48ÕfDÓÐQTRôRéßÄÜÆP^|îV_FïuÕqIKÃÇñöÿ×Ô|çÒÓÔIPWGTdÖÐýTVÓKáßprÝÄÒÑîgYGFZAG×ÞÖË}üpV_ at GCÐÁrc|éÆÐöÃƾÜOáûÑlUMSr×ÐmMûw{GUdVtV?XPÕ××üSoÉ}yRvPWÓÂݼ»¾ÃîKPQÖÃdV>13898gÛÚ½½ÞÄÛØßÄÅÃÃÄÖõ\2-047;;G×½·¶¹¿¾¼¿ÄÆÔäæïR at A>;?]D_^TËÐõõÒÄÙ¾ÙÃÃÀÄÀÂ~A^^]CTdcnIMPRRy|ýöðwSWRP|ÐæûÐÒÑÑÒã~ðÏIcrÏ÷ìÑÖÕÕÓüQRaodC]VrËáÇÄÆÛ¼½ØÝÅýSA:/,--09ZEvÓÃÝ¿¾ØØ¿ÛÄÐ÷þ÷åâíÓÙ¶´´¶ÚäMQU¾œž˜¢ß+k3»©œ›™”™¬þ7+()+-7ô°¤Ÿ˜˜œ©¸G()8Ë·«ª¬³ÞI]=;;\QÓº­ªª¦›‚‹›ó
+		ߝ됐•ž©?(4@¿¢”–“ž¨ÀU[0!*[Òƽ´±µÁG0,/5;<>Bײ«ª®®©¦«°¢ë–œW
+
+$µ’žž’ ¦Û.!/¿¶¨’”—˜ª|5./-&"$2bÁØ×ÖÄÇÉ>0,.;_RUcѾ¯®²½»·³°¯‘Œ’)«˜””›˜ «G#"4Ô¸¬Ÿ™—Ÿ·=,&'($$-lµ²¸ÃËôhY-(*/^tÏå׿»¸½ßÛ¿»¼¿Ù±˜Œ‚Œ˜Ç 		*®ž—”™Ÿ­_ #2S¾«ë—œ¸^/*)%"/Ͼ¾Û×Ä×r<-+-7[GQÉܼ¹º¾»µ´ÙÖݺª”•£F	6©Ÿž—”ž£·5!(3O¹¦ž—뛥½B9-&!$7grìÆØÝÄo9108:?CTÓݽ½º°«¬ºÀÂÝ®˜ŒŒ•œR6¬’žë”›¡¹7#1Q¸¤ž••™¢¹E6,"#6KýîýÛÇm7//58=GQÓظ·¶¯´¶µ¾Â¸Ÿ‘– F
+	0¬œž™”’­X!'.?௝듔œ®Öl>)'/>Dr¿¼»Àd?5:8:<?SÑ»¶®©¬­¯±¼Ã­™Œ‘˜Â$kЧ¤œž™Ÿµ2#"(/4=Q®——¥²¿Ò<( -g1!&/FÝÆT¿·ÚùA7,=rÒ¾³°±¨¥¬º²œ“‚“§4*Þ«§£’””œ¼5()03/0A³Ÿ™žŸ¦ª¬¶h,'2/ ,SÚÔÛ¯³»Á61AgÿÔ½·¯§ª¯³¬’‘™°8 $Cس¬œ™™’¬Ò[?_;/-7ͯ£¡¥§¦¥¨¶f?C1 /DE߯­¯³¹mFpvSgÂݾ±³¹·®¥”›©Ô6%kk&6VÔ¶¤ŸŸ¡©´¿ÙÆR>:>SÀ¸··²¬§¥­ÇB7,'"$/?SùÀ¿·°²»ÜÀÇÇÁ×éìÔÅÃÞÜ»¬¢œ§¹t8.)"#,5?Uö­ª¬°···¼ÛÔ÷éÅ¿½¾¾ºµ¶½ÕR=1-+**+1;EwôÓÀ¾¾½ÚÂÀÝÚßÄÆÔÕ×ÇÔÓ¾±¬®¹×F<60,(&&(-3:?Cpƾ½¾ÚÜ¿½»¼¿ÚØ»¹¸¸»¿Þ¿¸ÛA1--.--,2XUmÏ÷ÔÀ¿½ÁÀÜÜØÚÝ×ÓÇß¼¶°²»ßéVY93.+*+-/39=@PéÒÔÆÂܾ»º»ºº¹··¸º¼ÙßÚÞÍ]8540/.07?FVRgKûÕÃÁÀßÜÚÚÙÝßÝÚ¿¼¸µ¶½ÇdB?:61../2479<[Gb÷çÕÁÚ½»»º¹·µµ¶º¾ÝÁßÁöA<9841014;AEFRdqàÆÂÃßÜÚؾ¾ÚÚ¿»´¯³¾ÓnW_?<72/244568=]WSe~öÖß¿¼»º¹¶³²´¸½ÚÞÜÝÒW><=722227?\^FTPÉ×ÂÃÞÚ¿½»¼ØÙ¾¹²¯µÜånVB\=831233457<\DÕa|âÖݽ»º¹·µ³²µ¹¾ÛÝÞÀÐG><<633229?Z^GWQâÆÁÀÝÚ¿¼»½¿Ø¾¹³³¹ÀäyTD]?842233568;ZDÕa}ä×ܼº¹¹·µ´³µ¹½ÚßÅÑbDZ=977546;?\CÕPwéÕÅÂÜØ¿¾¾¿¿¿¾¼¹¸½ÂïbTCA\<75545789;?AWfrûÖß¾º¹¸¹·µµ·º½ÛÂÕû~G\>;87989=Z_CVQdrçÕÄßÜÙ¿¾¾¾¾¾¿¾¼½ÞÒKPVDB[;7666899:=[EQpìÔÃÙ¼º¹º¹¸·¸º¾ÙÜÀÆýWAY:8::8:=>[@CFSræÔ×ÂÝÚ¿¾¾¾½»½ÙؾÙÖeQGC_>97656888;?BRIöÑÅܽ»ºº¹¹¸¸¹»¿ÞÄÔÏPC?<<<<<<>?Z at EWSbüÐ×ÂßÜÙ¿¿¿¾½¿ßÂÀßÃûtPSVDAZ<98899:;>@VoñäÓÄÜ¿¼»¼¾½ºº½¿ØÙßÔeEBZ=>?>>X>>[_BWeþùÔÇÄßÜÚØ¿½»½ÞÄÃÄÇÒþfSSVA]X;88999;?_VnòïÒÇÀÙ¾¾¾¾½»º»½ÙÂÕôoTFA][YX???[_CGRyKéÕÇÄÀÞÜÛÙ¿¿ÜÅÖÔÓÒÐÉeUVTE_]?<:<==?\CTmóíÐÔÄÝ¿¿¿¾¿¾½½ØÁÖûËOQGC@\[ZXY[@DVS{wËÒÇÂÁÂßÝÞÁÁÞÂ×Óçü}pOPVGFDA__]Z[@BDWTfI÷ïùÒÕÅÁÝÜÝÞÞÝßÄÕÓæþvaTFEEA at BBBFSfyvýâÐÕÇÅÆÅÂÄÆÖÕÒÐæçÐáírPTWGWEB^[Z]ADEFTdqÏöäÑÖÃßÜÜÜÜÝßÃÇÖÑõpdSWECBBAABGTQiqÉïÑÕ×ÆÄÃÄÅÆÖÒæãÿüûÐË{SVGEBA\Z]EVGÕQh|ÏùéäÑÕÆÁßÁÂÃÄÅÇÕÑåÍshRVGFFFGGWTPhwpôæÐÔÖÇÆÆÇ×ÔÑîíðKb{opþ|nQTVEEEFVRQge{{uðõõéùÐÓÔÕÔÔÕÖ×ÕÒÐàéþInPRSRQRRPg{hwòñõÐÑÑÑÒÒÑÑÑàâÿIMtegPPytm{QRQgydyow}pðþóóËãåïôÏöíéèôìïïïì÷þðÿòq~~O|r}óÿñssÍýpòýþÿÍð}K|uO}uwvbiw}|~~|qrqórýüñËõ÷ÍÏ÷ËÿóóðÿñóqI~óòK~óòpsòððüãÉÉ÷qðõüÿòðüpÿIKMpMtwKö}EQõi~ñìùðîËöõÿè÷ðósÿqýsqO}psIñðpÿqþËæÓi_VtãqèàâàñËðröÿq}pòsÿÿIKtqþ|pKrssóIs~ðÍÉIK÷òq}ððÿÍqÍópþKrþIðrtÿóðóp÷ñÍp|ÍOósMstÏðósìpOþññwÉýóþõóðÍ}MwIðó|õÔàgSfh~tèÐåðÏÍýãÏóýs}~dusIpqÉÿvtIswñpþýpÍãýIóâ}|rððöññOwðrÿþìóqpuð||ýqròsöüý÷IwOròý|ò÷ÿpsI|óK~~ñsOðssÿüÉpòñþð}~|ññpüÿðöñòÉppsñs~ñrñMIóIÏqþMñ~}ñÿIòÉ~þâróöÉrðrýòI~ÿÉKÿpñwmOÿò|ýþMÏÍþóOÿòoÿpËñËpspÿv~÷prÉKÿösËÏwtþötýü|qr|pïâñòrplqrtrñôËÉüöäòÍÉKOuËòlrqbdrýiuÍñsòvrÍ~Iÿãéó~uMér|qòÏ}~mñËóÉsõíÿsíÍ|bvsqÍrÿóKÏÿñüqóÏIlwóîmròó|}Í}|òK~ãö÷ÿuý}÷åÉÿOw|ñrMÿqoheípivýpñ÷ùéÏéäpvnOÏûÀÀüFFAW{PíäÒôóïÐûÍývo{wÍÍimn~örÉæÐoòtKeqKeþÔùpMÑÿtÏV`ýíöÿòpÓãñÕìÕQcwwccwâKQMçÕÖÔïýóÍIQlËqgiÿKäÍËInaPÿrótQvpe{÷ÑÖî`cpÑÉiM}îuïöÐÕæ~|tbPóË÷Ðüÿòþ|ËöðÉnRvvoyPybrmÿûôÐÑÓÑÏËÏàÑâýèîòPR{SRCFe~mRýyiuyôÐýÕäöéåÔÐÄÒÒÖïülQTIMQQRhuuoPiuþÿó÷ÍåËvuIIýrIÉòÍýõõó÷ÉËÉÏÍÏéööüüóýîü}MñòKsñ÷ÉOOchm}qbh~òþþrðýr}òq|~~òKp~ÍsrIòÍýËrýqKýüqóý|ÿÿ~óËÍqòqýsñÏ|ÍqOþsihñýñKpýÿüþòKóòðË|}þéõvpòqptðÉsOwË~qÍòsKþròrË÷}thóñòõãírOmIñóóüüþÍÉqpüÉóñþ}þÍvetrusîrw|ñÉrþs~÷íÿóMummþñw}ìï|p~þþþsÉ|~þ|òËp÷s~~þsþÉ}pÏÏtuìðóþI~psòrrsýs}ÏÉwvÍì~|}óý}ÿüüuóóâãóMup~ñMMôñsrñõpwñüðqKóÏrsþñpcóÉOñàõ|pqotqvKrôôðÏIpËKKpÿþ}óõ÷÷õÏ÷rncmwÿñËóuÏñròoèìnMMqwKÉóääq~qòþIvâ~Oûr|ývuMËîýþ~mOh~èíËïâIþÿ|ðiw|}I`óþöüéÏw|huõõñþðÍ÷wKK}ýôIqôóâå}OÍþ~}qóKòòss|þ÷qrÍMl|ldIseuýsÉþóýqñq}pþîÏéåüýIéìËçåÉìðòðoPa}}y`PRR{mmñItröÍ÷áÒÕ×æþåÉÿôþò~OMIutuðôðp|üôÿÏñöüqIwytþfl|TQÏîýàÐçÐàËQPPTetvreEFGFdÍâåÕÞÀÁÜßÇÑÔÐâÐíÐãuhFWGWrQÕSSF^EGQvþçàÓÒæÆ×ÕÅÇÇq{~rÑäF>::=EöÕÀÚ¿ßÔËSRáÚ¼¼¾ÙÅÑðG^=9>X98XVöÕÁÀÅÑýàÓÖÆÓÓÆÃÅÐÏñwvQA\ZY\BÕQmÏìéâïÑÖÆ×ÇÅ×ÖÖÓæùìpmyPcðcSg`PfRUQmRÕadiüõpÿäåáÓÔÕÕÐìæÑ÷ìÒÒÓÖÔÑ×ÐF=6006>Dgu~ÐÇÆÇÄÂÇÇ×ÒÐÉv}üãùÓÕÓÇÄßµª©©¦«¿óX*!%0GÄ°¦££¢¦­·ÃF=8215:[ðÞº±­¬­¯»ÕT:-*&$)0Xwû²®±¹ØÖ~W?<>]@Wq×Ú¾¾½±¢ž™’©»{.k&=·¡˜œ¨Ý<+(&&(-@½ª¥¢¡¡¤­ÁF:,%#"'.<TÁ¶°®±¼Öi]9437XV|ÖÚ¼¹¹½Ü×Ðß­Ÿž˜§·ï4!k*B²œ˜˜Ÿ §µS.%&(+2B¾© œ¡¤©³í7,-($+/<åÛÚ»±·ßü_;853:@bÇÜÚ¾½ÛÂÕÏsIPoÞ¨ž•—¡³ï,5¿œ”—›Ÿ¤µÕ(")0Q´œ››’¢©¼A)"!$&,;д®¯°°ÛÕ8-,.04@о¶·¹º¾ÐTFRaQTQů’•–뤻;
+,Á£”—¤´_''5í¬’””› ¬Ä7% '4Tº¬ª«®ÀQ:*&)-5EÑ¿°±¸½Ýî`ÕE{KcüǼ¡”ŸÙX"
+
+*⥙—˜¨µE''=Ñ«’””˜¡°Ö4$",>®¿¼Å:,)-3;=R¾¸¹ÙÜÛÜéVtæÇûûìÒÙ¬˜ë–˜ºd)$^¬˜•ë›¥­ä+&8Q°Ÿ™”˜œ¬Û:%!)[³’¡öǽ=#$9íZ>»¯·ÒTÒ¶¿B`Á¿ÀñSֺߴŸë‘˜ÛE-"6¯˜•—˜¤ªÞ- (4A¸Ÿžž’œ¨¹X&#(6ͪ˜¦Ñ×Ð/$:n]K¯¬¹Ò~ļäZ|¿Ùáa}Ùµ¸©›‘“ªe9"k%ü£—•žŸ¤¬B%%*2y¨˜ž˜ŸœªÅ.$!"$+v²¹Û¶½ÔD/.8=/9TÐÞÓÖ¾³¿ÐÖÕÖÿ|ÿÇÂÑ׶£›ë›­Ü^'Ť˜ž›œ®B+%##%/K¬¢ŸŸªß>/)$$.hS^èßÞüB@òO99_RSBRƺÚÆ¿º¼À×ÒÇÒlM¾¢™— ´¶\(Ù¦’››’®F7-' ".`¶­¤’˜ŸªºÍ]/%!*öÉ*0¶¼Z7`»Ú]0qß@5=üÆR¿©¯Ââع×^妛™¤½µÓ$kk û­§¢˜™˜©Ôc^-"!,Xéï¡’œ¨­´½ù.!)/%!.rÅÑÕ¹­ØPEiQ<7=ðäQý½°¹½·¯¸ô{¼ ˜¢º¹´7k4Ľ®¤˜˜¡¯¼¾D-&,6:[ɯ¦¦©©¨®ÛA9T|$/@*'[´°¾í¹­õ8;mS;<g¶»×¿¬«Â蹜›¡°´­Ck)UQ¾¦˜¢§«®î2./2,0CÛ²±«¦¢¥­ÚRB3&$--2^Áº¿½»¸ÂbQQG<>ÕÏãâÙ´±º¾¶¨’­¸­û$k#9XÑ­œ’¡¢¥©¼C=82*,;SÒÁ´ª¥¥«±¼Ò>*'('&,=TðƼ¶»ÙÜÂäRGGGDÕûßÝݼ¸¹®œ’§®¬À4$(.\Ú«£¡œœ¡ª»ÇQ>/-15<_Ѹ­­¯«­¾IDX/**-13=`ÖÃÞº¸½ÁÂÄýSTtcgöÕÖÔÀ¾³¦¦¬ª²ÔD/&#*6TÙ´©¦£¢§ª±º×Õ^:::>YAÏáÕÜ¿ÛÅ×üSD?==>?@QOôÓÀÛÜÝÚ¿ÝÇÓÓ÷Qe|QQÐÀÄÚ²¿tÇ×Y247+),/42>PÒÁ¿²¯®¯°¯·¾ÁÔçQ@]B]>\WÕFRÍ÷lIÑàwcÏíMMìÓæî×ÇÒÐÕÖãÍïûbRMPTSUTQQf|qüîáýpüvPRQQGWQPo}õîáÑÓÔÓÒÑÒÓæûùíüðÿ}~rKMOOvMMcu|IvM|utI}psþÉþ÷ôÏ÷õ÷Ëþòñr|~ròóóñósrp|IvwwKIIòsòððòóÉÿñðüÿóòsòóqòþÿqrðòqsþÿsóñóI|qqIOp|~óòñÿÍöÏÍýýðqsspqspqóñýÿsóòpq}}Iqrrrsðñóòòóssróósósqsòósðüòóðÿþssðÿópqq}}ppróñññòóssóósròrqÿÉýòððósòóp~|pqpòòrsñòróñòóóòñssóóórsòrpóórrsñòóròÿrpsópòsqñððÿÿþÿòrppqrqòÿðòòðóqqsq}~qq|~qrrðòrsðòòòñðññðððñóòòóqrórsÿÿòòsp~~~qsqóórñþðòòóóðòsòñòsssóóqqsñrqññrqóòóórrrqpqñórñóróòðósrssróósrqòýòóòñðósrrrpqóspóðósòüò|só}rðòòÿÿñññÿÿrprpprsórrróspqsósòñòðþþórÿòqqrósqsósssssqsóqróòòòññpròsrròsrssðñòóòñññóðsppqsqòòrpsñrqrqsòÿñðÿóóqóðppñóqóðòóóròòqñórqrrqóóòòóósórqsòsñÿñòóòrsòððórrssróórp~r}srsqsðóñþÿññòósssrñòqÿþspsñqqsprssòsqsñóssrspóÿóòòòssðÿðssósròñrpqóòósssqròòñòssqróóòsrqpp|psróòýþòðÿðssóqqsóòññòñóssrrpqrórsssóòòòóðñrsqósrsssrrqqpqsòÿñðýðóóñrqósrròó~qóóppòrqòòòóòsrÿñðýðñóórppsrrsssqpòsóýöÑÝÜ@0>ÐÇgWõÆÇãrÏÒÔùòðéÏcP~ÍqomýóOu}pppIrðòsróqqòñððñòòsóýüÿósqÿrOrÿÿ}KórsrpòòþþòþðsòñrMpüñ|þó|qósrsósÿþòpsüðpòþòqqs}qýÿñÿpKrsKKòÿq~òËó~ðËýr~üÏq~òò}IqsóðqrþñsO}r|þþqñÿÍròÿüÿýÏÏòÍÒßß{>XVPWFbÐÕÔåsöÒÒ~iôïq|÷Ëÿýóòüù×ÁÐD^PmWDRrüÉóæÒÑþpççñaÏÐwPqàËouçÏfMõôbeÍÏMbÿËÉÿOIõÏItpËsbsìsòþqupýuKÿq|ðÉÉýçóMâÏcIÿðòlIÏóÿÍþÿpÿ|oq~|ósþ~MÏíbníýlýãýýþqÿÍvuÍòpðóüýIsñ~r|r|}÷v}íËñqõïqdpóKsIñðÉö|t|ÏóOðôýIñuËþIÍþó~ÉÉ|þsìòoöOoKsqòqqÉíô}ñKñuþÏôünòü}Kò÷q~}OvüâOtýîöIñÏñKþ÷ÏK|}rËqm}ÉKuðõýIñ}uìÏKüõðqwlpóp÷÷rÿðO~ËðþýÉð|}KðöqOõátP}É~mu~Ïìò|öåpvñpqðrMË|lKÍÉó÷óüþpþpðôq}ÉquvÉýhð÷}ñðósòM|÷pI|~ñÿðÿþÿývýâOðsu}þÿoqé}þòiïöt}ýã|}÷ðqñüËpqÿyOüwqqpòËËwðüñÍpKMóiwíqÉýïqppð~ñöMqì÷tyÏõ}óýÍóððâÉKorÏmusqOKsròüM}âôMOñð|uíísôõòìýusñurñððrñpqÿqctÿmdöüðÏrsþíËðsöËwrKpüKOÿÉpñwãIó|ÿíd~÷èðKÉvË~IüK}IóóËIýöKüî|eáÍPu÷ñKqIðÍÉó}üã÷KeþènhèswìýIòâðurÿóoóÏ}ué|r÷þucìñKô~höâýóôMrÍóñvðOñýrÏqüÉu{íðdþðþqIsrü~}ËóòòI|ýq{ÍæI~÷pãpgüRIòq÷þÍÐÑèâÒà÷ÏvwdTVWSQPðÍÍíËâËqðéàÑÒàîÏÏqõËðsPP`vPertpþs|âõüq|ôËÿåu}å~qõÉKÿÉÉruqñðwûôðÒpucbTF`ÕQË÷õâÐìoñMþwuwõÓüôÑïñöèûâôÉñÑügqsI~}swpÏeSñPsÉ|Ï÷ptèùmñäshMÏQOÒSPâþdOÓvMÕíRòÓytûsKðñhbòõahé|OK~rwüÉÉàáîòdóéqIöù~óÏmââbaõÔôótmôÏdKãðvwñKrÍItËäMlñ~huñi|ÒËIæìvoKOSQR{KaöéÿÒùlçÕhvÔèyïàiËàbìñhóÍsoËwSpÉ`ná`Qíð|IçülÑæbþÆþQÒæKãôdÿÐRUòqgirPnÉRS|ppÍÓÒÒÕûáäô÷}}trïÍËáð|ýOGFfDD}KQËæTSIVPäÑüçÅÓÅÀÄÔÐÓàæÄÖósTBWEECRaÕK~wKÉvoÑéä×ÔÐàûÍpçìQäÓgQèóUPppSt÷nm÷Ë`åÐfvûûRbÔvháÏvsÑMU÷ôTSiWFmw{àÖÿsÑÑmùÃârÒÒbòûbsÓþyÔÇ|ô×Ë}èËPPàRFÉcRhógfôiÕóüSPÍqTsÍRèòoÏïbõÓüôÕïíÑÑñýæðâöpträleËÏPQòuTotRsrfqÓïIÕÇûÑÖÑéàönhmTEVVBEÕGWPwoÉÑáÓÑÓÅÑÑÃÇïæÑsåìléîf{ùIQËähÍÅÆÕöÒÄÐhPýQ^X><647=Y]RÔßÂÀÙ½¾Ø¿¼¼ÛÄ×ÒóOsIpþ~bbQWGFBDWVPgbqssòpKvñäýòÓÒâûÓÓÐÄÞÀÛ½Ü×ÞÖMQF\=9355149=XWlÒÃݽ·¶·´µ·º¾ÛÂ×þyQEY>><::=XY]T{cýÐÖ×ÆÁÞÆÇÃÄÕÐÒÑ÷Í×Ýؾ»¸¹ÛÁÖnB<70-++,+.19YWÍÁ¼¸±­¬­­®¯´»¿ÆüRE^X;8=;:=?@BEgòsËÓÓçÐÑÐèýîåÉâÑÒÑÓÕÖÒÑ׿¸»»µ¶ÙÇào^53/+()**,0<]UÓ¿¸´®«ª«««¯¶½ÝÐQCB?58;688?]?VIcÒÕÔÒÐÇìüÒåÍâÑÐáï×ÕäÓÀº³·µ®´¿ÀÑn=00+%$&&&)0;YfÞ¹³®¨¦§¨§ª¯¶½ÀOB^?5173359\>AO~sÐÆÇÕæÆÐMæâþñãûãËÔÆÐÕ»²³±®¯·ÙÅ|[3.+$""$$&-5?Tù°¬¨¤¦¦§¨­µ¼Á|_X<4/44279^^Eñ÷ÒÒÆÂÔÐÒåcK|lyOãÍíÔÆÇÅÿ±¯¯®­¯½×õA4,*%!"$$*2?GÕ¸¯«¨¢£¥¦§«µ¼Ã}[;60..5\<0òç=qóßã@»ÔG~äþ[WÕòAÕÞÔÔÁºÁÖ¶ª®³¬ª³×Õþ<+)) #"",:]T¿®¬ª£œ£¥¥¦¯»¿ÕD883-+/5<VXFÛ|oÇÒÄTòÂFDSPA[`ïlsÚÞÁÛ¼»Á·¨ª±¬ª±Ôe}8'&&#""-YGKºª©¨¡Ÿ¡¦¦§±ÜÄÏ?231,-329ZBÿñ×ÃÄÞÕÅö÷oWW]D]WUeéÐÂÂؾº½Ø¶¬¬¯¬²°ÄUd1,%"!!$&.>P×»ª¨¥¢œ¡¦§«²ÞÒP>6//,-/9ÕW@ÝÛ`ÁÒÅöAÁV[CC_;GmIhÛ¿À¼ºµ¿¿¸ª©µ¬­³ÇFa7'#$"$#- at aÑ·¨¦¦ Ÿ¡§§ª´Åän;///,+/;SoBÙºnÞÅÆÑ]×V=Z at Z8ERI`ߺߺ·³¼¿·«©°®¬°ÕUF8( $ $$-@ôÕ¶§¤¥¡Ÿ §©ª¶ÒIU:.-/-.39BEöÜÖ¿¾ÂÞåûuAAZ>;Y\CSsÃÄÚ»¹¹¹¸¾¸««¯¯²³û?C/&!  "()1mÖ½±¦¢¤¡œ¢ª¬°¾þB\4.-/128]rtÂÛߺÆÂÖcg at A==:<^[f|ÖÁÛ¼¼·¸·½Ú°¨­·­¯¿F?^*! #!%(*>ƹ«¡£¤œ ¦®®µÔDX>.+.264>íÖþݺ½ÇÇÜMG]CX4<=?>VÑåÁظ»»³¶ºÀÙ¯¨¯Ù®¬Ð:@X&!$!+++A¾»¸©œ ¥¢ ¦²º¼ÒY683,,7=8BÔÇÑÀ»ÞÑÑï{^\Z=;;ZAQþÓܽº»¸³·¼ÀÄÞº°¸ßܽÔ>57/'#%&'(,2Z}ÕÛ³«ª«ªª¬°¶¼ÞÕÿQECDEGUVVGC\?X[@GSyndelþèæÑÕÆÃÃÄÇÓÐîöð}p}v``}áÖÆÄÂ×ÐÍ|iQSVFA^^__ at DWSPi|ñíÐÓÖÃÀÞÝÝÞÁÃÄÇÕÒÐô}nQWB at _]\]_ at AEÕQ`KõûÒÕÅÂÁÀßÞÁÂÃÆÔÐä÷lbo{aaPSTÕÕVGFEEFGWURP{uóöéàÓÖÕÇÂÂÃÂÂÃÄÅÖÒçéòc`TFDCA^@A at BFUTPpÏâÒÆÄÃÁßÀÁÂÄ×ÕÕÒáåíþóþ|PSTFAA@\X[][\DVVQqõèÓÃßßÚ¿ÙÚÚÚÞÀÞÃÒäâOTUG_ZZY=>Z[[BUShâÑÔÅÞÝÞÙÙÚÛÝßÂÁßÁÅ×ÒìMQG_X<976678;?^ERpæ×Àؾ¼»»»º»¼¾ÛÁÆ×ÖÓòUGEX;<<89===\EFTÿÓÖÃÜÚ¿½½½¾¾ÙÛ¿»¼ÜÄÇÑwSFZ953//0237=[CPÉÑÆܽ»º¹¸·¶·¸»¿ÜÂÇÕÓ÷U^\?98976:<=YCGÕ}ÒÇÂÛ¿¿½»º»½¿¿½º»ÙÄ×ædG@>731..0347<[EgöÒÅݾº¸¸¶µµ·¸»¾ÝÃ×ÒÐìR[XX968969<<?BVTvûÖÀÚ¿¾¼»º»¼¾¾¼º¼ÚÄ×åPD]>730..1458<ZF`ýÓÅÞ¿»¸·µ´¶¸º»¾ÜÂÆÕÐfDD[:9:989:;>\BGQðÓÇÃܾ½½»»¼½¿¿¼¹¼ÜÄÕöQE[=840./2569<[GoãÕÃݾ»º·µµ¶¸º¼¿ÛßÅÑ|QW_?=;9999;>X\AWdËÒÇÃÜ¿¾½½¼¼¾ÚÜ¿»»ÚÆÔùdG@?:61//2589<ZDPÉÓÅÀÙ¾¼¹¶µ¶¸º¼¿ÙÀÇÒàãR]\[:7889;<=[AFSnõÖÃßؽ½¼»¼½¾¿¾¼»¿ÂÖÑOV at Y;62//0378;?_Õ}ÑÆÁÛ¿½º·µµ¶¹»½ØÞÃÖÑä`][]=8998::<Y_EÕQKÑÆÁÙ¾½¼»½½½¿Ø¾¼½ÝÇÓíPE^>940//269:=ZEgöÕÄÞÙ¿¼¹¶´µ·º½¿ÛÞÂÕqRW at Y>=<:99:=X]AESIèÔÃÝؾ¾½½½¾ØÝÀؼ¾ÁÕÓÍQF at X:61/038;;>[DPþÓÄßÛؽº·µµ·»¾ÙÜÁÇÒû÷P]Y^?::::;;=Y_FQ`tæÅÀÛ¾¾½¼¾¿¾¿Ø¼º½ßÇÕõQGA?:51//379:<ZBSýÔÃßÛ¿½º¶´´·º½ØÝÁÄ×â`VD^X?=<989<?]BEÕ{sÐÇÂÞÙØ¿¾¾¿¿ÙÚ¾»¼ÛÄÖídÕC[=830037::<?_WtÐÇÀÛؾ¼¹µµ·º½ØÝÀÃÆælRG@]Y?><9:<>\ACGRlõÒÇÁÝÛÚ¿¾¾¾ØÚ¿»º¾ÁÇÓpRF_Y;500369:;=ZCQÍÔÃÞÛÙ¾º¶´¶¸¼¿ÜßÂÅÕÏfVC_]Z>=<:;=Y at CEVgKâÕÅÁÝÜÚÙØ¿ØÛÚ½¹»ÜÂÅáuSF_>830049::<?]Giä×ÂÀÝÚ½¸¶µ·º½ØÜÀÃÅÒóSFC@]Y?><;=>[BEGTf~åÓÇÂÞÞÞÜÚÙÛÝÛ½¸»ÚÁÅÑ~fWA?941159::<>ZEyôÔÅÁÞÛ¾¹¶¶·º¼¿ÛÞÃ×ÑÍPECA@^X>>==>[@EGVQlÉÑÖÆÂßßßÞÜÛÝÞÛ½º½ÞÃÆûsoW@?95237:::<>\GoâÔÇÂÞÛ¾¹·¶¸»¾ØÛßÃÖäqeVCB@^Y?>>>X\_EVTPiðäÔÇÄÃÁßÀÁÀßÁÃÞ½ºÙÃÁÇãqiTA?96459;:;<>^WmäÓ×ÅÁݾ¹··¹¼¾ØÛÝÁÖèIQTFA@^[?>?Z\^AEWTPtñâÑÖ×ÅÃÂÁÂÄÅÆÇÖÆݽ¿ÂÅÅÐþ}fW_>9559<<<=?ZCRqæÕÇÃÁÛ¼¹¸¹º½ØÛÞÁÇÐñfVFEEA^\YXY\@CEWÕQtüùÑÓÖÖÇÅÄÄÄÆ×ÕÓÓÒÐÑÇÛßéûÕód{RVAY=;:>^]Z^@CÕiîÓÖÇÄÃÀ¿½¼½¿ÛßÂÆÇÓô~QGDBCB at _]^_DÕQ`dOðËîÐÔÖÔÕÔÔÔÓÒÐäíþñq}|OvwvvuidnbblðÓÅÒîÔÒôââü|PUFADTRVUÕWSaKËìåûùçÔÄÂÁÃ×ÖÔÒÒÑåÍKaRSRQQSVUUTQPdOIsÍìåÑÑÐÐæÐáîáïô÷ÉýpMtbhgPfP`dbMòèàqhóþpssOt|p÷çäõËËüãûùÐÐùÐÔÑèáùòtePQSVFDDGWVTSPevr÷áÑÓÕÔÇÄÅÅÆ×ÓÑÐäõþ}bPRSTRTÕÕVTSQimMóþÍôùÑÑÑÑÐçæàäåâÏþòq}MwtbnydnhcmvwMqsýÉÿþËÏÏÏíôííËÍýðóqs~}~}}MwwOI~pppórñüË÷ýËËýÿòüÿsqq}~~rq}~sñþóòýòüÏËþrñðs~pp|~~~~||~qróðýËÍÉÉþÉÿÿÉñóqóò~~}|KI}K||~òròðÿÉþþÍÏÏþýþpqóórqqs}}rqr}~pqrsÿòóðóqrsórprñórñòòññüñóðÿÉðÿÿòqóq~q~~}}qppsòrrrrñóüËðþÿñòòòýòqóòóprròr~óóqqpóp~pròqòþssóñópsórsóÿþðþÿðóqòs~}rsóÿÿðpqspqrqqssòósðÿrsòÿñróñÿÿðþþsrrrp|~rprósóósóñssórrsóòñÿñòñóór}pqqýüòðþòssòóppqqróññsÿòqrqssróñòóóñòrsssqprsñóòþrsðòsrrqñpòsñsÿþðsÿr}rpq~sþòñÿÿs~rsrqróóòððñòòòòópqòspòÿðòsòóqq~~}qòñðÿóóóóór~~qqqrððsòñññsññqóÿþüððñsòspp~p~rqóñðñóqórñÿóüÿssòðpppqsóópsññóóÿðòrrsrqqssóðòòòrðòróós~rssóñððñÿÿñp}~qóñròóóòsñòróðñsóÿÿpqórqqñòsròðqsòqsrpóòñòrðýÿðòðrórqpròsssþþsóñò~rrqpróñóððsóñòqqprrrsòòóñðòòóssrrñòóñÿþýíÔÞÆQ_:4;BÖ·´ºÅW>?AlÖßØÙÂÑ{A[BdÓÁÅÓIWGGWRoìÖ×ÐhDATìÜ»ÝèG?\GfíïÑÇÅÒKEY_QÑÞÝÆçóommhOràÕÖÑñQGVSoKodybpËüÿòãÒÓÓäâìâÐÑæÍqKhmlbuvK|ePP`b|psþ~qqKòóíÓÑîËq|pKvOKðôÍswho~ÍÏÍr}sñò}vuq÷ÏËpOMbusçƾ³´¾ó8.1\Ò¾ØåÕ?=Y?ZAgÖ¿½Áò@_Sæܾ¿ÀÅ×ÒÍTCCRÉáÏRB_Wòûåó|ñÐÔÒùòíçÔÖìOfhñõÿPUTMõÿmDZ­µç6-,2ErÒÕÖÔâQ<53>æ¼³·ÚáenOâäÕ¿¯«¶I/&*;׺¼ÓW?<?>XGл³¶ßa[\fÕ¿½ÛÃÇ×Ö×Òà³£¦´0k*Þ«ª¶ÔY<0)),Q®œŸ§Þ:15Tݺ¶µ²µ»ï=2/4^sÐÓmWD???EÉ¿ÞÒUAGòÀ¿¾ÀÕäó}ü×Û»»ÜáÕP¸¡¡º+.¿«®Ýÿ_X5)&,Iª§À;3>öÛ¼»¸±°³Û?)$'4qÂßáDX>>ZRôÛ·¹Ùò@_ý¿¸¸ßïéÔÖÖÐtòIGDGÝ£˜œÁ5²¤©¶ÒE<-%#-Ö¤›§Ó92:PÄ¿¹°¬ª²K/""-{»·ÁD848YVɽ»Øä@=Bѽµ¹ÚÒöÐæ×ÅÑémS`Þ¥™™·!(¼œ¤¯ÖC7,%'G§™”œ½;+5PÞ´´²²²º×Z+*->àÄÖaA;;<?QîÛ¼½ÆnB\l׿¼ÀÐrðÑÝÞÓqPüÐÔËÔª™“œ1	ÒŸ¨Á]4-&/·›•™©C*+?±¯¯²²µÅF8,,:WåÓCX?XFUWTàÇÚÚïaFPÔÛ¿ÄðFRûÞ»¼ÀóSyììP÷¯›‘žu		7¢˜£¸P;1*%OŸ•ëœÀ/)7ó·±³±°±¼R.&(F«¨Æ-/Õ­¬ÁG\DqÖ`EeלּF1/E·ªª¼V=YoÂÙ´Ÿë™²"	·’¨Å=/+""5®›ëž©V,-=Ķ°¯¯®·Å<)&*C®Ÿ¬4kG®¡¨ß^:9^Õо³¬¸R1/Xº¨ª¸U;:Dů’ë«+
+P¤’¢²M6,-½œ”™¢ß:/5P¹²®«­»W2-/6ÕþcR<<>_VTt|ÃÁÂÔRSQÐß¿ÝçgÕáÿ¿ÕmRPhƼ¦——¡Dk
+6«œ£¯Ñ\7'$W©˜™ŸµW79fÇØ»¹´°µÃA/.SÙÐ]*!-^Ú±ÛQ==TÛ¿×èWìÚ¼ÙðCT߸´ÚPY=RÁ± ™›ª;3µ¥¤®ßT8)# 'V®Ÿ °÷X=Tõý¹·´°»å:++0AöÖðA;5>DüÕÅÁÅ×þfVfÓܼ¾ÝÔùãùÔãvSRĨ›”œO,½¨§¯½ÔQ4& 5¼ ˜œ­ÓB_níÒÇÆܵ®®º?,')\ðÀÆS?8=Xd}ûÞÁØÇmB_fƸµ¹ÃðPQýìôdɾ¥™™¦8=°ª­¹ÂÓi7'#<µ ’£µôVPÐÖÒ|hÞ±¬°Ð6,-9eÔÉW><ARMoRhÓÝÚÄa at EôØ·¸ÛÐ~q÷sRVR콦˜§>0Þ®°·ÞÄc?-%*9¾©¤¨´Àñíùín齬­¿V-)3AÅÞüC<:YQPmþåÀßÇþVGËÙ¸´¾ÒyESôÕÆÕ~ɺ©¡§P&k/ä¹Û×üÓíþX/4<߯¬¯ÚôqÅݾÂÔÜÂÆÖE=>>hÕæ~@:<EQõõyòçÖÓöÏÐŽ»ÙÇqRPevËÉðlq½­«®ñ+!&:iÞÖôVo`QQ>Egúº¿ÑåôÁ¾¼¹ßÐÿUBUCPìËàtEZ\@TþIÿyRtïÖÄÃÕÕÓ×Ä×ÓéËýååñ|UDAYCÚ©¨³P)$'0tÔçKSUOöTG]FÖØ»ÙæaóÁº¸¿ïFFSÏÐËqiþÿrQ__D}ÑÒðSGSáÄÂÖíËéÔÅÅÓñMðü|fGCWIÓÔÿPS~ÇÃÐg^XAÕweVDGuäÒöfTuÕÁÁÓPWRËÅÂÇùÿrÏÑùí}usËö|`RlÏÐÓå~PauíÔÓù|eKåÒÐ~QRTSSgüÐÔÏdTEQMíÓÐåstq}ðvðìÉådTFWiwõpwieþûáÏåÐÓÒôËüïÐÔÒãþpÉîÐî~QQh{onc~âÔÓõRBETÍÑèötñ~pÏyeoÉàíèpm`KÒîÍwTQvõä÷saPMåÕä~itöäônKõâÒqmM~äãÒÒ÷óQaMqíócdfRlÉéûíå~hPPÿèïö{{l÷Ö÷M||Í~qìùè}aMÿMeS|éÐÒ~SeIÐÕããuRIÍ÷rldKíîËyböÐéqomäöÐâubQñÿObhËñtËIcðbËÍöïââóûutvdîéÍrlcóöòð}Pañ×ÒdRþýÿsQhôü}M~sÉèÑrKr~ç÷þòl÷ýíôQoOhûÐð|PPòõûè|PaóËÒÑþðuprióüpvmOp|dPþÓÓÒöVVIñÓônePüîâòrâíÉu{b~ÐÒÐíaWQöÑÔìgRv÷îâöí}ròhQ~uååctPñéè÷SflàÓMiS~ÔÔäQQvÐÆÐhRPóèöã{dñÉÒvilP÷ÉÍ}|}~àü÷ÍvO~õþ}MtýÏòýKlMéáóqOþ~ôè{wvpýðwh÷pðõmIüñýÐÏcMòIqâ}vÍõsãÏ}s|÷ôüq}bnüþõÏtunIÉiaIíK|àc~élÍûðípgíôþõweÑÑqImhöícdRnãÍËé~sÏýèrrKt÷Ïþ}IIôãuvwp÷Ïrbb|ÿðòÍ~cöÍýîiaÍÐáñRoÿåötpýéí}dcûïâébRcð}çåQgw~ÍùðqìqutcKèËqåmóÿróÉwMÉ~héàðéèu|ÑÉpÿfobMíìd}dóávO{nsùùËðpûîòrðÿÿñrOö|~Ïm|ÉMvÍdððoOöÍcãÏsñÿvQÓõqÑg`ôõrâôQIål|÷P}âwöÐñwtopýüñóruþËñýrürvÏ÷uw|}ýÏÏu}òìÓIl~fòïöÍvMÿsÉþc`}þñþOi}ËöùèRTñèÒùK`mäÍÏðPþìðËõôþ÷M{{cópéüqI`}sîÐñQgðcËå~püçËâöiÏËonôÿóìemÍÏrôðgrp|wswÏMìæO}üþöse~~OíËlõ÷ûônlhqïóp}póãÿlöýKâþ{mvÿùËüOusð÷ÉpKãÉ}þtnüçpòâ~Ëq`uþ|bOtKs~~ñ÷sö|v÷÷üËÍþíéËùüòïKgIKtÍOy~süõrPi÷ÿü÷gasüèõËiyõãËËñ~÷âII~éââÉOòqóõsOoeýÿwOlKãÑèsObpìýimwqüðthö÷ÿpsóþwó÷ñ~Oqð÷ôõþþÿ}pqôðbunÉãqKmrÉÏtmqÍwwuóèãè~~òÉÐÐ÷hb}þûýt}ÉôÏ~Q{}òéýPRlOÏÐÿKmËäövIõæçñccqñÍÉe|Íq}qËýþpwpËìýò~hvËõóquuöô~csIÍM}ðòópuþq~pÿ÷ðpñçðOssðqöüðËüííócpÿ~Ïâ~MKhwwb}spþËòrpýüòÍñòÍýMfüïcwðóuiburMqýÿ÷÷÷ÉõåôýóñsqKburs}rÉ÷ËÍÍüüþss~~KK}óñòqpÿñòðóðsÿþppqñòrðÿósrsòñòððròsprpqóñòòñsssrqp~rñsqqrqòòñóñðñspppqsóñósòqqrrqqòññðððósspprðýððüòððóðòórprqqsóósòñpqrqqqsòsóòsòðs}}sóósñþòsñþðòssqqssòsrqqóóóósrqqrpsòròñòðóòsòñpññrròþópsóqrñsóðòòsóòòðòñrpsqpqóñóóòqrqpópsóòðÿóðñóþÿñsrssrrrsqqóòssqq~}rpssñþóðððsrssrðððrðÿòòqòsrsqrqòòsósqqòrqrpsñÿðÿþððqsq~}~ðósòññrròñósóòróðrsrssróòñòóñòqóò}~qsósÿópòñðòqóòÿòsðssssósrrsssppñðññòñsóóñðprrqòññóqq~qrósòðóýÿssñòrrññrrròssñòrqòóqqrsórrñspqóðrsòóópñòqsóñósñò~óðÿòósrósññóðóóòqrqpqqrpssrsòñðñòðñqsòrqqsórsñðòqqórsòrssróósóñðòqñÿòòsóñssðór}p~rrssóÿñòróq}~qóóððÿýþýòssqqqróóóóóòóróssòrpqsrqqqññósósssrrÿòóóósóññóóòñðóósóóròsp~òýrrsóqqóòsróðs~qsòòòÿpñÿñsòórsòsòòðþóòóórprssssqrqrósóósrsòsrórrssrsñóóóòñssòðñssrrppssròðòòóðÿóñqóóróqp~rÿñòñsóórsp|~pqóòòsÿþòÿsóòrðòóððsrsp}}rppóòòqrróÿósññsóòóóòÿòðþÿðóñÿpòòÿþñóòñóqrsqòsóñrs~}~MOOwmuwvwK~sðýýýüýÉýËíìíèäîïééâìéåäïåÐæìþphQSVFEB@@CEGSPeKýîÑÓÕÆÄÄÃÁÂÄÄÆÖÓçâðuaRÕGFEEFFGUTSPb~òöåÑÓÓÖ×ÖÖÖÔÓÑùâÍó}KwioingPPQQQQQPQPghtw}óñýõâéäçÑÑÑÑÒÒÐÐÐîíËÿs}IIOwuOðõãïÐáËðrugQSWFDEEEWUSRgMpõæÒÕÖÆÄÂÂÂÂÃÅÕÓÑûýImgPSTTVGGWGWÕSRalIóþíäáÐÒÓÔÓÓÔÒÑÐîãÏòKuhhoaaocmw|qðü÷ïáÐÐäèËpth`QRTÕVVSQQPnw|òâáæÒÔÕÕÖÖÕÕÔÑçãüqmnaPQRRQP`ydcMqýöéûÑÕÇÅÄÄÆÖÐ÷ýwQVD_]\\^^_BEGTnóâÐÔÇÃÀÝÚÙÚÛÞÀÄÖÓáË~mPSVFECAABCCEWTRPlqñôæÑÔÔÕ×ÖÖÖÔÔÓÑæûã÷Éò~K|OOIsÉËÏôïÏ}c{QVVVFDCCCDWSaIltüÏÑÕ×ÂÃÜÚؾÛÝÅÔÑãþ`RWB@@_^]\[]DWPnMöàÇÃÁÂÅÂßÜØ¿ÜÅÒôðïÅ¿¾ÁÿC;433569=]FPcnQSShÉÕÀؼº···º¾ÜÇÐ÷nRÕSSGDZ>=;[ES}qðIrqìÑçÖÕÖÖÑÑõóý÷åÑæûíìçÒÖÆÇÇß¼´°·ÞT4,().3;?X\^DVTWWSMǽ³®­®¯´¸¼ÛÅàwSGBA^X><<ZwÁÔo;.48Oº¸³¿ÐtG{|qbcrîÃßÀÒeRSñÅØ»¼Ø¿º±­°¿F,""*5ETU@>XZBVSPs×½°«©©¬²»ÝÕàòdQGC@[X=;;>DýÒÓâDB_CÖþ½ÇÒcaPyPTPWeóüÐôâðõÖ¿¾½Úß½³©§¬»Y(%3FüýQBXZ_GgnÏÖ¾±«§¦¨­¹ÃvGCBWVWE^Y=<<>[AUüØ°°ºö5..9ô¬®ÂD1-0?MÖÚÄÅÇÓÃÕÇÀÀ¼¹¶®©¥¦­×1!5IÜ¿ÔS>:<^QrÕÀ»¯ª¤¢¥«ºå^;;?ESPSAY=<>Z at GÉÙº¼ÞÕ=87oÁ¸±¾Ò^759AfÓÕÒÖî×ÇÖÁÂؽ¼»¼¶­¦¥«¿45Ô»¸ÁP=:?@OãÓÂÛ´¬¦¢¤©¶Ñ_87:\T`hUBZ>?]aÓÅÁùF];[sÕ»»ÛÕTBX_DÕIgôâèÇÔÆÂÀÜؾÜÞݹ©¢œ¥Û/!<Ù¶¸ÀU?=XWydMûÁµ©¢œ¡©¸ÿ>55;_SnuTA]Y[@GTÿÞØÝÓ\:57lßµ¯»Ó\739DlÁÀÃÞ×ÃÂÂÜÚØÜÚÙ¶§¡ §×+">¿´·ÞQ]\^VPUSý߯¥œŸ¡«¿Q:47=BTSTVECDBEcåÑÖR=<4\æݳ·ÙïDX<BFPäò×ÕÔÁÁÛÀÜßÂÛ×ݺ®¡œ£´7k3é»»ÂçPPugWY=_Ó²¦ŸŸ¢«½ÉCX>??>]ERðó`FZYCòÛÁÿ_/09Õ»±°¼ùA;[[FloÑ×ݾ¼¾ÇÕÒĽ¾¼»¯¦¢¤³=kk/ó¾¿ÄÐËéÐw]97?Æ­¢Ÿœ¥®¾ÐnWY:77?SïÖÐP]?XgÙÀS=++>ó¶­²ÚqGYVUZEBPß»¹½ÂðÏÆÙ¶¶ÛÑѾ©Ÿ¢¯<$8ÕftOǹ¹ÝR4,3g·§¢¥©­¯¯¶ÃF4-/=aÕÇüRSSIð@4..9òÝ»¼ÃÑûÕùsTYCtÔÝÁûQdé߸ºÚÂáö×Û³§¢§·C$)1?oÀ¼µ»ôA73>OÚµ­«¨¥§«µÑ^98<[GWVQoquhÔÀV:/%.>r¹¶´¿¿ÂRd;8]QÜ¿»ÇõÁľß×ÖÔÚÚ¹±©¤¬¾:! )1:ÉÚµ²Ûh;8;CÑÀº°ª¤£¥®Ùp_[Y><;]TÐÝÂÏE?9766;C÷À½¾ÀÖïs}uQRvÿçÒìÿáÅÚ¿ÝÂÀÀž³¨¥­Ö7%!&+:í»µ½ÖT_DEGVÿÜ°§¤¦«²¼ÁîE:56>Õüíâò|TZ826<GýÓÅßÙÜÃÐdSSdpþó|óâ×ÞßÞ»ÜÓÔ½¬¥«Ç;*$$$  '4~½ºÃâÏÏâbA?Tݱªª¬®­®¸×B89?]][C}ÇÅèF>;;<;>DõÂÙ¿ÃÖÒÐô`STOèåËpÐÅÚ¾ÝÂÄÁÀÅÛ¸®«±ÖX.&#" #*:nÅÚÁÄ×ÑWAAsܸ°®«ª«¯½ÑÕ\><;;ZSÑÄÐiC]]>;5=RÐÂÆÁÁßÁãuRess}Q|õÓÃÃÞÂݾ¾ÅqÒ¿¯ª³×@=1)$!*8FUïÔݼÂìDG{ËÅž³¬©­°»ÝÆv_98:>WhñòÏbW@==<\VaÐÐÂÞÂÄéçËó~RygÍæÒÕÐÂÚ¿¾ÚÄãÄ»³°½ÒÕ@8)%"%,2=Y~ÂÞÙÓÉipà}àǽ²¯®±°³¼Ây@>=>;[RMOvÕDC\[>^VvÐï×ÇÄÄÒÓôéòhigýýùÔ×ÞßÁÀÝÁ×ߺ²´½åG_5)%%(,3;\pÄßÄÑîÉ÷ý}ÐÀº³°¯¯¯´½×tG[>;:\QQTSGRE^Z>GSOðüÂÅÁÕàÔçÓwoIâ|èæÒÔ×Ø¿¾ß×Û·¯·ÂIW\.(%&,/6;EÐÕÆìËåíívùƽµµ°¯®±¹ÙæMF[=:<>]RÁÆ>[V@\7=V×Ç~ÃÆÚÞü|qÇIavwÕçûý×ÞÅÛÃÁÄÄ¿¸±»ÂÉQ[-)&(,-4:TÉäÕÏÓÐáËüƼ¹µ°°¯µºÜÒID\=>\CA\CFWA]@CSSdMäÇÖ×ÓÇ×Óæð÷ÿÿ|sæàæèÕÞÙÃÐÖÄ»³·¾×ûR9-))+,.5ZSiýíâæàãôÔÂغ·³°¯³·¼ÀÐPCZ?]@X?\^A\Z]EQSlræ×ÕÖÓÇÖÔÑèæûåýùùÏåôÓÄÂÄ×ÒÑضºÛÆæM?/,,.-/4<FÕPl÷ÐàÐäÆÞ¿»·³²±µ¸½ÝÔOTAABZ=?ZYY>?]GWTlöÔÒÒÔÅÅÔÕÔÕÓÐîáÒûééÐÓÇÖÐÕÖ×Ú¼ÛÂÔüU<5/00/37?_EVQñýèá×ÁÙ½ºµ´³µ·º¾ßÒÿQTV_>??>=;=X at CVgàçÑÑÖ××Ç×ÇÇÇÔÔÓÓÑîàÑÓæçæãåÇÞÁÇÑâuB=877777<Z_BFP|ôîÓÄÝؾ»¹¸¸¹»¾ÚÄÔãslVA]ZX=<=?[^CWQtqÍîÒÕÆÅÄÂßßÂÄÆ×ÓÑûéöñ|mnyl}ýËñ}lQVGGFEC at _BEEWTgm~÷äÓ×ÄÂÀßßßÞßÂÃÆÖÓáïãñgÕSWABB at ADB_EVTPywÏäàÒÖÆÃÂÄÆÄÃÄÆÖÓÑáíÉüüÍÉ}thRVVGB_]Y?[]_BGTPwýÐÕÇÂÞÜÛÙØÚÚÜßÃÇÕÑáîóRVUC]]\Z\_[\BGSPoqáÒÔÇÃÀÝÞÁÀÀÁÃÆÕÑæõ||}}vyd{ÕWWEBA_[\_ at BEVRhÏÑ×ÅÃÀÞÝÜÜÜÝßÁÄÇÔÑÑåwTÕW@\]\Z]]\@FÕRflýÐÒÕÆÃÀÞÀÁÞßÂÅÇÓÐàÍ|ttubyadQUVWDBB at _ABBEVSPvq÷ÐÔÇÄÁÞÝÝÝÜÝÀÃÅ×ÓÐõóbRUFB_^][\]@CEVPuröÐÕÇÄÂÀÀßßÀÃÅÆÕÑîöñOny{PPPyQUTTWFECADDCFURd|ðõÐÔÇÅÃÁßßÁÀßÀÄÅÆÕá÷ÿbTGE@^^]\^ACDWSe|ðâÑÖÆÃÁÀÞÞÀÃÅÇÔÒäýpMhfPffP`fSSSVGWWEFGEGTQglqÉéÑÔ×ÆÄÂÁÀÁÀÀÂÅÇÔáãÿiQSGCC_\]@@BFVSeIÿåÒÕÇÄÃÂÀÁÄÄÅ×ÔÑäÍóMeQRRSSRa`RQPRSQSVTSVWSahKóÿìÐÓÔ×ÆÄÂÃÅÅÃÅÆÕÑû÷~aQTGDAAAACEFWRnmrèÑÓÖÆÄÃÂÃÄÄÆÖÔæãþcgQRSTTRgPRQ`PQfPQPyPRPhc}òsÏåÐÑÔ×ÇÅÄÆÆÇÇÖÓÐõòwPRTVFEECCFGURdIÿìùÒÕÇÅÅÄÄÆÇÖÔÑåôþwyPRSÕTTSPPPydelmeebh`yob|pòÉíéáÒÓÓÖÇÖÕÕÕÓÑàìÍePQSÕUÕUVÕSQfh|òüãÐÒÒÓÔÕÔÓÓÒæïãÍtoaPRSRRRQ`nobMqóóüÍÍ÷ÏËðñÿóóóñqqòñüýÍöõôôéìíôÍËÉÉþósMOvwwuvOMKKrrÿüËÉü÷ÏËÉþþóóópIOKwmuMwOKpp~rqóppñðððýÉÉüýþþÿòÿðóðÿòóóóðÿÿÿýðòóòòóðñrqp||}p~qp~~qñrsðþðñðñÿðñÿññðsrórqp}|IpsqsróqqóðÿÿýÍüðþÿòsðñpròñssðññsòq}róqpp}prppqsóspsósòþýðñòðòròóóòòòòórsqrsrpqrppóórsðñssóÿòòýýññòòóqòòrqqpqqqsqròñórórròssssòsrñÿðñrpsóóóòññssðòròðòr~p}qópqòóqóÿòrsòòrðþÿþóqðþósòñpqòrqqòórpsòrqóÿrðóróósrsrsòq}psqqòþñsþÉýórþs~prqqñósóñòòðrósóróòóròó}rórpqròósÿþñòýðqórpprñóóðÿþqpss}}róóýþòñÿòqqqòóóóróóññrppr~qróssÿüñðþðósóqrððóñññrpprpsñósòòósòòòóòñqòsòrròóóórpppqqrðñðñsðróñóòppqòóqsóðñÿðññr~q|pòrrñþþðÿóqp|psrsòýñòýðsqqsprrsrñðóññðóp~próñòññÿððòppp}~qrrsòòóñññsqòòrróóðÿñÿÿñr~~qóóóñþñòýðssóñÉÒÐVG{e|IÉíöíñÉÿþíþÿËÉñ~òþrr}}~|p~~rprqóósrðþósðÿòsóòrðÿsñrqósrsrssðññósópsòÿÿòñóó~qpssppñrsðsrsóÿqüþñýóþðósðñ}ròq}pqrpòrIsñ~rÿóóþðËòüsóòóÿòóðÿpsðòIrsp|pÿpòñpÿssr~óòpqòòÿðòqñþsñòó~òÉðýqqòó}pðñpIqqqó|róqÿóÿsrðpp|qóñüü÷þóþòrôÏc~òw|MKqññ}rÿñþñssþópñþñsòrósrq}qóüñÿþðóOs|Ió~þrñüòüórñsñóróI|~pqñÿüòðÉñssñópqqsýÿqs}OIñýòñòòrsñ~Iòðssòñóð~~ÿñËËñ}rýówqËò}ýróóvòóôïIqñõIb~põòóò~~}st|òIðüõðpËrððssqüñsýò}qÉ~srÍÿñI}}vÏÒçIvu}IlwMüóp}róóü~ðËËýýópKóýs}ómrýIËqüðÉõËÉOýñprqðqròþüþtvòrKvIsòþþtðüsþ÷ì|õòiq|MlOi|ðnPrÿqýËÑÐÑþñÐàÒùåâåoFRKîïõÕ]?=@QôÐÓÆÜÙ¾¿×õQ]868?VÉÔÆß½¹»¾Ú¿ØÚÀïvVFVýöE[<4/34;RÓÀàÿ`c×Ú»»·¸¾Æ÷ýePaó~uq`ygRgðuUPOðfTCBPæÚ½»ÄuA;>@séây at RQwPUMwrvÏÒß¿ßØÀÂÛÞÆ÷PFeK[58<CÖÃÔwÕRÐؼ´³·ÜݺßÐýY1+',3=>4>ÍÇý|ÓÅÄÓáûß¼»¿À×ÐÚ»¸¸¿Ô~öyD\X at aæðmpbaG=?RU<5?GÕSBBRqSFÐÅÖÚ¹¶²²¹¿¾ÙÔìR\?Z\\RãèéÕÇ×ÕèoPPC^AEP|ñÍçífcÓÀØÀà~PEAUVSÕÁlDVEETVSTWlIUAPÕܸºßôð×ÖÓw_BR`c}hõ×ÓÑÅÞÜÃIEA__VqäÓÔål`óåÍluQDVyÿÕÃÂÔÔÆÁÞ×çÍñ}RTfO`GFSPSÕVUVTTQcfvìÓÑÒÖÖÒÿàÔõSWPRWEPoQfPÍ×ÂÅÄÞÞÁÒcbñeföÄÃÕÑæÓûýñåçd at YBCYXZ=>[^VóÕÅÞ¿Ø»¹»¿ßÖýrinÿòVX=:=_G{rhTgòä~Rmæܽ½¼¾ÝÇÓÐùrREDfýívVCFSRv}POþôõË÷þÉvoüéýÉöÏäÏrwv}mm{bcPSS`bK|öÑÑçâá÷IpòsÍÑÒÇÁÞÛÜÂÕÐP^?;7468>^DcÓÀÚ½¼½¾ÞÆÔçvRPhwlÿÐÔÔÇÃÅÅÖÔÒÿeQõßÁÑÃÙôY;7/,'(.23<qû´¯«ª¬´¶½Öh at Z??<YSwæ×Û¾»¼½ÙÒGX84559=BmïÕÂØÙÝÁ×ÓÉ{TQSWg|öåÖÝØØؼÚز±»ÞÅè>.*'&"#(/8Yù½±¬¬ªª­¶ÙÇwD;9;>XAqÕܾ»·¹»¿ÁOW_84036:YVÑÔÅؽ¿ÂÄÒôPCVTÕUóÒÔÆÃÛ¿¿ÜÚÛ¿·¸¼Û×õX0,)%"$(-5>ò¿³®«©©¬³¼ÞËD><<;>_nàÆÙ»¹»¼¼ÜÉTD=71389=BýæÖÝؾßÄ×ÒOWUTSTR÷×Ç×غ½ÜØ¿ÞÜÚ¾¿æIn>.,*&&'*1:]ã½µ®««ª­´¾ÀíF[==>?AyáÖݾ¼¼¾½Àð`F>7357;>]lÑÕÄÛ¿ÛÂ×ÔéQVPQRQ}ÐÔÄܾ¾¿¼ÛÅÀÚØÞÔóóD2.-*&&)/7;TÞ¹µ®«ª¬±·¼ÄgC^?=<[VlÉÖÚ¾¿¿Úݾ»@1îY)/3\>:CÛ¼E¾µÞÁÒßÓé_nÄ]FrÇ×ÔÃÛ²ÀÒ»¾Ûß¼ÝÐq>:/)'&'&,1<tÔ»°«ªªª®±½ÇÉGZ;;;=AVÏ×Ý¿½¼ØÜ×ãÔÛE*ZQ+*4QG?R¼°OÕ³¾ÐhÃÖÍEUÀwVóÂÀÐÄضßéÜÙÝÄÆÕáT930+&'),/5BÐݼ°«««­¯µØÓlÕ[<<>\AÕýÇßÜ¿¿ÛÃÒõìßä-5â2(/Ft<DÁ¯×f³¸ÆiÆÙïPEßÔC{ÖÚäÅؾÚÏÆÚ¾ÁçÔõS4.1*&%+//8EÀ½º®ª©¬®¯¸ÜpQC?;:Z at GaæÀßÛÚÙÁÑõèÞi0[I3-9RWZSߺwñ¼Á}hÇÖíiþÛî`ÕÝÅÒß¿¾ÔöÄÕsûÄÐñuFX73.---36?Vü¿·¶³³¸ºØÁÒüKghg}íûÓÔÇÖÓèO{GACÿË8?ÑB=Ed|ilóÝáQÆÐKù÷éÐiÆÇËÐÅÃÒÁÄÁÝûçìËÑÁÆìÅÐR>67.+*.54XTÔßÙ¶µ²¹¼½ßÖ}ó|hupÖ×ÆÄÁßÓîORC?>>^óô;G¼R>PÖéB{áÞQ_ÃÒ`R×ÄûïóÛÔSãÅÇpÓÃÜÖO×ÔÓÂÞÅÆÆPB;61,-.67>RpÄÃÚ¿¿ØÅÁÖÕÔÕÁÀØÚ¾¾ÞÃÑíRBZ=>;=YDó¿ÛZé»D=AIFTç¼|VÀÖrRãÐæoWÆÒcýÆÀÆÄ¿ÅsÏÕßÔÐÖÆðC>99.-18::WcæÐÒßßÀÕÂßÃÀÀ¾½½¿¾¿ÇÒòoG]Z?\^ABVhg{Oógmr|ÿóáÐÑáÐÒþöðó|tIu}wðõäÒÔÇ×ÅÇÖÕÐïÐÃ×ÒÖÒíP[;<7039=>ATräþà×ÅÕÇÀÛ¿Ù¾¼¼¿ÛÝÇçKPÕC]Z^DSA^MiEGQpdbóÒÕüçÓÔïðìâùM~Ë÷~{qðî÷éÖÆÕÑÆÕûééíåÓäáàõIV\??:7;?Y]FRÿËÐÕ×ÇÃßÛÙÙØØ¿ÜÁÆÔè|gUGEECBDCEGWVSatrýâûçûûÐûááÐáèåéôËËÉýýÉÏöâîùìËþsóppþôÏ÷÷ôð`ÕWFB_^ACFVSPmqüèÐÓÕ×ÅÃÃÃÂÂÃÆ×Ôæípwh{aQSUSRVTSRRPPQhtu~ñÍ÷îåáÑÐÑÑÐáçÐàääéÍ÷Ëüñ}MmvbhuvOIóþÏöð}~|ePRUWVÕVVSPymýìáÑÓÖ×ÇÅÆÆÇÇÖÓÐùéìõrodPUGGEDWWFVRQPhKñÏéàÒÓÔ××ÖÖÖÔÑÐáâÉÿs}Ichn`PPPPevOO~ÏìÏðññvbdPQQQTRQabvrÿôïæÒÒÔÖ××Ö×ÕÔÔÒÐìóMbPTÕUGGVWWÕSQfc|ðÏâæÒÔÕÖ×ÖÕÔÒæäåíþrImbheyPQPQRPhvKþéíüöìòñbd`QRPdhtw|ðýöîçÐÐÑÒÓÕÖ×ÕÑàäôòKvaQRÕUVVTTTSQehOýôåÐÒÓÔÕÔÕÔÒÑÐä÷ÍðpOchdygPfPgaa{dhuqÏùÐûïùïÉñó~uogQP`{eoniMpðõäÐÒÓÔÕÔÕÕÒÐïõò~te`QSTSRRQPP{bwñÏìûÐÑÑÑÒÑÐáîïìõÉÿrMOtyg{a`{`fyilw}pðéÐÑã÷àùËÿËñ|wogP`de{dmwOüâûÐÐÑÑÑÒÑàïãõÿq|ubyPPPggyoiOIqýËìéääåæääèôãËýñ~}wMvcbbcdyPSSnôÓÖÒîüOmKðýrubvM}pòýþñròñðýq~próppròþýËÍÍÏ÷ö÷ÏöõÍòòòq~K}~}I||~~sóóñÿýññòòòsòsq}wuOwK}pqròqqóòóóðÿÿËÉýr~óñþýþÿ|OI}psðüÍüþýýððñIvvOw|rñþüÍõããèï÷ýÿs}KMMKOO|||qrsóðüÿðòÿñrqIwvKKKpóóóñññÿüÉÍËÿþñsrrr~~qqóqpóóòñÿðóþñórqsóòsóòsóòñsppsróóñðóòòððóññññsòðssñðñósrrspq}p|~|~}prpóóòòñþüýððÿñóòòñòÿüsrrrrsssssðóñssÿsssòsqspqqróòrpsqqósssóñýðòððñòsrsprðñðÿñrq~~q~~}~~qqðñððóñòòññòóósóñóóñssrpsróróþþþðÿñqsqp~}ppsòsñprqppróñòðüÿÿþñññóósp~prsórqrqsòsssróñòñðòòòððòñóqqprsròòósqqppssórròñóròsróòñóóòòósððóòóspqsrrrsòòðñóóqrsqrrrqqqsñsòòññóòrrqprrsrqòòðòñðòþññòóñsssóñqsq}p~~}rsróóðróñóýðññññóýþróþq|sróòq}qrrÿòsósprsóóòþðòòórsrqròððÿððþÿñórqrsòóósrrr~ppqòðþþððòòr~ssprsóóòððñóòópqrpqòðñóÿðòòpqp~sòrðñòñòñðñòórppprqrssósqrsrósróóñòòþñðððòóòqssrqqróórrrp}~qsòððòÿðóñðóóòóósóðñðððòqpp~qqrr~qòóðñóòóósrsóòòòþñññóqqqqpssñðññòððssrròóòþòòósspqpq~ppsññòsssqsòóñòñþÿÿððñróópppqsrqrrp~pòósòòòósñórñssrqsròòðþñññòrñórsqqsðòrssqrsprsrrrqqròòñþððÿðqpósññòññssrprspróòòròróóròóòòóññòóóòóqsspqrrrsssòóósóòóòóòósórssósròððsñóppqsóóòòñòóðððóóóqsqprqqsqrqpqròòððñþñòñððòórqrósqssqóóssrsórrósñóròsóssqpórñþÿðððòósrssqppqróñórósqqqròñðððñðñòñóññóóórprrqrqsóssqróòsqóòsóóóósóóñðòòñssñqqsrrssqórqròóqóórsóqsòòñððsóòrórsóssqqqrðñóóóòsróòóóÿspqqqsÿðñòñrrðsròrqrrrsòðñòssórróóssóróòrssrrpssrórsòóqóñòðòòóòñòósppóósñòqsÿÿñspqqqsññsr~pñðñòq|I}prððróòòÿðÿÿÿÿòòrqòrqrpqqpqrqsñðÿððððrpósqssqqóòsñðòñssrsòóósòórsñóqrprsóóñòsñÿñòósqqqsòñòñósspsqqsóòñððñòñòqrrrqsñsróòóóórsqppqrqròòóòþþðòóssóósóñòóórqqrrpqrrpqrsòòÿððÿñÿòòðòòórspprrsñóñóósprróósÿòóñññssspqqsñrsrrórsòÿòòñsrsðòòñórqssrssrrsóòóóòóóòóqrsrsóðñóòñòóòóqq}póqòóññññóóóñòñòòððòóòsñóqóssórppsppsósòòsróòòóqórsósòóòòòÿòòñósóòrsórs~qr}qsòóòòñòñòóóssròñsóñòòòñóqsóqróòssòñòsóòrsrqqpqsòòòñsósqssòñóóòðóòþñqrrpppqñóòñðòsðsóóòÿóòósórrspóðósrópsrsòsqprsqrrrósñññòóòòsóósñòòòóòróñsñòeSRóÖÂÆÐóbgPlÿÿMQSSgOséâôý~Ëíææùîÿó|KróþórIutu}}|~qsñòóðòÿýÿðýüòr~||pssóññsóñsòýýðòòððñsqp~~}}qórrrrqrñòññòðssòsqqòòððóósòqròróóqsórqsrqqrssðòòþþþòóóósqsróóqrqpppprqsssòóñÿñÿþòósróòórññqòòóñòsqrqrrpóòsñòòññòsssssssrqss~~pppóñòsòñssñóòðññóqrqqpsðððððñórqsqsrprróósññsóòósòsrrprròñssrsòòòqrssòòsóðòósqrpqóòðòòòòóóðÿqqr~pqpprñóqsósssòñòòñþñsòsssórsòròrpósssóórósórsñsrsóssrqrqrsóóñþòðñòòròósrqsprqóñòðóòóòóróóòrqrrrqsrsqprsóqóðrÿþÿÿðñqsqpòrrsòóósqsrrqsòòòsóóósòòsñórrsróòññóórróóñòqqqqrssssóñòròññþóóòrróòssrrsqqrqpsññòñÿósóòósððòòórqprrrqrsóòóóssóóòòðórórsqqssórpqòrsòsñsròòðþþñòþñqórsòóósórqrqsq~pqqsqpqqsóòÿðññðñóòòñýÿsóqqñòrsq~||}póóòðprðòÿñðÉÍÏüÿóprpp~}~K|~qóòsóòóósqppóóóóðýðþñóðpqóppróòsñðÿñqsóórróÿýóðóóósrqqrsrpóòqp~òóððñðòòòòrñðsópòrpqrsprññýþÿþñspóqpqqòó}qrññrpróssòþÿñþórðñðòsóqrpóróðrssqqpósrósròòòòÿñqsóósrsrósóñóòþòrspssròss~òóósóòóqrsòðóÿþòñrsspssórppqòóóòóðÿòsrqsssóòrpqqñðòq~rqóñsñþüÿòðsrpsrsòsrsóssòðñrqq~qqqrsòñððòóóqsóòþðþýððrqpq}||}qqóòðþñóròòqqóòrróðòñÿðópssóñóòòððssqqqpqpròðóqòssòóòsrósóòððsððsór~óósñðÿññòsósspqqórròqsrsðsòsrñóðòòñpssóñsrsóqórrrròññòòòrrqróòðóqóóòðópsòòsqsòòsòspòsqóqqqsòñÿóóñssrqòòsóròðóñññòrrrqrsqqrrsrrpqsòóóÿóýÉþòpqpsósq}Irrðÿóýððÿñýðòòqòñsqqsq}|qóðñóòsòòròñòsqpsóòÿðòñþñssrsssósqpóósóósqrppqpòòòñòñþññþsrqqr~sñrssóòrsq~póñsòðñðÿÿðòÿòsqpqóósòóòrpqppsqpñòòÿóòóóñssrrósóñññÿðñópqprssqsrròòóñþðþóqrqrssóópñsqòrsssòórññññssóòórÿñpsssórsóósqqórsòrqqrrqòòóòòññññòñóóóórqqósróóþñqsrrrsòòósóóóóósñó|éqI÷Pós|äuÍÏMÍv}þòýqýMsq|îKýöqòM}IËðòòtóóþýþñ|óóóþþpr|Kþ~ñðrÉ~}ñssÿðóòþÉññr~òpsòñþ~ópwp~òððñqÿrsðòóprqsrÿÿss~ssÿýòò|rsòðòÿ~srqñqòq}qsqòÉòòsqsqsðósËI}Ï}ññrÍ|sÉsüËñslsöp|ðspq|rp|ýü~sIqËóìÍKM|qsþþôÉ~ñ}qðI~ÿýþsðqw}~òsñrqpñòñÿñòòÿs}ñòsòpòòÿËspòspqðòqrrsróñÿñs}ró~pósóórsrñðssrór~òýÿþÍþórqq|óòqr~ppròñðòÿsrðp~rrññòüòsñqòsñÿóññóóqp}qqrqsrñðsðñðýñóòþÿqòñóósÿðñórp}ppsópòñóðóqròóòñóñÿðñðòòòrsóròðórpórIIqðòð}ÿròüpÏÿðÉsq}ð~Oq~rp|òðrròÿýþÿþþÿþóóñòóppI|I|qpróððýðñþósòórròsòòrppqrpqòññðÿóòñ~~ósòrsòqssñýðÿÿósópprsqòósñóñsqs~rr~qrñòÿññýñóqrsprñÿðñórsòóóðsqpp}spqÿþñóñósròñpòòóðósròòóspp~óòóñðñssrqqsóññòÿóóósñòñrqp~}}qpñþÿòròqqòñþþþòóòñòrsqqrpprp}pqòñòðòóñòssprsrññÿðòñpqròñððñsqrsrpsòssóqóòrrsðóòñqrsóósóñðòþðòñsrsq}~ròÿòññsq~pròñðýñrsqrqqsñÿðÿþòóq~qsqsósrqòñóósññóòóñðóññóðsqrqóqrrsr}qq~qsóññróòssñòóññððñðòðóqóp~}psqsòóórsrpóóñðñÿþþñrrsósqrrssqrqròrñðrqóórðòòòññòðòòÿósóòóqpróóssrórqprñòòñóssssòññòÿðòòòòrprrssóssósr~pñrppqròðÿýþðññóq~rqrðsssróóóqóóqòsóðóñòsòóssóñòòòsópsñrprñsppqqrsóðýðóòsqpssñþñòòòrsóròósòróóóòròóróqqòsrsrsóòñðñqrp}qprññýýððqqqssóòñÿòrrórróóðòròóqqsñósòrqrrpqñóóspróðñðýþñrpq~}rññþÿÿñpqrpóòsrrqrrsóñðððóss}~rqòóósóòsqrÿòrðññðñññóóñsprrsórróssðóòórpqrsòsòrrrrqpqròñðÿþÿñòÿòqsspqÿÍþqrr}Irqóþóóqp|prÿþòðüðp}sÉòqüÉsðñ}ðIpðqðõÉðpr}wðüòóñsñòñÿòsrp~~qsòñÿñóóqóðÿþþòq}Irsrrórssrðróòsðòósòðñðssróòssóssòóóòpsòòñóóðòqsrpqrrróóÿñóñóssqqpqróósóñòñýýòòñqrsqsrsóósqqrróóññóòsqsòòqsñóssrrsrsñòñsóÿòórqrrsóssòñóósrqqòòòòòðósrqqprñòsòñrqrrórsðññññòòñqqrrósórqsñòòñòñòòñsqqrp~prósòñððòóóp~psñòÿþðþðóqsspsrrsssqp~}qrròññññÿðÿüððòqrprsqrssqòsrspróòññòssróòsòòòóóñqqrprrñññòsòóñòóñòóqpsóqqpppóòòññÿñòòsóóqpsñðÿðñòsrqósóððÿsrsss~qpqssòòñòsòsñðórsòsóðñòóóóssósssqsqrrròsñòóóqrpóòsósóróòsssqqóóóóòñòróòsóórrqñÿñðñðòròóqrr~qsróñóñÿósórI}psòðÿðòððññssòóóòóósòòsóóssósrsrqrrsñÿòssqqrssrðñóòróósqrrrsðþñòðñsósrq~rñðññþòpppsòóñþðóqpsórqsðóróñðóòñssóóórqsqpsñðñòóqprsórqrsðÿþþòóñò}ppròòòòórsòóssóñòòòóðñsq~qqqrqóóóýÿsòñòóósrqpròósòñòóóóssòñðñórrsqóòòóqrqqqqsóòòóròósópsòþÿóñsqsòq}pspsñðññðóòðñósórpppqsòññóóósósssqrròñóóóñðñòsssñóppròrsóóñsqqqrrqqsòòñÿþðósórrsròòññsrrrpp}ròóðþñðÿòórsóqóñóòòsóñðrsñp~}rqóòóspssróðñòðÿñðþñóóññsrpqqpssrqrrrsrqprsòñsóñÿðñÿòsróññóñðósrrpppósqsðsóòspqsq~qsòòòðòñÿþýðsóóróóósqprrqqqrrsórqsòsrññòðññóðÿórqsqpsÿððÿñsqrssóòsósrssqpppóóòòòóróóóóðüýþðspqsrqsóqp~qqróóórñÿóòóssrñññÿóññññsóssspqròpñóqpóóprrqsòððþþÿðñsqrrrósrqppqpóòsððñòósssrqsòòòðñsñs~~qqqòòósòñóòòóòrqóóòñsóñññsóðñrqrrppqqrqqóññòòrpssósòñóòòóóòóórrññòsñðóssòpprpòòóóróóqpòsqrsóòsròðÿýðsróqprqsrrrsññòòósòssóóòsrqqrròòsóóòóòósñsqòòsósqqpppróóóóñsrsrñòóðððþþòóóòsróóspsqppp~sòðþðþþsppqppóòssñÿÿñópqrsðóóñsrrósqrqppqròñòòsrqqsóóñÿÿðñrsqròrrósrsópsðñðþÿórsrpprsqróññrsñòsprrqsñrsññÿñóssqpðòqÿñóóòópsssòqqsqrqóñsóÿþðsqpsrròóñðñòósspI~òñðÿñóñóqrprrrppssórñþrsòñðqqsòðððýÿñÿórpp~IpqrsqròòóðñòspóòòòññóÿðórprsrrpsóssqróóóóððssóòñóñÿKR\;\lÔݽ¼ÀÑä¹µ¹ÝÔPA[:60049_BDPÓÀ¾¼¼ØßÜÂÇ×VDWWCDESu}èîÓÆÕÖÔÒÑæôune{PSað÷óqýôõðqòõÏqqsóMd{euMcmrüÏüþËüÍÍ÷ÍñþüÉýðÉñsóóÍür}OwuK|MMOM|qñýÉÉþðÉ|>$&öP>¥—•ëœÐ.'8¼±É;,(2©¯º¾¶«¦¢¢£¦±ç:4;401-,1>AÒµ¯²´¯²ÄTܺ·ÞD0,.8GÏÖÒòtG=320-.,,5R½«¦¦¦¦¥¦ª­®³ØÕr]3,(''()+/:FóÀ¹´´¸º¾Ø¿ÝÄÐËþiQTÕTVTPlKM}||þãìðýîÒÖÓù~SFCCW{qsO{acOËÓ××××ÕÔÐíösqpyRSRPdtsöíöýp~ó~iaPRWU{~ÑÅÃÂÃÇÑíýöùíòbÕEB_AWSP|ÍîÐàäÐÑÔÇÆÅÅ×Ñó`SVURQSTVVSuâÐÒÐþaRfdîÄÀÁ×ûvQgnÉûç÷fSGGPKiñÉÏÑÇÃÆÒÿfUSlwM}wnTVQtåÔÔÑèÿòüõÔÆÔã{F_BFSpõÐÓæöÉìùæîáÐôãÏ{GEWVoùÖ×Òæã|{i÷íñðOPVSnQ`hÿÐùÑÐÓÂÚÝÖÑlDDC_BTnIQFGFSàß¾¾ÛÇÉmPcâûÕÉC\XDiýÒÂÝî|éÍáèoWBDSóÿo{nóÇÃÄÂÃÝÐhÓ×éÏÕW3335;TÕÖÄÅÆàÓ¾¿¼·¼ßÖ×÷fWZY=<<649=;_îÆݺ¶¶µ±¯¯°µÚuY7-)0^PnuB4/4:FÚª¤©¶ÁvEPïÔÔmD^Z=G×àût<<_ýÙ¯ª°¹m601_s×ÜÜÒ[9/)7Ïݹ¯¬¶áE?BÖµ­·ÜI6+*1=ö²­³ÃA.&.BÞµ±²ÀC8=UÕ¸»ÃÆàTDÑÚÛÝÒV:57=ARÕÆãQ]^QÁ¸´´¹ÝpW_Z[[TñIFY>]ñÕÖÀÅÐÕ¿º»º»ÜuZ?4,6TPMîw][oÑý·¼ÓóP@@ÉßݾÙÆéQSF^^EZ4;DVâÞÛÐsÑÑÑ¿¯¯»ÅU4+.>澺¾ä]94:S¾¯­³ÝÓócÉöP]=61007FÔ¾º¼ÛÓÔ¿±«¬´Ó?3,.9DôíüS\X>WÕº­­´ÆFADPáÓòB;4/1>¾²®²¾ÇöóùÞ¼ÜæS[;6678<^GPáÅܼ¸¸¼¿ÀÇÔîðORW_><;=]WwÐÇÄÂÞÞÝÛÀÆÐISDACEUàþ.":—‚’±(.]#%A«£§”•›””˜ ¬¤™ë’Ã.k &Z¹^ÍG<±ß´¢œœ ”뛵<0"!!*9\=)$&(6e¹¦ª®­´µ·»Ù¼¿ÕÔT=>XÕP\9/.7[Rü»¿ÅÒËrÐÓÔæÕÙÙÇÍVY=_gvðrìÓæ|fSSÕméèùôìâs~tqÐÔÔÔÓÑÐÍdGACWW[<<BÒ¾«¥¦©×?>54<<30129`öVѶ®¯´¦§92.8’À¸§Õ¡°2k»±(E$<»Á¼2..ЦœÛE¦¶›™¥ëÂ]ò/ØD**?S,#1/±®¥“©°­qÖRºÄ?<),%={,FtmÖѸ¯°ÅKÐP¯§××¾ÓÓB/2<F4, at _ÕôÑËXÕG˾»ª¬­­ÀôIV=5/:7-4_]_ß¹¶­§­Í+
+-ž†‹—®;AŽˆŸ·õ"k
+%%Ýžˆ“8)!$,·?X‚ŒA)Œˆ”©
+Ö›—Ž‚ž‘”–‰—±,	-1˜“‰‹“˜™–Œœ$.§«Õ "¾ º¸¢»¦«=q¯™•£Ü-!**9³®½Z1ùï:)"!$.>t¿’Œ‘¡= ,Ä®¡¡®Á\7:(4·²­¬Õ28é×ÔÀÄ\:÷Ãܺ½Üß»³Á÷óY;=::S|V}ÔÚÚOeÑÖÕGE¿¼¸½ßGVY;57QÚ´²¼Ó[/,.6Gó{Pó×Ý¿¿ÂÇÔÕ×ÔÀßÓÑïngR@=42<BfÖ¾½½¾ÝÁÃÇÓð{RQyRTQu}vð~TWTDBVVQKsù×ÆÁÅÑÓÒÑÇÖÒÑpVCFVWVP|ræÇÅÅÔÉvóõôÐÒÐñRWFBACWRcüñwðÿKíîôÓÓÐçãÑÔÑÓÒâó~ðKÏÉqdRQRRQgbuwòhröÉäùËÉìâöâÐïýòIhmsÉýrIlib~üpýäÏöâñrýËð}~KeheevOÿÏÏâÍÉöÿ|qÏãâýwuMu}òò÷ìÍsqqKMO|pOþrqòÿñqòþÿÏ÷üüÏðvuIqñýüKqKwK}ñòrÍèírrðIóþ}r~pòIs}òÍýÿöýI~~vu~õöÉìòKrrÿüÉþrüq|òut|Isr}pmPKýMrü}üôðõéËÍïéãàìüqRfÉüöôMvQUOò}ôàãóýövvôdWtmeäûqá×Ñïíud|MíÖÇÐgUVB_BVQñõþ×ÄÐÖÖòðÐýQh~þþÉËËËÉüþÿñòsrp~~}}}}}~~ppqqrsssóóóòòòòòòòòòòòóóóóóóóóóssssssssssssssssssssssósóóóóóóóóóssóóóóóóssóóóósssóóóóóóóósssóóóóóósssssssssssssssssssssssssóóóóóóóóóóóóósssssssssssssssssssssssssssssssssóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ
\ No newline at end of file


Property changes on: misdn-user/trunk/example/test_file.out
___________________________________________________________________
Name: svn:executable
   + *

Added: misdn-user/trunk/example/test_x75.in
===================================================================
--- misdn-user/trunk/example/test_x75.in	                        (rev 0)
+++ misdn-user/trunk/example/test_x75.in	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,15 @@
+
+
+Welcome to SuSE Linux 7.1 (i386) - Kernel 
+ (l).
+
+
+
+pingi!login: test
+
+Password: 
+Last login: Fri May 18 20:48:26 on ttyI1
+Have a lot of fun...
+test at pingi:~ > ls -l
+insgesamt 0
+test at pingi:~ > logout


Property changes on: misdn-user/trunk/example/test_x75.in
___________________________________________________________________
Name: svn:executable
   + *

Added: misdn-user/trunk/example/test_x75.out
===================================================================
--- misdn-user/trunk/example/test_x75.out	                        (rev 0)
+++ misdn-user/trunk/example/test_x75.out	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,4 @@
+test
+test
+ls -l
+logout

Added: misdn-user/trunk/example/testcon.c
===================================================================
--- misdn-user/trunk/example/testcon.c	                        (rev 0)
+++ misdn-user/trunk/example/testcon.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,926 @@
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include "mISDNlib.h"
+#include "l3dss1.h"
+
+void usage(pname) 
+char *pname;
+{
+	fprintf(stderr,"Call with %s [options] [filename]\n",pname);
+	fprintf(stderr,"\n");
+	fprintf(stderr,"       filename   filename.in  incoming data\n");
+	fprintf(stderr,"                  filename.out outgoing data\n");
+	fprintf(stderr,"                  data is alaw for voice\n");
+	fprintf(stderr,"\n");
+	fprintf(stderr,"\n     Valid options are:\n");
+	fprintf(stderr,"\n");
+	fprintf(stderr,"  -?              Usage ; printout this information\n");
+	fprintf(stderr,"  -c<n>           use card number n (default 1)\n"); 
+	fprintf(stderr,"  -F<n>           use function n (default 0)\n"); 
+	fprintf(stderr,"                    0 send and recive voice\n"); 
+	fprintf(stderr,"                    1 send touchtones\n"); 
+	fprintf(stderr,"                    2 recive touchtones\n"); 
+	fprintf(stderr,"                    3 send and recive hdlc data\n"); 
+	fprintf(stderr,"                    4 send and recive X75 data\n"); 
+	fprintf(stderr,"                    5 send and recive voice early B connect\n");
+	fprintf(stderr,"  -n <phone nr>   Phonenumber to dial\n");
+	fprintf(stderr,"  -vn             Printing debug info level n\n");
+	fprintf(stderr,"\n");
+}
+
+typedef struct _devinfo {
+	int	device;
+	int	cardnr;
+	int	func;
+	char	phonenr[32];
+	int	d_stid;
+	int	layer1;
+	int	layer2;
+	int	layer3;
+	int	b_stid[2];
+	int	b_adress[2];
+	int     b_l2[2];
+	int	used_bchannel;
+	int	save;
+	int	play;
+	FILE	*fplay;
+	int	flag;
+	int	val;
+	int	cr;
+	int	si;
+	int	bl1_prot;
+	int	bl2_prot;
+	int	bl3_prot;
+} devinfo_t;
+
+#define FLG_SEND_TONE		0x0001
+#define FLG_SEND_DATA		0x0002
+#define FLG_BCHANNEL_SETUP	0x0010
+#define FLG_BCHANNEL_DOACTIVE	0x0020
+#define FLG_BCHANNEL_ACTIVE	0x0040
+#define FLG_BCHANNEL_ACTDELAYED	0x0080
+#define FLG_CALL_ORGINATE	0x0100
+#define FLG_BCHANNEL_EARLY	0x0200
+
+
+#define MAX_REC_BUF		4000
+#define MAX_DATA_BUF		1024
+
+static int VerifyOn=0;
+static char tt_char[] = "0123456789ABCD*#";
+
+#define PLAY_SIZE 64
+
+#define	MsgHead(ptr, cref, mty) \
+	*ptr++ = 0x8; \
+	if (cref == -1) { \
+		*ptr++ = 0x0; \
+	} else { \
+		*ptr++ = 0x1; \
+		*ptr++ = cref^0x80; \
+	} \
+	*ptr++ = mty
+
+int play_msg(devinfo_t *di) {
+	unsigned char buf[PLAY_SIZE+mISDN_HEADER_LEN];
+	iframe_t *frm = (iframe_t *)buf;
+	int len, ret;
+	
+	if (di->play<0)
+		return(0);
+	len = read(di->play, buf + mISDN_HEADER_LEN, PLAY_SIZE);
+	if (len<0) {
+		printf("play_msg err %d: \"%s\"\n", errno, strerror(errno));
+		close(di->play);
+		di->play = -1;
+	}
+	
+	frm->addr = di->b_adress[di->used_bchannel] | FLG_MSG_DOWN;
+	frm->prim = DL_DATA | REQUEST;
+	frm->dinfo = 0;
+	frm->len = len;
+	ret = mISDN_write(di->device, buf, len+mISDN_HEADER_LEN, 8000);
+	if (ret < 0)
+		fprintf(stdout,"play write error %d %s\n", errno, strerror(errno));
+	else if (VerifyOn>3)
+		fprintf(stdout,"play write ret=%d\n", ret);
+	return(ret);
+}
+
+int send_data(devinfo_t *di) {
+	char buf[MAX_DATA_BUF+mISDN_HEADER_LEN];
+	iframe_t *frm = (iframe_t *)buf;
+	char *data;
+	int len, ret;
+	
+	if (di->play<0 || !di->fplay)
+		return(0);
+	if (!(data = fgets(buf + mISDN_HEADER_LEN, MAX_DATA_BUF, di->fplay))) {
+		close(di->play);
+		di->play = -1;
+		data = buf + mISDN_HEADER_LEN;
+		data[0] = 4; /* ctrl-D */
+		data[1] = 0;
+	}
+	len = strlen(data);
+	if (len==0) {
+		close(di->play);
+		di->play = -1;
+		data[0] = 4; /* ctrl-D */
+		len = 1;
+	}
+	
+	frm->addr = di->b_adress[di->used_bchannel] | FLG_MSG_DOWN;
+	frm->prim = DL_DATA | REQUEST;
+	frm->dinfo = 0;
+	frm->len = len;
+	ret = mISDN_write(di->device, buf, len+mISDN_HEADER_LEN, 100000);
+	if (ret < 0)
+		fprintf(stdout,"send_data write error %d %s\n", errno, strerror(errno));
+	else if (VerifyOn>3)
+		fprintf(stdout,"send_data write ret=%d\n", ret);
+	return(ret);
+}
+
+int setup_bchannel(devinfo_t *di) {
+	mISDN_pid_t pid;
+	int ret;
+	layer_info_t li;
+
+
+	if ((di->used_bchannel<0) || (di->used_bchannel>1)) {
+		fprintf(stdout, "wrong channel %d\n", di->used_bchannel);
+		return(0);
+	}
+	memset(&li, 0, sizeof(layer_info_t));
+	strcpy(&li.name[0], "B L3");
+	li.object_id = -1;
+	li.extentions = 0;
+	li.pid.protocol[3] = di->bl3_prot;
+	li.pid.layermask = ISDN_LAYER(3);
+	li.st = di->b_stid[di->used_bchannel];
+	ret = mISDN_new_layer(di->device, &li);
+	if (ret) {
+		fprintf(stdout, "new_layer ret(%d)\n", ret);
+		return(0);
+	}
+	if (li.id) {
+		di->b_adress[di->used_bchannel] = li.id;
+		if (VerifyOn>2)
+			fprintf(stdout,"b_adress%d %08x\n",
+				di->used_bchannel+1, ret);
+		memset(&pid, 0, sizeof(mISDN_pid_t));
+		pid.protocol[1] = di->bl1_prot;
+		pid.protocol[2] = di->bl2_prot;
+		pid.protocol[3] = di->bl3_prot;
+		pid.layermask = ISDN_LAYER(1) | ISDN_LAYER(2)| ISDN_LAYER(3);
+		if (di->flag & FLG_CALL_ORGINATE)
+			pid.global = 1;
+		ret = mISDN_set_stack(di->device, di->b_stid[di->used_bchannel], &pid);
+		if (ret) {
+			fprintf(stdout, "set_stack ret(%d)\n", ret);
+			return(0);
+		}
+		/* Wait until the stack is really available */
+		ret = mISDN_get_setstack_ind(di->device, di->b_adress[di->used_bchannel]);
+		if (ret) {
+			fprintf(stdout, "get_setstack_ind ret (%d)\n", ret);
+			return(0);
+		}
+		/* get the registered id of the b3 layer */
+		ret = mISDN_get_layerid(di->device, di->b_stid[di->used_bchannel], 3);
+		if (ret <= 0) {
+			fprintf(stdout, "get_layerid b3 ret(%d)\n", ret);
+			return(0);
+		}
+		di->b_adress[di->used_bchannel] = ret;
+		/* get the registered id of the b2  layer */
+		ret = mISDN_get_layerid(di->device, di->b_stid[di->used_bchannel], 2);
+		if (ret > 0)
+			di->b_l2[di->used_bchannel] = ret;
+		fprintf(stdout, "b_l2 id %08x\n", ret);
+	} else
+		ret = 0;
+	return(ret);
+}
+
+int send_SETUP(devinfo_t *di, int SI, char *PNr) {
+	char  *msg, buf[1024];
+	char *np,*p;
+	int len, ret;
+
+	p = msg = buf + mISDN_HEADER_LEN;
+	MsgHead(p, di->cr, MT_SETUP);
+	*p++ = 0xa1; /* complete indicator */
+	*p++ = IE_BEARER;
+	if (SI == 1) { /* Audio */
+		*p++ = 0x3;	/* Length                               */
+		*p++ = 0x90;	/* Coding Std. CCITT, 3.1 kHz audio     */
+		*p++ = 0x90;	/* Circuit-Mode 64kbps                  */
+		*p++ = 0xa3;	/* A-Law Audio                          */
+	} else { /* default Datatransmission 64k */
+		*p++ = 0x2;	/* Length                               */
+		*p++ = 0x88;	/* Coding Std. CCITT, unrestr. dig. Inf */
+		*p++ = 0x90;	/* Circuit-Mode 64kbps                  */
+	}
+	*p++ = IE_CALLED_PN;
+	np = PNr;
+	*p++ = strlen(np) + 1;
+	/* Classify as AnyPref. */
+	*p++ = 0x81;		/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
+	while (*np)
+		*p++ = *np++ & 0x7f;
+	len = p - msg;
+	ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_DOWN,
+		DL_DATA | REQUEST, 0, len, msg, TIMEOUT_1SEC);
+	return(ret);
+}
+
+int activate_bchan(devinfo_t *di) {
+	unsigned char buf[128];
+	iframe_t *rfrm;
+	int ret;
+
+	ret = mISDN_write_frame(di->device, buf,
+		di->b_adress[di->used_bchannel] | FLG_MSG_DOWN,
+		DL_ESTABLISH | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"DL_ESTABLISH write ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 128, TIMEOUT_10SEC); 	
+	if (VerifyOn>3)
+		fprintf(stdout,"DL_ESTABLISH read ret=%d\n", ret);
+	rfrm = (iframe_t *)buf;
+	if (ret>0) {
+		if (rfrm->prim == (DL_ESTABLISH | CONFIRM)) {
+			di->flag |= FLG_BCHANNEL_ACTIVE;
+		}
+	}
+	return(ret);
+}
+
+int deactivate_bchan(devinfo_t *di) {
+	unsigned char buf[128];
+	int ret;
+
+	ret = mISDN_write_frame(di->device, buf,
+		di->b_adress[di->used_bchannel] | FLG_MSG_DOWN,
+		DL_RELEASE | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"DL_RELEASE write ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 128, TIMEOUT_10SEC); 	
+	if (VerifyOn>3)
+		fprintf(stdout,"DL_RELEASE read ret=%d\n", ret);
+	di->flag &= ~FLG_BCHANNEL_ACTIVE;
+	di->flag &= ~FLG_BCHANNEL_SETUP;
+	ret = mISDN_clear_stack(di->device, di->b_stid[di->used_bchannel]);
+	if (VerifyOn>3)
+		fprintf(stdout,"clear_stack ret=%d\n", ret);
+	return(ret);
+}
+
+int send_touchtone(devinfo_t *di, int tone) {
+	iframe_t frm;
+	int tval, ret;
+
+	if (VerifyOn>1)
+		fprintf(stdout,"send_touchtone %c\n", DTMF_TONE_MASK & tone);
+	tval = DTMF_TONE_VAL | tone;
+	ret = mISDN_write_frame(di->device, &frm,
+		di->b_adress[di->used_bchannel] | FLG_MSG_DOWN,
+		PH_CONTROL | REQUEST, 0, 4, &tval, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"tt send ret=%d\n", ret);
+	return(ret);
+}
+
+int read_mutiplexer(devinfo_t *di) {
+	unsigned char	*p, *msg, buf[MAX_REC_BUF];
+	iframe_t	*rfrm;
+	int		timeout = TIMEOUT_10SEC;
+	int		ret = 0;
+	int		len;
+
+	rfrm = (iframe_t *)buf;
+	/* Main loop */
+
+start_again:
+	while ((ret = mISDN_read(di->device, buf, MAX_REC_BUF, timeout))) {
+		if (VerifyOn>3)
+			fprintf(stdout,"readloop ret=%d\n", ret);
+		if (ret >= 16) {
+			if (VerifyOn>4)
+				fprintf(stdout,"readloop addr(%x) prim(%x) len(%d)\n",
+					rfrm->addr, rfrm->prim, rfrm->len);
+			if (rfrm->addr == (di->b_l2[di->used_bchannel] | FLG_MSG_UP)) {
+				/* B-Channel related messages */
+				if (rfrm->prim == (DL_DATA | INDICATION)) {
+					/* received data, save it */
+					write(di->save, &rfrm->data.i, rfrm->len);
+				} else if (rfrm->prim == (DL_DATA | CONFIRM)) {
+					/* get ACK of send data, so we can
+					 * send more
+					 */
+					if (VerifyOn>5)
+						fprintf(stdout,"DL_DATA_CNF\n");
+					switch (di->func) {
+						case 0:
+						case 2:
+							if (di->play > -1)
+								play_msg(di);
+							break;
+					}
+				} else if (rfrm->prim == (PH_CONTROL | INDICATION)) {
+					if ((rfrm->len == 4) &&
+						((rfrm->data.i & ~DTMF_TONE_MASK)
+						== DTMF_TONE_VAL)) {
+						fprintf(stdout,"GOT TT %c\n",
+							DTMF_TONE_MASK & rfrm->data.i);
+					} else
+						fprintf(stdout,"unknown PH_CONTROL len %d/val %x\n",
+							rfrm->len, rfrm->data.i);
+				}
+			/* D-Channel related messages */  
+			} else if ((ret > 19) && (buf[19] == MT_CONNECT) &&
+				(di->flag & FLG_CALL_ORGINATE)) {
+				/* We got connect, so bring B-channel up */
+				if (!(di->flag & FLG_BCHANNEL_EARLY)) {
+					if (!(di->flag & FLG_BCHANNEL_ACTDELAYED))
+						activate_bchan(di);
+					else
+						di->flag |= FLG_BCHANNEL_DOACTIVE;
+				}
+				/* send a CONNECT_ACKNOWLEDGE */
+				p = msg = buf + mISDN_HEADER_LEN;
+				MsgHead(p, di->cr, MT_CONNECT_ACKNOWLEDGE);
+				len = p - msg;
+				ret = mISDN_write_frame(di->device, buf,
+					di->layer3 | FLG_MSG_DOWN, DL_DATA | REQUEST,
+					0, len, msg, TIMEOUT_1SEC);
+				/* if here is outgoing data, send first part */
+				switch (di->func) {
+					case 0:
+					case 2:
+					case 5:
+						if (di->play > -1)
+							play_msg(di);
+						break;
+					case 1:
+						/* send next after 2 sec */
+						timeout = 2*TIMEOUT_1SEC;
+						di->flag |= FLG_SEND_TONE;
+						break;
+					case 3:
+					case 4:
+						/* setup B after 1 sec */
+						timeout = 1*TIMEOUT_1SEC;
+						break;
+				}
+			} else if ((ret > 19) && (buf[19] == MT_CONNECT_ACKNOWLEDGE) &&
+				(!(di->flag & FLG_CALL_ORGINATE))) {
+				/* We got connect ack, so bring B-channel up */
+				if (!(di->flag & FLG_BCHANNEL_EARLY)) {
+					if (!(di->flag & FLG_BCHANNEL_ACTDELAYED))
+						activate_bchan(di);
+					else
+						di->flag |= FLG_BCHANNEL_DOACTIVE;
+				}
+				/* if here is outgoing data, send first part */
+				switch (di->func) {
+					case 0:
+					case 2:
+					case 5:
+						if (di->play > -1)
+							play_msg(di);
+						break;
+					case 1:
+						/* send next after 2 sec */
+						timeout = 2*TIMEOUT_1SEC;
+						di->flag |= FLG_SEND_TONE;
+						break;
+					case 3:
+					case 4:
+						/* setup B after 1 sec */
+						timeout = 1*TIMEOUT_1SEC;
+						break;
+				}
+			} else if ((ret > 19) && (buf[19] == MT_DISCONNECT)) {
+				/* send a RELEASE */
+				p = msg = buf + mISDN_HEADER_LEN;
+				MsgHead(p, di->cr, MT_RELEASE);
+				len = p - msg;
+				ret = mISDN_write_frame(di->device, buf,
+					di->layer3 | FLG_MSG_DOWN, DL_DATA | REQUEST,
+					0, len, msg, TIMEOUT_1SEC);
+			} else if ((ret > 19) && (buf[19] == MT_RELEASE)) {
+				/* on a disconnecting msg leave loop */
+				/* send a RELEASE_COMPLETE */
+				p = msg = buf + mISDN_HEADER_LEN;
+				MsgHead(p, di->cr, MT_RELEASE_COMPLETE);
+				len = p - msg;
+				ret = mISDN_write_frame(di->device, buf,
+					di->layer3 | FLG_MSG_DOWN, DL_DATA | REQUEST,
+					0, len, msg, TIMEOUT_1SEC);
+				return(2);
+			} else if ((ret > 19) && (buf[19] == MT_RELEASE_COMPLETE)) {
+				/* on a disconnecting msg leave loop */
+				return(1);
+			}
+		}
+	}
+	if (di->flag & FLG_SEND_TONE) {
+		if (di->val) {
+			di->val--;
+			send_touchtone(di, tt_char[di->val]);
+		} else {
+			/* After last tone disconnect */
+			p = msg = buf + mISDN_HEADER_LEN;
+			MsgHead(p, di->cr, MT_DISCONNECT);
+			len = p - msg;
+			ret = mISDN_write_frame(di->device, buf,
+				di->layer3 | FLG_MSG_DOWN, DL_DATA | REQUEST,
+				0, len, msg, TIMEOUT_1SEC);
+			di->flag &= ~FLG_SEND_TONE;
+		}
+		goto start_again;
+	} else if (di->flag & FLG_SEND_DATA) {
+		if (di->play > -1)
+			send_data(di);
+		else
+			di->flag &= ~FLG_SEND_DATA;
+		goto start_again;
+	} else if (di->flag & FLG_BCHANNEL_DOACTIVE) {
+		ret = activate_bchan(di);
+		if (!ret) {
+			fprintf(stdout,"error on activate_bchan\n");
+			return(0);
+		}
+		di->flag &= ~FLG_BCHANNEL_DOACTIVE;
+		/* send next after 1 sec */
+		timeout = 1*TIMEOUT_1SEC;
+		di->flag |= FLG_SEND_DATA;
+		goto start_again;
+	}
+	return(0);
+}
+
+int do_connection(devinfo_t *di) {
+	unsigned char *p, *msg, buf[1024];
+	iframe_t *rfrm;
+	int len, idx, ret = 0;
+	int bchannel;
+
+	rfrm = (iframe_t *)buf;
+
+	if (strlen(di->phonenr)) {
+		di->flag |= FLG_CALL_ORGINATE;
+		di->cr = 0x81;
+		send_SETUP(di, di->si, di->phonenr);
+	}
+	bchannel= -1;
+	/* Wait for a SETUP message or a CALL_PROCEEDING */
+	while ((ret = mISDN_read(di->device, buf, 1024, 3*TIMEOUT_10SEC))) {
+		if (VerifyOn>3)
+			fprintf(stdout,"readloop ret=%d\n", ret);
+		if (ret >= 20) {
+			if (((!(di->flag & FLG_CALL_ORGINATE)) &&
+				(buf[19] == MT_SETUP)) ||
+				((di->flag & FLG_CALL_ORGINATE) &&
+				(buf[19] == MT_CALL_PROCEEDING))) {
+				if (!(di->flag & FLG_CALL_ORGINATE))
+					di->cr = buf[18];
+	 			idx = 20;
+				while (idx<ret) {
+					if (buf[idx] == IE_CHANNEL_ID) {
+						bchannel=buf[idx+2] & 0x3;
+						break;
+					} else if (!(buf[idx] & 0x80)) {
+						/* variable len IE */
+						idx++;
+						idx += buf[idx];
+					}
+					idx++;
+				}
+				break;
+			}
+		}
+	}
+	fprintf(stdout,"bchannel %d\n", bchannel);
+	if (bchannel > 0) {
+		/* setup a B-channel stack */
+		di->used_bchannel = bchannel -1;
+		switch (di->func) {
+			case 5:
+				di->flag |= FLG_BCHANNEL_EARLY;
+			case 0:
+			case 1:
+			case 2:
+			case 3:
+			case 4:
+				ret = setup_bchannel(di);
+				if (ret)
+					di->flag |= FLG_BCHANNEL_SETUP;
+				else {
+					fprintf(stdout,"error on setup_bchannel\n");
+					goto clean_up;
+				}
+				if (di->flag & FLG_BCHANNEL_EARLY) {
+					ret = activate_bchan(di);
+					if (!ret) {
+						fprintf(stdout,"error on activate_bchan\n");
+						goto clean_up;
+					}
+				}
+				break;
+		}
+		if (!(di->flag & FLG_CALL_ORGINATE)) {
+			p = msg = buf + mISDN_HEADER_LEN;
+			MsgHead(p, di->cr, MT_CONNECT);
+			len = p - msg;
+			ret = mISDN_write_frame(di->device, buf,
+				di->layer3 | FLG_MSG_DOWN, DL_DATA | REQUEST,
+				0, len, msg, TIMEOUT_1SEC);
+		}
+		if (!read_mutiplexer(di)) { /* timed out */
+			/* send a RELEASE_COMPLETE */
+			fprintf(stdout,"read_mutiplexer timed out sending RELEASE_COMPLETE\n");
+			p = msg = buf + mISDN_HEADER_LEN;;
+			MsgHead(p, di->cr, MT_RELEASE_COMPLETE);
+			len = p - msg;
+			ret = mISDN_write_frame(di->device, buf,
+				di->layer3 | FLG_MSG_DOWN, DL_DATA | REQUEST,
+				0, len, msg, TIMEOUT_1SEC);
+		}
+		deactivate_bchan(di);
+	} else {
+		fprintf(stdout,"no channel or no connection\n");
+	}
+clean_up:
+	sleep(1);
+	ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_DOWN,
+		DL_RELEASE | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"read ret=%d\n", ret);
+	sleep(1);
+	ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_DOWN,
+		MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"read ret=%d\n", ret);
+	return(0);
+}
+
+
+
+int
+add_dlayer3(devinfo_t *di, int prot)
+{
+	layer_info_t li;
+	stack_info_t si;
+	int lid, stid, ret;
+
+	if (di->layer3) {
+		memset(&si, 0, sizeof(stack_info_t));
+		si.extentions = EXT_STACK_CLONE;
+		si.mgr = -1;
+		si.id = di->d_stid;
+		stid = mISDN_new_stack(di->device, &si);
+		if (stid <= 0) {
+			fprintf(stdout, "clone stack failed ret(%d)\n", stid);
+			return(11);
+		}
+		memset(&li, 0, sizeof(layer_info_t));
+		li.object_id = -1;
+		li.extentions = EXT_INST_CLONE;
+		li.parent = di->layer2;
+		li.st = stid;
+		ret = mISDN_new_layer(di->device, &li);
+		if (ret) {
+			fprintf(stdout, "clone layer failed ret(%d)\n", ret);
+			return(11);
+		}
+		if (!li.clone) {
+			fprintf(stdout, "no cloned id\n");
+			return(11);
+		}
+		di->layer2 = li.clone;
+		di->d_stid = stid;
+	}
+	memset(&li, 0, sizeof(layer_info_t));
+	strcpy(&li.name[0], "user L3");
+	li.object_id = -1;
+	li.extentions = 0;
+	li.pid.protocol[3] = prot;
+	li.pid.layermask = ISDN_LAYER(3);
+	li.st = di->d_stid;
+	ret = mISDN_new_layer(di->device, &li);
+	if (ret)
+		return(12);
+	di->layer3 = li.id;
+	if (VerifyOn>1)
+		fprintf(stdout,"new layer3 id %08x\n", di->layer3);
+	if (!di->layer3)
+		return(13);
+	
+	ret = mISDN_register_layer(di->device, di->d_stid, di->layer3);
+	if (ret) {
+		fprintf(stdout, "register_layer ret(%d)\n", ret);
+		return(14);
+	}
+	lid = mISDN_get_layerid(di->device, di->d_stid, 3);
+	if (lid<0) {
+		fprintf(stdout,"cannot get layer3 (%d)\n", lid);
+		return(15);
+	}
+	di->layer3 = lid;
+#ifdef OBSOLATE
+	/* 
+	 * EXT_IF_CREATE | EXT_IF_EXCLUSIV sorgen dafuer, das wenn die L3
+	 * Schnittstelle schon benutzt ist, eine neue L2 Instanz erzeugt
+	 * wird
+	 */
+   	
+	ii.extentions = EXT_IF_CREATE | EXT_IF_EXCLUSIV;
+	ii.owner = di->layer3;
+	ii.peer = di->layer2;
+	ii.stat = FLG_MSG_DOWN;
+	ret = mISDN_connect(di->device, &ii);
+	if (ret)
+		return(13);
+	ii.owner = di->layer3;
+	ii.stat = FLG_MSG_TARGET | FLG_MSG_DOWN;
+	ret = mISDN_get_interface_info(di->device, &ii);
+	if (ret != 0)
+		return(14);
+	if (ii.peer == di->layer2)
+		fprintf(stdout, "Layer 2 not cloned\n");
+	else
+		fprintf(stdout, "Layer 2 %08x cloned from %08x\n",
+			ii.peer, di->layer2);
+	di->layer2 = ii.peer;
+#endif
+	return(0);
+}
+
+int do_setup(devinfo_t *di) {
+	unsigned char buf[1024];
+	iframe_t *frm = (iframe_t *)buf;
+	int i, ret = 0;
+	stack_info_t *stinf;
+	status_info_t *si;
+
+	di->bl2_prot = ISDN_PID_L2_B_TRANS;
+	di->bl3_prot = ISDN_PID_L3_B_TRANS;
+	switch (di->func) {
+		case 0:
+		case 5:
+			di->bl1_prot = ISDN_PID_L1_B_64TRANS;
+			di->si = 1;
+			break;
+		case 1:
+			di->bl1_prot = ISDN_PID_L1_B_64TRANS;
+			di->bl2_prot = ISDN_PID_L2_B_TRANSDTMF;
+			di->si = 1;
+			di->val= 8; /* send  8 touch tons (7 ... 0) */
+			break;
+		case 2:
+			di->bl1_prot = ISDN_PID_L1_B_64TRANS;
+			di->bl2_prot = ISDN_PID_L2_B_TRANSDTMF;
+			di->si = 1;
+			break;
+		case 3:
+			di->bl1_prot = ISDN_PID_L1_B_64HDLC;
+			di->si = 7;
+			break;
+		case 4:
+			di->bl1_prot = ISDN_PID_L1_B_64HDLC;
+			di->bl2_prot = ISDN_PID_L2_B_X75SLP;
+			di->si = 7;
+			di->flag |= FLG_BCHANNEL_ACTDELAYED;
+			break;
+		default:
+			fprintf(stdout,"unknown program function %d\n",
+				di->func);
+			return(1);
+	}
+
+	ret = mISDN_get_stack_count(di->device);
+	if (VerifyOn>1)
+		fprintf(stdout,"%d stacks found\n", ret);
+	if (ret < di->cardnr) {
+		fprintf(stdout,"cannot config card nr %d only %d cards\n",
+			di->cardnr, ret);
+		return(2);
+	}
+	ret = mISDN_get_stack_info(di->device, di->cardnr, buf, 1024);
+	if (ret<=0) {
+		fprintf(stdout,"cannot get stackinfo err: %d\n", ret);
+		return(3);
+	}
+	stinf = (stack_info_t *)&frm->data.p;
+	if (VerifyOn>1)
+		mISDNprint_stack_info(stdout, stinf);
+	di->d_stid = stinf->id;
+	for (i=0;i<2;i++) {
+		if (stinf->childcnt>i)
+			di->b_stid[i] = stinf->child[i];
+		else
+			di->b_stid[i] = 0;
+	}
+
+	di->layer1 = mISDN_get_layerid(di->device, di->d_stid, 1);
+	if (di->layer1<0) {
+		fprintf(stdout,"cannot get layer1\n");
+		return(4);
+	}
+	if (VerifyOn>1)
+		fprintf(stdout,"layer1 id %08x\n", di->layer1);
+
+	di->layer2 = mISDN_get_layerid(di->device, di->d_stid, 2);
+	if (di->layer2<0) {
+		fprintf(stdout,"cannot get layer2\n");
+		return(5);
+	}
+	if (VerifyOn>1)
+		fprintf(stdout,"layer2 id %08x\n", di->layer2);
+
+	di->layer3 = mISDN_get_layerid(di->device, di->d_stid, 3);
+	if (di->layer3<0) {
+		fprintf(stdout,"cannot get layer3\n");
+		di->layer3 = 0;
+	}
+	if (VerifyOn>1)
+		fprintf(stdout,"layer3 id %08x\n", di->layer3);
+
+
+	ret = add_dlayer3(di, ISDN_PID_L3_DSS1USER);
+	if (ret)
+		return(ret);
+
+	ret = mISDN_get_stack_info(di->device, di->d_stid, buf, 1024);
+	if (ret<=0) {
+		fprintf(stdout,"cannot get stackinfo err: %d\n", ret);
+		return(3);
+	}
+	stinf = (stack_info_t *)&frm->data.p;
+	if (VerifyOn>1)
+		mISDNprint_stack_info(stdout, stinf);
+
+	ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_DOWN,
+		DL_ESTABLISH | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"dl_etablish write ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"dl_etablish read ret=%d\n", ret);
+	if (ret>0) {
+		if (frm->prim != (DL_ESTABLISH | CONFIRM))
+			return(6);
+	} else {
+		fprintf(stdout,"DL_ESTABLISH | REQUEST return(%d)\n", ret);
+		return(7);
+	}
+	ret = mISDN_get_status_info(di->device, di->layer1, buf, 1024);
+	if (ret > mISDN_HEADER_LEN) {
+		si = (status_info_t *)&frm->data.p;
+		mISDNprint_status(stdout, si);
+	} else
+		fprintf(stdout,"mISDN_get_status_info ret(%d)\n", ret);
+	ret = mISDN_get_status_info(di->device, di->layer2, buf, 1024);
+	if (ret > mISDN_HEADER_LEN) {
+		si = (status_info_t *)&frm->data.p;
+		mISDNprint_status(stdout, si);
+	} else
+		fprintf(stdout,"mISDN_get_status_info ret(%d)\n", ret);
+	sleep(1);
+	return(0);
+}
+
+int main(argc,argv)
+int argc;
+char *argv[];
+
+{
+	char FileName[200],FileNameOut[200];
+	int aidx=1,para=1, idx;
+	char sw;
+	devinfo_t mISDN;
+	int err;
+
+	fprintf(stderr,"TestmISDN 1.0\n");
+	strcpy(FileName, "test_file");
+	memset(&mISDN, 0, sizeof(mISDN));
+	mISDN.cardnr = 1;
+	mISDN.func = 0;
+	mISDN.phonenr[0] = 0;
+	if (argc<1) {
+		fprintf(stderr,"Error: Not enough arguments please check\n");
+		usage(argv[0]);
+		exit(1);
+	} else {
+		do {
+			if (argv[aidx] && argv[aidx][0]=='-') {
+				sw=argv[aidx][1];
+				switch (sw) {
+					 case 'v':
+					 case 'V':
+						VerifyOn=1;
+						if (argv[aidx][2]) {
+							VerifyOn=atol(&argv[aidx][2]);
+						}
+						break;
+					case 'c':
+						if (argv[aidx][2]) {
+							mISDN.cardnr=atol(&argv[aidx][2]);
+						}
+						break;
+					case 'F':
+						if (argv[aidx][2]) {
+							mISDN.func=atol(&argv[aidx][2]);
+						}
+						break;
+					case 'n':
+					        if (!argv[aidx][2]) {
+					        	idx = 0;
+							aidx++;
+						} else {
+							idx=2;
+						}
+						if (aidx<=argc) {
+							strcpy(mISDN.phonenr, &argv[aidx][idx]);
+						} else {
+							fprintf(stderr," Switch %c without value\n",sw);
+							exit(1);
+						}
+						break;
+					case '?' :
+						usage(argv[0]);
+						exit(1);
+						break;
+					default  : fprintf(stderr,"Unknown Switch %c\n",sw);
+						usage(argv[0]);
+						exit(1);
+						break;
+				}
+			}  else {
+				if (para==1) {
+					if (argc > 1)
+						strcpy(FileName,argv[aidx]);
+					para++;
+				} else {
+					fprintf(stderr,"Undefined argument %s\n",argv[aidx]);
+					usage(argv[0]);
+					exit(1);
+				}
+			}
+                                   aidx++;
+		} while (aidx<argc);
+	}
+	if (0>(mISDN.device = mISDN_open())) {
+		printf("TestmISDN cannot open mISDN due to %s\n",
+			strerror(errno));
+		return(1);
+	}
+	sprintf(FileNameOut,"%s.out",FileName);
+	sprintf(FileName,"%s.in",FileName);
+	if (0>(mISDN.save = open(FileName, O_WRONLY|O_CREAT|O_TRUNC,S_IRWXU))) {
+		printf("TestmISDN cannot open %s due to %s\n",FileName,
+			strerror(errno));
+		close(mISDN.device);
+		return(1);
+	}
+	if (0>(mISDN.play = open(FileNameOut, O_RDONLY))) {
+		printf("TestmISDN cannot open %s due to %s\n",FileNameOut,
+			strerror(errno));
+		mISDN.play = -1;
+	} else 
+		mISDN.fplay = fdopen(mISDN.play, "r");
+	if (VerifyOn>8)
+		fprintf(stdout,"fileno %d/%d/%d\n",mISDN.save, mISDN.play,
+			mISDN.device);
+	err = do_setup(&mISDN);
+	if (err)
+		fprintf(stdout,"do_setup error %d\n", err);
+	else
+		do_connection(&mISDN);	
+	close(mISDN.save);
+	if (mISDN.play>=0)
+		close(mISDN.play);
+	err=mISDN_close(mISDN.device);
+	if (err)
+		fprintf(stdout,"mISDN_close: error(%d): %s\n", err,
+			strerror(err));
+	
+	return(0);
+}

Added: misdn-user/trunk/example/testcon.in
===================================================================


Property changes on: misdn-user/trunk/example/testcon.in
___________________________________________________________________
Name: svn:executable
   + *

Added: misdn-user/trunk/example/testcon_l2.c
===================================================================
--- misdn-user/trunk/example/testcon_l2.c	                        (rev 0)
+++ misdn-user/trunk/example/testcon_l2.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,873 @@
+/* Beispiel fuer ein L2 B-channel modul statt dem L3 */
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include "mISDNlib.h"
+#include "l3dss1.h"
+
+void usage(pname) 
+char *pname;
+{
+	fprintf(stderr,"Call with %s [options] [filename]\n",pname);
+	fprintf(stderr,"\n");
+	fprintf(stderr,"       filename   filename.in  incoming data\n");
+	fprintf(stderr,"                  filename.out outgoing data\n");
+	fprintf(stderr,"                  data is alaw for voice\n");
+	fprintf(stderr,"\n");
+	fprintf(stderr,"\n     Valid options are:\n");
+	fprintf(stderr,"\n");
+	fprintf(stderr,"  -?              Usage ; printout this information\n");
+	fprintf(stderr,"  -c<n>           use card number n (default 1)\n"); 
+	fprintf(stderr,"  -F<n>           use function n (default 0)\n"); 
+	fprintf(stderr,"                    0 send and recive voice\n"); 
+	fprintf(stderr,"                    1 send touchtones\n"); 
+	fprintf(stderr,"                    2 recive touchtones\n"); 
+	fprintf(stderr,"                    3 send and recive hdlc data\n"); 
+	fprintf(stderr,"                    4 send and recive X75 data\n"); 
+	fprintf(stderr,"                    5 send and recive voice early B connect\n");
+	fprintf(stderr,"  -n <phone nr>   Phonenumber to dial\n");
+	fprintf(stderr,"  -vn             Printing debug info level n\n");
+	fprintf(stderr,"\n");
+}
+
+typedef struct _devinfo {
+	int	device;
+	int	cardnr;
+	int	func;
+	char	phonenr[32];
+	int	d_stid;
+	int	layer1;
+	int	layer2;
+	int	layer3;
+	int	b_stid[2];
+	int	b_adress[2];
+	int	used_bchannel;
+	int	save;
+	int	play;
+	FILE	*fplay;
+	int	flag;
+	int	val;
+	int	cr;
+	int	si;
+	int	bl1_prot;
+	int	bl2_prot;
+	int	bl3_prot;
+} devinfo_t;
+
+#define FLG_SEND_TONE		0x0001
+#define FLG_SEND_DATA		0x0002
+#define FLG_BCHANNEL_SETUP	0x0010
+#define FLG_BCHANNEL_DOACTIVE	0x0020
+#define FLG_BCHANNEL_ACTIVE	0x0040
+#define FLG_BCHANNEL_ACTDELAYED	0x0080
+#define FLG_CALL_ORGINATE	0x0100
+#define FLG_BCHANNEL_EARLY	0x0200
+
+#define MAX_REC_BUF		4000
+#define MAX_DATA_BUF		1024
+
+#define ISDN_PID_L2_B_USER	0x420000ff
+
+static int VerifyOn=0;
+
+char tt_char[]="0123456789ABCD*#";
+
+#define PLAY_SIZE 64
+
+#define	MsgHead(ptr, cref, mty) \
+	*ptr++ = 0x8; \
+	if (cref == -1) { \
+		*ptr++ = 0x0; \
+	} else { \
+		*ptr++ = 0x1; \
+		*ptr++ = cref^0x80; \
+	} \
+	*ptr++ = mty
+
+int play_msg(devinfo_t *di) {
+	unsigned char buf[PLAY_SIZE+mISDN_HEADER_LEN];
+	iframe_t *frm = (iframe_t *)buf;
+	int len, ret;
+	
+	if (di->play<0)
+		return(0);
+	len = read(di->play, buf + mISDN_HEADER_LEN, PLAY_SIZE);
+	if (len<0) {
+		printf("play_msg err %d: \"%s\"\n", errno, strerror(errno));
+		close(di->play);
+		di->play = -1;
+	}
+	
+	frm->addr = di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN;
+	frm->prim = PH_DATA | REQUEST;
+	frm->dinfo = 0;
+	frm->len = len;
+	ret = mISDN_write(di->device, buf, len+mISDN_HEADER_LEN, 8000);
+	if (ret < 0)
+		fprintf(stdout,"play write error %d %s\n", errno, strerror(errno));
+	else if (VerifyOn>3)
+		fprintf(stdout,"play write ret=%d\n", ret);
+	return(ret);
+}
+
+int send_data(devinfo_t *di) {
+	unsigned char buf[MAX_DATA_BUF+mISDN_HEADER_LEN];
+	iframe_t *frm = (iframe_t *)buf;
+	unsigned char *data;
+	int len, ret;
+	
+	if (di->play<0 || !di->fplay)
+		return(0);
+	if (!(data = fgets(buf + mISDN_HEADER_LEN, MAX_DATA_BUF, di->fplay))) {
+		close(di->play);
+		di->play = -1;
+		data = buf + mISDN_HEADER_LEN;
+		data[0] = 4; /* ctrl-D */
+		data[1] = 0;
+	}
+	len = strlen(data);
+	if (len==0) {
+		close(di->play);
+		di->play = -1;
+		data[0] = 4; /* ctrl-D */
+		len = 1;
+	}
+	
+	frm->addr = di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN;
+	frm->prim = PH_DATA | REQUEST;
+	frm->dinfo = 0;
+	frm->len = len;
+	ret = mISDN_write(di->device, buf, len+mISDN_HEADER_LEN, 100000);
+	if (ret < 0)
+		fprintf(stdout,"send_data write error %d %s\n", errno, strerror(errno));
+	else if (VerifyOn>3)
+		fprintf(stdout,"send_data write ret=%d\n", ret);
+	return(ret);
+}
+
+int setup_bchannel(devinfo_t *di) {
+	mISDN_pid_t pid;
+	int ret;
+	layer_info_t li;
+
+
+	if ((di->used_bchannel<0) || (di->used_bchannel>1)) {
+		fprintf(stdout, "wrong channel %d\n", di->used_bchannel);
+		return(0);
+	}
+	memset(&li, 0, sizeof(layer_info_t));
+	strcpy(&li.name[0], "B L2");
+	li.object_id = -1;
+	li.extentions = 0;
+	li.pid.protocol[2] = di->bl2_prot;
+	li.pid.layermask = ISDN_LAYER(2);
+	li.st = di->b_stid[di->used_bchannel];
+	ret = mISDN_new_layer(di->device, &li);
+	if (ret<0) {
+		fprintf(stdout, "new_layer ret(%d)\n", ret);
+		return(0);
+	}
+	if (ret) {
+		di->b_adress[di->used_bchannel] = ret;
+		if (VerifyOn>2)
+			fprintf(stdout,"b_adress%d %08x\n",
+				di->used_bchannel+1, ret);
+		memset(&pid, 0, sizeof(mISDN_pid_t));
+		pid.protocol[1] = di->bl1_prot;
+		pid.protocol[2] = di->bl2_prot;
+//		pid.protocol[3] = di->bl3_prot;
+		pid.layermask = ISDN_LAYER(1) | ISDN_LAYER(2); // | ISDN_LAYER(3);
+		if (di->flag & FLG_CALL_ORGINATE)
+			pid.global = 1;
+		ret = mISDN_set_stack(di->device,
+			di->b_stid[di->used_bchannel], &pid);
+		if (ret) {
+			fprintf(stdout, "set_stack ret(%d)\n", ret);
+			return(0);
+		}
+		ret = di->b_adress[di->used_bchannel];
+	}
+	return(ret);
+}
+
+int send_SETUP(devinfo_t *di, int SI, char *PNr) {
+	unsigned char *np, *p, *msg, buf[1024];
+	int len, ret;
+
+	p = msg = buf + mISDN_HEADER_LEN;
+	MsgHead(p, di->cr, MT_SETUP);
+	*p++ = 0xa1; /* complete indicator */
+	*p++ = IE_BEARER;
+	if (SI == 1) { /* Audio */
+		*p++ = 0x3;	/* Length                               */
+		*p++ = 0x90;	/* Coding Std. CCITT, 3.1 kHz audio     */
+		*p++ = 0x90;	/* Circuit-Mode 64kbps                  */
+		*p++ = 0xa3;	/* A-Law Audio                          */
+	} else { /* default Datatransmission 64k */
+		*p++ = 0x2;	/* Length                               */
+		*p++ = 0x88;	/* Coding Std. CCITT, unrestr. dig. Inf */
+		*p++ = 0x90;	/* Circuit-Mode 64kbps                  */
+	}
+	*p++ = IE_CALLED_PN;
+	np = PNr;
+	*p++ = strlen(np) + 1;
+	/* Classify as AnyPref. */
+	*p++ = 0x81;		/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
+	while (*np)
+		*p++ = *np++ & 0x7f;
+	len = p - msg;
+	ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN,
+		DL_DATA | REQUEST, 0, len, msg, TIMEOUT_1SEC);
+	return(ret);
+}
+
+int activate_bchan(devinfo_t *di) {
+	unsigned char buf[128];
+	iframe_t *rfrm;
+	int ret;
+
+	ret = mISDN_write_frame(di->device, buf,
+		di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN,
+		PH_ACTIVATE | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"PH_ACTIVATE write ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 128, TIMEOUT_10SEC); 	
+	if (VerifyOn>3)
+		fprintf(stdout,"PH_ACTIVATE read ret=%d\n", ret);
+	rfrm = (iframe_t *)buf;
+	if (ret>0) {
+		if (rfrm->prim == (PH_ACTIVATE | CONFIRM)) {
+			di->flag |= FLG_BCHANNEL_ACTIVE;
+		}
+	}
+	return(ret);
+}
+
+int deactivate_bchan(devinfo_t *di) {
+	unsigned char buf[128];
+	int ret;
+
+	ret = mISDN_write_frame(di->device, buf,
+		di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN,
+		DL_RELEASE | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"DL_RELEASE write ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 128, TIMEOUT_10SEC); 	
+	if (VerifyOn>3)
+		fprintf(stdout,"DL_RELEASE read ret=%d\n", ret);
+	di->flag &= ~FLG_BCHANNEL_ACTIVE;
+	di->flag &= ~FLG_BCHANNEL_SETUP;
+	ret = mISDN_clear_stack(di->device, di->b_stid[di->used_bchannel]);
+	if (VerifyOn>3)
+		fprintf(stdout,"clear_stack ret=%d\n", ret);
+	return(ret);
+}
+
+int send_touchtone(devinfo_t *di, int tone) {
+	iframe_t frm;
+	int tval, ret;
+
+	if (VerifyOn>1)
+		fprintf(stdout,"send_touchtone %c\n", DTMF_TONE_MASK & tone);
+	tval = DTMF_TONE_VAL | tone;
+	ret = mISDN_write_frame(di->device, &frm,
+		di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN,
+		PH_CONTROL | REQUEST, 0, 4, &tval, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"tt send ret=%d\n", ret);
+	return(ret);
+}
+
+int read_mutiplexer(devinfo_t *di) {
+	unsigned char	*p, *msg, buf[MAX_REC_BUF];
+	iframe_t	*rfrm;
+	int		timeout = TIMEOUT_10SEC;
+	int		ret = 0;
+	int		len;
+
+	rfrm = (iframe_t *)buf;
+	/* Main loop */
+
+start_again:
+	while ((ret = mISDN_read(di->device, buf, MAX_REC_BUF, timeout))) {
+		if (VerifyOn>3)
+			fprintf(stdout,"readloop ret=%d\n", ret);
+		if (ret >= 16) {
+			if (VerifyOn>4)
+				fprintf(stdout,"readloop addr(%x) prim(%x) len(%d)\n",
+					rfrm->addr, rfrm->prim, rfrm->len);
+			if (rfrm->addr == (di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN)) {
+				/* B-Channel related messages */
+				if (rfrm->prim == (PH_DATA | INDICATION)) {
+					/* received data, save it */
+					write(di->save, &rfrm->data.i, rfrm->len);
+				} else if (rfrm->prim == (PH_DATA | CONFIRM)) {
+					/* get ACK of send data, so we can
+					 * send more
+					 */
+					if (VerifyOn>5)
+						fprintf(stdout,"PH_DATA_CNF\n");
+					switch (di->func) {
+						case 0:
+						case 2:
+							if (di->play > -1)
+								play_msg(di);
+							break;
+					}
+				} else if (rfrm->prim == (PH_CONTROL | INDICATION)) {
+					if ((rfrm->len == 4) &&
+						((rfrm->data.i & ~DTMF_TONE_MASK)
+						== DTMF_TONE_VAL)) {
+						fprintf(stdout,"GOT TT %c\n",
+							DTMF_TONE_MASK & rfrm->data.i);
+					} else
+						fprintf(stdout,"unknown PH_CONTROL len %d/val %x\n",
+							rfrm->len, rfrm->data.i);
+				}
+			/* D-Channel related messages */  
+			} else if ((ret > 19) && (buf[19] == MT_CONNECT) &&
+				(di->flag & FLG_CALL_ORGINATE)) {
+				/* We got connect, so bring B-channel up */
+				if (!(di->flag & FLG_BCHANNEL_EARLY)) {
+					if (!(di->flag & FLG_BCHANNEL_ACTDELAYED))
+						activate_bchan(di);
+					else
+						di->flag |= FLG_BCHANNEL_DOACTIVE;
+				}
+				/* send a CONNECT_ACKNOWLEDGE */
+				p = msg = buf + mISDN_HEADER_LEN;
+				MsgHead(p, di->cr, MT_CONNECT_ACKNOWLEDGE);
+				len = p - msg;
+				ret = mISDN_write_frame(di->device, buf,
+					di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
+					0, len, msg, TIMEOUT_1SEC);
+				/* if here is outgoing data, send first part */
+				switch (di->func) {
+					case 0:
+					case 2:
+					case 5:
+						if (di->play > -1)
+							play_msg(di);
+						break;
+					case 1:
+						/* send next after 2 sec */
+						timeout = 2*TIMEOUT_1SEC;
+						di->flag |= FLG_SEND_TONE;
+						break;
+					case 3:
+					case 4:
+						/* setup B after 1 sec */
+						timeout = 1*TIMEOUT_1SEC;
+						break;
+				}
+			} else if ((ret > 19) && (buf[19] == MT_CONNECT_ACKNOWLEDGE) &&
+				(!(di->flag & FLG_CALL_ORGINATE))) {
+				/* We got connect ack, so bring B-channel up */
+				if (!(di->flag & FLG_BCHANNEL_EARLY)) {
+					if (!(di->flag & FLG_BCHANNEL_ACTDELAYED))
+						activate_bchan(di);
+					else
+						di->flag |= FLG_BCHANNEL_DOACTIVE;
+				}
+				/* if here is outgoing data, send first part */
+				switch (di->func) {
+					case 0:
+					case 2:
+					case 5:
+						if (di->play > -1)
+							play_msg(di);
+						break;
+					case 1:
+						/* send next after 2 sec */
+						timeout = 2*TIMEOUT_1SEC;
+						di->flag |= FLG_SEND_TONE;
+						break;
+					case 3:
+					case 4:
+						/* setup B after 1 sec */
+						timeout = 1*TIMEOUT_1SEC;
+						break;
+				}
+			} else if ((ret > 19) && (buf[19] == MT_DISCONNECT)) {
+				/* send a RELEASE */
+				p = msg = buf + mISDN_HEADER_LEN;
+				MsgHead(p, di->cr, MT_RELEASE);
+				len = p - msg;
+				ret = mISDN_write_frame(di->device, buf,
+					di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
+					0, len, msg, TIMEOUT_1SEC);
+			} else if ((ret > 19) && (buf[19] == MT_RELEASE)) {
+				/* on a disconnecting msg leave loop */
+				/* send a RELEASE_COMPLETE */
+				p = msg = buf + mISDN_HEADER_LEN;
+				MsgHead(p, di->cr, MT_RELEASE_COMPLETE);
+				len = p - msg;
+				ret = mISDN_write_frame(di->device, buf,
+					di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
+					0, len, msg, TIMEOUT_1SEC);
+				return(2);
+			} else if ((ret > 19) && (buf[19] == MT_RELEASE_COMPLETE)) {
+				/* on a disconnecting msg leave loop */
+				return(1);
+			}
+		}
+	}
+	if (di->flag & FLG_SEND_TONE) {
+		if (di->val) {
+			di->val--;
+			send_touchtone(di, tt_char[di->val]);
+		} else {
+			/* After last tone disconnect */
+			p = msg = buf + mISDN_HEADER_LEN;
+			MsgHead(p, di->cr, MT_DISCONNECT);
+			len = p - msg;
+			ret = mISDN_write_frame(di->device, buf,
+				di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
+				0, len, msg, TIMEOUT_1SEC);
+			di->flag &= ~FLG_SEND_TONE;
+		}
+		goto start_again;
+	} else if (di->flag & FLG_SEND_DATA) {
+		if (di->play > -1)
+			send_data(di);
+		else
+			di->flag &= ~FLG_SEND_DATA;
+		goto start_again;
+	} else if (di->flag & FLG_BCHANNEL_DOACTIVE) {
+		ret = activate_bchan(di);
+		if (!ret) {
+			fprintf(stdout,"error on activate_bchan\n");
+			return(0);
+		}
+		di->flag &= ~FLG_BCHANNEL_DOACTIVE;
+		/* send next after 1 sec */
+		timeout = 1*TIMEOUT_1SEC;
+		di->flag |= FLG_SEND_DATA;
+		goto start_again;
+	}
+	return(0);
+}
+
+int do_connection(devinfo_t *di) {
+	unsigned char *p, *msg, buf[1024];
+	iframe_t *rfrm;
+	int len, idx, ret = 0;
+	int bchannel;
+
+	rfrm = (iframe_t *)buf;
+
+	if (strlen(di->phonenr)) {
+		di->flag |= FLG_CALL_ORGINATE;
+		di->cr = 0x81;
+		send_SETUP(di, di->si, di->phonenr);
+	}
+	bchannel= -1;
+	/* Wait for a SETUP message or a CALL_PROCEEDING */
+	while ((ret = mISDN_read(di->device, buf, 1024, 3*TIMEOUT_10SEC))) {
+		if (VerifyOn>3)
+			fprintf(stdout,"readloop ret=%d\n", ret);
+		if (ret >= 20) {
+			if (((!(di->flag & FLG_CALL_ORGINATE)) &&
+				(buf[19] == MT_SETUP)) ||
+				((di->flag & FLG_CALL_ORGINATE) &&
+				(buf[19] == MT_CALL_PROCEEDING))) {
+				if (!(di->flag & FLG_CALL_ORGINATE))
+					di->cr = buf[18];
+	 			idx = 20;
+				while (idx<ret) {
+					if (buf[idx] == IE_CHANNEL_ID) {
+						bchannel=buf[idx+2] & 0x3;
+						break;
+					} else if (!(buf[idx] & 0x80)) {
+						/* variable len IE */
+						idx++;
+						idx += buf[idx];
+					}
+					idx++;
+				}
+				break;
+			}
+		}
+	}
+	fprintf(stdout,"bchannel %d\n", bchannel);
+	if (bchannel > 0) {
+		/* setup a B-channel stack */
+		di->used_bchannel = bchannel -1;
+		switch (di->func) {
+			case 5:
+				di->flag |= FLG_BCHANNEL_EARLY;
+			case 0:
+			case 1:
+			case 2:
+			case 3:
+			case 4:
+				ret = setup_bchannel(di);
+				if (ret)
+					di->flag |= FLG_BCHANNEL_SETUP;
+				else {
+					fprintf(stdout,"error on setup_bchannel\n");
+					goto clean_up;
+				}
+				if (di->flag & FLG_BCHANNEL_EARLY) {
+					ret = activate_bchan(di);
+					if (!ret) {
+						fprintf(stdout,"error on activate_bchan\n");
+						goto clean_up;
+					}
+				}
+				break;
+		}
+		if (!(di->flag & FLG_CALL_ORGINATE)) {
+			p = msg = buf + mISDN_HEADER_LEN;
+			MsgHead(p, di->cr, MT_CONNECT);
+			len = p - msg;
+			ret = mISDN_write_frame(di->device, buf,
+				di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
+				0, len, msg, TIMEOUT_1SEC);
+		}
+		if (!read_mutiplexer(di)) { /* timed out */
+			/* send a RELEASE_COMPLETE */
+			fprintf(stdout,"read_mutiplexer timed out sending RELEASE_COMPLETE\n");
+			p = msg = buf + mISDN_HEADER_LEN;;
+			MsgHead(p, di->cr, MT_RELEASE_COMPLETE);
+			len = p - msg;
+			ret = mISDN_write_frame(di->device, buf,
+				di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
+				0, len, msg, TIMEOUT_1SEC);
+		}
+		deactivate_bchan(di);
+	} else {
+		fprintf(stdout,"no channel or no connection\n");
+	}
+clean_up:
+	sleep(1);
+	ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN,
+		DL_RELEASE | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"read ret=%d\n", ret);
+	sleep(1);
+	ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN,
+		MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"read ret=%d\n", ret);
+	return(0);
+}
+
+
+
+int
+add_dlayer3(devinfo_t *di, int prot)
+{
+	layer_info_t li;
+	stack_info_t si;
+#ifdef OBSOLETE
+	interface_info_t ii;
+#endif
+	int ret;
+
+	if (di->layer3) {
+		memset(&si, 0, sizeof(stack_info_t));
+		si.extentions = EXT_STACK_CLONE;
+		si.mgr = -1;
+		si.id = di->d_stid;
+		ret = mISDN_new_stack(di->device, &si);
+		if (ret <= 0) {
+			fprintf(stdout, "clone stack failed ret(%d)\n", ret);
+			return(11);
+		}
+		di->d_stid = ret;
+	}
+	memset(&li, 0, sizeof(layer_info_t));
+	strcpy(&li.name[0], "user L3");
+	li.object_id = -1;
+	li.extentions = 0;
+	li.pid.protocol[3] = prot;
+	li.pid.layermask = ISDN_LAYER(3);
+	li.st = di->d_stid;
+	ret = mISDN_new_layer(di->device, &li);
+	if (ret<0)
+		return(12);
+	di->layer3 = li.id;
+	if (!di->layer3)
+		return(13);
+	
+#ifdef OBSOLETE
+	/* 
+	 * EXT_IF_CREATE | EXT_IF_EXCLUSIV sorgen dafuer, das wenn die L3
+	 * Schnittstelle schon benutzt ist, eine neue L2 Instanz erzeugt
+	 * wird
+	 */
+   	
+	ii.extentions = EXT_IF_CREATE | EXT_IF_EXCLUSIV;
+	ii.owner = di->layer3;
+	ii.peer = di->layer2;
+	ii.stat = FLG_MSG_TARGET | FLG_MSG_DOWN;
+	ret = mISDN_connect(di->device, &ii);
+	if (ret)
+		return(13);
+	ii.owner = di->layer3;
+	ii.stat = FLG_MSG_TARGET | FLG_MSG_DOWN;
+	ret = mISDN_get_interface_info(di->device, &ii);
+	if (ret != 0)
+		return(14);
+	if (ii.peer == di->layer2)
+		fprintf(stdout, "Layer 2 not cloned\n");
+	else
+		fprintf(stdout, "Layer 2 %08x cloned from %08x\n",
+			ii.peer, di->layer2);
+	di->layer2 = ii.peer;
+#endif
+	return(0);
+}
+
+int do_setup(devinfo_t *di) {
+	unsigned char buf[1024];
+	iframe_t *frm = (iframe_t *)buf;
+	int i, ret = 0;
+	stack_info_t *stinf;
+	status_info_t *si;
+
+	di->bl2_prot = ISDN_PID_L2_B_USER;
+	di->bl3_prot = ISDN_PID_L3_B_TRANS;
+	switch (di->func) {
+		case 0:
+		case 5:
+			di->bl1_prot = ISDN_PID_L1_B_64TRANS;
+			di->si = 1;
+			break;
+		case 1:
+			di->bl1_prot = ISDN_PID_L1_B_64TRANS;
+			di->bl2_prot = ISDN_PID_L2_B_TRANSDTMF;
+			di->si = 1;
+			di->val= 8; /* send  8 touch tons (7 ... 0) */
+			break;
+		case 2:
+			di->bl1_prot = ISDN_PID_L1_B_64TRANS;
+			di->bl2_prot = ISDN_PID_L2_B_TRANSDTMF;
+			di->si = 1;
+			break;
+		case 3:
+			di->bl1_prot = ISDN_PID_L1_B_64HDLC;
+			di->si = 7;
+			break;
+		case 4:
+			fprintf(stdout,"X.75 not supported with L2 user\n");
+			return(1);
+		default:
+			fprintf(stdout,"unknown program function %d\n",
+				di->func);
+			return(1);
+	}
+
+	ret = mISDN_get_stack_count(di->device);
+	if (VerifyOn>1)
+		fprintf(stdout,"%d stacks found\n", ret);
+	if (ret < di->cardnr) {
+		fprintf(stdout,"cannot config card nr %d only %d cards\n",
+			di->cardnr, ret);
+		return(2);
+	}
+	ret = mISDN_get_stack_info(di->device, di->cardnr, buf, 1024);
+	if (ret<=0) {
+		fprintf(stdout,"cannot get stackinfo err: %d\n", ret);
+		return(3);
+	}
+	stinf = (stack_info_t *)&frm->data.p;
+	if (VerifyOn>1)
+		mISDNprint_stack_info(stdout, stinf);
+	di->d_stid = stinf->id;
+	for (i=0;i<2;i++) {
+		if (stinf->childcnt>i)
+			di->b_stid[i] = stinf->child[i];
+		else
+			di->b_stid[i] = 0;
+	}
+
+	di->layer1 = mISDN_get_layerid(di->device, di->d_stid, 1);
+	if (di->layer1<0) {
+		fprintf(stdout,"cannot get layer1\n");
+		return(4);
+	}
+	if (VerifyOn>1)
+		fprintf(stdout,"layer1 id %08x\n", di->layer1);
+
+	di->layer2 = mISDN_get_layerid(di->device, di->d_stid, 2);
+	if (di->layer2<0) {
+		fprintf(stdout,"cannot get layer2\n");
+		return(5);
+	}
+	if (VerifyOn>1)
+		fprintf(stdout,"layer2 id %08x\n", di->layer2);
+
+	di->layer3 = mISDN_get_layerid(di->device, di->d_stid, 3);
+	if (di->layer3<0) {
+		fprintf(stdout,"cannot get layer3\n");
+		di->layer3 = 0;
+	}
+	if (VerifyOn>1)
+		fprintf(stdout,"layer3 id %08x\n", di->layer3);
+
+
+	ret = add_dlayer3(di, ISDN_PID_L3_DSS1USER);
+	if (ret)
+		return(ret);
+	ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN,
+		DL_ESTABLISH | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"dl_etablish write ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"dl_etablish read ret=%d\n", ret);
+	if (ret>0) {
+		if (frm->prim != (DL_ESTABLISH | CONFIRM))
+			return(6);
+	} else {
+		fprintf(stdout,"DL_ESTABLISH | REQUEST return(%d)\n", ret);
+		return(7);
+	}
+	ret = mISDN_get_status_info(di->device, di->layer1, buf, 1024);
+	if (ret > mISDN_HEADER_LEN) {
+		si = (status_info_t *)&frm->data.p;
+		mISDNprint_status(stdout, si);
+	} else
+		fprintf(stdout,"mISDN_get_status_info ret(%d)\n", ret);
+	ret = mISDN_get_status_info(di->device, di->layer2, buf, 1024);
+	if (ret > mISDN_HEADER_LEN) {
+		si = (status_info_t *)&frm->data.p;
+		mISDNprint_status(stdout, si);
+	} else
+		fprintf(stdout,"mISDN_get_status_info ret(%d)\n", ret);
+	sleep(1);
+	return(0);
+}
+
+int main(argc,argv)
+int argc;
+char *argv[];
+
+{
+	char FileName[200],FileNameOut[200];
+	int aidx=1,para=1, idx;
+	char sw;
+	devinfo_t mISDN;
+	int err;
+
+	fprintf(stderr,"TestmISDN 1.0\n");
+	strcpy(FileName, "test_file");
+	memset(&mISDN, 0, sizeof(mISDN));
+	mISDN.cardnr = 1;
+	mISDN.func = 0;
+	mISDN.phonenr[0] = 0;
+	if (argc<1) {
+		fprintf(stderr,"Error: Not enough arguments please check\n");
+		usage(argv[0]);
+		exit(1);
+	} else {
+		do {
+			if (argv[aidx] && argv[aidx][0]=='-') {
+				sw=argv[aidx][1];
+				switch (sw) {
+					 case 'v':
+					 case 'V':
+						VerifyOn=1;
+						if (argv[aidx][2]) {
+							VerifyOn=atol(&argv[aidx][2]);
+						}
+						break;
+					case 'c':
+						if (argv[aidx][2]) {
+							mISDN.cardnr=atol(&argv[aidx][2]);
+						}
+						break;
+					case 'F':
+						if (argv[aidx][2]) {
+							mISDN.func=atol(&argv[aidx][2]);
+						}
+						break;
+					case 'n':
+					        if (!argv[aidx][2]) {
+					        	idx = 0;
+							aidx++;
+						} else {
+							idx=2;
+						}
+						if (aidx<=argc) {
+							strcpy(mISDN.phonenr, &argv[aidx][idx]);
+						} else {
+							fprintf(stderr," Switch %c without value\n",sw);
+							exit(1);
+						}
+						break;
+					case '?' :
+						usage(argv[0]);
+						exit(1);
+						break;
+					default  : fprintf(stderr,"Unknown Switch %c\n",sw);
+						usage(argv[0]);
+						exit(1);
+						break;
+				}
+			}  else {
+				if (para==1) {
+					if (argc > 1)
+						strcpy(FileName,argv[aidx]);
+					para++;
+				} else {
+					fprintf(stderr,"Undefined argument %s\n",argv[aidx]);
+					usage(argv[0]);
+					exit(1);
+				}
+			}
+                                   aidx++;
+		} while (aidx<argc);
+	}
+	if (0>(mISDN.device = mISDN_open())) {
+		printf("TestmISDN cannot open mISDN due to %s\n",
+			strerror(errno));
+		return(1);
+	}
+	sprintf(FileNameOut,"%s.out",FileName);
+	sprintf(FileName,"%s.in",FileName);
+	if (0>(mISDN.save = open(FileName, O_WRONLY|O_CREAT|O_TRUNC,S_IRWXU))) {
+		printf("TestmISDN cannot open %s due to %s\n",FileName,
+			strerror(errno));
+		close(mISDN.device);
+		return(1);
+	}
+	if (0>(mISDN.play = open(FileNameOut, O_RDONLY))) {
+		printf("TestmISDN cannot open %s due to %s\n",FileNameOut,
+			strerror(errno));
+		mISDN.play = -1;
+	} else 
+		mISDN.fplay = fdopen(mISDN.play, "r");
+	if (VerifyOn>8)
+		fprintf(stdout,"fileno %d/%d/%d\n",mISDN.save, mISDN.play,
+			mISDN.device);
+	err = do_setup(&mISDN);
+	if (err)
+		fprintf(stdout,"do_setup error %d\n", err);
+	else
+		do_connection(&mISDN);	
+	close(mISDN.save);
+	if (mISDN.play>=0)
+		close(mISDN.play);
+	err=mISDN_close(mISDN.device);
+	if (err)
+		fprintf(stdout,"mISDN_close: error(%d): %s\n", err,
+			strerror(err));
+	
+	return(0);
+}

Added: misdn-user/trunk/example/testlayer1.c
===================================================================
--- misdn-user/trunk/example/testlayer1.c	                        (rev 0)
+++ misdn-user/trunk/example/testlayer1.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,358 @@
+/*
+	Sample code to act as a userland dummy layer2
+	and communicate with Layer1
+	
+	(use layermask=3 to ensure your stack just 
+	consists of Layer0+Layer1)
+*/
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/time.h>
+#include "mISDNlib.h"
+
+void usage(pname) 
+char *pname;
+{
+	fprintf(stderr, "Call with %s [options]\n",pname);
+	fprintf(stderr, "\n");
+	fprintf(stderr, "\n     Valid options are:\n");
+	fprintf(stderr, "\n");
+	fprintf(stderr, "  -?              Usage ; printout this information\n");
+	fprintf(stderr, "  -c<n>           use card number n (default 1)\n"); 
+	fprintf(stderr, "  -vn             Printing debug info level n\n");
+	fprintf(stderr, "\n");
+}
+
+typedef struct _devinfo {
+	int	device;
+	int	cardnr;
+	int	func;
+	int	d_stid;
+	int	b_stid[2];
+	int	layer1;
+	int	layer2;
+	int	unconfirmed;
+} devinfo_t;
+
+
+static int VerifyOn=1;
+static devinfo_t mISDN;
+
+
+void sig_handler(int sig)
+{
+	int err;
+	fprintf(stdout, "exiting...\n");
+        err = mISDN_close(mISDN.device);
+        fprintf(stdout, "mISDN_close: error(%d): %s\n", err,
+        	strerror(err));
+	exit(0);
+}
+                        
+                        
+void set_signals()
+{
+        /* Set up the signal handler */
+        signal(SIGHUP, sig_handler);
+        signal(SIGINT, sig_handler);
+        signal(SIGTERM, sig_handler);
+}
+ 
+#define TICKS_PER_SEC 1000000
+long get_tick_count(void)
+{
+	struct timeval tp;
+
+	gettimeofday(&tp, 0);
+	return ((unsigned)tp.tv_sec)*TICKS_PER_SEC+((unsigned)tp.tv_usec);
+}
+
+
+/* create userland layer2 */
+int
+add_dlayer2(devinfo_t *di)
+{
+	layer_info_t li;
+	int ret, lid;
+
+	memset(&li, 0, sizeof(layer_info_t));
+	strcpy(&li.name[0], "user L2");
+	li.object_id = -1;
+	li.extentions = 0;
+	li.pid.protocol[2] = ISDN_PID_L2_LAPD;
+	li.pid.layermask = ISDN_LAYER(2);
+	li.st = di->d_stid;
+	ret = mISDN_new_layer(di->device, &li);
+	if (ret<0)
+		return(12);
+	
+	di->layer2 = li.id;
+	
+	ret = mISDN_register_layer(di->device, di->d_stid, di->layer2);
+        if (ret) {
+                fprintf(stdout, "register_layer ret(%d)\n", ret);
+                return(14);
+        }	
+        
+        lid = mISDN_get_layerid(di->device, di->d_stid, 2);
+	if (lid<0) {
+		fprintf(stdout, "cannot get layer2 (%d)\n", lid);
+		return(15);
+	}
+	di->layer2 = lid;
+                                                     
+	if (!di->layer2)
+		return(13);
+	
+	return(0);
+}
+
+int do_setup(devinfo_t *di)
+{
+	unsigned char buf[2048];
+	iframe_t *frm = (iframe_t *)buf;
+	int i, ret = 0;
+	stack_info_t *stinf;
+	long t1;
+
+	ret = mISDN_get_stack_count(di->device);
+	if (VerifyOn>1)
+		fprintf(stdout, "%d stacks found\n", ret);
+	if (ret < di->cardnr) {
+		fprintf(stdout, "cannot config card nr %d only %d cards\n",
+			di->cardnr, ret);
+		return(2);
+	}
+	ret = mISDN_get_stack_info(di->device, di->cardnr, buf, 2048);
+	if (ret<=0) {
+		fprintf(stdout, "cannot get stackinfo err: %d\n", ret);
+		return(3);
+	}
+	stinf = (stack_info_t *)&frm->data.p;
+	if (VerifyOn>1)
+		mISDNprint_stack_info(stdout, stinf);
+	di->d_stid = stinf->id;
+	for (i=0;i<2;i++) {
+		if (stinf->childcnt>i)
+			di->b_stid[i] = stinf->child[i];
+		else
+			di->b_stid[i] = 0;
+	}
+
+	di->layer1 = mISDN_get_layerid(di->device, di->d_stid, 1);
+	if (di->layer1<0) {
+		fprintf(stdout, "cannot get layer1\n");
+		return(4);
+	}
+	if (VerifyOn>1)
+		fprintf(stdout, "layer1 id %08x\n", di->layer1);
+
+	/* make sure this stack just consists of layer0 + layer1 */
+	di->layer2 = mISDN_get_layerid(di->device, di->d_stid, 2);
+	if (di->layer2 > 0) {
+		fprintf(stdout, "layer2 found (%i), use layermask=3\n", di->layer2);
+		return(5);
+	}
+
+	ret = add_dlayer2(di);
+	if (ret) {
+		fprintf(stdout, "add_dlayer2 failed\n");
+		return(ret);
+	} else {
+		fprintf(stdout, "created new User-Layer2: 0x%x\n", di->layer2);
+	}
+
+	fprintf(stdout, "sending PH_ACTIVATE | REQUEST to layer1...\n");
+	ret = mISDN_write_frame(di->device, buf, di->layer2 | FLG_MSG_DOWN,
+		PH_ACTIVATE | REQUEST, 0, 0, NULL, 0);
+
+	// wait for PH_ACTIVATE | INDICATION or CONFIRM
+	t1 = get_tick_count();
+	while (1) { 
+
+		ret = mISDN_read(di->device, buf, 2048, 0);
+		
+		if (ret > 0) {
+			if ((frm->prim == (PH_ACTIVATE | CONFIRM)) ||
+			    (frm->prim == (PH_ACTIVATE | INDICATION))) {
+				fprintf(stdout, "layer1 activated (0x%x)\n", frm->prim);
+				return(0);
+			}
+			
+			/*
+			if (frm->prim == (MGR_SHORTSTATUS | INDICATION)) {
+				fprintf(stdout, "got MGR_SHORTSTATUS | INDICATION\n");
+			}
+			fprintf(stdout, "got (0x%x), still waiting for PH_ACTIVATE | CONFIRM/INDICATION...\n", frm->prim);
+			*/
+		}
+		
+		if ((get_tick_count() - t1)  > (TICKS_PER_SEC * 5)) {
+			printf(stdout, "unable to activate layer1 (TIMEOUT)\n");
+			return(6);
+		}
+	}
+
+	return(7);
+}
+	
+
+int printhexdata(FILE *f, int len, u_char *p)
+{
+        while(len--) {
+        	fprintf(f, "0x%02x", *p++);
+        	if (len)
+        		fprintf(f, " ");
+	}
+	fprintf(f, "\n");
+	return(0);
+}
+
+
+                                
+
+void main_data_loop(devinfo_t *di)
+{
+	long t1;
+	unsigned char buf[2048];
+	unsigned char tx_buf[2048];
+		
+        iframe_t *frm = (iframe_t *)buf;
+        int ret, i;
+        
+        t1 = get_tick_count();
+	
+        printf ("waiting for data (use CTRL-C to cancel)...\n");
+        while (1)  {
+        	/* read data */
+        	ret = mISDN_read(di->device, buf, 2048, 0);
+        	if (ret >= mISDN_HEADER_LEN) {
+        		
+        		switch(frm->prim) {
+        			case (PH_DATA | INDICATION) :
+        				// layer1 gives rx frame
+        				printf ("(PH_DATA | INDICATION) : \n\t");
+					printhexdata(stdout, frm->len, buf + mISDN_HEADER_LEN);
+					break;
+					
+				case (PH_DATA | CONFIRM) :
+					// layer1 confirmes tx frame
+					di->unconfirmed--;
+					break;
+				default:
+					printf ("unhandled prim(0x%x) len(0x%x)\n", frm->prim, frm->len);
+        		}
+        	}
+        	
+        	/* write data */
+        	if ((get_tick_count()-t1) > TICKS_PER_SEC) {
+        		printf(".\n");
+
+        		i=0;
+
+        		/* send fake d-channel frame, here Tei request */
+			tx_buf[i++] = 0xfC;
+			tx_buf[i++] = 0xff;
+			tx_buf[i++] = 0x03;
+			tx_buf[i++] = 0x0f;
+			tx_buf[i++] = 0xe9;
+			tx_buf[i++] = 0x69;
+			tx_buf[i++] = 0x01;
+			tx_buf[i++] = 0xff;
+
+			ret = mISDN_write_frame(di->device, buf, di->layer2 | FLG_MSG_DOWN,
+				PH_DATA | REQUEST, 0, 8, tx_buf, 10);
+			if (ret>0) {
+				fprintf(stdout,"unable to send data (0x%x)\n", ret);
+			} else {
+				di->unconfirmed++;
+			}
+        		
+        		t1 = get_tick_count();
+        	}
+	}
+}
+        
+
+int main(argc,argv)
+int argc;
+char *argv[]; 
+{
+	int aidx=1;
+	char sw;
+	int err;
+
+	fprintf(stdout,"\n\nTest-L1 $Revision: 1.3 $\n");
+	memset(&mISDN, 0, sizeof(mISDN));
+	mISDN.cardnr = 1;
+	mISDN.func = 0;
+	if (argc<1) {
+		fprintf(stderr,"Error: Not enough arguments please check\n");
+		usage(argv[0]);
+		exit(1);
+	} else {
+		do {
+			if (argv[aidx] && argv[aidx][0]=='-') {
+				sw=argv[aidx][1];
+				switch (sw) {
+					 case 'v':
+					 case 'V':
+						VerifyOn=1;
+						if (argv[aidx][2]) {
+							VerifyOn=atol(&argv[aidx][2]);
+						}
+						break;
+					case 'c':
+						if (argv[aidx][2]) {
+							mISDN.cardnr=atol(&argv[aidx][2]);
+						}
+						break;
+					case 'F':
+						if (argv[aidx][2]) {
+							mISDN.func=atol(&argv[aidx][2]);
+						}
+						break;
+					case '?' :
+						usage(argv[0]);
+						exit(1);
+						break;
+					default  : fprintf(stderr,"Unknown Switch %c\n",sw);
+						usage(argv[0]);
+						exit(1);
+						break;
+				}
+			} 
+                        aidx++;
+		} while (aidx<argc);
+	}
+	if (0>(mISDN.device = mISDN_open())) {
+		printf("TestmISDN cannot open mISDN due to %s\n",
+			strerror(errno));
+		return(1);
+	}
+	
+	set_signals();
+	err = do_setup(&mISDN);
+	if (err) {
+		fprintf(stdout, "do_setup error %d\n", err);
+		return(0);
+	}
+
+	main_data_loop(&mISDN);
+
+	err=mISDN_close(mISDN.device);
+	if (err)
+		fprintf(stdout,"mISDN_close: error(%d): %s\n", err,
+			strerror(err));
+	
+	return(0);
+}

Added: misdn-user/trunk/example/testlayer3.c
===================================================================
--- misdn-user/trunk/example/testlayer3.c	                        (rev 0)
+++ misdn-user/trunk/example/testlayer3.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,1112 @@
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include "mISDNlib.h"
+#include "l3dss1.h"
+
+void usage(pname) 
+char *pname;
+{
+	fprintf(stderr,"Call with %s [options] [filename]\n",pname);
+	fprintf(stderr,"\n");
+	fprintf(stderr,"       filename   filename.in  incoming data\n");
+	fprintf(stderr,"                  filename.out outgoing data\n");
+	fprintf(stderr,"                  data is alaw for voice\n");
+	fprintf(stderr,"\n");
+	fprintf(stderr,"\n     Valid options are:\n");
+	fprintf(stderr,"\n");
+	fprintf(stderr,"  -?              Usage ; printout this information\n");
+	fprintf(stderr,"  -c<n>           use card number n (default 1)\n"); 
+	fprintf(stderr,"  -F<n>           use function n (default 0)\n"); 
+	fprintf(stderr,"                    0 send and recive voice\n"); 
+	fprintf(stderr,"                    1 send touchtones\n"); 
+	fprintf(stderr,"                    2 recive touchtones\n"); 
+	fprintf(stderr,"                    3 send and recive hdlc data\n"); 
+	fprintf(stderr,"                    4 send and recive X75 data\n"); 
+	fprintf(stderr,"                    5 send and recive voice early B connect\n");
+	fprintf(stderr,"  -n <phone nr>   Phonenumber to dial\n");
+	fprintf(stderr,"  -vn             Printing debug info level n\n");
+	fprintf(stderr,"\n");
+}
+
+typedef struct _devinfo {
+	int	device;
+	int	cardnr;
+	int	func;
+	char	phonenr[32];
+	u_int	d_stid;
+	u_int	layer1;
+	u_int	layer2;
+	u_int	layer3;
+	u_int	layer4;
+	u_int	l3_id;
+	u_int	idcnt;
+	u_int	entity;
+	u_int	b_stid[2];
+	u_int	b_adress[2];
+	u_int	b_l2[2];
+	int	used_bchannel;
+	int	save;
+	int	play;
+	FILE	*fplay;
+	int	flag;
+	int	val;
+	int	si;
+	u_int	bl1_prot;
+	u_int	bl2_prot;
+	u_int	bl3_prot;
+} devinfo_t;
+
+#define FLG_SEND_TONE		0x0001
+#define FLG_SEND_DATA		0x0002
+#define FLG_BCHANNEL_SETUP	0x0010
+#define FLG_BCHANNEL_DOACTIVE	0x0020
+#define FLG_BCHANNEL_ACTIVE	0x0040
+#define FLG_BCHANNEL_ACTDELAYED	0x0080
+#define FLG_CALL_ORGINATE	0x0100
+#define FLG_BCHANNEL_EARLY	0x0200
+
+
+#define MAX_REC_BUF		4000
+#define MAX_DATA_BUF		1024
+
+static int VerifyOn=0;
+static char tt_char[] = "0123456789ABCD*#";
+
+#define PLAY_SIZE 64
+
+/* this should be moved into library context */
+#ifndef MOVED_TO_LIB
+static signed char _mISDN_l3_ie2pos[128] = {
+			-1,-1,-1,-1, 0,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,
+			 2,-1,-1,-1, 3,-1,-1,-1, 4,-1,-1,-1, 5,-1, 6,-1,
+			 7,-1,-1,-1,-1,-1,-1, 8, 9,10,-1,-1,11,-1,-1,-1,
+			-1,-1,-1,-1,12,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+			13,-1,14,15,16,17,18,19,-1,-1,-1,-1,20,21,-1,-1,
+			-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+			-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,22,23,-1,-1,
+			24,25,-1,-1,26,-1,-1,-1,27,28,-1,-1,29,30,31,-1
+};
+			
+static unsigned char _mISDN_l3_pos2ie[32] = {
+			0x04, 0x08, 0x10, 0x14, 0x18, 0x1c, 0x1e, 0x20,
+			0x27, 0x28, 0x29, 0x2c, 0x34, 0x40, 0x42, 0x43,
+			0x44, 0x45, 0x46, 0x47, 0x4c, 0x4d, 0x6c, 0x6d,
+			0x70, 0x71, 0x74, 0x78, 0x79, 0x7c, 0x7d, 0x7e
+};
+
+signed int
+mISDN_l3_ie2pos(u_char c)
+{
+	if (c>0x7f)
+		return(-1);
+	return(_mISDN_l3_ie2pos[c]);
+}
+
+unsigned char
+mISDN_l3_pos2ie(int pos)
+{
+	return(_mISDN_l3_pos2ie[pos]);
+}
+
+void
+mISDN_initQ931_info(Q931_info_t *qi) {
+	memset(qi, 0, sizeof(Q931_info_t));
+};
+
+int mISDN_get_free_ext_ie(Q931_info_t *qi)
+{
+	int	i;
+
+	for (i = 0; i < 8; i++) {
+		if (qi->ext[i].ie.off == 0)
+			return(i);
+	}
+	return (-1);
+}
+
+int
+mISDN_AddvarIE(Q931_info_t *qi, u_char *p, u_char *ie)
+{
+	u_char		*ps;
+	ie_info_t	*ies;
+	int		l;
+
+	ies = &qi->bearer_capability;
+	ps = (u_char *) qi;
+	ps += L3_EXTRA_SIZE;
+	if (*ie & 0x80) { /* one octett IE */
+		if (*ie == IE_MORE_DATA)
+			ies = &qi->more_data;
+		else if (*ie == IE_COMPLETE)
+			ies = &qi->sending_complete;
+		else if ((*ie & 0xf0) == IE_CONGESTION)
+			ies = &qi->congestion_level;
+		else {
+			return(-1);
+		}
+		l = 1;
+	} else {
+		if (_mISDN_l3_ie2pos[*ie]<0) {
+			return(-2);
+		}
+		ies += _mISDN_l3_ie2pos[*ie];
+		if (ies->off) {
+			while (ies->repeated)
+				ies = &qi->ext[ies->ridx].ie;;
+			l = mISDN_get_free_ext_ie(qi);
+			if (l < 0) { // overflow
+				return(-3);
+			}
+			ies->ridx = l;
+			ies->repeated = 1;
+			ies = &qi->ext[l].ie;
+			ies->cs_flg = 0;
+			qi->ext[l].v.codeset = 0;
+			qi->ext[l].v.val = *ie;
+		}
+		l = ie[1] + 2;
+	}
+	ies->off = (u16)(p - ps);
+	memcpy(p, ie, l);
+	return(l);
+}
+
+int
+mISDN_AddIE(Q931_info_t *qi, u_char *p, u_char ie, u_char *iep)
+{
+	u_char		*ps;
+	ie_info_t	*ies;
+	int		l;
+
+	if (ie & 0x80) { /* one octett IE */
+		if (ie == IE_MORE_DATA)
+			ies = &qi->more_data;
+		else if (ie == IE_COMPLETE)
+			ies = &qi->sending_complete;
+		else if ((ie & 0xf0) == IE_CONGESTION)
+			ies = &qi->congestion_level;
+		else {
+			return(-1);
+		}
+		l = 0;
+	} else {
+		if (!iep || !iep[0])
+			return(-3);
+		ies = &qi->bearer_capability;
+		if (_mISDN_l3_ie2pos[ie]<0) {
+			return(-2);
+		}
+		ies += _mISDN_l3_ie2pos[ie];
+		if (ies->off) {
+			while (ies->repeated)
+				ies = &qi->ext[ies->ridx].ie;;
+			l = mISDN_get_free_ext_ie(qi);
+			if (l < 0) { // overflow
+				return(-3);
+			}
+			ies->ridx = l;
+			ies->repeated = 1;
+			ies = &qi->ext[l].ie;
+			ies->cs_flg = 0;
+			qi->ext[l].v.codeset = 0;
+			qi->ext[l].v.val = ie;
+		}
+		l = iep[0] + 1;
+	}
+	ps = (u_char *) qi;
+	ps += L3_EXTRA_SIZE;
+	ies->off = (u16)(p - ps);
+	*p++ = ie;
+	if (l)
+		memcpy(p, iep, l);
+	return(l+1);
+}
+#endif /* MOVED_TO_LIB */
+
+int play_msg(devinfo_t *di) {
+	unsigned char buf[PLAY_SIZE+mISDN_HEADER_LEN];
+	iframe_t *frm = (iframe_t *)buf;
+	int len, ret;
+	
+	if (di->play<0)
+		return(0);
+	len = read(di->play, buf + mISDN_HEADER_LEN, PLAY_SIZE);
+	if (len<0) {
+		printf("play_msg err %d: \"%s\"\n", errno, strerror(errno));
+		close(di->play);
+		di->play = -1;
+	}
+	
+	frm->addr = di->b_adress[di->used_bchannel] | FLG_MSG_DOWN;
+	frm->prim = DL_DATA | REQUEST;
+	frm->dinfo = 0;
+	frm->len = len;
+	ret = mISDN_write(di->device, buf, len+mISDN_HEADER_LEN, 8000);
+	if (ret < 0)
+		fprintf(stdout,"play write error %d %s\n", errno, strerror(errno));
+	else if (VerifyOn>3)
+		fprintf(stdout,"play write ret=%d\n", ret);
+	return(ret);
+}
+
+int send_data(devinfo_t *di) {
+	char buf[MAX_DATA_BUF+mISDN_HEADER_LEN];
+	iframe_t *frm = (iframe_t *)buf;
+	char *data;
+	int len, ret;
+	
+	if (di->play<0 || !di->fplay)
+		return(0);
+	if (!(data = fgets(buf + mISDN_HEADER_LEN, MAX_DATA_BUF, di->fplay))) {
+		close(di->play);
+		di->play = -1;
+		data = buf + mISDN_HEADER_LEN;
+		data[0] = 4; /* ctrl-D */
+		data[1] = 0;
+	}
+	len = strlen(data);
+	if (len==0) {
+		close(di->play);
+		di->play = -1;
+		data[0] = 4; /* ctrl-D */
+		len = 1;
+	}
+	
+	frm->addr = di->b_adress[di->used_bchannel] | FLG_MSG_DOWN;
+	frm->prim = DL_DATA | REQUEST;
+	frm->dinfo = 0;
+	frm->len = len;
+	ret = mISDN_write(di->device, buf, len+mISDN_HEADER_LEN, 100000);
+	if (ret < 0)
+		fprintf(stdout,"send_data write error %d %s\n", errno, strerror(errno));
+	else if (VerifyOn>3)
+		fprintf(stdout,"send_data write ret=%d\n", ret);
+	return(ret);
+}
+
+int setup_bchannel(devinfo_t *di) {
+	mISDN_pid_t pid;
+	int ret;
+	layer_info_t li;
+
+	if ((di->used_bchannel<0) || (di->used_bchannel>1)) {
+		fprintf(stdout, "wrong channel %d\n", di->used_bchannel);
+		return(0);
+	}
+	memset(&li, 0, sizeof(layer_info_t));
+	strcpy(&li.name[0], "B L3");
+	li.object_id = -1;
+	li.extentions = 0;
+	li.pid.protocol[3] = di->bl3_prot;
+	li.pid.layermask = ISDN_LAYER(3);
+	li.st = di->b_stid[di->used_bchannel];
+	ret = mISDN_new_layer(di->device, &li);
+	if (ret) {
+		fprintf(stdout, "new_layer ret(%d)\n", ret);
+		return(0);
+	}
+	if (li.id) {
+		di->b_adress[di->used_bchannel] = li.id;
+		if (VerifyOn>2)
+			fprintf(stdout,"b_adress%d %08x\n",
+				di->used_bchannel+1, ret);
+		memset(&pid, 0, sizeof(mISDN_pid_t));
+		pid.protocol[1] = di->bl1_prot;
+		pid.protocol[2] = di->bl2_prot;
+		pid.protocol[3] = di->bl3_prot;
+		pid.layermask = ISDN_LAYER(1) | ISDN_LAYER(2)| ISDN_LAYER(3);
+		if (di->flag & FLG_CALL_ORGINATE)
+			pid.global = 1;
+		ret = mISDN_set_stack(di->device, di->b_stid[di->used_bchannel], &pid);
+		if (ret) {
+			fprintf(stdout, "set_stack ret(%d)\n", ret);
+			return(0);
+		}
+		/* Wait until the stack is really available */
+		ret = mISDN_get_setstack_ind(di->device, di->b_adress[di->used_bchannel]);
+		if (ret) {
+			fprintf(stdout, "get_setstack_ind ret (%d)\n", ret);
+			return(0);
+		}
+		/* get the registered id of the b3 layer */
+		ret = mISDN_get_layerid(di->device, di->b_stid[di->used_bchannel], 3);
+		if (ret <= 0) {
+			fprintf(stdout, "get_layerid b3 ret(%d)\n", ret);
+			return(0);
+		}
+		di->b_adress[di->used_bchannel] = ret;
+		/* get the registered id of the b2  layer */
+		ret = mISDN_get_layerid(di->device, di->b_stid[di->used_bchannel], 2);
+		if (ret > 0)
+			di->b_l2[di->used_bchannel] = ret;
+		fprintf(stdout, "b_l2 id %08x\n", ret);
+	} else
+		ret = 0;
+	return(ret);
+}
+
+int send_SETUP(devinfo_t *di, int SI, char *PNr) {
+	unsigned char *np, *p, *msg, buf[1024],ie[64];
+	Q931_info_t *qi;
+	int len, ret;
+
+	di->idcnt++;
+	if (di->idcnt >0x7fff)
+		di->idcnt = 1;
+	di->l3_id = (di->entity << 16) | di->idcnt;
+	ret = mISDN_write_frame(di->device, buf, di->layer4 | FLG_MSG_DOWN,
+		CC_NEW_CR | REQUEST, di->l3_id, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"CC_NEW_CR | REQUEST l3_id %x ret=%d\n", di->l3_id, ret);
+	p = msg = buf + mISDN_HEADER_LEN;
+	qi = (Q931_info_t *)p;
+	mISDN_initQ931_info(qi);
+	qi->type = MT_SETUP;
+	p += L3_EXTRA_SIZE;
+	p++; /* needed to avoid offset 0 in IE array */
+	len = mISDN_AddIE(qi, p, IE_COMPLETE, NULL);
+	if (len<0) {
+		fprintf(stdout,"Add IE_COMPLETE error %d\n", len);
+		return(len);
+	}
+	p += len;
+	if (SI == 1) { /* Audio */
+		len = mISDN_AddIE(qi, p, IE_BEARER, (unsigned char*)"\x3\x90\x90\xa3");
+	} else { /* default Datatransmission 64k */
+		len = mISDN_AddIE(qi, p, IE_BEARER, (unsigned char*)"\x2\x88\x90");
+	}
+	if (len<0) {
+		fprintf(stdout,"Add IE_BEARER error %d\n", len);
+		return(len);
+	}
+	p += len;
+	np = ie;
+	*np++ = strlen(PNr) + 1;
+	/* Classify as AnyPref. */
+	*np++ = 0x81;            /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
+	while (*PNr)
+		*np++ = *PNr++ & 0x7f;
+	len = mISDN_AddIE(qi, p, IE_CALLED_PN, ie);
+	if (len<0) {
+		fprintf(stdout,"Add IE_CALLED_PNerror %d\n", len);
+		return(len);
+	}
+	p += len;
+	len = p - msg;
+	ret = mISDN_write_frame(di->device, buf, di->layer4 | FLG_MSG_DOWN,
+		CC_SETUP | REQUEST, di->l3_id, len, msg, TIMEOUT_1SEC);
+	return(ret);
+}
+
+int activate_bchan(devinfo_t *di) {
+	unsigned char buf[128];
+	iframe_t *rfrm;
+	int ret;
+
+	ret = mISDN_write_frame(di->device, buf,
+		di->b_adress[di->used_bchannel] | FLG_MSG_DOWN,
+		DL_ESTABLISH | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"DL_ESTABLISH write ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 128, TIMEOUT_10SEC); 	
+	if (VerifyOn>3)
+		fprintf(stdout,"DL_ESTABLISH read ret=%d\n", ret);
+	rfrm = (iframe_t *)buf;
+	if (ret>0) {
+		if (rfrm->prim == (DL_ESTABLISH | CONFIRM)) {
+			di->flag |= FLG_BCHANNEL_ACTIVE;
+		}
+	}
+	return(ret);
+}
+
+int deactivate_bchan(devinfo_t *di) {
+	unsigned char buf[128];
+	int ret;
+
+	ret = mISDN_write_frame(di->device, buf,
+		di->b_adress[di->used_bchannel] | FLG_MSG_DOWN,
+		DL_RELEASE | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"DL_RELEASE write ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 128, TIMEOUT_10SEC); 	
+	if (VerifyOn>3)
+		fprintf(stdout,"DL_RELEASE read ret=%d\n", ret);
+	di->flag &= ~FLG_BCHANNEL_ACTIVE;
+	di->flag &= ~FLG_BCHANNEL_SETUP;
+	ret = mISDN_clear_stack(di->device, di->b_stid[di->used_bchannel]);
+	if (VerifyOn>3)
+		fprintf(stdout,"clear_stack ret=%d\n", ret);
+	ret = mISDN_write_frame(di->device, buf, di->b_adress[di->used_bchannel] | FLG_MSG_DOWN,
+		MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"ret=%d\n", ret);
+	ret = mISDN_write_frame(di->device, buf, di->b_l2[di->used_bchannel] | FLG_MSG_DOWN,
+		MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"ret=%d\n", ret);
+	return(ret);
+}
+
+int send_touchtone(devinfo_t *di, int tone) {
+	iframe_t frm;
+	int tval, ret;
+
+	if (VerifyOn>1)
+		fprintf(stdout,"send_touchtone %c\n", DTMF_TONE_MASK & tone);
+	tval = DTMF_TONE_VAL | tone;
+	ret = mISDN_write_frame(di->device, &frm,
+		di->b_adress[di->used_bchannel] | FLG_MSG_DOWN,
+		PH_CONTROL | REQUEST, 0, 4, &tval, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"tt send ret=%d\n", ret);
+	return(ret);
+}
+
+int read_mutiplexer(devinfo_t *di) {
+	unsigned char	buf[MAX_REC_BUF];
+	iframe_t	*rfrm;
+	int		timeout = TIMEOUT_10SEC;
+	int		ret = 0;
+
+	rfrm = (iframe_t *)buf;
+	/* Main loop */
+
+start_again:
+	while ((ret = mISDN_read(di->device, buf, MAX_REC_BUF, timeout))) {
+		if (VerifyOn>3)
+			fprintf(stdout,"readloop ret=%d\n", ret);
+		if (ret >= 16) {
+			if (VerifyOn>4)
+				fprintf(stdout,"readloop addr(%x) prim(%x) len(%d)\n",
+					rfrm->addr, rfrm->prim, rfrm->len);
+			if (rfrm->addr == (di->b_l2[di->used_bchannel] | FLG_MSG_UP)) {
+				/* B-Channel related messages */
+				if (rfrm->prim == (DL_DATA | INDICATION)) {
+					/* received data, save it */
+					write(di->save, &rfrm->data.i, rfrm->len);
+				} else if (rfrm->prim == (DL_DATA | CONFIRM)) {
+					/* get ACK of send data, so we can
+					 * send more
+					 */
+					if (VerifyOn>5)
+						fprintf(stdout,"DL_DATA_CNF\n");
+					switch (di->func) {
+						case 0:
+						case 2:
+							if (di->play > -1)
+								play_msg(di);
+							break;
+					}
+				} else if (rfrm->prim == (PH_CONTROL | INDICATION)) {
+					if ((rfrm->len == 4) &&
+						((rfrm->data.i & ~DTMF_TONE_MASK)
+						== DTMF_TONE_VAL)) {
+						fprintf(stdout,"GOT TT %c\n",
+							DTMF_TONE_MASK & rfrm->data.i);
+					} else
+						fprintf(stdout,"unknown PH_CONTROL len %d/val %x\n",
+							rfrm->len, rfrm->data.i);
+				}
+			/* D-Channel related messages */  
+			} else if ((rfrm->prim == (CC_CONNECT | INDICATION)) &&
+				(di->flag & FLG_CALL_ORGINATE)) {
+				/* We got connect, so bring B-channel up */
+				if (!(di->flag & FLG_BCHANNEL_EARLY)) {
+					if (!(di->flag & FLG_BCHANNEL_ACTDELAYED))
+						activate_bchan(di);
+					else
+						di->flag |= FLG_BCHANNEL_DOACTIVE;
+				}
+				/* send a CONNECT_ACKNOWLEDGE */
+				switch (di->func) {
+					case 0:
+					case 2:
+					case 5:
+						if (di->play > -1)
+							play_msg(di);
+						break;
+					case 1:
+						/* send next after 2 sec */
+						timeout = 2*TIMEOUT_1SEC;
+						di->flag |= FLG_SEND_TONE;
+						break;
+					case 3:
+					case 4:
+						/* setup B after 1 sec */
+						timeout = 1*TIMEOUT_1SEC;
+						break;
+				}
+			} else if ((rfrm->prim == (CC_CONNECT_ACKNOWLEDGE | INDICATION)) &&
+				(!(di->flag & FLG_CALL_ORGINATE))) {
+				/* We got connect ack, so bring B-channel up */
+				if (!(di->flag & FLG_BCHANNEL_EARLY)) {
+					if (!(di->flag & FLG_BCHANNEL_ACTDELAYED))
+						activate_bchan(di);
+					else
+						di->flag |= FLG_BCHANNEL_DOACTIVE;
+				}
+				/* if here is outgoing data, send first part */
+				switch (di->func) {
+					case 0:
+					case 2:
+					case 5:
+						if (di->play > -1)
+							play_msg(di);
+						break;
+					case 1:
+						/* send next after 2 sec */
+						timeout = 2*TIMEOUT_1SEC;
+						di->flag |= FLG_SEND_TONE;
+						break;
+					case 3:
+					case 4:
+						/* setup B after 1 sec */
+						timeout = 1*TIMEOUT_1SEC;
+						break;
+				}
+			} else if (rfrm->prim == (CC_DISCONNECT | INDICATION)) {
+				/* send a RELEASE */
+				ret = mISDN_write_frame(di->device, buf,
+					di->layer4 | FLG_MSG_DOWN, CC_RELEASE | REQUEST,
+					di->l3_id, 0, NULL, TIMEOUT_1SEC);
+			} else if (rfrm->prim == (CC_RELEASE | INDICATION)) {
+				/* on a disconnecting msg leave loop */
+				return(2);
+			} else if (rfrm->prim == (CC_RELEASE_COMPLETE | INDICATION)) {
+				/* on a disconnecting msg leave loop */
+				return(1);
+			}
+		}
+	}
+	if (di->flag & FLG_SEND_TONE) {
+		if (di->val) {
+			di->val--;
+			send_touchtone(di, tt_char[di->val]);
+		} else {
+			/* After last tone disconnect */
+			ret = mISDN_write_frame(di->device, buf,
+				di->layer4 | FLG_MSG_DOWN, CC_DISCONNECT | REQUEST,
+				di->l3_id, 0, NULL, TIMEOUT_1SEC);
+			di->flag &= ~FLG_SEND_TONE;
+		}
+		goto start_again;
+	} else if (di->flag & FLG_SEND_DATA) {
+		if (di->play > -1)
+			send_data(di);
+		else
+			di->flag &= ~FLG_SEND_DATA;
+		goto start_again;
+	} else if (di->flag & FLG_BCHANNEL_DOACTIVE) {
+		ret = activate_bchan(di);
+		if (!ret) {
+			fprintf(stdout,"error on activate_bchan\n");
+			return(0);
+		}
+		di->flag &= ~FLG_BCHANNEL_DOACTIVE;
+		/* send next after 1 sec */
+		timeout = 1*TIMEOUT_1SEC;
+		di->flag |= FLG_SEND_DATA;
+		goto start_again;
+	}
+	return(0);
+}
+
+int do_connection(devinfo_t *di) {
+	unsigned char *p, buf[1024];
+	iframe_t *rfrm;
+	Q931_info_t	*qi;
+	int ret = 0;
+	int bchannel;
+
+	rfrm = (iframe_t *)buf;
+
+	if (strlen(di->phonenr)) {
+		di->flag |= FLG_CALL_ORGINATE;
+//		di->cr = 0x81;
+		ret = send_SETUP(di, di->si, di->phonenr);
+		if (ret) {
+			return(1);
+		}
+	}
+	bchannel= -1;
+	/* Wait for a SETUP message or a CALL_PROCEEDING */
+	while ((ret = mISDN_read(di->device, buf, 1024, 3*TIMEOUT_10SEC))) {
+		if (VerifyOn>3)
+			fprintf(stdout,"readloop ret=%d addr(%08x) prim=%x dinfo=%x\n",
+				ret, rfrm->addr, rfrm->prim, rfrm->dinfo);
+		if (ret >= 16) {
+			if ((!(di->flag & FLG_CALL_ORGINATE)) &&
+				(rfrm->prim == (CC_NEW_CR | INDICATION))) {
+				di->l3_id = rfrm->dinfo;
+				if (VerifyOn>3)
+					fprintf(stdout,"new layer3 process id %x\n", di->l3_id);
+			} else if (((!(di->flag & FLG_CALL_ORGINATE)) && (rfrm->prim == (CC_SETUP | INDICATION))) ||
+				((di->flag & FLG_CALL_ORGINATE) && (rfrm->prim == (CC_PROCEEDING | INDICATION)))) {
+				p = buf + mISDN_HEADER_LEN;
+				qi = (Q931_info_t *)p;
+				p += L3_EXTRA_SIZE;
+				if (qi->channel_id.off > 0) {
+					bchannel = p[qi->channel_id.off + 2] & 0x3;
+				} else {
+					fprintf(stdout,"no bchannel IE found\n");
+					return(2);
+				}
+				break;
+			}
+		}
+	}
+	fprintf(stdout,"bchannel %d\n", bchannel);
+	if (bchannel > 0) {
+		/* setup a B-channel stack */
+		di->used_bchannel = bchannel -1;
+		switch (di->func) {
+			case 5:
+				di->flag |= FLG_BCHANNEL_EARLY;
+			case 0:
+			case 1:
+			case 2:
+			case 3:
+			case 4:
+				ret = setup_bchannel(di);
+				if (ret)
+					di->flag |= FLG_BCHANNEL_SETUP;
+				else {
+					fprintf(stdout,"error on setup_bchannel\n");
+					goto clean_up;
+				}
+				if (di->flag & FLG_BCHANNEL_EARLY) {
+					ret = activate_bchan(di);
+					if (!ret) {
+						fprintf(stdout,"error on activate_bchan\n");
+						goto clean_up;
+					}
+				}
+				break;
+		}
+		if (!(di->flag & FLG_CALL_ORGINATE)) {
+			ret = mISDN_write_frame(di->device, buf,
+				di->layer4 | FLG_MSG_DOWN, CC_CONNECT | REQUEST,
+				di->l3_id, 0, NULL, TIMEOUT_1SEC);
+		}
+		if (!read_mutiplexer(di)) { /* timed out */
+			/* send a RELEASE_COMPLETE */
+			fprintf(stdout,"read_mutiplexer timed out sending RELEASE_COMPLETE\n");
+			ret = mISDN_write_frame(di->device, buf,
+				di->layer4 | FLG_MSG_DOWN, CC_RELEASE_COMPLETE | REQUEST,
+				di->l3_id, 0, NULL, TIMEOUT_1SEC);
+		}
+		deactivate_bchan(di);
+	} else {
+		fprintf(stdout,"no channel or no connection\n");
+	}
+clean_up:
+	sleep(1);
+	ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_DOWN,
+		DL_RELEASE | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"read ret=%d\n", ret);
+	sleep(1);
+	ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_DOWN,
+		MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"read ret=%d\n", ret);
+	ret = mISDN_write_frame(di->device, buf, di->layer3,
+		MGR_DELENTITY | REQUEST, di->entity, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"MGR_DELENTITY | REQUEST ret=%d\n", ret);
+	while((ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC))) {
+		if (VerifyOn>3)
+			fprintf(stdout,"MGR_DELENTITY | REQUEST read ret=%d\n", ret);
+		if (rfrm->prim == (MGR_DELENTITY | CONFIRM)) {
+			if (VerifyOn>4)
+				fprintf(stdout,"entity(%x) removed\n", di->entity);
+			break;
+		} else {
+			if (VerifyOn)
+				fprintf(stdout,"read prim %x instead of MGR_DELENTITY | CONFIRM (%x)\n",
+					rfrm->prim, (MGR_DELENTITY | CONFIRM));
+		}
+	}
+	if (!ret) {
+		fprintf(stdout,"MGR_DELENTITY | REQUEST read timed out\n");
+		return(6);
+	}
+	return(0);
+}
+
+
+
+int
+add_dlayer4(devinfo_t *di, int prot)
+{
+	layer_info_t li;
+	stack_info_t si;
+	int lid, stid, ret;
+
+	if (di->layer4) {
+		memset(&si, 0, sizeof(stack_info_t));
+		si.extentions = EXT_STACK_CLONE;
+		si.mgr = -1;
+		si.id = di->d_stid;
+		stid = mISDN_new_stack(di->device, &si);
+		if (stid <= 0) {
+			fprintf(stdout, "clone stack failed ret(%d)\n", stid);
+			return(11);
+		}
+		memset(&li, 0, sizeof(layer_info_t));
+		li.object_id = -1;
+		li.extentions = EXT_INST_CLONE;
+		li.parent = di->layer2;
+		li.st = stid;
+		ret = mISDN_new_layer(di->device, &li);
+		if (ret) {
+			fprintf(stdout, "clone layer failed ret(%d)\n", ret);
+			return(11);
+		}
+		if (!li.clone) {
+			fprintf(stdout, "no cloned id\n");
+			return(11);
+		}
+		di->layer2 = li.clone;
+		di->layer3 = 0;
+		di->d_stid = stid;
+	}
+	if (!di->layer3) {
+		/* search for DSS1 */
+		fprintf(stdout, "currently L3 must already exist\n");
+		return (12); /* currently not implemented */
+	}
+	memset(&li, 0, sizeof(layer_info_t));
+	strcpy(&li.name[0], "user L4");
+	li.object_id = -1;
+	li.extentions = 0;
+	li.pid.protocol[4] = prot;
+	li.pid.layermask = ISDN_LAYER(4);
+	li.st = di->d_stid;
+	ret = mISDN_new_layer(di->device, &li);
+	if (ret)
+		return(12);
+	di->layer4 = li.id;
+	if (VerifyOn>1)
+		fprintf(stdout,"new layer3 id %08x\n", di->layer4);
+	if (!di->layer4)
+		return(13);
+	
+	ret = mISDN_register_layer(di->device, di->d_stid, di->layer4);
+	if (ret) {
+		fprintf(stdout, "register_layer ret(%d)\n", ret);
+		return(14);
+	}
+	lid = mISDN_get_layerid(di->device, di->d_stid, 3);
+	if (lid<0) {
+		fprintf(stdout,"cannot get layer3 (%d)\n", lid);
+		return(15);
+	}
+	di->layer3 = lid;
+	lid = mISDN_get_layerid(di->device, di->d_stid, 4);
+	if (lid<0) {
+		fprintf(stdout,"cannot get layer4 (%d)\n", lid);
+		return(16);
+	}
+	di->layer4 = lid;
+	return(0);
+}
+
+int do_setup(devinfo_t *di) {
+	unsigned char buf[1024];
+	iframe_t *frm = (iframe_t *)buf;
+	int i, ret = 0;
+	stack_info_t *stinf;
+//	status_info_t *si;
+
+	di->bl2_prot = ISDN_PID_L2_B_TRANS;
+	di->bl3_prot = ISDN_PID_L3_B_TRANS;
+	switch (di->func) {
+		case 0:
+		case 5:
+			di->bl1_prot = ISDN_PID_L1_B_64TRANS;
+			di->si = 1;
+			break;
+		case 1:
+			di->bl1_prot = ISDN_PID_L1_B_64TRANS;
+			di->bl2_prot = ISDN_PID_L2_B_TRANSDTMF;
+			di->si = 1;
+			di->val= 8; /* send  8 touch tons (7 ... 0) */
+			break;
+		case 2:
+			di->bl1_prot = ISDN_PID_L1_B_64TRANS;
+			di->bl2_prot = ISDN_PID_L2_B_TRANSDTMF;
+			di->si = 1;
+			break;
+		case 3:
+			di->bl1_prot = ISDN_PID_L1_B_64HDLC;
+			di->si = 7;
+			break;
+		case 4:
+			di->bl1_prot = ISDN_PID_L1_B_64HDLC;
+			di->bl2_prot = ISDN_PID_L2_B_X75SLP;
+			di->si = 7;
+			di->flag |= FLG_BCHANNEL_ACTDELAYED;
+			break;
+		default:
+			fprintf(stdout,"unknown program function %d\n",
+				di->func);
+			return(1);
+	}
+
+	ret = mISDN_get_stack_count(di->device);
+	if (VerifyOn>1)
+		fprintf(stdout,"%d stacks found\n", ret);
+	if (ret < di->cardnr) {
+		fprintf(stdout,"cannot config card nr %d only %d cards\n",
+			di->cardnr, ret);
+		return(2);
+	}
+	ret = mISDN_get_stack_info(di->device, di->cardnr, buf, 1024);
+	if (ret<=0) {
+		fprintf(stdout,"cannot get stackinfo err: %d\n", ret);
+		return(3);
+	}
+	stinf = (stack_info_t *)&frm->data.p;
+	if (VerifyOn>1)
+		mISDNprint_stack_info(stdout, stinf);
+	di->d_stid = stinf->id;
+	for (i=0;i<2;i++) {
+		if (stinf->childcnt>i)
+			di->b_stid[i] = stinf->child[i];
+		else
+			di->b_stid[i] = 0;
+	}
+
+	di->layer1 = mISDN_get_layerid(di->device, di->d_stid, 1);
+	if (di->layer1<0) {
+		fprintf(stdout,"cannot get layer1\n");
+		return(4);
+	}
+	if (VerifyOn>1)
+		fprintf(stdout,"layer1 id %08x\n", di->layer1);
+
+	di->layer2 = mISDN_get_layerid(di->device, di->d_stid, 2);
+	if (di->layer2<0) {
+		fprintf(stdout,"cannot get layer2\n");
+		return(5);
+	}
+	if (VerifyOn>1)
+		fprintf(stdout,"layer2 id %08x\n", di->layer2);
+
+	di->layer3 = mISDN_get_layerid(di->device, di->d_stid, 3);
+	if (di->layer3<0) {
+		fprintf(stdout,"cannot get layer3\n");
+		di->layer3 = 0;
+	}
+	if (VerifyOn>1)
+		fprintf(stdout,"layer3 id %08x\n", di->layer3);
+
+
+	di->layer4 = mISDN_get_layerid(di->device, di->d_stid, 4);
+	if (di->layer4<0) {
+		fprintf(stdout,"cannot get layer4\n");
+		di->layer4 = 0;
+	}
+	if (VerifyOn>1)
+		fprintf(stdout,"layer4 id %08x\n", di->layer4);
+
+
+	ret = add_dlayer4(di, ISDN_PID_L4_CAPI20);
+	if (ret)
+		return(ret);
+
+	ret = mISDN_get_stack_info(di->device, di->d_stid, buf, 1024);
+	if (ret<=0) {
+		fprintf(stdout,"cannot get stackinfo err: %d\n", ret);
+		return(3);
+	}
+	stinf = (stack_info_t *)&frm->data.p;
+	if (VerifyOn>1)
+		mISDNprint_stack_info(stdout, stinf);
+
+	ret = mISDN_write_frame(di->device, buf, di->layer3,
+		MGR_NEWENTITY | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"MGR_NEWENTITY | REQUEST ret=%d\n", ret);
+	while((ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC))) {
+		if (VerifyOn>3)
+			fprintf(stdout,"MGR_NEWENTITY | REQUEST read ret=%d\n", ret);
+		if (frm->prim == (MGR_NEWENTITY | CONFIRM)) {
+			di->entity = frm->dinfo;
+			if (VerifyOn>4)
+				fprintf(stdout,"entity = %x\n", di->entity);
+			break;
+		} else {
+			if (VerifyOn)
+				fprintf(stdout,"read prim %x instead of MGR_NEWENTITY | CONFIRM (%x)\n",
+					frm->prim, (MGR_NEWENTITY | CONFIRM));
+		}
+	}
+	if (!ret) {
+		fprintf(stdout,"MGR_NEWENTITY | REQUEST read timed out\n");
+		return(6);
+	}
+#ifdef OBSOLATE
+	ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_DOWN,
+		DL_ESTABLISH | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"dl_etablish write ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"dl_etablish read ret=%d\n", ret);
+	if (ret>0) {
+		if (frm->prim != (DL_ESTABLISH | CONFIRM))
+			return(6);
+	} else {
+		fprintf(stdout,"DL_ESTABLISH | REQUEST return(%d)\n", ret);
+		return(7);
+	}
+	ret = mISDN_get_status_info(di->device, di->layer1, buf, 1024);
+	if (ret > mISDN_HEADER_LEN) {
+		si = (status_info_t *)&frm->data.p;
+		mISDNprint_status(stdout, si);
+	} else
+		fprintf(stdout,"mISDN_get_status_info ret(%d)\n", ret);
+	ret = mISDN_get_status_info(di->device, di->layer2, buf, 1024);
+	if (ret > mISDN_HEADER_LEN) {
+		si = (status_info_t *)&frm->data.p;
+		mISDNprint_status(stdout, si);
+	} else
+		fprintf(stdout,"mISDN_get_status_info ret(%d)\n", ret);
+	sleep(1);
+#endif
+ 	return(0);
+}
+
+int main(argc,argv)
+int argc;
+char *argv[];
+
+{
+	char FileName[200],FileNameOut[200];
+	int aidx=1,para=1, idx;
+	char sw;
+	devinfo_t mISDN;
+	int err;
+
+	fprintf(stderr,"TestmISDN 1.0\n");
+	strcpy(FileName, "test_file");
+	memset(&mISDN, 0, sizeof(mISDN));
+	mISDN.cardnr = 1;
+	mISDN.func = 0;
+	mISDN.phonenr[0] = 0;
+	if (argc<1) {
+		fprintf(stderr,"Error: Not enough arguments please check\n");
+		usage(argv[0]);
+		exit(1);
+	} else {
+		do {
+			if (argv[aidx] && argv[aidx][0]=='-') {
+				sw=argv[aidx][1];
+				switch (sw) {
+					 case 'v':
+					 case 'V':
+						VerifyOn=1;
+						if (argv[aidx][2]) {
+							VerifyOn=atol(&argv[aidx][2]);
+						}
+						break;
+					case 'c':
+						if (argv[aidx][2]) {
+							mISDN.cardnr=atol(&argv[aidx][2]);
+						}
+						break;
+					case 'F':
+						if (argv[aidx][2]) {
+							mISDN.func=atol(&argv[aidx][2]);
+						}
+						break;
+					case 'n':
+					        if (!argv[aidx][2]) {
+					        	idx = 0;
+							aidx++;
+						} else {
+							idx=2;
+						}
+						if (aidx<=argc) {
+							strcpy(mISDN.phonenr, &argv[aidx][idx]);
+						} else {
+							fprintf(stderr," Switch %c without value\n",sw);
+							exit(1);
+						}
+						break;
+					case '?' :
+						usage(argv[0]);
+						exit(1);
+						break;
+					default  : fprintf(stderr,"Unknown Switch %c\n",sw);
+						usage(argv[0]);
+						exit(1);
+						break;
+				}
+			}  else {
+				if (para==1) {
+					if (argc > 1)
+						strcpy(FileName,argv[aidx]);
+					para++;
+				} else {
+					fprintf(stderr,"Undefined argument %s\n",argv[aidx]);
+					usage(argv[0]);
+					exit(1);
+				}
+			}
+                                   aidx++;
+		} while (aidx<argc);
+	}
+	if (0>(mISDN.device = mISDN_open())) {
+		printf("TestmISDN cannot open mISDN due to %s\n",
+			strerror(errno));
+		return(1);
+	}
+	sprintf(FileNameOut,"%s.out",FileName);
+	sprintf(FileName,"%s.in",FileName);
+	if (0>(mISDN.save = open(FileName, O_WRONLY|O_CREAT|O_TRUNC,S_IRWXU))) {
+		printf("TestmISDN cannot open %s due to %s\n",FileName,
+			strerror(errno));
+		close(mISDN.device);
+		return(1);
+	}
+	if (0>(mISDN.play = open(FileNameOut, O_RDONLY))) {
+		printf("TestmISDN cannot open %s due to %s\n",FileNameOut,
+			strerror(errno));
+		mISDN.play = -1;
+	} else 
+		mISDN.fplay = fdopen(mISDN.play, "r");
+	if (VerifyOn>8)
+		fprintf(stdout,"fileno %d/%d/%d\n",mISDN.save, mISDN.play,
+			mISDN.device);
+	err = do_setup(&mISDN);
+	if (err)
+		fprintf(stdout,"do_setup error %d\n", err);
+	else
+		do_connection(&mISDN);	
+	close(mISDN.save);
+	if (mISDN.play>=0)
+		close(mISDN.play);
+	err=mISDN_close(mISDN.device);
+	if (err)
+		fprintf(stdout,"mISDN_close: error(%d): %s\n", err,
+			strerror(err));
+	
+	return(0);
+}

Added: misdn-user/trunk/example/testnet.c
===================================================================
--- misdn-user/trunk/example/testnet.c	                        (rev 0)
+++ misdn-user/trunk/example/testnet.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,967 @@
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include "mISDNlib.h"
+#include "l3dss1.h"
+
+
+unsigned char ulaw_to_Alaw[256] = {
+     0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
+     0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
+     0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
+     0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
+     0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02,
+     0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x1a,
+     0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12,
+     0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x6b,
+     0x68, 0x69, 0x6e, 0x6f, 0x6c, 0x6d, 0x62, 0x63,
+     0x60, 0x61, 0x66, 0x67, 0x64, 0x65, 0x7b, 0x79,
+     0x7e, 0x7f, 0x7c, 0x7d, 0x72, 0x73, 0x70, 0x71,
+     0x76, 0x77, 0x74, 0x75, 0x4b, 0x49, 0x4f, 0x4d,
+     0x42, 0x43, 0x40, 0x41, 0x46, 0x47, 0x44, 0x45,
+     0x5a, 0x5b, 0x58, 0x59, 0x5e, 0x5f, 0x5c, 0x5d,
+     0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51,
+     0x56, 0x56, 0x57, 0x57, 0x54, 0x54, 0x55, 0xd5,
+     0xaa, 0xab, 0xa8, 0xa9, 0xae, 0xaf, 0xac, 0xad,
+     0xa2, 0xa3, 0xa0, 0xa1, 0xa6, 0xa7, 0xa4, 0xa5,
+     0xba, 0xbb, 0xb8, 0xb9, 0xbe, 0xbf, 0xbc, 0xbd,
+     0xb2, 0xb3, 0xb0, 0xb1, 0xb6, 0xb7, 0xb4, 0xb5,
+     0x8b, 0x88, 0x89, 0x8e, 0x8f, 0x8c, 0x8d, 0x82,
+     0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85, 0x9a,
+     0x9b, 0x98, 0x99, 0x9e, 0x9f, 0x9c, 0x9d, 0x92,
+     0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, 0xeb,
+     0xe8, 0xe9, 0xee, 0xef, 0xec, 0xed, 0xe2, 0xe3,
+     0xe0, 0xe1, 0xe6, 0xe7, 0xe4, 0xe5, 0xfb, 0xf9,
+     0xfe, 0xff, 0xfc, 0xfd, 0xf2, 0xf3, 0xf0, 0xf1,
+     0xf6, 0xf7, 0xf4, 0xf5, 0xcb, 0xc9, 0xcf, 0xcd,
+     0xc2, 0xc3, 0xc0, 0xc1, 0xc6, 0xc7, 0xc4, 0xc5,
+     0xda, 0xdb, 0xd8, 0xd9, 0xde, 0xdf, 0xdc, 0xdd,
+     0xd2, 0xd2, 0xd3, 0xd3, 0xd0, 0xd0, 0xd1, 0xd1,
+     0xd6, 0xd6, 0xd7, 0xd7, 0xd4, 0xd4, 0xd5, 0xd5,
+    
+};
+
+unsigned char Alaw_to_ulaw[256] = {
+     0x29, 0x2a, 0x27, 0x28, 0x2d, 0x2e, 0x2b, 0x2c,
+     0x21, 0x22, 0x1f, 0x20, 0x25, 0x26, 0x23, 0x24,
+     0x39, 0x3a, 0x37, 0x38, 0x3d, 0x3e, 0x3b, 0x3c,
+     0x31, 0x32, 0x2f, 0x30, 0x35, 0x36, 0x33, 0x34,
+     0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
+     0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
+     0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
+     0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
+     0x62, 0x63, 0x60, 0x61, 0x66, 0x67, 0x64, 0x65,
+     0x5d, 0x5d, 0x5c, 0x5c, 0x5f, 0x5f, 0x5e, 0x5e,
+     0x74, 0x76, 0x70, 0x72, 0x7c, 0x7e, 0x78, 0x7a,
+     0x6a, 0x6b, 0x68, 0x69, 0x6e, 0x6f, 0x6c, 0x6d,
+     0x48, 0x49, 0x46, 0x47, 0x4c, 0x4d, 0x4a, 0x4b,
+     0x40, 0x41, 0x3f, 0x3f, 0x44, 0x45, 0x42, 0x43,
+     0x56, 0x57, 0x54, 0x55, 0x5a, 0x5b, 0x58, 0x59,
+     0x4f, 0x4f, 0x4e, 0x4e, 0x52, 0x53, 0x50, 0x51,
+     0xa9, 0xaa, 0xa7, 0xa8, 0xad, 0xae, 0xab, 0xac,
+     0xa1, 0xa2, 0x9f, 0xa0, 0xa5, 0xa6, 0xa3, 0xa4,
+     0xb9, 0xba, 0xb7, 0xb8, 0xbd, 0xbe, 0xbb, 0xbc,
+     0xb1, 0xb2, 0xaf, 0xb0, 0xb5, 0xb6, 0xb3, 0xb4,
+     0x8a, 0x8b, 0x88, 0x89, 0x8e, 0x8f, 0x8c, 0x8d,
+     0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85,
+     0x9a, 0x9b, 0x98, 0x99, 0x9e, 0x9f, 0x9c, 0x9d,
+     0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95,
+     0xe2, 0xe3, 0xe0, 0xe1, 0xe6, 0xe7, 0xe4, 0xe5,
+     0xdd, 0xdd, 0xdc, 0xdc, 0xdf, 0xdf, 0xde, 0xde,
+     0xf4, 0xf6, 0xf0, 0xf2, 0xfc, 0xfe, 0xf8, 0xfa,
+     0xea, 0xeb, 0xe8, 0xe9, 0xee, 0xef, 0xec, 0xed,
+     0xc8, 0xc9, 0xc6, 0xc7, 0xcc, 0xcd, 0xca, 0xcb,
+     0xc0, 0xc1, 0xbf, 0xbf, 0xc4, 0xc5, 0xc2, 0xc3,
+     0xd6, 0xd7, 0xd4, 0xd5, 0xda, 0xdb, 0xd8, 0xd9,
+     0xcf, 0xcf, 0xce, 0xce, 0xd2, 0xd3, 0xd0, 0xd1,
+    
+};
+
+void usage(pname) 
+char *pname;
+{
+	fprintf(stderr,"Call with %s [options] [filename]\n",pname);
+	fprintf(stderr,"\n");
+	fprintf(stderr,"       filename   filename.in  incoming data\n");
+	fprintf(stderr,"                  filename.out outgoing data\n");
+	fprintf(stderr,"                  data is sun audio 8khz 8bi for voice\n");
+	fprintf(stderr,"\n");
+	fprintf(stderr,"\n     Valid options are:\n");
+	fprintf(stderr,"\n");
+	fprintf(stderr,"  -?              Usage ; printout this information\n");
+	fprintf(stderr,"  -c<n>           use card number n (default 1)\n");
+	fprintf(stderr,"  -d <text>       Display text (default \"Test Display\")\n");
+	fprintf(stderr,"  -m <number>     Called PN (default 789)\n");
+	fprintf(stderr,"  -n <number>     Calling PN (default keine)\n");
+	fprintf(stderr,"  -F<n>           use function n (default 0)\n"); 
+	fprintf(stderr,"                    0 outgoing call\n"); 
+	fprintf(stderr,"                    1 incomming call\n"); 
+	fprintf(stderr,"  -vn             Printing debug info level n\n");
+	fprintf(stderr,"\n");
+}
+
+typedef struct _devinfo {
+	int	device;
+	int	cardnr;
+	int	func;
+	char	phonenr[32];
+	char	display[32];
+	char	msn[32];
+	int	d_stid;
+	int	layer1;
+	int	layer2;
+	int	layer3;
+	int	b_stid[2];
+	int	b_adress[2];
+	int	used_bchannel;
+	int	save;
+	int	play;
+	FILE	*fplay;
+	int	flag;
+	int	val;
+	int	cr;
+	int	si;
+	int	bl1_prot;
+	int	bl2_prot;
+	int	bl3_prot;
+} devinfo_t;
+
+#define FLG_SEND_TONE		0x0001
+#define FLG_SEND_DATA		0x0002
+#define FLG_BCHANNEL_SETUP	0x0010
+#define FLG_BCHANNEL_DOACTIVE	0x0020
+#define FLG_BCHANNEL_ACTIVE	0x0040
+#define FLG_BCHANNEL_ACTDELAYED	0x0080
+#define FLG_CALL_ORGINATE	0x0100
+
+
+#define MAX_REC_BUF		4000
+#define MAX_DATA_BUF		1024
+
+static int VerifyOn=0;
+
+char tt_char[]="0123456789ABCD*#";
+
+#define PLAY_SIZE 64
+
+#define	MsgHead(ptr, cref, mty) \
+	*ptr++ = 0x8; \
+	if (cref == -1) { \
+		*ptr++ = 0x0; \
+	} else { \
+		*ptr++ = 0x1; \
+		*ptr++ = cref^0x80; \
+	} \
+	*ptr++ = mty
+
+int save_alaw(devinfo_t *di, unsigned char *buf, int len) {
+	int i;
+	unsigned char *p = buf;
+	
+	for (i=0; i<len; i++) {
+		*p = ulaw_to_Alaw[*p];
+		p++;
+	}
+	write(di->save, buf, len);
+	return(len);		
+}
+
+int play_msg(devinfo_t *di) {
+	unsigned char buf[PLAY_SIZE+mISDN_HEADER_LEN], *p;
+	iframe_t *frm = (iframe_t *)buf;
+	int len, ret, i;
+	
+	if (di->play<0)
+		return(0);
+	len = read(di->play, buf + mISDN_HEADER_LEN, PLAY_SIZE);
+	if (len<0) {
+		printf("play_msg err %d: \"%s\"\n", errno, strerror(errno));
+		close(di->play);
+		di->play = -1;
+	}
+	p = buf + mISDN_HEADER_LEN;
+	for (i=0; i<len; i++) {
+		*p = Alaw_to_ulaw[*p];
+		p++;
+	}
+	frm->addr = di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN;
+	frm->prim = DL_DATA | REQUEST;
+	frm->dinfo = 0;
+	frm->len = len;
+	ret = mISDN_write(di->device, buf, len+mISDN_HEADER_LEN, 8000);
+	if (ret < 0)
+		fprintf(stdout,"play write error %d %s\n", errno, strerror(errno));
+	else if (VerifyOn>3)
+		fprintf(stdout,"play write ret=%d\n", ret);
+	return(ret);
+}
+
+int send_data(devinfo_t *di) {
+	unsigned char buf[MAX_DATA_BUF+mISDN_HEADER_LEN];
+	iframe_t *frm = (iframe_t *)buf;
+	unsigned char *data;
+	int len, ret;
+	
+	if (di->play<0 || !di->fplay)
+		return(0);
+	if (!(data = fgets(buf + mISDN_HEADER_LEN, MAX_DATA_BUF, di->fplay))) {
+		close(di->play);
+		di->play = -1;
+		data = buf + mISDN_HEADER_LEN;
+		data[0] = 4; /* ctrl-D */
+		data[1] = 0;
+	}
+	len = strlen(data);
+	if (len==0) {
+		close(di->play);
+		di->play = -1;
+		data[0] = 4; /* ctrl-D */
+		len = 1;
+	}
+	
+	frm->addr = di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN;
+	frm->prim = DL_DATA | REQUEST;
+	frm->dinfo = 0;
+	frm->len = len;
+	ret = mISDN_write(di->device, buf, len+mISDN_HEADER_LEN, 100000);
+	if (ret < 0)
+		fprintf(stdout,"send_data write error %d %s\n", errno, strerror(errno));
+	else if (VerifyOn>3)
+		fprintf(stdout,"send_data write ret=%d\n", ret);
+	return(ret);
+}
+
+int setup_bchannel(devinfo_t *di) {
+	mISDN_pid_t pid;
+	int ret;
+	layer_info_t li;
+
+
+	if ((di->used_bchannel<0) || (di->used_bchannel>1)) {
+		fprintf(stdout, "wrong channel %d\n", di->used_bchannel);
+		return(0);
+	}
+	memset(&li, 0, sizeof(layer_info_t));
+	strcpy(&li.name[0], "B L3");
+	li.object_id = -1;
+	li.extentions = 0;
+	li.pid.protocol[3] = di->bl3_prot;
+	li.pid.layermask = ISDN_LAYER(3);
+	li.st = di->b_stid[di->used_bchannel];
+	ret = mISDN_new_layer(di->device, &li);
+	if (ret<0) {
+		fprintf(stdout, "new_layer ret(%d)\n", ret);
+		return(0);
+	}
+	if (ret) {
+		di->b_adress[di->used_bchannel] = ret;
+		if (VerifyOn>2)
+			fprintf(stdout,"b_adress%d %08x\n",
+				di->used_bchannel+1, ret);
+		memset(&pid, 0, sizeof(mISDN_pid_t));
+		pid.protocol[1] = di->bl1_prot;
+		pid.protocol[2] = di->bl2_prot;
+		pid.protocol[3] = di->bl3_prot;
+		pid.layermask = ISDN_LAYER(1) | ISDN_LAYER(2)| ISDN_LAYER(3);
+		if (di->flag & FLG_CALL_ORGINATE)
+			pid.global = 1;
+		ret = mISDN_set_stack(di->device,
+			di->b_stid[di->used_bchannel], &pid);
+		if (ret) {
+			fprintf(stdout, "set_stack ret(%d)\n", ret);
+			return(0);
+		}
+		ret = di->b_adress[di->used_bchannel];
+	}
+	return(ret);
+}
+
+int send_SETUP(devinfo_t *di, int SI, char *PNr) {
+	unsigned char *np, *p, *msg, buf[1024];
+	int len, ret;
+
+	p = msg = buf + mISDN_HEADER_LEN;
+	MsgHead(p, di->cr, MT_SETUP);
+	*p++ = 0xa1; /* complete indicator */
+	*p++ = IE_BEARER;
+	if (SI == 1) { /* Audio */
+		*p++ = 0x3;	/* Length                               */
+		*p++ = 0x90;	/* Coding Std. CCITT, 3.1 kHz audio     */
+		*p++ = 0x90;	/* Circuit-Mode 64kbps                  */
+		*p++ = 0xa3;	/* A-Law Audio                          */
+	} else { /* default Datatransmission 64k */
+		*p++ = 0x2;	/* Length                               */
+		*p++ = 0x88;	/* Coding Std. CCITT, unrestr. dig. Inf */
+		*p++ = 0x90;	/* Circuit-Mode 64kbps                  */
+	}
+	*p++ = IE_CHANNEL_ID;
+	*p++ = 0x1;	/* Length */
+	*p++ = 0x80 | (1 + di->used_bchannel);
+	if (strlen(di->display)) {
+		*p++ = IE_DISPLAY;
+		*p++ = strlen(di->display);
+		np = di->display;
+		while(*np)
+			*p++ = *np++ & 0x7f;
+	}
+	if (strlen(di->msn)) {
+		*p++ = IE_CALLING_PN;
+		*p++ = strlen(PNr) +2;
+		*p++ = 0x01;
+		*p++ = 0x80;
+		np = PNr;
+		while(*np)
+			*p++ = *np++ & 0x7f;
+	}
+	if (PNr && strlen(PNr)) {
+		*p++ = IE_CALLED_PN;
+		np = di->msn;
+		*p++ = strlen(np) + 1;
+		/* Classify as AnyPref. */
+		*p++ = 0x81;		/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
+		while (*np)
+			*p++ = *np++ & 0x7f;
+	}
+	len = p - msg;
+	ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN,
+		DL_UNITDATA | REQUEST, 0, len, msg, TIMEOUT_1SEC);
+	return(ret);
+}
+
+int activate_bchan(devinfo_t *di) {
+	unsigned char buf[128];
+	iframe_t *rfrm;
+	int ret;
+
+	ret = mISDN_write_frame(di->device, buf,
+		di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN,
+		DL_ESTABLISH | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"DL_ESTABLISH write ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 128, TIMEOUT_10SEC); 	
+	if (VerifyOn>3)
+		fprintf(stdout,"DL_ESTABLISH read ret=%d\n", ret);
+	rfrm = (iframe_t *)buf;
+	if (ret>0) {
+		if (rfrm->prim == (DL_ESTABLISH | CONFIRM)) {
+			di->flag |= FLG_BCHANNEL_ACTIVE;
+		}
+	}
+	return(ret);
+}
+
+int deactivate_bchan(devinfo_t *di) {
+	unsigned char buf[128];
+	int ret;
+
+	ret = mISDN_write_frame(di->device, buf,
+		di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN,
+		DL_RELEASE | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"DL_RELEASE write ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 128, TIMEOUT_10SEC); 	
+	if (VerifyOn>3)
+		fprintf(stdout,"DL_RELEASE read ret=%d\n", ret);
+	di->flag &= ~FLG_BCHANNEL_ACTIVE;
+	di->flag &= ~FLG_BCHANNEL_SETUP;
+	ret = mISDN_clear_stack(di->device, di->b_stid[di->used_bchannel]);
+	if (VerifyOn>3)
+		fprintf(stdout,"clear_stack ret=%d\n", ret);
+	return(ret);
+}
+
+int send_touchtone(devinfo_t *di, int tone) {
+	iframe_t frm;
+	int tval, ret;
+
+	if (VerifyOn>1)
+		fprintf(stdout,"send_touchtone %c\n", DTMF_TONE_MASK & tone);
+	tval = DTMF_TONE_VAL | tone;
+	ret = mISDN_write_frame(di->device, &frm,
+		di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN,
+		PH_CONTROL | REQUEST, 0, 4, &tval, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"tt send ret=%d\n", ret);
+	return(ret);
+}
+
+int read_mutiplexer(devinfo_t *di) {
+	unsigned char	*p, *msg, buf[MAX_REC_BUF];
+	iframe_t	*rfrm;
+	int		timeout = TIMEOUT_10SEC;
+	int		ret = 0;
+	int		len;
+
+	rfrm = (iframe_t *)buf;
+	/* Main loop */
+
+start_again:
+	while ((ret = mISDN_read(di->device, buf, MAX_REC_BUF, timeout))) {
+		if (VerifyOn>3)
+			fprintf(stdout,"readloop ret=%d\n", ret);
+		if (ret >= 16) {
+			if (VerifyOn>4)
+				fprintf(stdout,"readloop addr(%x) prim(%x) len(%d)\n",
+					rfrm->addr, rfrm->prim, rfrm->len);
+			if (rfrm->addr == (di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN)) {
+				/* B-Channel related messages */
+				if (rfrm->prim == (DL_DATA | INDICATION)) {
+					/* received data, save it */
+					save_alaw(di, (unsigned char *)&rfrm->data.i,
+						rfrm->len);
+				} else if (rfrm->prim == (DL_DATA | CONFIRM)) {
+					/* get ACK of send data, so we can
+					 * send more
+					 */
+					if (VerifyOn>5)
+						fprintf(stdout,"DL_DATA_CNF\n");
+					switch (di->func) {
+						case 0:
+						case 1:
+							if (di->play > -1)
+								play_msg(di);
+							break;
+					}
+				} else if (rfrm->prim == (PH_CONTROL | INDICATION)) {
+					if ((rfrm->len == 4) &&
+						((rfrm->data.i & ~DTMF_TONE_MASK)
+						== DTMF_TONE_VAL)) {
+						fprintf(stdout,"GOT TT %c\n",
+							DTMF_TONE_MASK & rfrm->data.i);
+					} else
+						fprintf(stdout,"unknown PH_CONTROL len %d/val %x\n",
+							rfrm->len, rfrm->data.i);
+				}
+			/* D-Channel related messages */  
+			} else if ((ret > 19) && (buf[19] == MT_CONNECT) &&
+				(di->flag & FLG_CALL_ORGINATE)) {
+				/* We got connect, so bring B-channel up */
+				if (!(di->flag & FLG_BCHANNEL_ACTDELAYED))
+					activate_bchan(di);
+				else
+					di->flag |= FLG_BCHANNEL_DOACTIVE;
+				/* send a CONNECT_ACKNOWLEDGE */
+				p = msg = buf + mISDN_HEADER_LEN;
+				MsgHead(p, di->cr, MT_CONNECT_ACKNOWLEDGE);
+				len = p - msg;
+				ret = mISDN_write_frame(di->device, buf,
+					di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
+					0, len, msg, TIMEOUT_1SEC);
+				/* if here is outgoing data, send first part */
+				switch (di->func) {
+					case 0:
+					case 1:
+						if (di->play > -1)
+							play_msg(di);
+						break;
+				}
+			} else if ((ret > 19) && (buf[19] == MT_CONNECT_ACKNOWLEDGE) &&
+				(!(di->flag & FLG_CALL_ORGINATE))) {
+				/* We got connect ack, so bring B-channel up */
+				if (!(di->flag & FLG_BCHANNEL_ACTDELAYED))
+					activate_bchan(di);
+				else
+					di->flag |= FLG_BCHANNEL_DOACTIVE;
+				/* if here is outgoing data, send first part */
+				switch (di->func) {
+					case 0:
+					case 1:
+						if (di->play > -1)
+							play_msg(di);
+						break;
+				}
+			} else if ((ret > 19) && (buf[19] == MT_DISCONNECT)) {
+				/* send a RELEASE */
+				p = msg = buf + mISDN_HEADER_LEN;
+				MsgHead(p, di->cr, MT_RELEASE);
+				len = p - msg;
+				ret = mISDN_write_frame(di->device, buf,
+					di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
+					0, len, msg, TIMEOUT_1SEC);
+			} else if ((ret > 19) && (buf[19] == MT_RELEASE)) {
+				/* on a disconnecting msg leave loop */
+				/* send a RELEASE_COMPLETE */
+				p = msg = buf + mISDN_HEADER_LEN;
+				MsgHead(p, di->cr, MT_RELEASE_COMPLETE);
+				len = p - msg;
+				ret = mISDN_write_frame(di->device, buf,
+					di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
+					0, len, msg, TIMEOUT_1SEC);
+				return(2);
+			} else if ((ret > 19) && (buf[19] == MT_RELEASE_COMPLETE)) {
+				/* on a disconnecting msg leave loop */
+				return(1);
+			}
+		}
+	}
+	if (di->flag & FLG_SEND_TONE) {
+		if (di->val) {
+			di->val--;
+			send_touchtone(di, tt_char[di->val]);
+		} else {
+			/* After last tone disconnect */
+			p = msg = buf + mISDN_HEADER_LEN;
+			MsgHead(p, di->cr, MT_DISCONNECT);
+			len = p - msg;
+			ret = mISDN_write_frame(di->device, buf,
+				di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
+				0, len, msg, TIMEOUT_1SEC);
+			di->flag &= ~FLG_SEND_TONE;
+		}
+		goto start_again;
+	} else if (di->flag & FLG_SEND_DATA) {
+		if (di->play > -1)
+			send_data(di);
+		else
+			di->flag &= ~FLG_SEND_DATA;
+		goto start_again;
+	} else if (di->flag & FLG_BCHANNEL_DOACTIVE) {
+		ret = activate_bchan(di);
+		if (!ret) {
+			fprintf(stdout,"error on activate_bchan\n");
+			return(0);
+		}
+		di->flag &= ~FLG_BCHANNEL_DOACTIVE;
+		/* send next after 1 sec */
+		timeout = 1*TIMEOUT_1SEC;
+		di->flag |= FLG_SEND_DATA;
+		goto start_again;
+	}
+	return(0);
+}
+
+int do_connection(devinfo_t *di) {
+	unsigned char *p, *msg, buf[1024];
+	iframe_t *rfrm;
+	int len, idx, ret = 0;
+	int bchannel;
+	time_t		tim;
+	struct tm	*ts;
+
+	rfrm = (iframe_t *)buf;
+
+	if (di->func == 0) {
+		di->flag |= FLG_CALL_ORGINATE;
+		di->cr = 0x81;
+		send_SETUP(di, di->si, di->phonenr);
+	}
+	bchannel= di->used_bchannel + 1;
+	/* Wait for a SETUP message or a CALL_PROCEEDING */
+	while ((ret = mISDN_read(di->device, buf, 1024, 3*TIMEOUT_10SEC))) {
+		if (VerifyOn>3)
+			fprintf(stdout,"readloop ret=%d\n", ret);
+		if (ret >= 20) {
+			if (((!(di->flag & FLG_CALL_ORGINATE)) &&
+				(buf[19] == MT_SETUP)) ||
+				((di->flag & FLG_CALL_ORGINATE) &&
+				(buf[19] == MT_ALERTING))) {
+				
+				if (!(di->flag & FLG_CALL_ORGINATE))
+					di->cr = buf[18];
+	 			idx = 20;
+				break;
+			}
+		}
+	}
+	fprintf(stdout,"bchannel %d\n", bchannel);
+	if (bchannel > 0) {
+		/* setup a B-channel stack */
+		switch (di->func) {
+			case 0:
+			case 1:
+			case 2:
+			case 3:
+			case 4:
+				ret = setup_bchannel(di);
+				if (ret)
+					di->flag |= FLG_BCHANNEL_SETUP;
+				else {
+					fprintf(stdout,"error on setup_bchannel\n");
+					goto clean_up;
+				}
+				break;
+		}
+		if (!(di->flag & FLG_CALL_ORGINATE)) {
+			p = msg = buf + mISDN_HEADER_LEN;
+			MsgHead(p, di->cr, MT_CONNECT);
+			time(&tim);
+			ts = localtime(&tim);
+			if (ts->tm_year > 99)
+				ts->tm_year -=100;
+			printf("Time %d:%d %d/%d/%d\n",
+				ts->tm_hour, ts->tm_min,
+				ts->tm_mday, ts->tm_mon+1, ts->tm_year);
+			*p++ = IE_CHANNEL_ID;
+			*p++ = 0x1;	/* Length */
+			*p++ = 0x80 | (1 + di->used_bchannel);
+			*p++ = IE_DISPLAY;
+			*p++ = strlen(di->display);
+			for (idx=0; idx < strlen(di->display); idx++)
+				*p++ = di->display[idx];
+			*p++ = IE_DATE;
+			*p++ = 5;
+			*p++ = ts->tm_year;
+			*p++ = ts->tm_mon+1;
+			*p++ = ts->tm_mday;
+			*p++ = ts->tm_hour;
+			*p++ = ts->tm_min;
+			len = p - msg;
+			ret = mISDN_write_frame(di->device, buf,
+				di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
+				0, len, msg, TIMEOUT_1SEC);
+		}
+		if (!read_mutiplexer(di)) { /* timed out */
+			/* send a RELEASE_COMPLETE */
+			fprintf(stdout,"read_mutiplexer timed out sending RELEASE_COMPLETE\n");
+			p = msg = buf + mISDN_HEADER_LEN;;
+			MsgHead(p, di->cr, MT_RELEASE_COMPLETE);
+			len = p - msg;
+			ret = mISDN_write_frame(di->device, buf,
+				di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
+				0, len, msg, TIMEOUT_1SEC);
+		}
+		deactivate_bchan(di);
+	} else {
+		fprintf(stdout,"no channel or no connection\n");
+	}
+clean_up:
+	sleep(1);
+	ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN,
+		DL_RELEASE | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"read ret=%d\n", ret);
+	sleep(1);
+	ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN,
+		MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"read ret=%d\n", ret);
+	return(0);
+}
+
+
+
+int
+add_dlayer3(devinfo_t *di, int prot)
+{
+	layer_info_t li;
+	stack_info_t si;
+#ifdef OBSOLETE
+	interface_info_t ii;
+#endif
+	int lid, ret;
+
+	if (di->layer3) {
+		memset(&si, 0, sizeof(stack_info_t));
+		si.extentions = EXT_STACK_CLONE;
+		si.mgr = -1;
+		si.id = di->d_stid;
+		ret = mISDN_new_stack(di->device, &si);
+		if (ret <= 0) {
+			fprintf(stdout, "clone stack failed ret(%d)\n", ret);
+			return(11);
+		}
+		di->d_stid = ret;
+	}
+	memset(&li, 0, sizeof(layer_info_t));
+	strcpy(&li.name[0], "user L3");
+	li.object_id = -1;
+	li.extentions = 0;
+	li.pid.protocol[3] = prot;
+	li.pid.layermask = ISDN_LAYER(3);
+	li.st = di->d_stid;
+	lid = mISDN_new_layer(di->device, &li);
+	if (lid<0)
+		return(12);
+	di->layer3 = lid;
+	if (!di->layer3)
+		return(13);
+	
+#ifdef OBSOLETE
+	/* 
+	 * EXT_IF_CREATE | EXT_IF_EXCLUSIV sorgen dafuer, das wenn die L3
+	 * Schnittstelle schon benutzt ist, eine neue L2 Instanz erzeugt
+	 * wird
+	 */
+   	
+	ii.extentions = EXT_IF_CREATE | EXT_IF_EXCLUSIV;
+	ii.owner = di->layer3;
+	ii.peer = di->layer2;
+	ii.stat = FLG_MSG_TARGET | FLG_MSG_DOWN;
+	ret = mISDN_connect(di->device, &ii);
+	if (ret)
+		return(13);
+	ii.owner = di->layer3;
+	ii.stat = FLG_MSG_TARGET | FLG_MSG_DOWN;
+	ret = mISDN_get_interface_info(di->device, &ii);
+	if (ret != 0)
+		return(14);
+	if (ii.peer == di->layer2)
+		fprintf(stdout, "Layer 2 not cloned\n");
+	else
+		fprintf(stdout, "Layer 2 %08x cloned from %08x\n",
+			ii.peer, di->layer2);
+	di->layer2 = ii.peer;
+#endif
+	return(0);
+}
+
+int do_setup(devinfo_t *di) {
+	unsigned char buf[1024];
+	iframe_t *frm = (iframe_t *)buf;
+	int i, ret = 0;
+	stack_info_t *stinf;
+	status_info_t *si;
+
+	di->bl2_prot = ISDN_PID_L2_B_TRANS;
+	di->bl3_prot = ISDN_PID_L3_B_TRANS;
+	di->bl1_prot = ISDN_PID_L1_B_64TRANS;
+	di->si = 1;
+
+	ret = mISDN_get_stack_count(di->device);
+	if (VerifyOn>1)
+		fprintf(stdout,"%d stacks found\n", ret);
+	if (ret < di->cardnr) {
+		fprintf(stdout,"cannot config card nr %d only %d cards\n",
+			di->cardnr, ret);
+		return(2);
+	}
+	ret = mISDN_get_stack_info(di->device, di->cardnr, buf, 1024);
+	if (ret<=0) {
+		fprintf(stdout,"cannot get stackinfo err: %d\n", ret);
+		return(3);
+	}
+	stinf = (stack_info_t *)&frm->data.p;
+	if (VerifyOn>1)
+		mISDNprint_stack_info(stdout, stinf);
+	di->d_stid = stinf->id;
+	for (i=0;i<2;i++) {
+		if (stinf->childcnt>i)
+			di->b_stid[i] = stinf->child[i];
+		else
+			di->b_stid[i] = 0;
+	}
+
+	di->layer1 = mISDN_get_layerid(di->device, di->d_stid, 1);
+	if (di->layer1<0) {
+		fprintf(stdout,"cannot get layer1\n");
+		return(4);
+	}
+	if (VerifyOn>1)
+		fprintf(stdout,"layer1 id %08x\n", di->layer1);
+
+	di->layer2 = mISDN_get_layerid(di->device, di->d_stid, 2);
+	if (di->layer2<0) {
+		fprintf(stdout,"cannot get layer2\n");
+		return(5);
+	}
+	if (VerifyOn>1)
+		fprintf(stdout,"layer2 id %08x\n", di->layer2);
+
+	di->layer3 = mISDN_get_layerid(di->device, di->d_stid, 3);
+	if (di->layer3<0) {
+		fprintf(stdout,"cannot get layer3\n");
+		di->layer3 = 0;
+	}
+	if (VerifyOn>1)
+		fprintf(stdout,"layer3 id %08x\n", di->layer3);
+
+
+	ret = add_dlayer3(di, ISDN_PID_L3_DSS1NET);
+	if (ret)
+		return(ret);
+	ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN,
+		DL_ESTABLISH | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"dl_etablish write ret=%d\n", ret);
+	ret = mISDN_read(di->device, buf, 1024, TIMEOUT_1SEC);
+	if (VerifyOn>3)
+		fprintf(stdout,"dl_etablish read ret=%d\n", ret);
+	if (ret>0) {
+		if (frm->prim != (DL_ESTABLISH | CONFIRM)) {
+			fprintf(stdout,"DL_ESTABLISH | REQUEST return prim:%x\n",
+				frm->prim);
+//			return(6);
+		}
+	} else {
+		fprintf(stdout,"DL_ESTABLISH | REQUEST return(%d)\n", ret);
+//		return(7);
+	}
+	ret = mISDN_get_status_info(di->device, di->layer1, buf, 1024);
+	if (ret > mISDN_HEADER_LEN) {
+		si = (status_info_t *)&frm->data.p;
+		mISDNprint_status(stdout, si);
+	} else
+		fprintf(stdout,"mISDN_get_status_info ret(%d)\n", ret);
+	ret = mISDN_get_status_info(di->device, di->layer2, buf, 1024);
+	if (ret > mISDN_HEADER_LEN) {
+		si = (status_info_t *)&frm->data.p;
+		mISDNprint_status(stdout, si);
+	} else
+		fprintf(stdout,"mISDN_get_status_info ret(%d)\n", ret);
+	sleep(1);
+	return(0);
+}
+
+int main(argc,argv)
+int argc;
+char *argv[];
+
+{
+	char FileName[200],FileNameOut[200];
+	int aidx=1,para=1, idx;
+	char sw;
+	devinfo_t mISDN;
+	int err;
+
+	fprintf(stderr,"Test HFCNet 1.0\n");
+	strcpy(FileName, "test_file");
+	memset(&mISDN, 0, sizeof(mISDN));
+	mISDN.cardnr = 1;
+	mISDN.func = 0;
+	strcpy(mISDN.display, "Test Display");
+	strcpy(mISDN.msn, "789");
+	mISDN.phonenr[0] = 0;
+	if (argc<1) {
+		fprintf(stderr,"Error: Not enough arguments please check\n");
+		usage(argv[0]);
+		exit(1);
+	} else {
+		do {
+			if (argv[aidx] && argv[aidx][0]=='-') {
+				sw=argv[aidx][1];
+				switch (sw) {
+					 case 'v':
+					 case 'V':
+						VerifyOn=1;
+						if (argv[aidx][2]) {
+							VerifyOn=atol(&argv[aidx][2]);
+						}
+						break;
+					case 'c':
+						if (argv[aidx][2]) {
+							mISDN.cardnr=atol(&argv[aidx][2]);
+						}
+						break;
+					case 'F':
+						if (argv[aidx][2]) {
+							mISDN.func=atol(&argv[aidx][2]);
+						}
+						break;
+					case 'd':
+					        if (!argv[aidx][2]) {
+					        	idx = 0;
+							aidx++;
+						} else {
+							idx=2;
+						}
+						if (aidx<=argc) {
+							strcpy(mISDN.display, &argv[aidx][idx]);
+						} else {
+							fprintf(stderr," Switch %c without value\n",sw);
+							exit(1);
+						}
+						break;
+					case 'm':
+					        if (!argv[aidx][2]) {
+					        	idx = 0;
+							aidx++;
+						} else {
+							idx=2;
+						}
+						if (aidx<=argc) {
+							strcpy(mISDN.msn, &argv[aidx][idx]);
+						} else {
+							fprintf(stderr," Switch %c without value\n",sw);
+							exit(1);
+						}
+						break;
+					case 'n':
+					        if (!argv[aidx][2]) {
+					        	idx = 0;
+							aidx++;
+						} else {
+							idx=2;
+						}
+						if (aidx<=argc) {
+							strcpy(mISDN.phonenr, &argv[aidx][idx]);
+						} else {
+							fprintf(stderr," Switch %c without value\n",sw);
+							exit(1);
+						}
+						break;
+					case '?' :
+						usage(argv[0]);
+						exit(1);
+						break;
+					default  : fprintf(stderr,"Unknown Switch %c\n",sw);
+						usage(argv[0]);
+						exit(1);
+						break;
+				}
+			}  else {
+				if (para==1) {
+					if (argc > 1)
+						strcpy(FileName,argv[aidx]);
+					para++;
+				} else {
+					fprintf(stderr,"Undefined argument %s\n",argv[aidx]);
+					usage(argv[0]);
+					exit(1);
+				}
+			}
+                                   aidx++;
+		} while (aidx<argc);
+	}
+	if (0>(mISDN.device = mISDN_open())) {
+		printf("TestmISDN cannot open mISDN due to %s\n",
+			strerror(errno));
+		return(1);
+	}
+	sprintf(FileNameOut,"%s.out",FileName);
+	sprintf(FileName,"%s.in",FileName);
+	printf("TestmISDN open in %s\n",FileName);
+	if (0>(mISDN.save = open(FileName, O_WRONLY|O_CREAT|O_TRUNC,S_IRWXU))) {
+		printf("TestmISDN cannot open %s due to %s\n",FileName,
+			strerror(errno));
+		close(mISDN.device);
+		return(1);
+	}
+	printf("TestmISDN open out %s\n",FileNameOut);
+	if (0>(mISDN.play = open(FileNameOut, O_RDONLY))) {
+		printf("TestmISDN cannot open %s due to %s\n",FileNameOut,
+			strerror(errno));
+		mISDN.play = -1;
+	} else 
+		mISDN.fplay = fdopen(mISDN.play, "r");
+	printf("TestmISDN files open\n");
+	if (VerifyOn>8)
+		fprintf(stdout,"fileno %d/%d/%d\n",mISDN.save, mISDN.play,
+			mISDN.device);
+	err = do_setup(&mISDN);
+	if (err)
+		fprintf(stdout,"do_setup error %d\n", err);
+	else
+		do_connection(&mISDN);	
+	close(mISDN.save);
+	if (mISDN.play>=0)
+		close(mISDN.play);
+	err=mISDN_close(mISDN.device);
+	if (err)
+		fprintf(stdout,"mISDN_close: error(%d): %s\n", err,
+			strerror(err));
+	
+	return(0);
+}

Added: misdn-user/trunk/i4lnet/Makefile
===================================================================
--- misdn-user/trunk/i4lnet/Makefile	                        (rev 0)
+++ misdn-user/trunk/i4lnet/Makefile	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,70 @@
+CC = gcc
+AR = ar
+RANLIB = ranlib
+
+all: libisdnnet.a libisdnnet_pic.a libisdnnet.so
+
+install:
+	install -m 644 libisdnnet.a $(INSTALL_PREFIX)/usr/lib
+	install -m 644 libisdnnet_pic.a $(INSTALL_PREFIX)/usr/lib
+	install -m 644 libisdnnet.so $(INSTALL_PREFIX)/usr/lib
+	cp *.h $(INSTALL_PREFIX)/usr/include/mISDNuser/
+
+ISDNNET_OBJ = net_if.o isdn_debug.o isdn_msg.o fsm.o net_l2.o tei.o net_l3.o \
+		manager.o tone.o bchannel.o g711.o
+ISDNNET_PICOBJ = $(ISDNNET_OBJ:%.o=%.lo)
+
+ifeq ($(shell uname -m),x86_64)
+CFLAGS         += -fPIC
+endif
+
+
+libisdnnet_pic.a: $(ISDNNET_PICOBJ)
+	$(AR) cru $@ $^
+	$(RANLIB) $@
+
+libisdnnet.a: $(ISDNNET_OBJ)
+	$(AR) cru $@ $^
+	$(RANLIB) $@
+
+libisdnnet.so: $(ISDNNET_OBJ)
+	$(CC) $(CFLAGS) -shared -Xlinker -x -o $@ $^
+
+.c.o:
+	$(CC) $(CFLAGS) -o $@ -c $<
+
+.c.lo:
+	$(CC) $(CFLAGS) -fPIC -o $@ -c $<
+
+isdn_msg.o isdn_msg.lo: isdn_msg.c $(INCLUDEDIR)/isdn_msg.h $(INCLUDEDIR)/isdn_net.h
+
+isdn_debug.o isdn_debug.lo: isdn_debug.c $(INCLUDEDIR)/isdn_debug.h
+
+net_l2.o net_l2.lo: net_l2.c net_l2.h $(INCLUDEDIR)/isdn_net.h fsm.h
+
+fsm.o fsm.lo: fsm.c fsm.h $(INCLUDEDIR)/isdn_net.h
+
+tei.o tei.lo: tei.c net_l2.h $(INCLUDEDIR)/isdn_net.h
+
+net_l3.o net_l3.lo: net_l3.c $(INCLUDEDIR)/isdn_net.h net_l3.h
+
+manager.o manager.lo: manager.c $(INCLUDEDIR)/isdn_net.h $(INCLUDEDIR)/bchannel.h
+
+net_if.o net_if.lo: net_if.c $(INCLUDEDIR)/isdn_net.h
+
+tone.o tone.lo: tone.c $(INCLUDEDIR)/tone.h $(INCLUDEDIR)/bchannel.h \
+	$(INCLUDEDIR)/isdn_net.h $(INCLUDEDIR)/ibuffer.h
+
+bchannel.o bchannel.lo: bchannel.c $(INCLUDEDIR)/isdn_net.h $(INCLUDEDIR)/tone.h \
+	$(INCLUDEDIR)/bchannel.h net_l3.h $(INCLUDEDIR)/ibuffer.h
+
+g711.o g711.lo: g711.c $(INCLUDEDIR)/g711.h
+
+clean:
+	rm -f *.o *.lo *~ DEADJOE 
+	rm -f libisdnnet.a libisdnnet_pic.a libisdnnet.so
+
+distclean: clean
+	rm -f *.a
+
+.SUFFIXES: .lo

Added: misdn-user/trunk/i4lnet/bchannel.c
===================================================================
--- misdn-user/trunk/i4lnet/bchannel.c	                        (rev 0)
+++ misdn-user/trunk/i4lnet/bchannel.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,1380 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "isdn_net.h"
+#include "helper.h"
+#include "tone.h"
+#include "bchannel.h"
+#include "net_l3.h"
+#include "l3dss1.h"
+
+static int
+open_record_files(bchannel_t *bc)
+{
+	int	ret = -EINVAL;
+
+	if (bc->manager->application)
+		ret = bc->manager->application(bc->manager,
+			PR_APP_OPEN_RECFILES, bc);
+	return(ret);
+}
+
+static int
+close_record_files(bchannel_t *bc)
+{
+	int	ret = -EINVAL;
+
+	if (bc->manager->application)
+		ret = bc->manager->application(bc->manager,
+			PR_APP_CLOSE_RECFILES, bc);
+	return(ret);
+}
+
+static int
+setup_bchannel(bchannel_t *bc) {
+	struct {
+		int		id;
+		mISDN_pid_t	pid;
+	}	para;
+		
+	if ((bc->channel<1) || (bc->channel>2)) {
+		eprint("wrong channel %d\n", bc->channel);
+		return(-EINVAL);
+	}
+	dprint(DBGM_BC, -1,"%s:ch%d bst(%d)\n", __FUNCTION__,
+		bc->channel, bc->bstate);
+	if ((bc->bstate != BC_BSTATE_NULL) &&
+		(bc->bstate != BC_BSTATE_CLEANUP))
+		return(-EBUSY); 
+	memset(&para.pid, 0, sizeof(mISDN_pid_t));
+	para.pid.protocol[1] = bc->l1_prot;
+	if (FLG_BC_RAWDEVICE & bc->Flags) {
+		para.pid.protocol[2] = ISDN_PID_L2_B_RAWDEV;
+		para.pid.protocol[3] = ISDN_PID_L3_B_USER;
+		para.pid.layermask = ISDN_LAYER(1) | ISDN_LAYER(2) |
+					ISDN_LAYER(3);
+	} else {
+		para.pid.protocol[2] = ISDN_PID_L2_B_USER;
+		para.pid.layermask = ISDN_LAYER(1) | ISDN_LAYER(2);
+	}
+	if (bc->Flags & FLG_BC_CALL_ORGINATE)
+		para.pid.global = 1;
+	para.id = bc->l3id;
+	bc->bstate = BC_BSTATE_SETUP;
+	if (!bc->sbuf) {
+		bc->sbuf = init_ibuffer(2048);
+		if (bc->sbuf) {
+			bc->sbuf->rsem = &bc->work;
+			bc->sbuf->wsem = &bc->work;
+		}
+	}
+	if_link(bc->manager->nst, (ifunc_t)bc->manager->man2stack,
+		BC_SETUP | REQUEST, bc->channel, sizeof(para), &para, 0);
+	return(0);
+}
+
+static int
+activate_bchannel(bchannel_t *bc)
+{
+	dprint(DBGM_BC, -1,"%s:ch%d bst(%d)\n", __FUNCTION__,
+		bc->channel, bc->bstate);
+	if (!bc->b_addr) {
+		wprint("%s:ch%d not setup\n", __FUNCTION__,
+			bc->channel);
+		return(-EINVAL);
+	}
+	if ((bc->bstate == BC_BSTATE_SETUP) ||
+		(bc->bstate == BC_BSTATE_DEACTIVATE)) {
+		bc->bstate = BC_BSTATE_ACTIVATE;
+		return(if_link(bc->manager->nst,
+			(ifunc_t)bc->manager->man2stack,
+			PH_ACTIVATE | REQUEST, bc->b_addr | FLG_MSG_DOWN,
+			0, NULL, 0));
+	} else
+		return(-EBUSY);
+}
+
+static int
+deactivate_bchannel(bchannel_t *bc)
+{
+	dprint(DBGM_BC, -1,"%s:ch%d bst(%d)\n", __FUNCTION__,
+		bc->channel, bc->bstate);
+	if (!bc->b_addr) {
+		wprint("%s:ch%d not setup\n", __FUNCTION__,
+			bc->channel);
+		return(-EINVAL);
+	}
+	if ((bc->bstate == BC_BSTATE_ACTIVATE) ||
+		(bc->bstate == BC_BSTATE_ACTIV)) {
+		bc->bstate = BC_BSTATE_DEACTIVATE;
+		return(if_link(bc->manager->nst,
+			(ifunc_t)bc->manager->man2stack,
+			PH_DEACTIVATE | REQUEST, bc->b_addr | FLG_MSG_DOWN,
+			0, NULL, 0));
+	} else
+		return(-EBUSY);
+}
+
+static int
+bc_cleanup(bchannel_t *bc)
+{
+	int	ret;
+
+	dprint(DBGM_BC, -1,"%s:ch%d bst(%d)\n", __FUNCTION__,
+		bc->channel, bc->bstate);
+	if (!bc->b_addr) {
+		wprint("%s:ch%d not setup\n", __FUNCTION__,
+			bc->channel);
+	}
+	if (!bc->l3id) {
+		wprint("%s:ch%d no l3id\n", __FUNCTION__,
+			bc->channel);
+		return(-EINVAL);
+	}
+	if ((bc->bstate == BC_BSTATE_DEACTIVATE) ||
+		(bc->bstate == BC_BSTATE_SETUP)) {
+		bc->bstate = BC_BSTATE_CLEANUP;
+		ret = if_link(bc->manager->nst,
+			(ifunc_t)bc->manager->man2stack, BC_CLEANUP | REQUEST,
+			bc->l3id, 0, NULL, 0);
+	} else
+		ret = EBUSY;
+	return(ret);
+}
+
+static int
+clear_bc(bchannel_t *bc)
+{
+	pthread_mutex_lock(&bc->lock);
+	free_ibuffer(bc->sbuf);
+	bc->sbuf = NULL;
+	free_ibuffer(bc->rbuf);
+	bc->rbuf = NULL;
+	if (bc->Flags & FLG_BC_RECORDING)
+		close_record_files(bc);
+	bc->Flags = 0;
+	bc->nr[0] = 0;
+	bc->msn[0] = 0;
+	bc->display[0] = 0;
+	bc->usednr = NULL;
+	bc->smsg = NULL;
+	pthread_mutex_unlock(&bc->lock);
+	if ((bc->bstate == BC_BSTATE_ACTIV) ||
+		(bc->bstate == BC_BSTATE_ACTIVATE))
+			deactivate_bchannel(bc);
+	return(0);
+}
+
+static int
+do_b_activated(bchannel_t *bc, mISDNuser_head_t *hh, msg_t *msg) {
+	dprint(DBGM_BC, -1,"%s:ch%d state(%d/%d) Flags(%x) smsg(%p)\n", __FUNCTION__,
+		bc->channel, bc->cstate, bc->bstate, bc->Flags, bc->smsg);
+	clear_ibuffer(bc->rbuf);
+	if (!(bc->Flags & FLG_BC_KEEP_SEND))
+		clear_ibuffer(bc->sbuf);
+	if (bc->sbuf && bc->sbuf->wsem)
+		sem_post(bc->sbuf->wsem);
+	if (bc->bstate == BC_BSTATE_ACTIVATE)
+		bc->bstate = BC_BSTATE_ACTIV;
+	free_msg(msg);
+	return(0);
+}
+
+static int
+do_b_deactivated(bchannel_t *bc, mISDNuser_head_t *hh, msg_t *msg) {
+	dprint(DBGM_BC, -1,"%s:ch%d Flags(%x) smsg(%p)\n", __FUNCTION__,
+		bc->channel, bc->Flags, bc->smsg);
+	bc_cleanup(bc);
+	free_msg(msg);
+	return(0);
+}
+
+static int
+do_b_setup_conf(bchannel_t *bc, mISDNuser_head_t *hh, msg_t *msg)
+{
+	int	*addr;
+
+	addr = (int *)msg->data;
+	bc->b_addr = *addr;
+	activate_bchannel(bc);
+	free_msg(msg);
+	return(0);
+}
+
+
+static int
+do_b_cleanup_conf(bchannel_t *bc, mISDNuser_head_t *hh, msg_t *msg)
+{
+	dprint(DBGM_BC, -1,"%s:ch%d bst(%d)\n", __FUNCTION__,
+		bc->channel, bc->bstate);
+	bc->b_addr = 0;
+	if (bc->cstate == BC_CSTATE_NULL) {
+		bc->l3id = 0;
+		bc->cstate = BC_CSTATE_NULL;
+	}
+	bc->bstate = BC_BSTATE_NULL;
+	free_msg(msg);
+	return(0);
+}
+
+
+static int
+do_b_data_cnf(bchannel_t *bc, mISDNuser_head_t *hh, msg_t *msg)
+{
+	bc->smsg = NULL;
+	if (bc->sbuf && bc->sbuf->rsem)
+		sem_post(bc->sbuf->rsem);
+	free_msg(msg);
+	return(0);
+}
+
+static int
+do_b_data_ind(bchannel_t *bc, mISDNuser_head_t *hh, msg_t *msg)
+{
+	int		len;
+	int		ret = 0;
+
+	if (bc->bstate != BC_BSTATE_ACTIV)
+		return(-EBUSY);
+	dprint(DBGM_BCDATA, -1, "%s:ch%d get %d bytes\n", __FUNCTION__,
+		bc->channel, msg->len);
+	if (bc->rbuf) {
+		len = ibuf_freecount(bc->rbuf);
+		if (msg->len > len)
+			ret = -ENOSPC;
+		else {
+			ibuf_memcpy_w(bc->rbuf, msg->data, msg->len);
+		}
+		if (bc->rbuf->rsem)
+			sem_post(bc->rbuf->rsem);
+	} else
+		ret = -EINVAL;
+	dprint(DBGM_BCDATA, -1, "%s: finish ret %d\n", __FUNCTION__, ret);
+	if (bc->Flags & FLG_BC_RECORD) {
+		if (bc->Flags & FLG_BC_RECORDING) {
+			write(bc->rrid, msg->data, msg->len);
+		} else {
+			if (!open_record_files(bc))
+				write(bc->rrid, msg->data, msg->len);
+		}
+	} else if (bc->Flags & FLG_BC_RECORDING) {
+		close_record_files(bc);
+	}
+	if (!ret)
+		free_msg(msg);
+	return(ret);
+}
+
+static int
+b_send(bchannel_t *bc)
+{
+	int	len = 0, ret = -EINVAL;
+	u_char	*p;
+
+	if (bc->smsg)
+		goto out;
+	if (bc->bstate != BC_BSTATE_ACTIV)
+		goto out;
+	len = ibuf_usedcount(bc->sbuf);
+	if (!len)
+		goto out;
+	if (len > MAX_DATA_SIZE)
+		len = MAX_DATA_SIZE;
+	dprint(DBGM_BCDATA, -1, "%s:ch%d %d bytes\n", __FUNCTION__, bc->channel, len);
+	bc->smsg = prep_l3data_msg(PH_DATA | REQUEST, bc->b_addr | FLG_MSG_DOWN,
+		0, len, NULL);
+	if (!bc->smsg) {
+		len = -ENOMEM;
+		goto out;
+	}
+	p = msg_put(bc->smsg, len);
+	ibuf_memcpy_r(p, bc->sbuf, len);
+	if (bc->Flags & FLG_BC_RECORD) {
+		if (bc->Flags & FLG_BC_RECORDING) {
+			write(bc->rsid, p, len);
+		} else {
+			if (!open_record_files(bc))
+				write(bc->rsid, p, len);
+		}
+	} else if (bc->Flags & FLG_BC_RECORDING) {
+		close_record_files(bc);
+	}
+	if (bc->manager->man2stack)
+		ret = bc->manager->man2stack(bc->manager->nst, bc->smsg);
+	if (ret) {
+		free_msg(bc->smsg);
+		bc->smsg = NULL;
+		len = ret;
+	}
+	if (bc->sbuf->wsem)
+		sem_post(bc->sbuf->wsem);
+out:
+	return(len);
+}
+
+/* call handling */
+
+static int
+add_nr(bchannel_t *bc, unsigned char *cpn)
+{
+	if (bc->nr[0]) {
+		if (*cpn>1) {
+			memcpy(bc->nr + bc->nr[0] + 1, cpn + 2, *cpn -1);
+			bc->nr[0] += *cpn -1;
+		} else
+			dprint(DBGM_BC, -1,"%s: cpn len %d\n", __FUNCTION__, *cpn);
+	} else if (*cpn)
+		memcpy(bc->nr, cpn, *cpn + 1);
+	dprint(DBGM_BC, -1,"%s: nr:%s\n", __FUNCTION__, &bc->nr[2]);
+	return(0);
+}
+
+static int
+send_setup_ack(bchannel_t *bc)
+{
+	SETUP_ACKNOWLEDGE_t	*sa;
+	msg_t			*msg;
+	int			len, ret;
+	unsigned char		*p;
+	
+	dprint(DBGM_BC, -1,"%s: bc%d l3id(%x)\n", __FUNCTION__,
+		bc->channel, bc->l3id);
+	msg = prep_l3data_msg(CC_SETUP_ACKNOWLEDGE | REQUEST, bc->l3id,
+		sizeof(SETUP_ACKNOWLEDGE_t), 128, NULL);
+	if (!msg)
+		return(-ENOMEM);
+	sa = (SETUP_ACKNOWLEDGE_t *)(msg->data + mISDNUSER_HEAD_SIZE);
+	pthread_mutex_lock(&bc->lock);
+	bc->cstate = BC_CSTATE_OVERLAP_REC;
+	if (!(bc->Flags & FLG_BC_SENT_CID)) {
+		bc->Flags |= FLG_BC_SENT_CID;
+		sa->CHANNEL_ID = msg_put(msg, 2);
+		sa->CHANNEL_ID[0] = 1;
+		sa->CHANNEL_ID[1] = 0x88 | bc->channel;
+	}
+	pthread_mutex_unlock(&bc->lock);
+	if (bc->Flags & FLG_BC_PROGRESS) {
+		sa->PROGRESS = p = msg_put(msg, 3);;
+		*p++ = 2;
+		*p++ = 0x80 | CAUSE_LOC_PNET_LOCUSER;
+		*p++ = 0x80 | PROGRESS_TONE;
+		setup_bchannel(bc);
+	}
+	if (bc->display[0]) {
+		len = strlen(bc->display);
+		sa->DISPLAY = p = msg_put(msg, len+1);
+		*p++ = len;
+		strcpy(p, bc->display);
+		bc->display[0] = 0;
+	}
+	ret = -EINVAL;
+	if (bc->manager->man2stack)
+		ret = bc->manager->man2stack(bc->manager->nst, msg);
+	if (ret)
+		free_msg(msg);
+	return(ret);
+}
+
+static int
+send_setup(bchannel_t *bc)
+{
+	SETUP_t		*setup;
+	msg_t		*msg;
+	int		len, ret;
+	unsigned char	*p;
+	
+	if (bc->cstate != BC_CSTATE_OCALL) {
+		dprint(DBGM_BC, -1,"%s: bc%d state(%d/%d) not OCALL\n", __FUNCTION__,
+			bc->channel, bc->cstate, bc->bstate);
+		return(-EINVAL);
+	}
+#warning testing: more crefs for S2M
+	bc->l3id = 0xff00 | bc->channel;	
+	msg = prep_l3data_msg(CC_SETUP | REQUEST, bc->l3id,
+		sizeof(SETUP_t), 256, NULL);
+	if (!msg)
+		return(-ENOMEM);
+	setup = (SETUP_t *)(msg->data + mISDNUSER_HEAD_SIZE);
+	switch (bc->l1_prot) {
+		case ISDN_PID_L1_B_64TRANS:
+			bc->bc[0] = 3;
+			bc->bc[1] = 0x80;
+			bc->bc[2] = 0x90;
+			bc->bc[3] = 0xa3;
+			break;
+		default:
+			dprint(DBGM_BC, -1,"%s: no protocol %x\n", __FUNCTION__,
+				bc->l1_prot);
+			free_msg(msg);
+			return(-ENOPROTOOPT);
+	}
+	setup->BEARER = p = msg_put(msg, bc->bc[0] + 1);
+	memcpy(p, bc->bc, bc->bc[0] + 1);
+	bc->Flags |= FLG_BC_SENT_CID;
+	setup->CHANNEL_ID = msg_put(msg, 2);
+	setup->CHANNEL_ID[0] = 1;
+	setup->CHANNEL_ID[1] = 0x88 | bc->channel;
+	if (bc->display[0]) {
+		len = strlen(bc->display);
+		setup->DISPLAY = p = msg_put(msg, len+1);
+		*p++ = len;
+		strcpy(p, bc->display);
+		bc->display[0] = 0;
+	}
+	if (bc->nr[0]) {
+		setup->CALLING_PN = p = msg_put(msg, bc->nr[0] + 1);
+		memcpy(p, bc->nr, bc->nr[0] + 1);
+	}
+	if (bc->clisub[0]) {
+		setup->CALLING_SUB = p = msg_put(msg, bc->clisub[0] + 1);
+		memcpy(p, bc->clisub, bc->clisub[0] + 1);
+		bc->clisub[0] = 0;
+	}
+	if (bc->msn[0]) {
+		setup->CALLED_PN = p = msg_put(msg, bc->msn[0] + 1);;
+		memcpy(p, bc->msn, bc->msn[0] + 1);
+	}
+	if (bc->cldsub[0]) {
+		setup->CALLED_SUB = p = msg_put(msg, bc->cldsub[0] + 1);
+		memcpy(p, bc->cldsub, bc->cldsub[0] + 1);
+		bc->cldsub[0] = 0;
+	}
+	if (bc->fac[0]) {
+		setup->FACILITY = p = msg_put(msg, bc->fac[0] + 1);
+		memcpy(p, bc->fac, bc->fac[0] + 1);
+		bc->fac[0] = 0;
+	}
+	if (bc->uu[0]) {
+		setup->USER_USER = p = msg_put(msg, bc->uu[0] + 1);
+		memcpy(p, bc->uu, bc->uu[0] + 1);
+		bc->uu[0] = 0;
+	}
+	ret = -EINVAL;
+	if (bc->manager->man2stack)
+		ret = bc->manager->man2stack(bc->manager->nst, msg);
+	if (ret)
+		free_msg(msg);
+	return(ret);
+}
+
+static int
+send_proceeding(bchannel_t *bc)
+{
+	CALL_PROCEEDING_t	*proc;
+	msg_t			*msg;
+	int			len, ret;
+	unsigned char		*p;
+	
+	msg = prep_l3data_msg(CC_PROCEEDING | REQUEST, bc->l3id,
+		sizeof(CALL_PROCEEDING_t), 128, NULL);
+	if (!msg)
+		return(-ENOMEM);
+	proc = (CALL_PROCEEDING_t *)(msg->data + mISDNUSER_HEAD_SIZE);
+	pthread_mutex_lock(&bc->lock);
+	bc->cstate = BC_CSTATE_PROCEED;
+	if (!(bc->Flags & FLG_BC_SENT_CID)) {
+		bc->Flags |= FLG_BC_SENT_CID;
+		proc->CHANNEL_ID = msg_put(msg, 2);
+		proc->CHANNEL_ID[0] = 1;
+		proc->CHANNEL_ID[1] = 0x88 | bc->channel;
+	}
+	pthread_mutex_unlock(&bc->lock);
+	if (bc->display[0]) {
+		len = strlen(bc->display);
+		proc->DISPLAY = p = msg_put(msg, len+1);
+		*p++ = len;
+		strcpy(p, bc->display);
+		bc->display[0] = 0;
+	}
+	ret = -EINVAL;
+	if (bc->manager->man2stack)
+		ret = bc->manager->man2stack(bc->manager->nst, msg);
+	if (ret)
+		free_msg(msg);
+	if (bc->manager->application) {
+		bc->Flags |= FLG_BC_APPLICATION;
+		len = bc->manager->application(bc->manager, PR_APP_ICALL, bc);
+		dprint(DBGM_BC, -1, "%s: bc%d application ret(%d)\n", __FUNCTION__,
+			bc->channel, len);
+	}	
+	return(ret);
+}
+
+static int
+send_alert(bchannel_t *bc)
+{
+	ALERTING_t	*at;
+	msg_t		*msg;
+	int		len, ret;
+	unsigned char	*p;
+	
+	dprint(DBGM_BC, -1, "%s: bc%d flg(%x) display(%s)\n", __FUNCTION__,
+		bc->channel, bc->Flags, bc->display);
+	msg = prep_l3data_msg(CC_ALERTING | REQUEST, bc->l3id,
+		sizeof(ALERTING_t), 128, NULL);
+	if (!msg)
+		return(-ENOMEM);
+	at = (ALERTING_t *)(msg->data + mISDNUSER_HEAD_SIZE);
+	pthread_mutex_lock(&bc->lock);
+	bc->cstate = BC_CSTATE_PROCEED;
+	if (!(bc->Flags & FLG_BC_SENT_CID)) {
+		bc->Flags |= FLG_BC_SENT_CID;
+		at->CHANNEL_ID = msg_put(msg, 2);
+		at->CHANNEL_ID[0] = 1;
+		at->CHANNEL_ID[1] = 0x88 | bc->channel;
+	}
+	if (bc->Flags & FLG_BC_PROGRESS) {
+		bc->Flags &= ~FLG_BC_PROGRESS;
+		set_tone(bc, FLG_BC_TONE_ALERT);
+		at->PROGRESS = p = msg_put(msg, 3);;
+		*p++ = 2;
+		*p++ = 0x80 | CAUSE_LOC_PNET_LOCUSER;
+		*p++ = 0x80 | PROGRESS_TONE;
+		setup_bchannel(bc);
+	}
+	pthread_mutex_unlock(&bc->lock);
+	if (bc->display[0]) {
+		len = strlen(bc->display);
+		at->DISPLAY = p = msg_put(msg, len+1);
+		*p++ = len;
+		strcpy(p, bc->display);
+		bc->display[0] = 0;
+	}
+	if (bc->fac[0]) {
+		at->FACILITY = p = msg_put(msg, bc->fac[0] + 1);
+		memcpy(p, bc->fac, bc->fac[0] + 1);
+		bc->fac[0] = 0;
+	}
+	if (bc->uu[0]) {
+		at->USER_USER = p = msg_put(msg, bc->uu[0] + 1);
+		memcpy(p, bc->uu, bc->uu[0] + 1);
+		bc->uu[0] = 0;
+	}
+	ret = -EINVAL;
+	if (bc->manager->man2stack)
+		ret = bc->manager->man2stack(bc->manager->nst, msg);
+	if (ret)
+		free_msg(msg);
+	return(ret);
+}
+
+static int
+send_connect(bchannel_t *bc)
+{
+	CONNECT_t	*conn;
+	time_t		tim;
+	struct tm	*ts;
+	msg_t		*msg;
+	int		len, ret;
+	unsigned char	*p;
+	
+	msg = prep_l3data_msg(CC_CONNECT | REQUEST, bc->l3id,
+		sizeof(CONNECT_t), 128, NULL);
+	if (!msg)
+		return(-ENOMEM);
+	conn = (CONNECT_t *)(msg->data + mISDNUSER_HEAD_SIZE);
+	pthread_mutex_lock(&bc->lock);
+	bc->cstate = BC_CSTATE_PROCEED;
+	bc->Flags &= ~FLG_BC_TONE;
+	if (!(bc->Flags & FLG_BC_SENT_CID)) {
+		bc->Flags |= FLG_BC_SENT_CID;
+		conn->CHANNEL_ID = msg_put(msg, 2);
+		conn->CHANNEL_ID[0] = 1;
+		conn->CHANNEL_ID[1] = 0x88 | bc->channel;
+	}
+	pthread_mutex_unlock(&bc->lock);
+	if (bc->display[0]) {
+		len = strlen(bc->display);
+		conn->DISPLAY = p = msg_put(msg, len+1);
+		*p++ = len;
+		strcpy(p, bc->display);
+		bc->display[0] = 0;
+	}
+	if (bc->fac[0]) {
+		conn->FACILITY = p = msg_put(msg, bc->fac[0] + 1);
+		memcpy(p, bc->fac, bc->fac[0] + 1);
+		bc->fac[0] = 0;
+	}
+	if (bc->uu[0]) {
+		conn->USER_USER = p = msg_put(msg, bc->uu[0] + 1);
+		memcpy(p, bc->uu, bc->uu[0] + 1);
+		bc->uu[0] = 0;
+	}
+	time(&tim);
+	ts = localtime(&tim);
+	if (ts->tm_year > 99)
+		ts->tm_year -=100;
+	conn->DATE = p = msg_put(msg, 6);
+	*p++ = 5;
+	*p++ = ts->tm_year;
+	*p++ = ts->tm_mon+1;
+	*p++ = ts->tm_mday;
+	*p++ = ts->tm_hour;
+	*p++ = ts->tm_min;
+
+	ret = -EINVAL;
+	if (bc->manager->man2stack)
+		ret = bc->manager->man2stack(bc->manager->nst, msg);
+	if (ret)
+		free_msg(msg);
+	return(ret);
+}
+
+static int
+send_connect_ack(bchannel_t *bc)
+{
+	CONNECT_ACKNOWLEDGE_t	*ca;
+	msg_t			*msg;
+	int			len, ret;
+	unsigned char		*p;
+	
+	msg = prep_l3data_msg(CC_CONNECT | RESPONSE, bc->l3id,
+		sizeof(CONNECT_ACKNOWLEDGE_t), 128, NULL);
+	if (!msg)
+		return(-ENOMEM);
+	setup_bchannel(bc);
+	ca = (CONNECT_ACKNOWLEDGE_t *)(msg->data + mISDNUSER_HEAD_SIZE);
+	pthread_mutex_lock(&bc->lock);
+	bc->cstate = BC_CSTATE_ACTIV;
+	bc->Flags &= ~FLG_BC_TONE; 
+	if (!(bc->Flags & FLG_BC_SENT_CID)) {
+		bc->Flags |= FLG_BC_SENT_CID;
+		ca->CHANNEL_ID = msg_put(msg, 2);
+		ca->CHANNEL_ID[0] = 1;
+		ca->CHANNEL_ID[1] = 0x88 | bc->channel;
+	}
+	pthread_mutex_unlock(&bc->lock);
+	if (bc->display[0]) {
+		len = strlen(bc->display);
+		ca->DISPLAY = p = msg_put(msg, len+1);
+		*p++ = len;
+		strcpy(p, bc->display);
+		bc->display[0] = 0;
+	}
+	ret = -EINVAL;
+	if (bc->manager->man2stack)
+		ret = bc->manager->man2stack(bc->manager->nst, msg);
+	if (ret)
+		free_msg(msg);
+	return(ret);
+}
+
+static int
+send_disc(bchannel_t *bc)
+{
+	DISCONNECT_t	*disc;
+	msg_t		*msg;
+	int		len, ret;
+	unsigned char	*p;
+	
+	msg = prep_l3data_msg(CC_DISCONNECT | REQUEST, bc->l3id,
+		sizeof(DISCONNECT_t), 128, NULL);
+	if (!msg)
+		return(-ENOMEM);
+	disc = (DISCONNECT_t *)(msg->data + mISDNUSER_HEAD_SIZE);
+	pthread_mutex_lock(&bc->lock);
+	bc->cstate = BC_CSTATE_DISCONNECT;
+	pthread_mutex_unlock(&bc->lock);
+	if (bc->cause_val) {
+		disc->CAUSE = p = msg_put(msg, 3);
+		*p++ = 2;
+		*p++ = 0x80 | bc->cause_loc;
+		*p++ = 0x80 | bc->cause_val;
+	}
+	if (bc->Flags & FLG_BC_PROGRESS) {
+		set_tone(bc, FLG_BC_TONE_BUSY);
+		disc->PROGRESS = p = msg_put(msg, 3);;
+		*p++ = 2;
+		*p++ = 0x80 | CAUSE_LOC_PNET_LOCUSER;
+		*p++ = 0x80 | PROGRESS_TONE;
+		setup_bchannel(bc);
+	}
+	if (bc->display[0]) {
+		len = strlen(bc->display);
+		disc->DISPLAY = p = msg_put(msg, len+1);
+		*p++ = len;
+		strcpy(p, bc->display);
+		bc->display[0] = 0;
+	}
+	if (bc->fac[0]) {
+		disc->FACILITY = p = msg_put(msg, bc->fac[0] + 1);
+		memcpy(p, bc->fac, bc->fac[0] + 1);
+		bc->fac[0] = 0;
+	}
+	if (bc->uu[0]) {
+		disc->USER_USER = p = msg_put(msg, bc->uu[0] + 1);
+		memcpy(p, bc->uu, bc->uu[0] + 1);
+		bc->uu[0] = 0;
+	}
+	ret = -EINVAL;
+	if (bc->manager->man2stack)
+		ret = bc->manager->man2stack(bc->manager->nst, msg);
+	if (ret)
+		free_msg(msg);
+	return(ret);
+}
+
+static int
+send_facility(bchannel_t *bc)
+{
+	FACILITY_t	*fac;
+	msg_t		*msg;
+	int		len, ret;
+	unsigned char	*p;
+	
+	msg = prep_l3data_msg(CC_FACILITY | REQUEST, bc->l3id,
+		sizeof(FACILITY_t), 128, NULL);
+	if (!msg)
+		return(-ENOMEM);
+	fac = (FACILITY_t *)(msg->data + mISDNUSER_HEAD_SIZE);
+	if (bc->display[0]) {
+		len = strlen(bc->display);
+		fac->DISPLAY = p = msg_put(msg, len+1);
+		*p++ = len;
+		strcpy(p, bc->display);
+		bc->display[0] = 0;
+	}
+	if (bc->fac[0]) {
+		fac->FACILITY = p = msg_put(msg, bc->fac[0] + 1);
+		memcpy(p, bc->fac, bc->fac[0] + 1);
+		bc->fac[0] = 0;
+	}
+	ret = -EINVAL;
+	if (bc->manager->man2stack)
+		ret = bc->manager->man2stack(bc->manager->nst, msg);
+	if (ret)
+		free_msg(msg);
+	return(ret);
+}
+
+static int
+send_userinfo(bchannel_t *bc)
+{
+	USER_INFORMATION_t	*ui;
+	msg_t			*msg;
+	int			ret;
+	unsigned char		*p;
+	
+	msg = prep_l3data_msg(CC_USER_INFORMATION | REQUEST, bc->l3id,
+		sizeof(USER_INFORMATION_t), 128, NULL);
+	if (!msg)
+		return(-ENOMEM);
+	ui = (USER_INFORMATION_t *)(msg->data + mISDNUSER_HEAD_SIZE);
+	if (bc->uu[0]) {
+		ui->USER_USER = p = msg_put(msg, bc->uu[0] + 1);
+		memcpy(p, bc->uu, bc->uu[0] + 1);
+		bc->uu[0] = 0;
+	}
+	ret = -EINVAL;
+	if (bc->manager->man2stack)
+		ret = bc->manager->man2stack(bc->manager->nst, msg);
+	if (ret)
+		free_msg(msg);
+	return(ret);
+}
+
+static int
+send_rel(bchannel_t *bc)
+{
+	RELEASE_t	*rel;
+	msg_t		*msg;
+	int		len, ret;
+	unsigned char	*p;
+	
+	msg = prep_l3data_msg(CC_RELEASE | REQUEST, bc->l3id,
+		sizeof(RELEASE_t), 128, NULL);
+	if (!msg)
+		return(-ENOMEM);
+	rel = (RELEASE_t *)(msg->data + mISDNUSER_HEAD_SIZE);
+	pthread_mutex_lock(&bc->lock);
+	bc->cstate = BC_CSTATE_RELEASE;
+	pthread_mutex_unlock(&bc->lock);
+	if (bc->cause_val) {
+		rel->CAUSE = p = msg_put(msg, 3);
+		*p++ = 2;
+		*p++ = 0x80 | bc->cause_loc;
+		*p++ = 0x80 | bc->cause_val;
+	}
+	if (bc->display[0]) {
+		len = strlen(bc->display);
+		rel->DISPLAY = p = msg_put(msg, len+1);
+		*p++ = len;
+		strcpy(p, bc->display);
+		bc->display[0] = 0;
+	}
+	if (bc->fac[0]) {
+		rel->FACILITY = p = msg_put(msg, bc->fac[0] + 1);
+		memcpy(p, bc->fac, bc->fac[0] + 1);
+		bc->fac[0] = 0;
+	}
+	if (bc->uu[0]) {
+		rel->USER_USER = p = msg_put(msg, bc->uu[0] + 1);
+		memcpy(p, bc->uu, bc->uu[0] + 1);
+		bc->uu[0] = 0;
+	}
+	ret = -EINVAL;
+	if (bc->manager->man2stack)
+		ret = bc->manager->man2stack(bc->manager->nst, msg);
+	if (ret)
+		free_msg(msg);
+	return(ret);
+}
+
+static int
+send_relcomp(bchannel_t *bc, int l3id, int cause) {
+	RELEASE_COMPLETE_t	*rc;
+	msg_t			*msg;
+	int			ret, len;
+	unsigned char		*p;
+
+	msg = prep_l3data_msg(CC_RELEASE_COMPLETE | REQUEST, l3id,
+		sizeof(RELEASE_COMPLETE_t), 128, NULL);
+	if (!msg)
+		return(-ENOMEM);
+	rc = (RELEASE_COMPLETE_t *)(msg->data + mISDNUSER_HEAD_SIZE);
+	clear_bc(bc);
+	pthread_mutex_lock(&bc->lock);
+	bc->cstate = BC_CSTATE_NULL;
+	pthread_mutex_unlock(&bc->lock);
+	if (cause) {
+		bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
+		bc->cause_val = cause;
+		rc->CAUSE = msg_put(msg, 3);
+		rc->CAUSE[0] = 2;
+		rc->CAUSE[1] = 0x80 | CAUSE_LOC_PNET_LOCUSER;
+		rc->CAUSE[2] = 0x80 | cause;
+	}
+	if (bc->display[0]) {
+		len = strlen(bc->display);
+		rc->DISPLAY = p = msg_put(msg, len+1);
+		*p++ = len;
+		strcpy(p, bc->display);
+		bc->display[0] = 0;
+	}
+	if (bc->fac[0]) {
+		rc->FACILITY = p = msg_put(msg, bc->fac[0] + 1);
+		memcpy(p, bc->fac, bc->fac[0] + 1);
+		bc->fac[0] = 0;
+	}
+	if (bc->uu[0]) {
+		rc->USER_USER = p = msg_put(msg, bc->uu[0] + 1);
+		memcpy(p, bc->uu, bc->uu[0] + 1);
+		bc->uu[0] = 0;
+	}
+	ret = -EINVAL;
+	if (bc->manager->man2stack)
+		ret = bc->manager->man2stack(bc->manager->nst, msg);
+	if (ret)
+		free_msg(msg);
+	return(ret);
+}
+
+static int
+info_ind(bchannel_t *bc, void *arg)
+{
+	INFORMATION_t	*info = arg;
+	int		ret;
+
+	if (info->CALLED_PN) {
+		set_tone(bc, FLG_BC_TONE_SILENCE);
+		add_nr(bc, info->CALLED_PN);
+		ret = match_nr(bc->manager, bc->nr, &bc->usednr);
+		dprint(DBGM_BC, -1, "%s: match_nr ret(%d)\n", __FUNCTION__,
+			ret);
+		if (!ret) {
+			send_proceeding(bc); 
+		} else if (ret == 2 || info->COMPLETE) {
+			bc->Flags |= FLG_BC_PROGRESS;
+			set_tone(bc, FLG_BC_TONE_BUSY);
+			bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
+			bc->cause_val = CAUSE_UNASSIGNED_NUMBER;
+			send_disc(bc);
+		}
+	}
+	return(0);
+}
+
+static int
+setup_ind(bchannel_t *bc, int l3id, void *arg)
+{
+	SETUP_t		*setup = arg;
+	int		cause,ret;
+
+	if (bc->cstate != BC_CSTATE_ICALL)
+		return(send_relcomp(bc, l3id, CAUSE_NOTCOMPAT_STATE));
+	bc->l3id = l3id;
+	cause = CAUSE_INCOMPATIBLE_DEST;
+	if (setup->BEARER) {
+		memcpy(bc->bc, setup->BEARER, setup->BEARER[0] +1);
+		if (setup->BEARER[0] == 3) {
+			if ((setup->BEARER[1] == 0x80) &&
+				(setup->BEARER[2] == 0x90) &&
+				(setup->BEARER[3] == 0xa3)) {
+				cause = 0;
+				bc->l1_prot = ISDN_PID_L1_B_64TRANS;		
+			}
+		}
+	} else
+		cause = CAUSE_MANDATORY_IE_MISS;
+	if (cause)
+		return(send_relcomp(bc, bc->l3id, cause));
+	if (setup->CALLING_PN)
+		memcpy(bc->msn, setup->CALLING_PN, setup->CALLING_PN[0] + 1);
+	else
+		bc->msn[0] = 0;
+	if (setup->CALLING_SUB)
+		memcpy(bc->clisub, setup->CALLING_SUB,
+			setup->CALLING_SUB[0] + 1);
+	else
+		bc->clisub[0] = 0;
+	if (setup->CALLED_SUB)
+		memcpy(bc->cldsub, setup->CALLED_SUB,
+			setup->CALLED_SUB[0] + 1);
+	else
+		bc->cldsub[0] = 0;
+	if (setup->FACILITY)
+		memcpy(bc->fac, setup->FACILITY, setup->FACILITY[0] + 1);
+	else
+		bc->fac[0] = 0;
+	if (setup->USER_USER)
+		memcpy(bc->uu, setup->USER_USER, setup->USER_USER[0] + 1);
+	else
+		bc->uu[0] = 0;
+	if (!bc->sbuf)
+		bc->sbuf = init_ibuffer(2048);
+	set_tone(bc, FLG_BC_TONE_DIAL);
+	if (!setup->CALLED_PN) {
+		bc->Flags |= FLG_BC_PROGRESS;
+		send_setup_ack(bc);
+	} else {
+		set_tone(bc, FLG_BC_TONE_SILENCE);
+		bc->Flags |= FLG_BC_PROGRESS;
+		add_nr(bc, setup->CALLED_PN);
+		ret = match_nr(bc->manager, bc->nr, &bc->usednr);
+		dprint(DBGM_BC, -1, "%s: match_nr ret(%d)\n", __FUNCTION__,
+			ret);
+		if (!ret) {
+			send_proceeding(bc); 
+		} else if (ret == 2 || setup->COMPLETE) {
+			return(send_relcomp(bc, bc->l3id, CAUSE_UNASSIGNED_NUMBER));
+		} else {
+			send_setup_ack(bc);
+		}
+	}
+	return(0);
+}
+
+static int
+conn_ind(bchannel_t *bc, void *arg)
+{
+	CONNECT_t	*conn = arg;
+	int		ret;
+
+	if (conn) {
+		if (conn->FACILITY)
+			memcpy(bc->fac, conn->FACILITY, conn->FACILITY[0] + 1);
+		else
+			bc->fac[0] = 0;
+		if (conn->USER_USER)
+			memcpy(bc->uu, conn->USER_USER, conn->USER_USER[0] + 1);
+		else
+			bc->uu[0] = 0;
+	}
+	if ((bc->Flags & FLG_BC_APPLICATION) && bc->manager->application) {
+		setup_bchannel(bc);
+		ret = bc->manager->application(bc->manager, PR_APP_CONNECT, bc);
+		dprint(DBGM_BC, -1, "%s: bc%d application ret(%d)\n", __FUNCTION__,
+			bc->channel, ret);
+		if (!ret) {
+			send_connect_ack(bc);
+		}
+	}	
+	return(0);
+}
+
+static int
+alert_ind(bchannel_t *bc, void *arg)
+{
+	ALERTING_t	*alert = arg;
+	int		ret;
+
+	pthread_mutex_lock(&bc->lock);
+	bc->cstate = BC_CSTATE_ALERTING;
+	pthread_mutex_unlock(&bc->lock);
+	if (alert->FACILITY)
+		memcpy(bc->fac, alert->FACILITY, alert->FACILITY[0] + 1);
+	else
+		bc->fac[0] = 0;
+	if (alert->USER_USER)
+		memcpy(bc->uu, alert->USER_USER, alert->USER_USER[0] + 1);
+	else
+		bc->uu[0] = 0;
+	if ((bc->Flags & FLG_BC_APPLICATION) && bc->manager->application) {
+		ret = bc->manager->application(bc->manager, PR_APP_ALERT, bc);
+		dprint(DBGM_BC, -1, "%s: bc%d application ret(%d)\n", __FUNCTION__,
+			bc->channel, ret);
+	}	
+	return(0);
+}
+
+static int
+facility_ind(bchannel_t *bc, void *arg)
+{
+	FACILITY_t	*fac = arg;
+	int		ret;
+
+	if (fac) {
+		if (fac->FACILITY)
+			memcpy(bc->fac, fac->FACILITY, fac->FACILITY[0] + 1);
+		else
+			bc->fac[0] = 0;
+	}
+	if ((bc->Flags & FLG_BC_APPLICATION) && bc->manager->application) {
+		ret = bc->manager->application(bc->manager, PR_APP_FACILITY, bc);
+		dprint(DBGM_BC, -1, "%s: bc%d application ret(%d)\n", __FUNCTION__,
+			bc->channel, ret);
+	}	
+	return(0);
+}
+
+static int
+userinfo_ind(bchannel_t *bc, void *arg)
+{
+	USER_INFORMATION_t	*ui = arg;
+	int			ret;
+
+	if (ui) {
+		if (ui->USER_USER)
+			memcpy(bc->uu, ui->USER_USER, ui->USER_USER[0] + 1);
+		else
+			bc->uu[0] = 0;
+	}
+	if ((bc->Flags & FLG_BC_APPLICATION) && bc->manager->application) {
+		ret = bc->manager->application(bc->manager, PR_APP_USERUSER, bc);
+		dprint(DBGM_BC, -1, "%s: bc%d application ret(%d)\n", __FUNCTION__,
+			bc->channel, ret);
+	}	
+	return(0);
+}
+
+static int
+disc_ind(bchannel_t *bc, void *arg)
+{
+	DISCONNECT_t	*disc = arg;
+	int		cause = 0;
+	int		ret;
+
+	if (disc->CAUSE) {
+		if (disc->CAUSE[0] >1) {
+			dprint(DBGM_BC, -1, "%s: loc(%d) cause(%d)\n", __FUNCTION__,
+				disc->CAUSE[1] & 0xf, disc->CAUSE[2] & 0x7f);
+			bc->cause_loc = disc->CAUSE[1] & 0xf;
+			bc->cause_val = disc->CAUSE[2] & 0x7f;
+		} else {
+			dprint(DBGM_BC, -1, "%s: cause len %d\n", __FUNCTION__,
+				disc->CAUSE[0]);
+			cause = CAUSE_INVALID_CONTENTS;
+		}
+	} else {
+		cause = CAUSE_MANDATORY_IE_MISS;
+	}
+	if (cause) {
+		bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
+		bc->cause_val = cause;
+	}
+	pthread_mutex_lock(&bc->lock);
+	bc->cstate = BC_CSTATE_DISCONNECT;
+	pthread_mutex_unlock(&bc->lock);
+	send_rel(bc);
+	if (disc->FACILITY)
+		memcpy(bc->fac, disc->FACILITY, disc->FACILITY[0] + 1);
+	else
+		bc->fac[0] = 0;
+	if (disc->USER_USER)
+		memcpy(bc->uu, disc->USER_USER, disc->USER_USER[0] + 1);
+	else
+		bc->uu[0] = 0;
+	if ((bc->Flags & FLG_BC_APPLICATION) && bc->manager->application) {
+		ret = bc->manager->application(bc->manager, PR_APP_HANGUP, bc);
+		dprint(DBGM_BC, -1, "%s: bc%d application ret(%d)\n", __FUNCTION__,
+			bc->channel, ret);
+	}	
+	return(0);
+}
+
+static int
+rel_ind(bchannel_t *bc, void *arg)
+{
+	RELEASE_t	*rel = arg;
+	int		ret;
+
+	if (rel) {
+		if (rel->FACILITY)
+			memcpy(bc->fac, rel->FACILITY, rel->FACILITY[0] + 1);
+		else
+			bc->fac[0] = 0;
+		if (rel->USER_USER)
+			memcpy(bc->uu, rel->USER_USER, rel->USER_USER[0] + 1);
+		else
+			bc->uu[0] = 0;
+		if (rel->CAUSE) {
+			if (rel->CAUSE[0] > 1) {
+				dprint(DBGM_BC, -1, "%s: loc(%d) cause(%d)\n", __FUNCTION__,
+					rel->CAUSE[1] & 0xf, rel->CAUSE[2] & 0x7f);
+				bc->cause_loc = rel->CAUSE[1] & 0xf;
+				bc->cause_val = rel->CAUSE[2] & 0x7f;
+			}
+		}
+	}
+	if ((bc->Flags & FLG_BC_APPLICATION) && bc->manager->application) {
+		ret = bc->manager->application(bc->manager, PR_APP_CLEAR, bc);
+		dprint(DBGM_BC, -1, "%s: bc%d application ret(%d)\n", __FUNCTION__,
+			bc->channel, ret);
+	}	
+	clear_bc(bc);
+	pthread_mutex_lock(&bc->lock);
+	bc->cstate = BC_CSTATE_NULL;
+	pthread_mutex_unlock(&bc->lock);
+	return(0);
+}
+
+static int
+relcmpl_ind(bchannel_t *bc, void *arg)
+{
+	RELEASE_COMPLETE_t	*rc = arg;
+	int			ret;
+
+	if (rc) {
+		if (rc->FACILITY)
+			memcpy(bc->fac, rc->FACILITY, rc->FACILITY[0] + 1);
+		else
+			bc->fac[0] = 0;
+		if (rc->USER_USER)
+			memcpy(bc->uu, rc->USER_USER, rc->USER_USER[0] + 1);
+		else
+			bc->uu[0] = 0;
+		if (rc->CAUSE) {
+			if (rc->CAUSE[0] > 1) {
+				dprint(DBGM_BC, -1, "%s: loc(%d) cause(%d)\n", __FUNCTION__,
+					rc->CAUSE[1] & 0xf, rc->CAUSE[2] & 0x7f);
+				bc->cause_loc = rc->CAUSE[1] & 0xf;
+				bc->cause_val = rc->CAUSE[2] & 0x7f;
+			}
+		}
+	}
+	if ((bc->Flags & FLG_BC_APPLICATION) && bc->manager->application) {
+		ret = bc->manager->application(bc->manager, PR_APP_CLEAR, bc);
+		dprint(DBGM_BC, -1, "%s: bc%d application ret(%d)\n", __FUNCTION__,
+			bc->channel, ret);
+	}	
+	clear_bc(bc);
+	pthread_mutex_lock(&bc->lock);
+	bc->cstate = BC_CSTATE_NULL;
+	pthread_mutex_unlock(&bc->lock);
+	return(0);
+}
+
+static int
+relcr_ind(bchannel_t *bc, void *arg)
+{
+	int	ret, *err = arg;
+	
+	dprint(DBGM_BC, -1, "%s: bc%d cause(%x)\n", __FUNCTION__,
+		bc->channel, *err);
+	if ((bc->Flags & FLG_BC_APPLICATION) && bc->manager->application) {
+		ret = bc->manager->application(bc->manager, PR_APP_CLEAR, bc);
+		dprint(DBGM_BC, -1, "%s: bc%d application ret(%d)\n", __FUNCTION__,
+			bc->channel, ret);
+	}
+	if (bc->cstate != BC_CSTATE_NULL) {
+		clear_bc(bc);
+		pthread_mutex_lock(&bc->lock);
+		bc->cstate = BC_CSTATE_NULL;
+		pthread_mutex_unlock(&bc->lock);
+	}
+	return(0);
+}
+
+static void
+cleanup_bchannel(void *arg)
+{
+	bchannel_t	*bc = arg;
+
+	dprint(DBGM_BC, -1,"%s: bc %d\n", __FUNCTION__, bc->channel);
+	pthread_mutex_lock(&bc->lock);
+	msg_queue_purge(&bc->workq);
+	bc->smsg = NULL;
+	free_ibuffer(bc->sbuf);
+	bc->sbuf = NULL;
+	free_ibuffer(bc->rbuf);
+	bc->rbuf = NULL;
+	bc->cstate = BC_CSTATE_NULL;
+	while(1)
+		if (!sem_trywait(&bc->work))
+			break;
+	pthread_mutex_unlock(&bc->lock);
+	dprint(DBGM_BC, -1,"%s: bc %d end\n", __FUNCTION__, bc->channel);
+}
+
+static void *
+main_bc_task(void *arg)
+{
+	bchannel_t	*bc = arg;
+	msg_t		*msg;
+	int		ret, id;
+	mISDNuser_head_t	*hh;
+
+	pthread_cleanup_push(cleanup_bchannel, (void *)bc);
+	dprint(DBGM_BC, -1,"%s bc %d\n", __FUNCTION__, bc->channel);
+	while(1) {
+		
+		sem_wait(&bc->work);
+		if (bc->Flags & FLG_BC_TERMINATE)
+			pthread_exit(NULL);
+		if (!bc->smsg) { 
+			if (bc->Flags & FLG_BC_TONE)
+				tone_handler(bc); 
+			if (ibuf_usedcount(bc->sbuf))
+				b_send(bc);
+		}
+		msg = msg_dequeue(&bc->workq);
+		if (msg) {
+			hh = (mISDNuser_head_t *)msg->data;
+			msg_pull(msg, mISDNUSER_HEAD_SIZE);
+			dprint(DBGM_BC, -1,"%s: bc%d st(%d/%d) prim(%x) dinfo(%x) len(%d)\n", __FUNCTION__,
+				bc->channel, bc->cstate, bc->bstate, hh->prim, hh->dinfo, msg->len);
+			ret = -EINVAL;
+			switch(hh->prim) {
+				case PH_DATA | INDICATION:
+					ret = do_b_data_ind(bc, hh, msg);
+					break;
+				case PH_DATA | CONFIRM:
+					ret = do_b_data_cnf(bc, hh, msg);
+					break;
+				case PH_ACTIVATE | INDICATION:
+				case PH_ACTIVATE | CONFIRM:
+					ret = do_b_activated(bc, hh, msg);
+					break;
+				case PH_DEACTIVATE | INDICATION:
+				case PH_DEACTIVATE | CONFIRM:
+					ret = do_b_deactivated(bc, hh, msg);
+					break;
+				case BC_SETUP | CONFIRM:
+					ret = do_b_setup_conf(bc, hh, msg);
+					break;
+				case BC_SETUP | SUB_ERROR:
+				case BC_CLEANUP | SUB_ERROR:
+					wprint("%s:ch%d %x error %x\n", __FUNCTION__,
+						bc->channel, hh->prim, *((int *)msg->data));
+				case BC_CLEANUP | CONFIRM:
+					ret = do_b_cleanup_conf(bc, hh, msg);
+					break;
+
+				case CC_SETUP | INDICATION:
+					setup_ind(bc, hh->dinfo, msg->data);
+					break;
+				case CC_SETUP | CONFIRM:
+					bc->l3id = *((int *)msg->data);
+					break;
+				case CC_NEW_CR | INDICATION:
+					pthread_mutex_lock(&bc->lock);
+					id = *((int *)msg->data);
+					msg_push(msg, mISDNUSER_HEAD_SIZE);
+					if (bc->manager && bc->manager->man2stack)
+						ret = bc->manager->man2stack(
+							bc->manager->nst, msg);
+					bc->l3id = id;
+					pthread_mutex_unlock(&bc->lock);
+					break;
+				case CC_RELEASE_CR | INDICATION:
+					relcr_ind(bc, msg->data);
+					break;
+				case CC_INFORMATION | INDICATION:
+					info_ind(bc, msg->data);
+					break;
+				case CC_ALERTING | INDICATION:
+					alert_ind(bc, msg->data);
+					break;
+				case CC_CONNECT | INDICATION:
+					conn_ind(bc, msg->data);
+					break;
+				case CC_FACILITY | INDICATION:
+					facility_ind(bc, msg->data);
+					break;
+				case CC_USER_INFORMATION | INDICATION:
+					userinfo_ind(bc, msg->data);
+					break;
+				case CC_DISCONNECT | INDICATION:
+					disc_ind(bc, msg->data);
+					break;
+				case CC_RELEASE | INDICATION:
+					rel_ind(bc, msg->data);
+					break;
+				case CC_RELEASE | CONFIRM:
+					rel_ind(bc, NULL);
+					break;
+				case CC_RELEASE_COMPLETE | INDICATION:
+					relcmpl_ind(bc, msg->data);
+					break;
+
+				case CC_SETUP | REQUEST:
+					send_setup(bc);
+					break;
+				case CC_ALERTING | REQUEST:
+					send_alert(bc);
+					break;
+				case CC_CONNECT | REQUEST:
+					send_connect(bc);
+					break;
+				case CC_DISCONNECT | REQUEST:
+					send_disc(bc);
+					break;
+				case CC_FACILITY | REQUEST:
+					send_facility(bc);
+					break;
+				case CC_USER_INFORMATION | REQUEST:
+					send_userinfo(bc);
+					break;
+				case CC_TIMEOUT | INDICATION:
+					dprint(DBGM_MAN,"%s: bc%d got CC_TIMEOUT\n", __FUNCTION__,
+						bc->channel);
+					break;
+				default:
+					wprint("%s:ch%d unhandled prim(%x) di(%x)\n", __FUNCTION__,
+						bc->channel, hh->prim, hh->dinfo);
+					break;
+			}
+			if (ret)
+				free_msg(msg);
+		}
+	}
+	pthread_cleanup_pop(1);
+	return(NULL);
+}
+
+
+int
+init_bchannel(bchannel_t *bc, int channel)
+{
+	int	ret;
+
+	bc->channel = channel;
+	msg_queue_init(&bc->workq);
+	bc->cstate = BC_CSTATE_NULL;
+	bc->bstate = BC_BSTATE_NULL;
+	pthread_mutex_init(&bc->lock, NULL);
+	sem_init (&bc->work, 0, 0);
+	ret = pthread_create(&bc->tid, NULL, main_bc_task, (void *)bc);
+	dprint(DBGM_BC, -1, "%s: create bc%d thread %ld ret %d\n", __FUNCTION__,
+		channel, bc->tid, ret);
+	return(0);
+}
+
+int
+term_bchannel(bchannel_t *bc)
+{
+	dprint(DBGM_BC, -1, "%s: bc%d\n", __FUNCTION__, bc->channel);
+	bc->Flags |= FLG_BC_TERMINATE;
+	sem_post(&bc->work);
+	return(0);
+}

Added: misdn-user/trunk/i4lnet/fsm.c
===================================================================
--- misdn-user/trunk/i4lnet/fsm.c	                        (rev 0)
+++ misdn-user/trunk/i4lnet/fsm.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,163 @@
+/* $Id: fsm.c,v 1.0 2003/08/27 07:35:31 kkeil Exp $
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "fsm.h"
+
+#define FSM_TIMER_DEBUG 0
+
+void
+FsmNew(struct Fsm *fsm,
+       struct FsmNode *fnlist, int fncount)
+{
+	int i;
+
+	fsm->jumpmatrix = (FSMFNPTR *)
+		malloc(sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count);
+	if (!fsm->jumpmatrix)
+		return;
+	memset(fsm->jumpmatrix, 0, sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count);
+	for (i = 0; i < fncount; i++) 
+		if ((fnlist[i].state>=fsm->state_count) || (fnlist[i].event>=fsm->event_count)) {
+			eprint("FsmNew Error line %d st(%ld/%ld) ev(%ld/%ld)\n",
+				i,(long)fnlist[i].state,(long)fsm->state_count,
+				(long)fnlist[i].event,(long)fsm->event_count);
+		} else		
+			fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
+				fnlist[i].state] = (FSMFNPTR) fnlist[i].routine;
+}
+
+void
+FsmFree(struct Fsm *fsm)
+{
+	free(fsm->jumpmatrix);
+}
+
+int
+FsmEvent(struct FsmInst *fi, int event, void *arg)
+{
+	FSMFNPTR r;
+
+	if ((fi->state>=fi->fsm->state_count) || (event >= fi->fsm->event_count)) {
+		eprint("FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n",
+			(long)fi->state,(long)fi->fsm->state_count,event,(long)fi->fsm->event_count);
+		return(1);
+	}
+	r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
+	if (r) {
+		if (fi->debug)
+			fi->printdebug(fi, "State %s Event %s",
+				fi->fsm->strState[fi->state],
+				fi->fsm->strEvent[event]);
+		r(fi, event, arg);
+		return (0);
+	} else {
+		if (fi->debug)
+			fi->printdebug(fi, "State %s Event %s no action",
+				fi->fsm->strState[fi->state],
+				fi->fsm->strEvent[event]);
+		return (!0);
+	}
+}
+
+void
+FsmChangeState(struct FsmInst *fi, int newstate)
+{
+	fi->state = newstate;
+	if (fi->debug)
+		fi->printdebug(fi, "ChangeState %s",
+			fi->fsm->strState[newstate]);
+}
+
+static int
+FsmExpireTimer(struct FsmTimer *ft)
+{
+#if FSM_TIMER_DEBUG
+	if (ft->fi->debug)
+		ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);
+#endif
+	FsmEvent(ft->fi, ft->event, ft->arg);
+	return(0);
+}
+
+void
+FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
+{
+	ft->fi = fi;
+	ft->tl.function = (void *)FsmExpireTimer;
+	ft->tl.data = (long) ft;
+#if FSM_TIMER_DEBUG
+	if (ft->fi->debug)
+		ft->fi->printdebug(ft->fi, "FsmInitTimer %lx", (long) ft);
+#endif
+	init_timer(&ft->tl, ft->fi->nst);
+}
+
+void
+FsmDelTimer(struct FsmTimer *ft, int where)
+{
+#if FSM_TIMER_DEBUG
+	if (ft->fi->debug)
+		ft->fi->printdebug(ft->fi, "FsmDelTimer %lx %d", (long) ft, where);
+#endif
+	del_timer(&ft->tl);
+}
+
+void
+FsmRemoveTimer(struct FsmTimer *ft)
+{
+	remove_timer(&ft->tl);
+}
+
+int
+FsmAddTimer(struct FsmTimer *ft,
+	    int millisec, int event, void *arg, int where)
+{
+
+#if FSM_TIMER_DEBUG
+	if (ft->fi->debug)
+		ft->fi->printdebug(ft->fi, "FsmAddTimer %lx %d %d",
+			(long) ft, millisec, where);
+#endif
+
+	if (timer_pending(&ft->tl)) {
+		wprint("FsmAddTimer: timer already active!\n");
+		ft->fi->printdebug(ft->fi, "FsmAddTimer already active!");
+		return -1;
+	}
+	init_timer(&ft->tl, ft->fi->nst);
+	ft->event = event;
+	ft->arg = arg;
+	ft->tl.expires = millisec;
+	add_timer(&ft->tl);
+	return 0;
+}
+
+void
+FsmRestartTimer(struct FsmTimer *ft,
+	    int millisec, int event, void *arg, int where)
+{
+
+#if FSM_TIMER_DEBUG
+	if (ft->fi->debug)
+		ft->fi->printdebug(ft->fi, "FsmRestartTimer %lx %d %d",
+			(long) ft, millisec, where);
+#endif
+
+	if (timer_pending(&ft->tl))
+		del_timer(&ft->tl);
+	init_timer(&ft->tl, ft->fi->nst);
+	ft->event = event;
+	ft->arg = arg;
+	ft->tl.expires = millisec;
+	add_timer(&ft->tl);
+}

Added: misdn-user/trunk/i4lnet/fsm.h
===================================================================
--- misdn-user/trunk/i4lnet/fsm.h	                        (rev 0)
+++ misdn-user/trunk/i4lnet/fsm.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,53 @@
+/* $Id: fsm.h,v 1.0 2003/08/27 07:35:31 kkeil Exp $
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+
+/* Statemachine */
+
+#include "isdn_net.h"
+
+struct FsmInst;
+
+typedef void (* FSMFNPTR)(struct FsmInst *, int, void *);
+
+struct Fsm {
+	FSMFNPTR *jumpmatrix;
+	int state_count, event_count;
+	char **strEvent, **strState;
+};
+
+struct FsmInst {
+	struct Fsm	*fsm;
+	net_stack_t	*nst;
+	int		state;
+	int		debug;
+	void		*userdata;
+	int		userint;
+	void		(*printdebug) (struct FsmInst *, char *, ...);
+};
+
+struct FsmNode {
+	int state, event;
+	void (*routine) (struct FsmInst *, int, void *);
+};
+
+struct FsmTimer {
+	struct FsmInst	*fi;
+	itimer_t	tl;
+	int		event;
+	void		*arg;
+};
+
+extern void FsmNew(struct Fsm *, struct FsmNode *, int);
+extern void FsmFree(struct Fsm *);
+extern int FsmEvent(struct FsmInst *, int , void *);
+extern void FsmChangeState(struct FsmInst *, int);
+extern void FsmInitTimer(struct FsmInst *, struct FsmTimer *);
+extern int FsmAddTimer(struct FsmTimer *, int, int, void *, int);
+extern void FsmRestartTimer(struct FsmTimer *, int, int, void *, int);
+extern void FsmDelTimer(struct FsmTimer *, int);
+extern void FsmRemoveTimer(struct FsmTimer *);
+

Added: misdn-user/trunk/i4lnet/g711.c
===================================================================
--- misdn-user/trunk/i4lnet/g711.c	                        (rev 0)
+++ misdn-user/trunk/i4lnet/g711.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,928 @@
+/*
+ * This source code is quick table lookup implementation of
+ * convert 16 bit linear PCM and A-law u-law (ITU G.711) codings
+ * Tables are generated using ITU G.711 example code from
+ * Sun Microsystems, Inc.
+ *
+ * (C)2001 Karsten Keil kkeil at suse.de
+ *
+ *
+ *
+ */
+ 
+#include "g711.h"
+
+unsigned char _l2u[4096] = {
+	0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7,
+	0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0, 0xef,
+	0xef, 0xee, 0xee, 0xed, 0xed, 0xec, 0xec, 0xeb,
+	0xeb, 0xea, 0xea, 0xe9, 0xe9, 0xe8, 0xe8, 0xe7,
+	0xe7, 0xe6, 0xe6, 0xe5, 0xe5, 0xe4, 0xe4, 0xe3,
+	0xe3, 0xe2, 0xe2, 0xe1, 0xe1, 0xe0, 0xe0, 0xdf,
+	0xdf, 0xdf, 0xdf, 0xde, 0xde, 0xde, 0xde, 0xdd,
+	0xdd, 0xdd, 0xdd, 0xdc, 0xdc, 0xdc, 0xdc, 0xdb,
+	0xdb, 0xdb, 0xdb, 0xda, 0xda, 0xda, 0xda, 0xd9,
+	0xd9, 0xd9, 0xd9, 0xd8, 0xd8, 0xd8, 0xd8, 0xd7,
+	0xd7, 0xd7, 0xd7, 0xd6, 0xd6, 0xd6, 0xd6, 0xd5,
+	0xd5, 0xd5, 0xd5, 0xd4, 0xd4, 0xd4, 0xd4, 0xd3,
+	0xd3, 0xd3, 0xd3, 0xd2, 0xd2, 0xd2, 0xd2, 0xd1,
+	0xd1, 0xd1, 0xd1, 0xd0, 0xd0, 0xd0, 0xd0, 0xcf,
+	0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xce,
+	0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xcd,
+	0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcc,
+	0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb,
+	0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xca,
+	0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xc9,
+	0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc8,
+	0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc7,
+	0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc6,
+	0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc5,
+	0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc4,
+	0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc3,
+	0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc2,
+	0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc1,
+	0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc0,
+	0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xbf,
+	0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+	0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbe,
+	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
+	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbd,
+	0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
+	0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc,
+	0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
+	0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbb,
+	0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+	0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba,
+	0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
+	0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xb9,
+	0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9,
+	0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb8,
+	0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
+	0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb7,
+	0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
+	0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6,
+	0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6,
+	0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb5,
+	0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
+	0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb4,
+	0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+	0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb3,
+	0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
+	0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb2,
+	0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
+	0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb1,
+	0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
+	0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb0,
+	0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
+	0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xaf,
+	0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+	0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+	0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+	0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xae,
+	0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+	0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+	0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+	0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xad,
+	0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+	0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+	0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+	0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xac,
+	0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+	0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+	0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+	0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xab,
+	0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+	0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+	0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+	0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xaa,
+	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa9,
+	0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+	0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+	0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+	0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8,
+	0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+	0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+	0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+	0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa7,
+	0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+	0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+	0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+	0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa6,
+	0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+	0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+	0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+	0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa5,
+	0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+	0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+	0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+	0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4,
+	0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+	0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+	0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+	0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa3,
+	0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+	0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+	0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+	0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2,
+	0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+	0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+	0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+	0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa1,
+	0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+	0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+	0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+	0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa0,
+	0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+	0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+	0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+	0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0x9f,
+	0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+	0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+	0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+	0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+	0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+	0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+	0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+	0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9e,
+	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d,
+	0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+	0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+	0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+	0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+	0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+	0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+	0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+	0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c,
+	0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+	0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+	0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+	0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+	0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+	0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+	0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+	0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9b,
+	0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+	0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+	0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+	0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+	0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+	0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+	0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+	0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a,
+	0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+	0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+	0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+	0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+	0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+	0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+	0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+	0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x99,
+	0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+	0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+	0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+	0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+	0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+	0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+	0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+	0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98,
+	0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+	0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+	0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+	0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+	0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+	0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+	0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+	0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x97,
+	0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+	0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+	0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+	0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+	0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+	0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+	0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+	0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96,
+	0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+	0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+	0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+	0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+	0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+	0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+	0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+	0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x95,
+	0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+	0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+	0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+	0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+	0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+	0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+	0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+	0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x94,
+	0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+	0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+	0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+	0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+	0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+	0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+	0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+	0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x93,
+	0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+	0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+	0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+	0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+	0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+	0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+	0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+	0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x92,
+	0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+	0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+	0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+	0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+	0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+	0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+	0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+	0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x91,
+	0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+	0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+	0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+	0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+	0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+	0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+	0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+	0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x90,
+	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x8f,
+	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8e,
+	0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+	0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+	0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+	0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+	0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+	0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+	0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+	0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+	0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+	0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+	0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+	0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+	0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+	0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+	0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+	0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8d,
+	0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+	0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+	0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+	0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+	0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+	0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+	0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+	0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+	0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+	0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+	0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+	0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+	0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+	0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+	0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+	0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8c,
+	0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+	0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+	0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+	0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+	0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+	0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+	0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+	0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+	0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+	0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+	0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+	0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+	0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+	0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+	0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+	0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8b,
+	0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+	0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+	0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+	0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+	0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+	0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+	0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+	0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+	0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+	0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+	0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+	0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+	0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+	0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+	0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+	0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8a,
+	0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+	0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+	0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+	0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+	0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+	0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+	0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+	0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+	0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+	0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+	0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+	0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+	0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+	0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+	0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+	0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x89,
+	0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+	0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+	0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+	0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+	0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+	0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+	0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+	0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+	0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+	0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+	0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+	0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+	0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+	0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+	0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+	0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88,
+	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x87,
+	0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+	0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+	0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+	0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+	0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+	0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+	0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+	0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+	0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+	0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+	0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+	0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+	0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+	0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+	0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+	0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x86,
+	0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+	0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+	0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+	0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+	0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+	0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+	0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+	0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+	0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+	0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+	0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+	0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+	0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+	0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+	0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+	0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x85,
+	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84,
+	0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+	0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+	0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+	0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+	0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+	0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+	0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+	0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+	0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+	0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+	0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+	0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+	0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+	0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+	0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+	0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x83,
+	0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+	0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+	0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+	0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+	0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+	0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+	0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+	0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+	0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+	0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+	0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+	0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+	0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+	0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+	0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+	0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82,
+	0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+	0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+	0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+	0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+	0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+	0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+	0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+	0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+	0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+	0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+	0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+	0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+	0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+	0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+	0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+	0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81,
+	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+};
+
+unsigned char _l2A[2048] = {
+	0xd5, 0xd4, 0xd7, 0xd6, 0xd1, 0xd0, 0xd3, 0xd2,
+	0xdd, 0xdc, 0xdf, 0xde, 0xd9, 0xd8, 0xdb, 0xda,
+	0xc5, 0xc4, 0xc7, 0xc6, 0xc1, 0xc0, 0xc3, 0xc2,
+	0xcd, 0xcc, 0xcf, 0xce, 0xc9, 0xc8, 0xcb, 0xca,
+	0xf5, 0xf5, 0xf4, 0xf4, 0xf7, 0xf7, 0xf6, 0xf6,
+	0xf1, 0xf1, 0xf0, 0xf0, 0xf3, 0xf3, 0xf2, 0xf2,
+	0xfd, 0xfd, 0xfc, 0xfc, 0xff, 0xff, 0xfe, 0xfe,
+	0xf9, 0xf9, 0xf8, 0xf8, 0xfb, 0xfb, 0xfa, 0xfa,
+	0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4,
+	0xe7, 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6,
+	0xe1, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0,
+	0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2,
+	0xed, 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec,
+	0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee,
+	0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8,
+	0xeb, 0xeb, 0xeb, 0xeb, 0xea, 0xea, 0xea, 0xea,
+	0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+	0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+	0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+	0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+	0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+	0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+	0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+	0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+	0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+	0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+	0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+	0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+	0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+	0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+	0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+	0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+	0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+	0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+	0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+	0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+	0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+	0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+	0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+	0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+	0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+	0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+	0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+	0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+	0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+	0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+	0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+	0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+	0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+	0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+	0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+	0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+	0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
+	0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
+	0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
+	0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
+	0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+	0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+	0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+	0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+	0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
+	0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
+	0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
+	0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
+	0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6,
+	0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6,
+	0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6,
+	0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6,
+	0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
+	0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
+	0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
+	0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
+	0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
+	0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
+	0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
+	0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
+	0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
+	0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
+	0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
+	0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
+	0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
+	0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
+	0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
+	0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
+	0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
+	0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
+	0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
+	0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
+	0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
+	0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
+	0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
+	0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
+	0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+	0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+	0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+	0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
+	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
+	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
+	0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
+	0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9,
+	0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9,
+	0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9,
+	0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9,
+	0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
+	0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
+	0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
+	0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
+	0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+	0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+	0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+	0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+	0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
+	0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
+	0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
+	0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
+	0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+	0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+	0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+	0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+	0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+	0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+	0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+	0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+	0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+	0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+	0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+	0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+	0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+	0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+	0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+	0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+	0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+	0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+	0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+	0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+	0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+	0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+	0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+	0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+	0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+	0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+	0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+	0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+	0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+	0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+	0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+	0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+	0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+	0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+	0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+	0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+	0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+	0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+	0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+	0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+	0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+	0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+	0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+	0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+	0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+	0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+	0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+	0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+	0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+	0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+	0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+	0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+	0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+	0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+	0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+	0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+	0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+	0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+	0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+	0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+	0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+	0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+	0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+	0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+	0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+	0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+	0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+	0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+	0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+	0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+	0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+	0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+	0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+	0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+	0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+	0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+	0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+	0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+	0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+	0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+	0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+	0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+	0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+	0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+	0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+	0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+	0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+	0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+	0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+	0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+	0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+	0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+	0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+	0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+	0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+	0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+	0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+	0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+	0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+	0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+	0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+	0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+	0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+	0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+	0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+	0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+	0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+	0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+	0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+	0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+	0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+	0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+	0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+	0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+	0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+	0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+	0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+	0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+	0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+	0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+};
+
+signed short _u2l[256] = {
+	-32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
+	-23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
+	-15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
+	-11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
+	 -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
+	 -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
+	 -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
+	 -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
+	 -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
+	 -1372, -1308, -1244, -1180, -1116, -1052,  -988,  -924,
+	  -876,  -844,  -812,  -780,  -748,  -716,  -684,  -652,
+	  -620,  -588,  -556,  -524,  -492,  -460,  -428,  -396,
+	  -372,  -356,  -340,  -324,  -308,  -292,  -276,  -260,
+	  -244,  -228,  -212,  -196,  -180,  -164,  -148,  -132,
+	  -120,  -112,  -104,   -96,   -88,   -80,   -72,   -64,
+	   -56,   -48,   -40,   -32,   -24,   -16,    -8,    -2,
+	 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
+	 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
+	 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
+	 11900, 11388, 10876, 10364,  9852,  9340,  8828,  8316,
+	  7932,  7676,  7420,  7164,  6908,  6652,  6396,  6140,
+	  5884,  5628,  5372,  5116,  4860,  4604,  4348,  4092,
+	  3900,  3772,  3644,  3516,  3388,  3260,  3132,  3004,
+	  2876,  2748,  2620,  2492,  2364,  2236,  2108,  1980,
+	  1884,  1820,  1756,  1692,  1628,  1564,  1500,  1436,
+	  1372,  1308,  1244,  1180,  1116,  1052,   988,   924,
+	   876,   844,   812,   780,   748,   716,   684,   652,
+	   620,   588,   556,   524,   492,   460,   428,   396,
+	   372,   356,   340,   324,   308,   292,   276,   260,
+	   244,   228,   212,   196,   180,   164,   148,   132,
+	   120,   112,   104,    96,    88,    80,    72,    64,
+	    56,    48,    40,    32,    24,    16,     8,     2,
+};
+
+signed short _A2l[256] = {
+	 -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
+	 -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
+	 -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
+	 -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
+	-22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
+	-30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
+	-11008,-10496,-12032,-11520, -8960, -8448, -9984, -9472,
+	-15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
+	  -344,  -328,  -376,  -360,  -280,  -264,  -312,  -296,
+	  -472,  -456,  -504,  -488,  -408,  -392,  -440,  -424,
+	   -88,   -72,  -120,  -104,   -24,    -8,   -56,   -40,
+	  -216,  -200,  -248,  -232,  -152,  -136,  -184,  -168,
+	 -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
+	 -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
+	  -688,  -656,  -752,  -720,  -560,  -528,  -624,  -592,
+	  -944,  -912, -1008,  -976,  -816,  -784,  -880,  -848,
+	  5504,  5248,  6016,  5760,  4480,  4224,  4992,  4736,
+	  7552,  7296,  8064,  7808,  6528,  6272,  7040,  6784,
+	  2752,  2624,  3008,  2880,  2240,  2112,  2496,  2368,
+	  3776,  3648,  4032,  3904,  3264,  3136,  3520,  3392,
+	 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
+	 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
+	 11008, 10496, 12032, 11520,  8960,  8448,  9984,  9472,
+	 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
+	   344,   328,   376,   360,   280,   264,   312,   296,
+	   472,   456,   504,   488,   408,   392,   440,   424,
+	    88,    72,   120,   104,    24,     8,    56,    40,
+	   216,   200,   248,   232,   152,   136,   184,   168,
+	  1376,  1312,  1504,  1440,  1120,  1056,  1248,  1184,
+	  1888,  1824,  2016,  1952,  1632,  1568,  1760,  1696,
+	   688,   656,   752,   720,   560,   528,   624,   592,
+	   944,   912,  1008,   976,   816,   784,   880,   848,
+};
+
+unsigned char _u2A[256] = {
+	0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
+	0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
+	0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
+	0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
+	0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
+	0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
+	0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12,
+	0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x6a,
+	0x68, 0x69, 0x6e, 0x6f, 0x6c, 0x6d, 0x62, 0x63,
+	0x60, 0x61, 0x66, 0x67, 0x64, 0x65, 0x7a, 0x78,
+	0x7e, 0x7f, 0x7c, 0x7d, 0x72, 0x73, 0x70, 0x71,
+	0x76, 0x77, 0x74, 0x75, 0x4b, 0x49, 0x4f, 0x4d,
+	0x42, 0x43, 0x40, 0x41, 0x46, 0x47, 0x44, 0x45,
+	0x5a, 0x5b, 0x58, 0x59, 0x5e, 0x5f, 0x5c, 0x5d,
+	0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51,
+	0x56, 0x56, 0x57, 0x57, 0x54, 0x54, 0x55, 0x55,
+	0xaa, 0xab, 0xa8, 0xa9, 0xae, 0xaf, 0xac, 0xad,
+	0xa2, 0xa3, 0xa0, 0xa1, 0xa6, 0xa7, 0xa4, 0xa5,
+	0xba, 0xbb, 0xb8, 0xb9, 0xbe, 0xbf, 0xbc, 0xbd,
+	0xb2, 0xb3, 0xb0, 0xb1, 0xb6, 0xb7, 0xb4, 0xb5,
+	0x8a, 0x8b, 0x88, 0x89, 0x8e, 0x8f, 0x8c, 0x8d,
+	0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85,
+	0x9b, 0x98, 0x99, 0x9e, 0x9f, 0x9c, 0x9d, 0x92,
+	0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, 0xea,
+	0xe8, 0xe9, 0xee, 0xef, 0xec, 0xed, 0xe2, 0xe3,
+	0xe0, 0xe1, 0xe6, 0xe7, 0xe4, 0xe5, 0xfa, 0xf8,
+	0xfe, 0xff, 0xfc, 0xfd, 0xf2, 0xf3, 0xf0, 0xf1,
+	0xf6, 0xf7, 0xf4, 0xf5, 0xcb, 0xc9, 0xcf, 0xcd,
+	0xc2, 0xc3, 0xc0, 0xc1, 0xc6, 0xc7, 0xc4, 0xc5,
+	0xda, 0xdb, 0xd8, 0xd9, 0xde, 0xdf, 0xdc, 0xdd,
+	0xd2, 0xd2, 0xd3, 0xd3, 0xd0, 0xd0, 0xd1, 0xd1,
+	0xd6, 0xd6, 0xd7, 0xd7, 0xd4, 0xd4, 0xd5, 0xd5,
+};
+
+unsigned char _A2u[256] = {
+	0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
+	0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
+	0x39, 0x3a, 0x37, 0x38, 0x3d, 0x3e, 0x3b, 0x3c,
+	0x31, 0x32, 0x30, 0x30, 0x35, 0x36, 0x33, 0x34,
+	0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
+	0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
+	0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
+	0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
+	0x62, 0x63, 0x60, 0x61, 0x66, 0x67, 0x64, 0x65,
+	0x5d, 0x5d, 0x5c, 0x5c, 0x5f, 0x5f, 0x5e, 0x5e,
+	0x74, 0x76, 0x70, 0x72, 0x7c, 0x7e, 0x78, 0x7a,
+	0x6a, 0x6b, 0x68, 0x69, 0x6e, 0x6f, 0x6c, 0x6d,
+	0x48, 0x49, 0x46, 0x47, 0x4c, 0x4d, 0x4a, 0x4b,
+	0x40, 0x41, 0x3f, 0x3f, 0x44, 0x45, 0x42, 0x43,
+	0x56, 0x57, 0x54, 0x55, 0x5a, 0x5b, 0x58, 0x59,
+	0x4f, 0x4f, 0x4e, 0x4e, 0x52, 0x53, 0x50, 0x51,
+	0xaa, 0xab, 0xa8, 0xa9, 0xae, 0xaf, 0xac, 0xad,
+	0xa2, 0xa3, 0xa0, 0xa1, 0xa6, 0xa7, 0xa4, 0xa5,
+	0xb9, 0xba, 0xb7, 0xb8, 0xbd, 0xbe, 0xbb, 0xbc,
+	0xb1, 0xb2, 0xb0, 0xb0, 0xb5, 0xb6, 0xb3, 0xb4,
+	0x8a, 0x8b, 0x88, 0x89, 0x8e, 0x8f, 0x8c, 0x8d,
+	0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85,
+	0x9a, 0x9b, 0x98, 0x99, 0x9e, 0x9f, 0x9c, 0x9d,
+	0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95,
+	0xe2, 0xe3, 0xe0, 0xe1, 0xe6, 0xe7, 0xe4, 0xe5,
+	0xdd, 0xdd, 0xdc, 0xdc, 0xdf, 0xdf, 0xde, 0xde,
+	0xf4, 0xf6, 0xf0, 0xf2, 0xfc, 0xfe, 0xf8, 0xfa,
+	0xea, 0xeb, 0xe8, 0xe9, 0xee, 0xef, 0xec, 0xed,
+	0xc8, 0xc9, 0xc6, 0xc7, 0xcc, 0xcd, 0xca, 0xcb,
+	0xc0, 0xc1, 0xbf, 0xbf, 0xc4, 0xc5, 0xc2, 0xc3,
+	0xd6, 0xd7, 0xd4, 0xd5, 0xda, 0xdb, 0xd8, 0xd9,
+	0xcf, 0xcf, 0xce, 0xce, 0xd2, 0xd3, 0xd0, 0xd1,
+};
+

Added: misdn-user/trunk/i4lnet/isdn_debug.c
===================================================================
--- misdn-user/trunk/i4lnet/isdn_debug.c	                        (rev 0)
+++ misdn-user/trunk/i4lnet/isdn_debug.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,160 @@
+#include <stdarg.h>
+#include <time.h>
+#include <string.h>
+#include "isdn_debug.h"
+
+
+static unsigned int	debug_mask = 0;
+static FILE		*debug_file = NULL;
+static FILE		*warn_file = NULL;
+static FILE		*error_file = NULL;
+
+int
+debug_init(unsigned int mask, char *dfile, char *wfile, char *efile)
+{
+	if (dfile) {
+		if (debug_file && (debug_file != stdout))
+			debug_file = freopen(dfile, "a", debug_file);
+		else
+			debug_file = fopen(dfile, "a");
+		if (!debug_file) {
+			debug_file = stdout;
+			fprintf(debug_file,
+				"%s: cannot open %s for debug log, using stdout\n",
+				__FUNCTION__, dfile);
+		}
+	} else {
+		if (!debug_file) {
+			debug_file = stdout;
+//			fprintf(debug_file,
+//				"%s: using stdout for debug log\n", __FUNCTION__);
+		}
+	}
+	if (wfile) {
+		if (warn_file && (warn_file != stderr))
+			warn_file = freopen(wfile, "a", warn_file);
+		else
+			warn_file = fopen(wfile, "a");
+		if (!warn_file) {
+			warn_file = stderr;
+			fprintf(warn_file,
+				"%s: cannot open %s for warning log, using stderr\n",
+				__FUNCTION__, wfile);
+		}
+	} else {
+		if (!warn_file) {
+			warn_file = stderr;
+//			fprintf(warn_file,
+//				"%s: using stderr for warning log\n", __FUNCTION__);
+		}
+	}
+	if (efile) {
+		if (error_file && (error_file != stderr))
+			error_file = freopen(efile, "a", error_file);
+		else
+			error_file = fopen(efile, "a");
+		if (!error_file) {
+			error_file = stderr;
+			fprintf(error_file,
+				"%s: cannot open %s for error log, using stderr\n",
+				__FUNCTION__, efile);
+		}
+	} else {
+		if (!error_file) {
+			error_file = stderr;
+//			fprintf(error_file,
+//				"%s: using stderr for error log\n", __FUNCTION__);
+		}
+	}
+	debug_mask = mask;
+//	fprintf(debug_file, "%s: debug_mask = %x\n", __FUNCTION__, debug_mask);
+	return(0);
+}
+
+void
+debug_close(void)
+{
+//	fprintf(debug_file, "%s: debug channel now closed\n", __FUNCTION__);
+	if (debug_file && (debug_file != stdout))
+		fclose(debug_file);
+//	fprintf(warn_file, "%s:  warn channel now closed\n", __FUNCTION__);
+	if (warn_file && (warn_file != stderr))
+		fclose(warn_file);
+//	fprintf(error_file, "%s: error channel now closed\n", __FUNCTION__);
+	if (error_file && (error_file != stderr))
+		fclose(error_file);
+}
+
+int
+dprint(unsigned int mask, int port, const char *fmt, ...)
+{
+	int	ret = 0;
+	va_list	args;
+	time_t tm = time(NULL);
+	char *tmp=ctime(&tm),*p;
+	
+	p=strchr(tmp,'\n');
+	if (p) *p=':';
+
+	va_start(args, fmt);
+	if (debug_mask & mask) {
+		if (debug_file != stdout)
+			fprintf(debug_file, "%s P(%02d): L(0x%02x):",tmp, port,mask);
+		ret = vfprintf(debug_file, fmt, args);
+		if (debug_file != stdout)
+			fflush(debug_file);
+	}
+	va_end(args);
+	return(ret);
+}
+
+int
+wprint(const char *fmt, ...)
+{
+	int	ret = 0;
+	va_list	args;
+
+	va_start(args, fmt);
+	ret = vfprintf(warn_file, fmt, args);
+	fflush(warn_file);
+	va_end(args);
+	return(ret);
+}
+
+
+int
+eprint(const char *fmt, ...)
+{
+	int	ret = 0;
+	va_list	args;
+
+	va_start(args, fmt);
+	ret = vfprintf(error_file, fmt, args);
+	fflush(error_file);
+	va_end(args);
+	return(ret);
+}
+
+int
+dhexprint(unsigned int mask, char *head, unsigned char *buf, int len)
+{
+	int	ret = 0;
+	char	*p,*obuf;
+
+	if (debug_mask & mask) {
+		obuf = malloc(3*(len+1));
+		if (!obuf)
+			return(-ENOMEM);
+		p = obuf;
+		while (len) {
+			p += sprintf(p,"%02x ", *buf);
+			buf++;
+			len--;
+		}
+		p--;
+		*p=0;
+		ret = fprintf(debug_file, "%s %s\n", head, obuf);
+		free(obuf);
+	}
+	return(ret);
+}

Added: misdn-user/trunk/i4lnet/isdn_msg.c
===================================================================
--- misdn-user/trunk/i4lnet/isdn_msg.c	                        (rev 0)
+++ misdn-user/trunk/i4lnet/isdn_msg.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,112 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "isdn_msg.h"
+#include "isdn_debug.h"
+
+static	msg_queue_t	_free_queue;
+msg_queue_t		*free_queue;
+
+void
+msg_init(void)
+{
+	free_queue = & _free_queue;
+	msg_queue_init(free_queue);
+	free_queue->maxlen = 200;
+}
+
+
+static  int alloc_msg_cnt = 0;
+
+msg_t *
+_new_msg(int size)
+{
+	msg_t *m;
+
+	if (size <= MAX_MSG_SIZE)
+		size = MAX_MSG_SIZE;
+	else
+		goto err;
+	m = malloc(sizeof(msg_t));
+	if (!m)
+		goto err;
+	m->size = size;
+	alloc_msg_cnt++;
+	return(m);
+err:
+	eprint("%s: no mem for size %d msg\n", __FUNCTION__,
+		size);
+	return(NULL);
+}
+
+msg_t *
+alloc_msg(int size)
+{
+	msg_t *m;
+	
+	if (size > MAX_MSG_SIZE)
+		return(NULL);
+	if (msg_queue_len(free_queue))
+		m = msg_dequeue(free_queue);
+	else
+		m = _new_msg(size);
+	if (!m) {
+		eprint("%s: no mem for msg len (%d)\n", __FUNCTION__,
+			size);
+		return(NULL);
+	}
+	m->list = NULL;
+	m->prev = NULL;
+	m->next = NULL;
+	m->head = &m->__data[0];
+	m->data = m->head + DEFAULT_HEADROOM;
+	m->tail = m->data;
+	m->end  = m->head + m->size;
+	m->len = 0;
+	dprint(DBGM_MSG, -1,"%s: %d msg(%p)\n", __FUNCTION__,
+		alloc_msg_cnt, m);
+	return(m);
+}
+
+
+void
+free_msg(msg_t *msg) {
+	if (!msg) {
+		wprint("free NULL msg\n");
+		return;
+	}
+	dprint(DBGM_MSG, -1,"%s: %d/%d msg(%p) \n", __FUNCTION__,
+		alloc_msg_cnt, free_queue->len, msg);
+
+	if (msg->list) {
+		if  (msg->list == free_queue)
+			wprint("%s: free twice msg(%p)\n", __FUNCTION__,
+				msg);
+		else
+			wprint("%s: msg(%p) in queue(%p)\n", __FUNCTION__,
+				msg, msg->list);
+		return;
+	}
+	if (free_queue->len>=free_queue->maxlen) {
+		alloc_msg_cnt--;
+		dprint(DBGM_MSG, -1, "free msg no free_queue %d/%d\n",
+			free_queue->len, free_queue->maxlen);
+		free(msg);
+		return;
+	}
+	msg_queue_head(free_queue, msg);
+}
+
+msg_t *
+msg_copy(msg_t *msg) {
+	msg_t	*nmsg;
+
+	dprint(DBGM_MSG, -1,"%s: old(%p)\n", __FUNCTION__, msg);
+	nmsg = alloc_msg(msg->size);
+	if (!nmsg)
+		return(NULL);
+	dprint(DBGM_MSG, -1,"%s: new(%p) size(%d)\n", __FUNCTION__,
+		nmsg, msg->size);
+	memcpy(nmsg, msg, sizeof(msg_t));
+	return(nmsg);
+}

Added: misdn-user/trunk/i4lnet/manager.c
===================================================================
--- misdn-user/trunk/i4lnet/manager.c	                        (rev 0)
+++ misdn-user/trunk/i4lnet/manager.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,286 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include "isdn_net.h"
+#include "l3dss1.h"
+#include "net_l2.h"
+#include "net_l3.h"
+#include "bchannel.h"
+#include "helper.h"
+
+int
+match_nr(manager_t *mgr, unsigned char *nx, nr_list_t **nrx)
+{
+	int		l,i,ret = 2;
+	unsigned char	*p;
+	nr_list_t	*nr = mgr->nrlist;
+
+	if (!nrx)
+		return(3);
+	l = nx[0] - 1;
+	if (l<=0)
+		return(3);
+	while(nr) {
+		p = nx + 2;
+		dprint(DBGM_MAN, -1,"%s: cpn(%s) nr(%s)\n", __FUNCTION__,
+			p, nr->nr);
+		for(i=0;i<nr->len;i++) {
+			if (*p != nr->nr[i])
+				break;
+			if ((i+1) == nr->len) {
+				*nrx = nr;
+				return(0);
+			}
+			if (l == (i+1)) {
+				ret = 1;
+				break;
+			}
+			p++;	
+		}
+		nr = nr->next;
+	}
+	return(ret);
+}
+
+static int
+manager2stack(void *dat, void *arg)
+{
+	net_stack_t	*nst = dat;
+	msg_t		*msg = arg;
+	mISDNuser_head_t	*hh;
+
+	dprint(DBGM_MAN, -1, "%s:dat(%p) arg(%p)\n", __FUNCTION__,
+		dat, arg);
+	if (!nst | !arg)
+		return(-EINVAL);
+	hh = (mISDNuser_head_t *)msg->data;
+	dprint(DBGM_MAN, -1, "%s: prim(%x) dinfo(%x) msg->len(%d)\n", __FUNCTION__,
+		hh->prim, hh->dinfo, msg->len);
+	if (hh->prim == (CC_NEW_CR | INDICATION)) /* high prio */
+		msg_queue_head(&nst->wqueue, arg);
+	else
+		msg_queue_tail(&nst->wqueue, arg);
+	sem_post(&nst->work);
+	return(0);
+}
+
+static int
+stack2manager(void *dat, void *arg) {
+	manager_t 	*mgr = dat;
+	msg_t		*msg = arg;
+	mISDNuser_head_t	*hh;
+
+	if (!msg || !mgr)
+		return(-EINVAL);
+	hh = (mISDNuser_head_t *)msg->data;
+	dprint(DBGM_MAN, -1, "%s: prim(%x) dinfo(%x) msg->len(%d) bid(%x/%x)\n", __FUNCTION__,
+		hh->prim, hh->dinfo, msg->len, mgr->bc[0].l3id, mgr->bc[1].l3id);
+	if (hh->prim == (CC_SETUP | INDICATION)) {
+		SETUP_t			*setup;
+		RELEASE_COMPLETE_t	*rc;
+		unsigned char		cause[4];
+
+		setup = (SETUP_t*)(msg->data + mISDNUSER_HEAD_SIZE);
+		pthread_mutex_lock(&mgr->bc[0].lock);
+		if (mgr->bc[0].cstate == BC_CSTATE_NULL) {
+			mgr->bc[0].cstate = BC_CSTATE_ICALL;
+			msg_queue_tail(&mgr->bc[0].workq, msg);
+			pthread_mutex_unlock(&mgr->bc[0].lock);
+			sem_post(&mgr->bc[0].work);
+			return(0);
+		}
+		pthread_mutex_unlock(&mgr->bc[0].lock);
+		pthread_mutex_lock(&mgr->bc[1].lock);
+		if (mgr->bc[1].cstate == BC_CSTATE_NULL) {
+			mgr->bc[1].cstate = BC_CSTATE_ICALL;
+			msg_queue_tail(&mgr->bc[1].workq, msg);
+			pthread_mutex_unlock(&mgr->bc[1].lock);
+			sem_post(&mgr->bc[1].work);
+			return(0);
+		}
+		pthread_mutex_unlock(&mgr->bc[1].lock);
+		/* No channel available */
+		cause[0] = 2;
+		cause[1] = 0x80 | CAUSE_LOC_PNET_LOCUSER;
+		if (setup->CHANNEL_ID)
+			cause[2] = 0x80 | CAUSE_CHANNEL_UNACCEPT;
+		else
+			cause[2] = 0x80 | CAUSE_NO_CHANNEL;
+		prep_l3data_msg(CC_RELEASE_COMPLETE | REQUEST, hh->dinfo,
+			sizeof(RELEASE_COMPLETE_t), 3, msg);
+		rc = (RELEASE_COMPLETE_t *)(msg->data + mISDNUSER_HEAD_SIZE);
+		rc->CAUSE = msg_put(msg, 3);
+		memcpy(rc->CAUSE, &cause, 3);
+		if (manager2stack(mgr->nst, msg))
+			free_msg(msg);
+	} else if (hh->dinfo == mgr->bc[0].l3id) {
+		msg_queue_tail(&mgr->bc[0].workq, msg);
+		sem_post(&mgr->bc[0].work);
+	} else if (hh->dinfo == mgr->bc[1].l3id) {
+		msg_queue_tail(&mgr->bc[1].workq, msg);
+		sem_post(&mgr->bc[1].work);
+	} else {
+		wprint("%s: prim(%x) dinfo(%x) msg->len(%d) not handled\n", __FUNCTION__,
+			hh->prim, hh->dinfo, msg->len);
+		return(-ESRCH);
+	}
+	return(0);
+}
+
+static int
+appl2bc(manager_t *mgr, int prim, void *arg)
+{
+	bchannel_t	*bc = arg;
+	msg_t		*msg;
+
+	dprint(DBGM_MAN, -1, "%s(%p,%x,%p)\n", __FUNCTION__,
+		 mgr, prim, arg);
+	if (!mgr || !bc)
+		return(-EINVAL);
+	if (prim == PR_APP_OCHANNEL) {
+		bchannel_t **bcp = arg;
+
+		pthread_mutex_lock(&mgr->bc[0].lock);
+		if (mgr->bc[0].cstate == BC_CSTATE_NULL) {
+			mgr->bc[0].cstate = BC_CSTATE_OCALL;
+			pthread_mutex_unlock(&mgr->bc[0].lock);
+			*bcp = &mgr->bc[0];
+			return(1);
+		}
+		pthread_mutex_unlock(&mgr->bc[0].lock);
+		pthread_mutex_lock(&mgr->bc[1].lock);
+		if (mgr->bc[1].cstate == BC_CSTATE_NULL) {
+			mgr->bc[1].cstate = BC_CSTATE_OCALL;
+			pthread_mutex_unlock(&mgr->bc[1].lock);
+			*bcp = &mgr->bc[1];
+			return(2);
+		}
+		pthread_mutex_unlock(&mgr->bc[1].lock);
+		/* No channel available */
+		return(-EBUSY);
+	} else if (prim == PR_APP_OCALL) {
+		pthread_mutex_lock(&bc->lock);
+		msg = create_link_msg(CC_SETUP | REQUEST, bc->l3id, 0,
+			NULL, 0);
+		if (!msg)
+			return(-ENOMEM);
+		msg_queue_tail(&bc->workq, msg);
+		sem_post(&bc->work);
+		pthread_mutex_unlock(&bc->lock);
+	} else if (prim == PR_APP_ALERT) {
+		pthread_mutex_lock(&bc->lock);
+		msg = create_link_msg(CC_ALERTING | REQUEST, bc->l3id, 0,
+			NULL, 0);
+		if (!msg)
+			return(-ENOMEM);
+		msg_queue_tail(&bc->workq, msg);
+		sem_post(&bc->work);
+		pthread_mutex_unlock(&bc->lock);
+	} else if (prim == PR_APP_CONNECT) {
+		pthread_mutex_lock(&bc->lock);
+		msg = create_link_msg(CC_CONNECT | REQUEST, bc->l3id, 0,
+			NULL, 0);
+		if (!msg)
+			return(-ENOMEM);
+		msg_queue_tail(&bc->workq, msg);
+		sem_post(&bc->work);
+		pthread_mutex_unlock(&bc->lock);
+	} else if (prim == PR_APP_HANGUP) {
+		pthread_mutex_lock(&bc->lock);
+		msg = create_link_msg(CC_DISCONNECT | REQUEST, bc->l3id, 0,
+			NULL, 0);
+		if (!msg)
+			return(-ENOMEM);
+		msg_queue_tail(&bc->workq, msg);
+		sem_post(&bc->work);
+		pthread_mutex_unlock(&bc->lock);
+	} else if (prim == PR_APP_FACILITY) {
+		pthread_mutex_lock(&bc->lock);
+		msg = create_link_msg(CC_FACILITY | REQUEST, bc->l3id,
+			0, NULL, 0);
+		if (!msg)
+			return(-ENOMEM);
+		msg_queue_tail(&bc->workq, msg);
+		sem_post(&bc->work);
+		pthread_mutex_unlock(&bc->lock);
+	} else if (prim == PR_APP_USERUSER) {
+		pthread_mutex_lock(&bc->lock);
+		msg = create_link_msg(CC_USER_INFORMATION | REQUEST, bc->l3id,
+			0, NULL, 0);
+		if (!msg)
+			return(-ENOMEM);
+		msg_queue_tail(&bc->workq, msg);
+		sem_post(&bc->work);
+		pthread_mutex_unlock(&bc->lock);
+	} else {
+		wprint("%s(%p,%x,%p) unhandled\n", __FUNCTION__,
+			mgr, prim, arg);
+	}
+	return(0);
+}
+
+int
+init_manager(manager_t **mlist, afunc_t application)
+{
+	manager_t	*mgr;
+	int		ret;
+
+	*mlist = NULL;
+	mgr = malloc(sizeof(manager_t));
+	if (!mgr)
+		return(-ENOMEM);
+	memset(mgr, 0, sizeof(manager_t));
+	mgr->nst = malloc(sizeof(net_stack_t));
+	if (!mgr->nst) {
+		free(mgr);
+		return(-ENOMEM);
+	}
+	memset(mgr->nst, 0, sizeof(net_stack_t));
+	ret = do_net_stack_setup(mgr->nst);
+	if (ret) {
+		free(mgr->nst);
+		free(mgr);
+		return(ret);
+	}
+	mgr->application = application;
+	mgr->app_bc = appl2bc;
+	mgr->man2stack = manager2stack;
+	mgr->nst->l3_manager = stack2manager;
+	mgr->nst->manager = mgr;
+	Isdnl2Init(mgr->nst);
+	Isdnl3Init(mgr->nst);
+	mgr->bc[0].manager = mgr;
+	mgr->bc[1].manager = mgr;
+	init_bchannel(&mgr->bc[0], 1); 
+	init_bchannel(&mgr->bc[1], 2);
+	*mlist = mgr;
+	return(0);
+} 
+
+int
+cleanup_manager(manager_t *mgr)
+{
+	int	ret, *retv;
+
+	dprint(DBGM_MAN, -1,"%s\n", __FUNCTION__);
+	term_bchannel(&mgr->bc[0]);
+	term_bchannel(&mgr->bc[1]);
+	cleanup_Isdnl3(mgr->nst);
+	cleanup_Isdnl2(mgr->nst);
+	do_net_stack_cleanup(mgr->nst);
+	ret = pthread_join(mgr->bc[0].tid, (void *)&retv);
+	dprint(DBGM_MAN, -1,"%s: join ret(%d) bc1 retv(%p)\n", __FUNCTION__,
+		ret, retv);
+	ret = pthread_join(mgr->bc[1].tid, (void *)&retv);
+	dprint(DBGM_MAN, -1,"%s: join ret(%d) bc2 retv(%p)\n", __FUNCTION__,
+		ret, retv);
+	while(mgr->nrlist) {
+		nr_list_t *nr = mgr->nrlist;
+
+		REMOVE_FROM_LISTBASE(nr, mgr->nrlist);
+		free(nr);
+	}
+	free(mgr->nst);
+	free(mgr);
+	return(0);
+}

Added: misdn-user/trunk/i4lnet/net_if.c
===================================================================
--- misdn-user/trunk/i4lnet/net_if.c	                        (rev 0)
+++ misdn-user/trunk/i4lnet/net_if.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,712 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "net_l2.h"
+#include "isdn_net.h"
+#include "bchannel.h"
+#include "helper.h"
+
+
+int
+do_net_stack_setup(net_stack_t	*nst)
+{
+	int		ret;
+	unsigned char	buf[1024];
+	int		i,cnt;
+	iframe_t	*frm = (iframe_t *)buf;
+	stack_info_t	*stinf;
+	layer_info_t	li;
+#ifdef OBSOLETE
+	interface_info_t ii;
+#endif
+	
+
+	if (!nst)
+		return(-EINVAL);
+	if (nst->device)
+		return(-EBUSY);
+	ret = mISDN_open();
+	if (0 > ret) {
+		wprint("cannot open mISDN due to %s\n",
+			strerror(errno));
+		return(ret);
+	}
+	nst->device = ret;
+	cnt = mISDN_get_stack_count(nst->device);
+	if (cnt < 1) {
+		mISDN_close(nst->device);
+		wprint("no cards found ret(%d)\n", cnt);
+		return(-ENODEV);
+	}
+	for (i=1; i<=cnt; i++) {
+		ret = mISDN_get_stack_info(nst->device, i, buf, 1024);
+		if (ret<=0)
+			dprint(DBGM_NET, nst->cardnr, "cannot get stackinfo err: %d\n", ret);
+		stinf = (stack_info_t *)&frm->data.p;
+//		mISDNprint_stack_info(stdout, stinf);
+		if ((stinf->pid.protocol[0] == ISDN_PID_L0_NT_S0) &&
+			(stinf->pid.protocol[1] == ISDN_PID_L1_NT_S0)) {
+			if (stinf->instcnt == 1) {
+				nst->cardnr = i;
+				nst->d_stid = stinf->id;
+				nst->b_stid[0] = stinf->child[0];
+				nst->b_stid[1] = stinf->child[1];
+				dprint(DBGM_NET, nst->cardnr, "bst1 %x bst2 %x\n",
+					nst->b_stid[0], nst->b_stid[1]);
+				break;
+			} else
+				dprint(DBGM_NET, nst->cardnr, "stack %d instcnt is %d\n",
+					i, stinf->instcnt);
+		} else
+			dprint(DBGM_NET, nst->cardnr, "stack %d protocol %x\n",
+				i, stinf->pid.protocol[0]);
+	}
+	if (i>cnt) {
+		mISDN_close(nst->device);
+		wprint("no NT cards found\n");
+		return(-ENODEV);
+	}
+	nst->l1_id = mISDN_get_layerid(nst->device, nst->d_stid, 1);
+	if (nst->l1_id < 0) {
+		mISDN_close(nst->device);
+		eprint("no layer1 id found\n");
+		return(-EINVAL);
+	}
+	dprint(DBGM_NET, nst->cardnr, "found NT card stack card%d dst(%x) l1(%x)\n",
+		nst->cardnr, nst->d_stid, nst->l1_id);
+	memset(&li, 0, sizeof(layer_info_t));
+	strcpy(&li.name[0], "net l2");
+	li.object_id = -1;
+	li.extentions = 0;
+	li.pid.protocol[2] = ISDN_PID_L2_LAPD_NET;
+	li.pid.layermask = ISDN_LAYER(2);
+	li.st = nst->d_stid;
+	nst->l2_id = mISDN_new_layer(nst->device, &li);
+	if (nst->l2_id<=0) {
+		eprint("cannot add layer2 error %d %s\n",
+			nst->l2_id, strerror(-nst->l2_id));
+		mISDN_close(nst->device);
+		return(nst->l2_id);
+	}
+#ifdef OBSOLETE
+	ii.extentions = EXT_IF_EXCLUSIV;
+	ii.owner = nst->l2_id;
+	ii.peer = nst->l1_id;
+	ii.stat = IF_DOWN;
+	ret = mISDN_connect(nst->device, &ii);
+	if (ret) {
+		eprint("cannot connect layer1 error %d %s\n",
+			ret, strerror(-ret));
+		mISDN_close(nst->device);
+		return(ret);
+	}
+#endif
+	dprint(DBGM_NET, nst->cardnr, "add nt net layer2  %x\n",
+		nst->l2_id);
+	msg_queue_init(&nst->down_queue);
+	msg_queue_init(&nst->rqueue);
+	msg_queue_init(&nst->wqueue);
+	pthread_mutex_init(&nst->lock, NULL);
+	ret = sem_init (&nst->work, 0, 0);
+	if (ret) {
+		eprint("cannot init semaphore ret(%d) %d %s\n",
+			ret, errno, strerror(errno));
+		return(ret);
+	}
+	return(0);
+}
+
+int
+do_net_stack_cleanup(net_stack_t  *nst)
+{
+	int ret;
+
+	msg_queue_purge(&nst->down_queue);
+	msg_queue_purge(&nst->rqueue);
+	msg_queue_purge(&nst->wqueue);
+	if (nst->phd_down_msg)
+		free_msg(nst->phd_down_msg);
+	nst->phd_down_msg = NULL;
+	mISDN_close(nst->device);
+	ret = sem_destroy(&nst->work);
+	if (ret) {
+		eprint("cannot destroy semaphore ret(%d) %d %s\n",
+			ret, errno, strerror(errno));
+		return(ret);
+	}
+	ret = pthread_mutex_destroy(&nst->lock);
+	if (ret) {
+		eprint("cannot destroy mutex ret(%d) %s\n",
+			ret, strerror(ret));
+		return(ret);
+	}
+	return(0);
+}
+
+static itimer_t
+*get_timer(net_stack_t *nst, int id)
+{
+	itimer_t	*it = nst->tlist;
+
+	while(it) {
+		if (it->id == id)
+			break;
+		it = it->next;
+	}
+	return(it);
+}
+
+int
+init_timer(itimer_t *it, net_stack_t *nst)
+{
+	iframe_t	frm;
+	int		ret;
+
+	if (!nst)
+		return(-ENODEV);
+	if (!get_timer(nst, it->id)) {
+		it->id = (int)it;
+		it->Flags = 0;
+		it->nst = nst;
+		it->prev = NULL;
+		if (nst->tlist) {
+			nst->tlist->prev = it;
+			it->next = nst->tlist;
+		}
+		nst->tlist = it;
+	}
+	dprint(DBGM_NET, nst->cardnr, "init timer(%x)\n", it->id);
+	if (test_bit(FLG_TIMER_RUNING, &it->Flags))
+		dprint(DBGM_NET, nst->cardnr, "init timer(%x) while running\n", it->id);
+	ret = mISDN_write_frame(it->nst->device, &frm, it->id,
+		MGR_INITTIMER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (ret)
+		wprint("cannot init timer %p err(%d) %s\n",
+			it, errno, strerror(errno));
+	return(ret);
+}
+
+int
+remove_timer(itimer_t *it)
+{
+	iframe_t	frm;
+	int		ret;
+
+	
+	if (!it->nst)
+		return(-ENODEV);
+	if (!get_timer(it->nst, it->id))
+		return(-ENODEV);
+	
+	ret = mISDN_write_frame(it->nst->device, &frm, it->id,
+		MGR_REMOVETIMER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (ret)
+		wprint("cannot remove timer %p err(%d) %s\n",
+			it, errno, strerror(errno));
+	REMOVE_FROM_LISTBASE(it, it->nst->tlist);
+	return(ret);
+}
+
+int
+add_timer(itimer_t *it)
+{
+	iframe_t	frm;
+	int		ret;
+
+	if (!it->nst)
+		return(-ENODEV);
+	if (!get_timer(it->nst, it->id))
+		return(-ENODEV);
+	if (timer_pending(it))
+		return(-EBUSY);
+	dprint(DBGM_NET, it->nst->cardnr, "add timer(%x)\n", it->id);
+	test_and_set_bit(FLG_TIMER_RUNING, &it->Flags);
+	ret = mISDN_write_frame(it->nst->device, &frm, it->id,
+		MGR_ADDTIMER | REQUEST, it->expires, 0, NULL, TIMEOUT_1SEC);
+	if (ret)
+		wprint("cannot add timer %p (%d ms) err(%d) %s\n",
+			it, it->expires, errno, strerror(errno));
+	return(ret);
+}
+
+int
+del_timer(itimer_t *it)
+{
+	iframe_t	frm;
+	int		ret;
+
+	if (!it->nst)
+		return(-ENODEV);
+	if (!get_timer(it->nst, it->id))
+		return(-ENODEV);
+	dprint(DBGM_NET, it->nst->cardnr, "del timer(%x)\n", it->id);
+	test_and_clear_bit(FLG_TIMER_RUNING, &it->Flags);
+	ret = mISDN_write_frame(it->nst->device, &frm, it->id,
+		MGR_DELTIMER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if (ret)
+		wprint("cannot del timer %p (%d ms) err(%d) %s\n",
+			it, it->expires, errno, strerror(errno));
+	return(ret);
+}
+
+int
+timer_pending(itimer_t *it)
+{
+	return(test_bit(FLG_TIMER_RUNING, &it->Flags));
+}
+
+static int
+handle_timer(net_stack_t *nst, int id)
+{
+	itimer_t	*it;
+	int		ret = 0;
+
+	it = get_timer(nst, id);
+	if (!it)
+		return(-ENODEV);
+//	dprint(DBGM_NET, nst->cardnr, "handle timer(%x)\n", it->id);
+	test_and_clear_bit(FLG_TIMER_RUNING, &it->Flags);
+	if (it->function)
+		ret = it->function(it->data);
+	return(ret);
+}
+
+int
+write_dmsg(net_stack_t *nst, msg_t *msg)
+{
+	iframe_t	*frm;
+	mISDNuser_head_t	*hh;
+
+	hh = (mISDNuser_head_t *)msg->data;
+	dprint(DBGM_NET, nst->cardnr, "%s: msg(%p) len(%d) pr(%x) di(%x) q(%d)\n", __FUNCTION__,
+		msg, msg->len, hh->prim, hh->dinfo, nst->phd_down_msg?1:0);
+	msg_pull(msg, mISDNUSER_HEAD_SIZE);
+	frm = (iframe_t *)msg_push(msg, mISDN_HEADER_LEN);
+	frm->prim = hh->prim;
+	frm->dinfo = hh->dinfo;
+	frm->addr = nst->l2_id | FLG_MSG_DOWN;
+	frm->len = msg->len - mISDN_HEADER_LEN;
+	if (frm->prim == PH_DATA_REQ) {
+		frm->dinfo = (int)msg;
+		if (nst->phd_down_msg) {
+			msg_queue_tail(&nst->down_queue, msg);
+			return(0);
+		}
+		nst->phd_down_msg = msg;
+	}
+	mISDN_write(nst->device, msg->data, msg->len, -1);
+	free_msg(msg);
+	return(0);
+}
+
+int
+phd_conf(net_stack_t *nst, iframe_t *frm, msg_t *msg)
+{
+	dprint(DBGM_NET, nst->cardnr, "%s: di(%x)\n", __FUNCTION__, frm->dinfo);
+	if (frm->dinfo == (int)nst->phd_down_msg) {
+		free_msg(msg);
+		nst->phd_down_msg = msg_dequeue(&nst->down_queue);
+		if (nst->phd_down_msg) {
+			mISDN_write(nst->device, nst->phd_down_msg->data,
+				nst->phd_down_msg->len, -1);
+			free_msg(nst->phd_down_msg);
+		}
+		return(0);
+	} else {
+		wprint("%s: not matching %p/%#x\n", __FUNCTION__,
+			nst->phd_down_msg, frm->dinfo);
+		return(-EINVAL);
+	}
+}
+
+static int
+do_net_read(net_stack_t *nst)
+{
+	msg_t		*msg;
+	iframe_t	*frm;
+	int		ret;
+	
+	msg = alloc_msg(MAX_MSG_SIZE);
+	if (!msg)
+		return(-ENOMEM);
+	ret = mISDN_read(nst->device, msg->data, MAX_MSG_SIZE, -1);
+	if (ret<0) {
+		free_msg(msg);
+		if (errno == EAGAIN)
+			return(0);
+		else
+			return(-errno);
+	}
+	if (!ret) {
+		wprint("do_net_read read nothing\n");
+		free_msg(msg);
+		return(-EINVAL);
+	}
+	__msg_trim(msg, ret);
+	frm = (iframe_t *)msg->data;
+	
+	dprint(DBGM_NET, nst->cardnr,"%s: prim(%x) addr(%x)\n", __FUNCTION__,
+		frm->prim, frm->addr);
+	switch (frm->prim) {
+		case MGR_INITTIMER | CONFIRM:
+		case MGR_ADDTIMER | CONFIRM:
+		case MGR_DELTIMER | CONFIRM:
+		case MGR_REMOVETIMER | CONFIRM:
+//			dprint(DBGM_NET, nst->cardnr, "timer(%x) cnf(%x)\n",
+//				frm->addr, frm->prim);
+			free_msg(msg);
+			return(0);
+	}
+	msg_queue_tail(&nst->rqueue, msg);
+	sem_post(&nst->work);
+	return(0);
+}
+
+static int
+b_message(net_stack_t *nst, int ch, iframe_t *frm, msg_t *msg)
+{
+	mISDNuser_head_t	*hh;
+
+	msg_pull(msg, mISDN_HEADER_LEN);
+	hh = (mISDNuser_head_t *)msg_push(msg, mISDNUSER_HEAD_SIZE);
+	hh->prim = frm->prim;
+	hh->dinfo = nst->bcid[ch];
+	if (nst->l3_manager)
+		return(nst->l3_manager(nst->manager, msg));
+	return(-EINVAL);
+	
+}
+
+static int
+do_readmsg(net_stack_t *nst, msg_t *msg)
+{
+	iframe_t	*frm;
+	int		ret = -EINVAL;
+
+	if (!nst || !msg)
+		return(-EINVAL);
+	frm = (iframe_t *)msg->data;
+	
+	dprint(DBGM_NET, nst->cardnr,"%s: prim(%x) addr(%x)\n", __FUNCTION__,
+		frm->prim, frm->addr);
+	if (frm->prim == (MGR_TIMER | INDICATION)) {
+		mISDN_write_frame(nst->device, msg->data, frm->addr,
+			MGR_TIMER | RESPONSE, 0, 0, NULL, TIMEOUT_1SEC);
+		ret = handle_timer(nst, frm->addr);
+		free_msg(msg);
+		return(0);
+	}
+	if ((frm->addr & INST_ID_MASK) == nst->l2_id) {
+		if (nst->l1_l2) {
+			ret = nst->l1_l2(nst, msg);
+		}
+	} else if (nst->b_addr[0] &&
+		((frm->addr & INST_ID_MASK) == nst->b_addr[0])) {
+		ret = b_message(nst, 0, frm, msg);
+	} else if (nst->b_addr[1] &&
+		((frm->addr & INST_ID_MASK) == nst->b_addr[1])) {
+		ret = b_message(nst, 1, frm, msg);
+	} else if (nst->b_stid[0] == frm->addr) {
+		ret = b_message(nst, 0, frm, msg);
+	} else if (nst->b_stid[1] == frm->addr) {
+		ret = b_message(nst, 1, frm, msg);
+	} else if (frm->prim == (MGR_DELLAYER | CONFIRM)) {
+		dprint(DBGM_NET, nst->cardnr,"%s: MGR_DELLAYER CONFIRM addr(%x)\n", __FUNCTION__,
+			frm->addr);
+		free_msg(msg);
+		return(0);
+	} else {
+		wprint("%s: unhandled msg(%d) prim(%x) addr(%x) dinfo(%x)\n", __FUNCTION__,
+			frm->len, frm->prim, frm->addr, frm->dinfo);
+	}
+	return(ret);
+}
+
+static int 
+setup_bchannel(net_stack_t *nst, mISDNuser_head_t *hh, msg_t *msg) {
+	mISDN_pid_t	*pid;
+	int		ret, ch, *id;
+	layer_info_t	li;
+	unsigned char	buf[32];
+
+	if ((hh->dinfo < 1) || (hh->dinfo > 2)) {
+		eprint("wrong channel %d\n", hh->dinfo);
+		return(-EINVAL);
+	}
+	ch = hh->dinfo -1;
+	dprint(DBGM_NET, nst->cardnr,"%s:ch%d\n", __FUNCTION__, hh->dinfo);
+	msg_pull(msg, mISDNUSER_HEAD_SIZE);
+	id = (int *)msg->data;
+	nst->bcid[ch] = *id;
+	msg_pull(msg, sizeof(int));
+	pid = (mISDN_pid_t *)msg->data;
+	memset(&li, 0, sizeof(layer_info_t));
+	li.object_id = -1;
+	li.extentions = 0;
+	li.st = nst->b_stid[ch];
+	if (pid->protocol[2] == ISDN_PID_L2_B_USER) {
+		strcpy(&li.name[0], "B L2");
+		li.pid.protocol[2] = ISDN_PID_L2_B_USER;
+		li.pid.layermask = ISDN_LAYER(2);
+	} else {
+		strcpy(&li.name[0], "B L3");
+		li.pid.protocol[3] = pid->protocol[3];
+		li.pid.layermask = ISDN_LAYER(3);
+	}
+	if (nst->b_addr[ch])
+		wprint("%s: b_addr[%d] %x in use\n", __FUNCTION__,
+			ch, nst->b_addr[ch]);
+	ret = mISDN_new_layer(nst->device, &li);
+	if (ret<=0) {
+		wprint("%s: new_layer ret(%d)\n", __FUNCTION__, ret);
+		goto error;
+	}
+	if (ret) {
+		nst->b_addr[ch] = ret;
+		dprint(DBGM_NET, nst->cardnr,"%s: b_address%d %08x\n", __FUNCTION__,
+			hh->dinfo, ret);
+		ret = mISDN_set_stack(nst->device, nst->b_stid[ch],
+			pid);
+		if (ret) {
+			wprint("set_stack ret(%d)\n", ret);
+			mISDN_write_frame(nst->device, buf,
+				nst->b_addr[ch], MGR_DELLAYER | REQUEST,
+				0, 0, NULL, TIMEOUT_1SEC);
+			nst->b_addr[ch] = 0;
+			goto error;
+		}
+		if_link(nst->manager, (ifunc_t)nst->l3_manager,
+			BC_SETUP | CONFIRM, nst->bcid[ch], sizeof(int),
+			&nst->b_addr[ch], 0);
+		free_msg(msg);
+		return(0);
+	} 
+error:
+	if_link(nst->manager, (ifunc_t)nst->l3_manager, BC_SETUP | SUB_ERROR,
+		nst->bcid[ch], sizeof(int), &ret, 0);
+	free_msg(msg);
+	return(0);
+}
+
+static int 
+cleanup_bc(net_stack_t *nst, mISDNuser_head_t *hh, msg_t *msg)
+{
+	unsigned char	buf[32];
+	int 		ch;
+
+	if (hh->dinfo == nst->bcid[0])
+		ch = 0;
+	else if (hh->dinfo == nst->bcid[1])
+		ch = 1;
+	else {
+		wprint("%s:not channel match %x %x/%x\n", __FUNCTION__,
+			hh->dinfo, nst->bcid[0], nst->bcid[1]);
+		
+		if_link(nst->manager, (ifunc_t)nst->l3_manager,
+			BC_CLEANUP | SUB_ERROR, hh->dinfo, 0, NULL, 0);
+		free_msg(msg);
+		return(0);
+	}
+	dprint(DBGM_NET, nst->cardnr,"%s:ch%d\n", __FUNCTION__, ch + 1);
+	mISDN_clear_stack(nst->device, nst->b_stid[ch]);
+	if (nst->b_addr[ch])
+		mISDN_write_frame(nst->device, buf, nst->b_addr[ch],
+			MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+	if_link(nst->manager, (ifunc_t)nst->l3_manager,
+		BC_CLEANUP | CONFIRM, hh->dinfo, 0, NULL, 0);
+	nst->b_addr[ch] = 0;
+	free_msg(msg);
+	return(0);
+}
+
+static int
+l1_request(net_stack_t *nst, mISDNuser_head_t *hh, msg_t *msg)
+{
+	iframe_t	*frm;
+
+	hh = (mISDNuser_head_t *)msg->data;
+	dprint(DBGM_NET, nst->cardnr, "%s: msg(%p) len(%d) pr(%x) di(%x)\n", __FUNCTION__,
+		msg, msg->len, hh->prim, hh->dinfo);
+	msg_pull(msg, mISDNUSER_HEAD_SIZE);
+	frm = (iframe_t *)msg_push(msg, mISDN_HEADER_LEN);
+	frm->prim = hh->prim;
+	frm->addr = hh->dinfo;
+	if (frm->prim == PH_DATA_REQ)
+		frm->dinfo = (int)msg;
+	else
+		frm->dinfo = 0;
+	frm->len = msg->len - mISDN_HEADER_LEN;
+	mISDN_write(nst->device, msg->data, msg->len, -1);
+	free_msg(msg);
+	return(0);
+}
+
+static int
+do_writemsg(net_stack_t *nst, msg_t *msg)
+{
+	mISDNuser_head_t	*hh;
+	int		ret = -EINVAL;
+
+	if (!nst || !msg)
+		return(-EINVAL);
+	hh = (mISDNuser_head_t *)msg->data;
+	dprint(DBGM_NET, nst->cardnr,"%s: prim(%x) dinfo(%x)\n", __FUNCTION__,
+		hh->prim, hh->dinfo);
+	if ((hh->prim & LAYER_MASK) == MSG_L1_PRIM) {
+		ret = l1_request(nst, hh, msg);
+	} else if (hh->prim == (BC_SETUP | REQUEST)) {
+		ret = setup_bchannel(nst, hh, msg);
+	} else if (hh->prim == (BC_CLEANUP | REQUEST)) {
+		ret = cleanup_bc(nst, hh, msg);
+	} else if (hh->prim == (CC_NEW_CR | INDICATION)) {
+		msg_pull(msg, mISDNUSER_HEAD_SIZE);
+		if (hh->dinfo == nst->bcid[0]) {
+			nst->bcid[0] = *((int *)msg->data);
+			free_msg(msg);
+			ret = 0;
+		} else if (hh->dinfo == nst->bcid[1]) {
+			nst->bcid[1] = *((int *)msg->data);
+			free_msg(msg);
+			ret = 0;
+		} else
+			ret = -ENXIO;
+	} else if ((hh->prim & LAYER_MASK) == MSG_L3_PRIM) {
+		if (nst->manager_l3)
+			ret = nst->manager_l3(nst, msg);
+	} else {
+		wprint("%s: prim(%x) dinfo(%x) unhandled msg(%d)\n", __FUNCTION__,
+			hh->prim, hh->dinfo, msg->len);
+	}
+	return(ret);
+}
+
+static void *
+main_readloop(void *arg)
+{
+	net_stack_t	*nst = arg;
+	int		lp = 1;
+	int		sel, ret;
+	int		maxfd;
+	fd_set		rfd;
+	fd_set		efd; 
+	pthread_t	tid;
+
+
+	tid = pthread_self();
+	dprint(DBGM_NET, nst->cardnr, "%s: tid %ld\n", __FUNCTION__, tid);
+	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+	while(lp) {
+//		dprint(DBGM_NET, nst->cardnr, "%s: begin dev %d\n", __FUNCTION__, nst->device);
+		maxfd = nst->device;
+		FD_ZERO(&rfd);
+		FD_SET(nst->device, &rfd);
+		FD_ZERO(&efd);
+		FD_SET(nst->device, &efd);
+		maxfd++;
+restart:
+		sel = mISDN_select(maxfd, &rfd, NULL, &efd, NULL);
+		if (sel < 0) {
+			if (errno == EINTR) {
+				if (test_bit(FLG_NST_TERMINATION, &nst->flag))
+					break;
+				dprint(DBGM_NET, nst->cardnr, "%s: select restart\n", __FUNCTION__);
+				goto restart;
+			}
+			wprint("%s: error(%d) in select %s\n", __FUNCTION__,
+				errno, strerror(errno));
+			break;
+		}
+		if (sel) {
+			if (FD_ISSET(nst->device, &rfd)) {
+				ret = do_net_read(nst);
+				if (ret) {
+					dprint(DBGM_NET, nst->cardnr, "%s: rdfunc ret(%d)\n", __FUNCTION__, ret);
+				}
+			}
+			if (FD_ISSET(nst->device, &efd)) {
+				dprint(DBGM_NET, nst->cardnr, "%s: exception\n", __FUNCTION__);
+			}
+		}
+	}
+	dprint(DBGM_NET, nst->cardnr,"%s: fall trough, abort\n", __FUNCTION__);
+	pthread_mutex_lock(&nst->lock);
+	test_and_set_bit(FLG_NST_READER_ABORT, &nst->flag);
+	pthread_mutex_unlock(&nst->lock);
+	sem_post(&nst->work);
+	return(NULL);
+}
+
+void *
+do_netthread(void *arg) {
+	net_stack_t	*nst = arg;
+	int	ret;
+	pthread_t	tid;
+	void	*retval = NULL;
+
+	/* create reader thread */
+	tid = pthread_self();
+	dprint(DBGM_NET, nst->cardnr, "%s: tid %ld\n", __FUNCTION__, tid);
+	ret = pthread_create(&nst->reader, NULL, main_readloop, (void *)nst);
+	tid = pthread_self();
+	dprint(DBGM_NET, nst->cardnr, "%s: tid %ld crated %ld\n", __FUNCTION__, tid, nst->reader);
+	if (ret) {
+		eprint("%s: cannot create reader %d\n", __FUNCTION__,
+			ret);
+		return(NULL);
+	}
+	while(1) {
+		msg_t	*msg;
+
+		sem_wait(&nst->work);
+		msg = msg_dequeue(&nst->wqueue);
+		if (msg) {
+			ret = do_writemsg(nst, msg);
+			if (ret) {
+				wprint("%s: do_writemsg return %d\n", __FUNCTION__,
+					ret);
+				free_msg(msg);
+			}
+		}
+		
+		msg = msg_dequeue(&nst->rqueue);
+		if (msg) {
+			ret = do_readmsg(nst, msg);
+			if (ret) {
+				wprint("%s: do_readmsg return %d\n", __FUNCTION__,
+					ret);
+				free_msg(msg);
+			}
+		}
+		pthread_mutex_lock(&nst->lock);
+		if (test_and_clear_bit(FLG_NST_READER_ABORT, &nst->flag)) {
+			pthread_mutex_unlock(&nst->lock);
+			dprint(DBGM_NET, nst->cardnr,"%s: reader aborted\n", __FUNCTION__);
+			ret = pthread_join(nst->reader, &retval);
+			dprint(DBGM_NET, nst->cardnr,"%s: join ret(%d) reader retval %p\n", __FUNCTION__,
+				ret, retval);
+			break;
+		}
+		if (test_bit(FLG_NST_TERMINATION, &nst->flag)) {
+			pthread_mutex_unlock(&nst->lock);
+			dprint(DBGM_NET, nst->cardnr,"%s: reader cancel\n", __FUNCTION__);
+			ret = pthread_cancel(nst->reader);
+			dprint(DBGM_NET, nst->cardnr,"%s: cancel reader ret(%d)\n", __FUNCTION__,
+				ret);
+			ret = pthread_join(nst->reader, &retval);
+			dprint(DBGM_NET, nst->cardnr,"%s: join ret(%d) reader retval %p\n", __FUNCTION__,
+				ret, retval);
+			break;
+		}
+		pthread_mutex_unlock(&nst->lock);
+	}
+	return(retval);
+}
+
+int
+term_netstack(net_stack_t *nst)
+{
+	test_and_set_bit(FLG_NST_TERMINATION, &nst->flag);
+	sem_post(&nst->work);
+	return(0);
+}

Added: misdn-user/trunk/i4lnet/net_l2.c
===================================================================
--- misdn-user/trunk/i4lnet/net_l2.c	                        (rev 0)
+++ misdn-user/trunk/i4lnet/net_l2.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,2104 @@
+/* $Id: net_l2.c,v 1.10 2006/08/09 10:29:44 crich Exp $
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ *		This file is (c) under GNU PUBLIC LICENSE
+ *		For changes and modifications please read
+ *		../../../Documentation/isdn/mISDN.cert
+ *
+ */
+
+#include <stdlib.h>
+#include "net_l2.h"
+#include "helper.h"
+// #include "debug.h"
+
+const char *l2_revision = "$Revision: 1.10 $";
+
+static void l2m_debug(struct FsmInst *fi, char *fmt, ...);
+
+static int debug = 0xff;
+
+enum {
+	ST_L2_1,
+	ST_L2_2,
+	ST_L2_3,
+	ST_L2_4,
+	ST_L2_5,
+	ST_L2_6,
+	ST_L2_7,
+	ST_L2_8,
+};
+
+#define L2_STATE_COUNT (ST_L2_8+1)
+
+enum {
+	EV_L2_UI,
+	EV_L2_SABME,
+	EV_L2_DISC,
+	EV_L2_DM,
+	EV_L2_UA,
+	EV_L2_FRMR,
+	EV_L2_SUPER,
+	EV_L2_I,
+	EV_L2_DL_DATA,
+	EV_L2_ACK_PULL,
+	EV_L2_DL_UNITDATA,
+	EV_L2_DL_ESTABLISH_REQ,
+	EV_L2_DL_RELEASE_REQ,
+	EV_L2_MDL_ASSIGN,
+	EV_L2_MDL_REMOVE,
+	EV_L2_MDL_ERROR,
+	EV_L1_DEACTIVATE,
+	EV_L2_T200,
+	EV_L2_T203,
+	EV_L2_SET_OWN_BUSY,
+	EV_L2_CLEAR_OWN_BUSY,
+	EV_L2_FRAME_ERROR,
+};
+
+#define L2_EVENT_COUNT (EV_L2_FRAME_ERROR+1)
+
+static char *strL2Event[] =
+{
+	"EV_L2_UI",
+	"EV_L2_SABME",
+	"EV_L2_DISC",
+	"EV_L2_DM",
+	"EV_L2_UA",
+	"EV_L2_FRMR",
+	"EV_L2_SUPER",
+	"EV_L2_I",
+	"EV_L2_DL_DATA",
+	"EV_L2_ACK_PULL",
+	"EV_L2_DL_UNITDATA",
+	"EV_L2_DL_ESTABLISH_REQ",
+	"EV_L2_DL_RELEASE_REQ",
+	"EV_L2_MDL_ASSIGN",
+	"EV_L2_MDL_REMOVE",
+	"EV_L2_MDL_ERROR",
+	"EV_L1_DEACTIVATE",
+	"EV_L2_T200",
+	"EV_L2_T203",
+	"EV_L2_SET_OWN_BUSY",
+	"EV_L2_CLEAR_OWN_BUSY",
+	"EV_L2_FRAME_ERROR",
+};
+
+static int l2addrsize(layer2_t *l2);
+
+static int
+l2up(layer2_t *l2, u_int prim, int dinfo, msg_t *msg)
+{
+	return(if_newhead(l2->nst, l2->nst->l2_l3, prim, dinfo, msg));
+}
+
+static int
+l2up_create(layer2_t *l2, u_int prim, int dinfo, int len, void *arg)
+{
+	return(if_link(l2->nst, l2->nst->l2_l3, prim, dinfo, len, arg, 0));
+}
+
+static int
+l2down_msg(layer2_t *l2, msg_t *msg) {
+	int ret;
+
+	ret = write_dmsg(l2->nst, msg);
+	if (ret)
+		dprint(DBGM_L2, l2->nst->cardnr, "l2down_msg: error %d\n", ret);
+	return(ret);
+}
+
+static int
+l2down(layer2_t *l2, u_int prim, int dinfo, msg_t *msg)
+{
+	mISDN_newhead(prim, dinfo, msg);
+	return(l2down_msg(l2, msg));
+}
+
+static int
+l2down_create(layer2_t *l2, u_int prim, int dinfo, int len, void *arg)
+{
+	msg_t	*msg;
+	int		err;
+
+	msg = create_link_msg(prim, dinfo, len, arg, 0);
+	if (!msg)
+		return(-ENOMEM);
+	err = l2down_msg(l2, msg);
+	if (err)
+		free_msg(msg);
+	return(err);
+}
+
+static int
+l2mgr(layer2_t *l2, u_int prim, void *arg) {
+	long c = (long)arg;
+
+	dprint(DBGM_L2, l2->nst->cardnr, "l2mgr: prim %x %c\n", prim, (char)c);
+      l2->nst->phd_down_msg=NULL;
+      msg_queue_purge(&l2->nst->down_queue);
+	return(0);
+}
+
+static void
+set_peer_busy(layer2_t *l2) {
+	test_and_set_bit(FLG_PEER_BUSY, &l2->flag);
+	dprint(DBGM_L2, l2->nst->cardnr, "Peer Busy\n");
+	if (msg_queue_len(&l2->i_queue) || msg_queue_len(&l2->ui_queue))
+		test_and_set_bit(FLG_L2BLOCK, &l2->flag);
+}
+
+static void
+clear_peer_busy(layer2_t *l2) {
+	dprint(DBGM_L2, l2->nst->cardnr, "Clear Peer Busy\n");
+	if (test_and_clear_bit(FLG_PEER_BUSY, &l2->flag))
+		test_and_clear_bit(FLG_L2BLOCK, &l2->flag);
+}
+
+static void
+InitWin(layer2_t *l2)
+{
+	int i;
+
+	for (i = 0; i < MAX_WINDOW; i++)
+		l2->windowar[i] = NULL;
+}
+
+static int
+freewin(layer2_t *l2)
+{
+	int i, cnt = 0;
+
+	for (i = 0; i < MAX_WINDOW; i++) {
+		if (l2->windowar[i]) {
+			cnt++;
+			free_msg(l2->windowar[i]);
+			l2->windowar[i] = NULL;
+		}
+	}
+	return cnt;
+}
+
+static void
+ReleaseWin(layer2_t *l2)
+{
+	int cnt;
+
+	if((cnt = freewin(l2)))
+		dprint(DBGM_L2, l2->nst->cardnr, "isdnl2 freed %d msguffs in release\n", cnt);
+}
+
+inline unsigned int
+cansend(layer2_t *l2)
+{
+	unsigned int p1;
+
+	if(test_bit(FLG_MOD128, &l2->flag))
+		p1 = (l2->vs - l2->va) % 128;
+	else
+		p1 = (l2->vs - l2->va) % 8;
+	return ((p1 < l2->window) && !test_bit(FLG_PEER_BUSY, &l2->flag));
+}
+
+inline void
+clear_exception(layer2_t *l2)
+{
+	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
+	test_and_clear_bit(FLG_REJEXC, &l2->flag);
+	test_and_clear_bit(FLG_OWN_BUSY, &l2->flag);
+	clear_peer_busy(l2);
+}
+
+inline int
+l2headersize(layer2_t *l2, int ui)
+{
+	return (((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) +
+		(test_bit(FLG_LAPD, &l2->flag) ? 2 : 1));
+}
+
+inline int
+l2addrsize(layer2_t *l2)
+{
+	return (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1);
+}
+
+static int
+sethdraddr(layer2_t *l2, u_char *header, int rsp)
+{
+	u_char *ptr = header;
+	int crbit = rsp;
+
+	if (test_bit(FLG_LAPD, &l2->flag)) {
+		if (test_bit(FLG_LAPD_NET, &l2->flag))
+			crbit = !crbit;
+		*ptr++ = (l2->sapi << 2) | (crbit ? 2 : 0);
+		*ptr++ = (l2->tei << 1) | 1;
+		return (2);
+	} else {
+		if (test_bit(FLG_ORIG, &l2->flag))
+			crbit = !crbit;
+		if (crbit)
+			*ptr++ = l2->addr.B;
+		else
+			*ptr++ = l2->addr.A;
+		return (1);
+	}
+}
+
+inline static void
+enqueue_super(layer2_t *l2, msg_t *msg)
+{
+	if (l2down(l2, PH_DATA | REQUEST, DINFO_SKB, msg))
+		free_msg(msg);
+}
+
+#define enqueue_ui(a, b) enqueue_super(a, b)
+
+inline int
+IsUI(u_char * data, layer2_t *l2)
+{
+	return ((data[0] & 0xef) == UI);
+}
+
+inline int
+IsUA(u_char * data, layer2_t *l2)
+{
+	return ((data[0] & 0xef) == UA);
+}
+
+inline int
+IsDM(u_char * data, layer2_t *l2)
+{
+	return ((data[0] & 0xef) == DM);
+}
+
+inline int
+IsDISC(u_char * data, layer2_t *l2)
+{
+	return ((data[0] & 0xef) == DISC);
+}
+
+inline int
+IsRR(u_char * data, layer2_t *l2)
+{
+	if (test_bit(FLG_MOD128, &l2->flag))
+		return (data[0] == RR);
+	else
+		return ((data[0] & 0xf) == 1);
+}
+
+inline int
+IsSFrame(u_char * data, layer2_t *l2)
+{
+	register u_char d = *data;
+	
+	if (!test_bit(FLG_MOD128, &l2->flag))
+		d &= 0xf;
+	return(((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c));
+}
+
+inline int
+IsSABME(u_char * data, layer2_t *l2)
+{
+	u_char d = data[0] & ~0x10;
+	return (test_bit(FLG_MOD128, &l2->flag) ? d == SABME : d == SABM);
+}
+
+inline int
+IsREJ(u_char * data, layer2_t *l2)
+{
+	return (test_bit(FLG_MOD128, &l2->flag) ? data[0] == REJ : (data[0] & 0xf) == REJ);
+}
+
+inline int
+IsFRMR(u_char * data, layer2_t *l2)
+{
+	return ((data[0] & 0xef) == FRMR);
+}
+
+inline int
+IsRNR(u_char * data, layer2_t *l2)
+{
+	return (test_bit(FLG_MOD128, &l2->flag) ? data[0] == RNR : (data[0] & 0xf) == RNR);
+}
+
+int
+iframe_error(layer2_t *l2, msg_t *msg)
+{
+	int i = l2addrsize(l2) + (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1);
+	int rsp = *msg->data & 0x2;
+	
+	if (test_bit(FLG_ORIG, &l2->flag))
+		rsp = !rsp;
+	if (rsp)
+		return 'L';
+	if (msg->len < i)
+		return 'N';
+	if ((msg->len - i) > l2->maxlen)
+		return 'O';
+	return 0;
+}
+
+int
+super_error(layer2_t *l2, msg_t *msg)
+{
+	if (msg->len != l2addrsize(l2) +
+	    (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1))
+		return 'N';
+	return 0;
+}
+
+int
+unnum_error(layer2_t *l2, msg_t *msg, int wantrsp)
+{
+	int rsp = (*msg->data & 0x2) >> 1;
+	if (test_bit(FLG_ORIG, &l2->flag))
+		rsp = !rsp;
+	if (rsp != wantrsp)
+		return 'L';
+	if (msg->len != l2addrsize(l2) + 1)
+		return 'N';
+	return 0;
+}
+
+int
+UI_error(layer2_t *l2, msg_t *msg)
+{
+	int rsp = *msg->data & 0x2;
+	if (test_bit(FLG_ORIG, &l2->flag))
+		rsp = !rsp;
+	if (rsp)
+		return 'L';
+	if (msg->len > l2->maxlen + l2addrsize(l2) + 1)
+		return 'O';
+	return 0;
+}
+
+int
+FRMR_error(layer2_t *l2, msg_t *msg)
+{
+	int headers = l2addrsize(l2) + 1;
+	u_char *datap = msg->data + headers;
+	int rsp = *msg->data & 0x2;
+
+	if (test_bit(FLG_ORIG, &l2->flag))
+		rsp = !rsp;
+	if (!rsp)
+		return 'L';
+	if (test_bit(FLG_MOD128, &l2->flag)) {
+		if (msg->len < headers + 5)
+			return 'N';
+		else
+			l2m_debug(&l2->l2m, "FRMR information %2x %2x %2x %2x %2x",
+				datap[0], datap[1], datap[2],
+				datap[3], datap[4]);
+	} else {
+		if (msg->len < headers + 3)
+			return 'N';
+		else
+			l2m_debug(&l2->l2m, "FRMR information %2x %2x %2x",
+				datap[0], datap[1], datap[2]);
+	}
+	return 0;
+}
+
+static unsigned int
+legalnr(layer2_t *l2, unsigned int nr)
+{
+	if(test_bit(FLG_MOD128, &l2->flag))
+		return ((nr - l2->va) % 128) <= ((l2->vs - l2->va) % 128);
+	else
+		return ((nr - l2->va) % 8) <= ((l2->vs - l2->va) % 8);
+}
+
+static void
+setva(layer2_t *l2, unsigned int nr)
+{
+	while (l2->va != nr) {
+		(l2->va)++;
+		if(test_bit(FLG_MOD128, &l2->flag))
+			l2->va %= 128;
+		else
+			l2->va %= 8;
+		l2up(l2, DL_DATA | CONFIRM, (int)l2->windowar[l2->sow], NULL);
+		free_msg(l2->windowar[l2->sow]);
+		l2->windowar[l2->sow] = NULL;
+		l2->sow = (l2->sow + 1) % l2->window;
+	}
+}
+
+static void
+send_uframe(layer2_t *l2, msg_t *msg, u_char cmd, u_char cr)
+{
+	u_char tmp[MAX_HEADER_LEN];
+	int i;
+
+	i = sethdraddr(l2, tmp, cr);
+	tmp[i++] = cmd;
+	if (msg)
+		msg_trim(msg, 0);
+	else if ((msg = alloc_msg(i + mISDNUSER_HEAD_SIZE)))
+		msg_reserve(msg, mISDNUSER_HEAD_SIZE);
+	else {
+		dprint(DBGM_L2, l2->nst->cardnr,"%s: can't alloc msguff\n", __FUNCTION__);
+		return;
+	}
+	memcpy(msg_put(msg, i), tmp, i);
+	msg_push(msg, mISDNUSER_HEAD_SIZE);
+	enqueue_super(l2, msg);
+}
+
+
+inline u_char
+get_PollFlag(layer2_t *l2, msg_t * msg)
+{
+	return (msg->data[l2addrsize(l2)] & 0x10);
+}
+
+inline u_char
+get_PollFlagFree(layer2_t *l2, msg_t *msg)
+{
+	u_char PF;
+
+	PF = get_PollFlag(l2, msg);
+	free_msg(msg);
+	return (PF);
+}
+
+inline void
+start_t200(layer2_t *l2, int i)
+{
+	FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i);
+	test_and_set_bit(FLG_T200_RUN, &l2->flag);
+}
+
+inline void
+restart_t200(layer2_t *l2, int i)
+{
+	FsmRestartTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i);
+	test_and_set_bit(FLG_T200_RUN, &l2->flag);
+}
+
+inline void
+stop_t200(layer2_t *l2, int i)
+{
+	if(test_and_clear_bit(FLG_T200_RUN, &l2->flag))
+		FsmDelTimer(&l2->t200, i);
+}
+
+inline void
+st5_dl_release_l2l3(layer2_t *l2)
+{
+	int pr;
+
+	if (test_and_clear_bit(FLG_PEND_REL, &l2->flag)) {
+		pr = DL_RELEASE | CONFIRM;
+	} else {
+		pr = DL_RELEASE | INDICATION;
+	}
+	l2up_create(l2, pr, CES(l2), 0, NULL);
+}
+
+inline void
+lapb_dl_release_l2l3(layer2_t *l2, int f)
+{
+	if (test_bit(FLG_LAPB, &l2->flag))
+		l2down_create(l2, PH_DEACTIVATE | REQUEST, 0, 0, NULL);
+	l2up_create(l2, DL_RELEASE | f, CES(l2), 0, NULL);
+}
+
+static void
+establishlink(struct FsmInst *fi)
+{
+	layer2_t *l2 = fi->userdata;
+	u_char cmd;
+
+	clear_exception(l2);
+	l2->rc = 0;
+	cmd = (test_bit(FLG_MOD128, &l2->flag) ? SABME : SABM) | 0x10;
+	send_uframe(l2, NULL, cmd, CMD);
+	FsmDelTimer(&l2->t203, 1);
+	restart_t200(l2, 1);
+	test_and_clear_bit(FLG_PEND_REL, &l2->flag);
+	freewin(l2);
+	FsmChangeState(fi, ST_L2_5);
+}
+
+static void
+l2_mdl_error_ua(struct FsmInst *fi, int event, void *arg)
+{
+	msg_t *msg = arg;
+	layer2_t *l2 = fi->userdata;
+
+	if (get_PollFlagFree(l2, msg))
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'C');
+	else
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'D');
+	
+}
+
+static void
+l2_mdl_error_dm(struct FsmInst *fi, int event, void *arg)
+{
+	msg_t *msg = arg;
+	layer2_t *l2 = fi->userdata;
+
+	if (get_PollFlagFree(l2, msg))
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'B');
+	else {
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'E');
+		establishlink(fi);
+		test_and_clear_bit(FLG_L3_INIT, &l2->flag);
+	}
+}
+
+static void
+l2_st8_mdl_error_dm(struct FsmInst *fi, int event, void *arg)
+{
+	msg_t *msg = arg;
+	layer2_t *l2 = fi->userdata;
+
+	if (get_PollFlagFree(l2, msg))
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'B');
+	else {
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'E');
+	}
+	establishlink(fi);
+	test_and_clear_bit(FLG_L3_INIT, &l2->flag);
+}
+
+static void
+l2_go_st3(struct FsmInst *fi, int event, void *arg)
+{
+	free_msg((msg_t *)arg);
+	FsmChangeState(fi, ST_L2_3); 
+}
+
+static void
+l2_mdl_assign(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t	*l2 = fi->userdata;
+	msg_t	*msg = arg;
+	mISDNuser_head_t	*hh;
+
+	FsmChangeState(fi, ST_L2_3);
+	msg_trim(msg, 0);
+	hh = (mISDNuser_head_t *)msg_put(msg, mISDNUSER_HEAD_SIZE);
+	hh->prim = MDL_ASSIGN | INDICATION;
+	hh->dinfo = 0;
+	if (l2_tei(l2->tm, msg))
+		free_msg(msg);
+}
+
+static void
+l2_queue_ui_assign(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	msg_queue_tail(&l2->ui_queue, msg);
+	FsmChangeState(fi, ST_L2_2);
+	if ((msg = create_link_msg(MDL_ASSIGN | INDICATION, 0, 0, NULL, 0))) {
+		if (l2_tei(l2->tm, msg))
+			free_msg(msg);
+	}
+}
+
+static void
+l2_queue_ui(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	msg_queue_tail(&l2->ui_queue, msg);
+}
+
+static void
+tx_ui(layer2_t *l2)
+{
+	msg_t *msg;
+	u_char header[MAX_HEADER_LEN];
+	int i;
+
+	i = sethdraddr(l2, header, CMD);
+	if (test_bit(FLG_LAPD_NET, &l2->flag))
+		header[1] = 0xff; /* tei 127 */
+	header[i++] = UI;
+	while ((msg = msg_dequeue(&l2->ui_queue))) {
+		msg_pull(msg, mISDNUSER_HEAD_SIZE);
+		memcpy(msg_push(msg, i), header, i);
+		msg_push(msg, mISDNUSER_HEAD_SIZE);
+		enqueue_ui(l2, msg);
+	}
+}
+
+static void
+l2_send_ui(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	msg_queue_tail(&l2->ui_queue, msg);
+	tx_ui(l2);
+}
+
+static void
+l2_got_ui(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	msg_pull(msg, l2headersize(l2, 1));
+/*
+ *		in states 1-3 for broadcast
+ */
+	msg_push(msg, mISDNUSER_HEAD_SIZE);
+	if (l2up(l2, DL_UNITDATA | INDICATION, CES(l2), msg))
+		free_msg(msg);
+}
+
+static void
+l2_establish(struct FsmInst *fi, int event, void *arg)
+{
+	msg_t *msg = arg;
+	layer2_t *l2 = fi->userdata;
+
+	establishlink(fi);
+	test_and_set_bit(FLG_L3_INIT, &l2->flag);
+	free_msg(msg);
+}
+
+static void
+l2_discard_i_setl3(struct FsmInst *fi, int event, void *arg)
+{
+	msg_t *msg = arg;
+	layer2_t *l2 = fi->userdata;
+
+	msg_queue_purge(&l2->i_queue);
+	test_and_set_bit(FLG_L3_INIT, &l2->flag);
+	test_and_clear_bit(FLG_PEND_REL, &l2->flag);
+	free_msg(msg);
+} 
+
+static void
+l2_l3_reestablish(struct FsmInst *fi, int event, void *arg)
+{
+	msg_t *msg = arg;
+	layer2_t *l2 = fi->userdata;
+
+	msg_queue_purge(&l2->i_queue);
+	establishlink(fi);
+	test_and_set_bit(FLG_L3_INIT, &l2->flag);
+	free_msg(msg);
+}
+
+static void
+l2_release(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	msg_trim(msg, mISDNUSER_HEAD_SIZE);
+	if (l2up(l2, DL_RELEASE | CONFIRM, CES(l2), msg))
+		free_msg(msg);
+}
+
+static void
+l2_pend_rel(struct FsmInst *fi, int event, void *arg)
+{
+	msg_t *msg = arg;
+	layer2_t *l2 = fi->userdata;
+
+	test_and_set_bit(FLG_PEND_REL, &l2->flag);
+	free_msg(msg);
+}
+
+static void
+l2_disconnect(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	msg_queue_purge(&l2->i_queue);
+	freewin(l2);
+	FsmChangeState(fi, ST_L2_6);
+	l2->rc = 0;
+	send_uframe(l2, NULL, DISC | 0x10, CMD);
+	FsmDelTimer(&l2->t203, 1);
+	restart_t200(l2, 2);
+	if (msg)
+		free_msg(msg);
+}
+
+static void
+l2_start_multi(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	send_uframe(l2, NULL, UA | get_PollFlag(l2, msg), RSP);
+
+	clear_exception(l2);
+	l2->vs = 0;
+	l2->va = 0;
+	l2->vr = 0;
+	l2->sow = 0;
+	FsmChangeState(fi, ST_L2_7);
+	FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3);
+	msg_trim(msg, 0);
+	msg_push(msg, mISDNUSER_HEAD_SIZE);
+	if (l2up(l2, DL_ESTABLISH | INDICATION, CES(l2), msg))
+		free_msg(msg);
+}
+
+static void
+l2_send_UA(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	send_uframe(l2, msg, UA | get_PollFlag(l2, msg), RSP);
+}
+
+static void
+l2_send_DM(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	send_uframe(l2, msg, DM | get_PollFlag(l2, msg), RSP);
+}
+
+static void
+l2_restart_multi(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+	int est = 0;
+
+	send_uframe(l2, msg, UA | get_PollFlag(l2, msg), RSP);
+
+	l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'F');
+
+	if (l2->vs != l2->va) {
+		msg_queue_purge(&l2->i_queue);
+		est = 1;
+	}
+
+	clear_exception(l2);
+	l2->vs = 0;
+	l2->va = 0;
+	l2->vr = 0;
+	l2->sow = 0;
+	FsmChangeState(fi, ST_L2_7);
+	stop_t200(l2, 3);
+	FsmRestartTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3);
+
+	if (est)
+		l2up_create(l2, DL_ESTABLISH | INDICATION, CES(l2), 0, NULL);
+
+	if (msg_queue_len(&l2->i_queue) && cansend(l2))
+		FsmEvent(fi, EV_L2_ACK_PULL, NULL);
+}
+
+static void
+l2_stop_multi(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	FsmChangeState(fi, ST_L2_4);
+	FsmDelTimer(&l2->t203, 3);
+	stop_t200(l2, 4);
+
+	send_uframe(l2, msg, UA | get_PollFlag(l2, msg), RSP);
+	msg_queue_purge(&l2->i_queue);
+	freewin(l2);
+	lapb_dl_release_l2l3(l2, INDICATION);
+}
+
+static void
+l2_connected(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+	int pr=-1;
+
+	if (!get_PollFlag(l2, msg)) {
+		l2_mdl_error_ua(fi, event, arg);
+		return;
+	}
+	free_msg(msg);
+	if (test_and_clear_bit(FLG_PEND_REL, &l2->flag))
+		l2_disconnect(fi, event, NULL);
+	if (test_and_clear_bit(FLG_L3_INIT, &l2->flag)) {
+		pr = DL_ESTABLISH | CONFIRM;
+	} else if (l2->vs != l2->va) {
+		msg_queue_purge(&l2->i_queue);
+		pr = DL_ESTABLISH | INDICATION;
+	}
+	stop_t200(l2, 5);
+
+	l2->vr = 0;
+	l2->vs = 0;
+	l2->va = 0;
+	l2->sow = 0;
+	FsmChangeState(fi, ST_L2_7);
+	FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 4);
+	if (pr != -1)
+		l2up_create(l2, pr, CES(l2), 0, NULL);
+
+	if (msg_queue_len(&l2->i_queue) && cansend(l2))
+		FsmEvent(fi, EV_L2_ACK_PULL, NULL);
+}
+
+static void
+l2_released(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	if (!get_PollFlag(l2, msg)) {
+		l2_mdl_error_ua(fi, event, arg);
+		return;
+	}
+	free_msg(msg);
+	stop_t200(l2, 6);
+	lapb_dl_release_l2l3(l2, CONFIRM);
+	FsmChangeState(fi, ST_L2_4);
+}
+
+static void
+l2_reestablish(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	if (!get_PollFlagFree(l2, msg)) {
+		establishlink(fi);
+		test_and_set_bit(FLG_L3_INIT, &l2->flag);
+	}
+}
+
+static void
+l2_st5_dm_release(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	if (get_PollFlagFree(l2, msg)) {
+		stop_t200(l2, 7);
+	 	if (!test_bit(FLG_L3_INIT, &l2->flag))
+			msg_queue_purge(&l2->i_queue);
+		if (test_bit(FLG_LAPB, &l2->flag))
+			l2down_create(l2, PH_DEACTIVATE | REQUEST, 0, 0, NULL);
+		st5_dl_release_l2l3(l2);
+		FsmChangeState(fi, ST_L2_4);
+	}
+}
+
+static void
+l2_st6_dm_release(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	if (get_PollFlagFree(l2, msg)) {
+		stop_t200(l2, 8);
+		lapb_dl_release_l2l3(l2, CONFIRM);
+		FsmChangeState(fi, ST_L2_4);
+	}
+}
+
+void
+enquiry_cr(layer2_t *l2, u_char typ, u_char cr, u_char pf)
+{
+	msg_t *msg;
+	u_char tmp[MAX_HEADER_LEN];
+	int i;
+
+	i = sethdraddr(l2, tmp, cr);
+	if (test_bit(FLG_MOD128, &l2->flag)) {
+		tmp[i++] = typ;
+		tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0);
+	} else
+		tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0);
+	if (!(msg = alloc_msg(i + mISDNUSER_HEAD_SIZE))) {
+		dprint(DBGM_L2, l2->nst->cardnr, "isdnl2 can't alloc sbbuff for enquiry_cr\n");
+		return;
+	} else
+		msg_reserve(msg, mISDNUSER_HEAD_SIZE);
+	memcpy(msg_put(msg, i), tmp, i);
+	msg_push(msg, mISDNUSER_HEAD_SIZE);
+	enqueue_super(l2, msg);
+}
+
+inline void
+enquiry_response(layer2_t *l2)
+{
+	if (test_bit(FLG_OWN_BUSY, &l2->flag))
+		enquiry_cr(l2, RNR, RSP, 1);
+	else
+		enquiry_cr(l2, RR, RSP, 1);
+	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
+}
+
+inline void
+transmit_enquiry(layer2_t *l2)
+{
+	if (test_bit(FLG_OWN_BUSY, &l2->flag))
+		enquiry_cr(l2, RNR, CMD, 1);
+	else
+		enquiry_cr(l2, RR, CMD, 1);
+	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
+	start_t200(l2, 9);
+}
+
+
+static void
+nrerrorrecovery(struct FsmInst *fi)
+{
+	layer2_t *l2 = fi->userdata;
+
+	l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'J');
+	establishlink(fi);
+	test_and_clear_bit(FLG_L3_INIT, &l2->flag);
+}
+
+static void
+invoke_retransmission(layer2_t *l2, unsigned int nr)
+{
+	unsigned int p1;
+
+	if (l2->vs != nr) {
+		while (l2->vs != nr) {
+			(l2->vs)--;
+			if(test_bit(FLG_MOD128, &l2->flag)) {
+				l2->vs %= 128;
+				p1 = (l2->vs - l2->va) % 128;
+			} else {
+				l2->vs %= 8;
+				p1 = (l2->vs - l2->va) % 8;
+			}
+			p1 = (p1 + l2->sow) % l2->window;
+//			if (test_bit(FLG_LAPB, &l2->flag))
+//				st->l1.bcs->tx_cnt += l2->windowar[p1]->len + l2headersize(l2, 0);
+			msg_queue_head(&l2->i_queue, l2->windowar[p1]);
+			l2->windowar[p1] = NULL;
+		}
+		FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL);
+	}
+}
+
+static void
+l2_st7_got_super(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+	int PollFlag, rsp, typ = RR;
+	unsigned int nr;
+
+	rsp = *msg->data & 0x2;
+	if (test_bit(FLG_ORIG, &l2->flag))
+		rsp = !rsp;
+
+	msg_pull(msg, l2addrsize(l2));
+	if (IsRNR(msg->data, l2)) {
+		set_peer_busy(l2);
+		typ = RNR;
+	} else
+		clear_peer_busy(l2);
+	if (IsREJ(msg->data, l2))
+		typ = REJ;
+
+	if (test_bit(FLG_MOD128, &l2->flag)) {
+		PollFlag = (msg->data[1] & 0x1) == 0x1;
+		nr = msg->data[1] >> 1;
+	} else {
+		PollFlag = (msg->data[0] & 0x10);
+		nr = (msg->data[0] >> 5) & 0x7;
+	}
+	free_msg(msg);
+
+	if (PollFlag) {
+		if (rsp)
+			l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'A');
+		else
+			enquiry_response(l2);
+	}
+	if (legalnr(l2, nr)) {
+		if (typ == REJ) {
+			setva(l2, nr);
+			invoke_retransmission(l2, nr);
+			stop_t200(l2, 10);
+			if (FsmAddTimer(&l2->t203, l2->T203,
+					EV_L2_T203, NULL, 6))
+				l2m_debug(&l2->l2m, "Restart T203 ST7 REJ");
+		} else if ((nr == l2->vs) && (typ == RR)) {
+			setva(l2, nr);
+			stop_t200(l2, 11);
+			FsmRestartTimer(&l2->t203, l2->T203,
+					EV_L2_T203, NULL, 7);
+		} else if ((l2->va != nr) || (typ == RNR)) {
+			setva(l2, nr);
+			if (typ != RR)
+				FsmDelTimer(&l2->t203, 9);
+			restart_t200(l2, 12);
+		}
+		if (msg_queue_len(&l2->i_queue) && (typ == RR))
+			FsmEvent(fi, EV_L2_ACK_PULL, NULL);
+	} else
+		nrerrorrecovery(fi);
+}
+
+static void
+l2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+//	if (test_bit(FLG_LAPB, &l2->flag))
+//		st->l1.bcs->tx_cnt += msg->len + l2headersize(l2, 0);
+	if (!test_bit(FLG_L3_INIT, &l2->flag))
+		msg_queue_tail(&l2->i_queue, msg);
+	else
+		free_msg(msg);
+}
+
+static void
+l2_feed_i_pull(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+//	if (test_bit(FLG_LAPB, &l2->flag))
+//		st->l1.bcs->tx_cnt += msg->len + l2headersize(l2, 0);
+	msg_queue_tail(&l2->i_queue, msg);
+	FsmEvent(fi, EV_L2_ACK_PULL, NULL);
+}
+
+static void
+l2_feed_iqueue(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+//	if (test_bit(FLG_LAPB, &l2->flag))
+//		st->l1.bcs->tx_cnt += msg->len + l2headersize(l2, 0);
+	msg_queue_tail(&l2->i_queue, msg);
+}
+
+static void
+l2_got_iframe(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+	int PollFlag, ns, i;
+	unsigned int nr;
+
+	i = l2addrsize(l2);
+	if (test_bit(FLG_MOD128, &l2->flag)) {
+		PollFlag = ((msg->data[i + 1] & 0x1) == 0x1);
+		ns = msg->data[i] >> 1;
+		nr = (msg->data[i + 1] >> 1) & 0x7f;
+	} else {
+		PollFlag = (msg->data[i] & 0x10);
+		ns = (msg->data[i] >> 1) & 0x7;
+		nr = (msg->data[i] >> 5) & 0x7;
+	}
+	if (test_bit(FLG_OWN_BUSY, &l2->flag)) {
+		free_msg(msg);
+		if (PollFlag)
+			enquiry_response(l2);
+	} else if (l2->vr == ns) {
+		(l2->vr)++;
+		if(test_bit(FLG_MOD128, &l2->flag))
+			l2->vr %= 128;
+		else
+			l2->vr %= 8;
+		test_and_clear_bit(FLG_REJEXC, &l2->flag);
+		if (PollFlag)
+			enquiry_response(l2);
+		else
+			test_and_set_bit(FLG_ACK_PEND, &l2->flag);
+		msg_pull(msg, l2headersize(l2, 0));
+		msg_push(msg, mISDNUSER_HEAD_SIZE);
+		if (l2up(l2, DL_DATA | INDICATION, CES(l2), msg))
+			free_msg(msg);
+	} else {
+		/* n(s)!=v(r) */
+		free_msg(msg);
+		if (test_and_set_bit(FLG_REJEXC, &l2->flag)) {
+			if (PollFlag)
+				enquiry_response(l2);
+		} else {
+			enquiry_cr(l2, REJ, RSP, PollFlag);
+			test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
+		}
+	}
+	if (legalnr(l2, nr)) {
+		if (!test_bit(FLG_PEER_BUSY, &l2->flag) && (fi->state == ST_L2_7)) {
+			if (nr == l2->vs) {
+				stop_t200(l2, 13);
+				FsmRestartTimer(&l2->t203, l2->T203,
+						EV_L2_T203, NULL, 7);
+			} else if (nr != l2->va)
+				restart_t200(l2, 14);
+		}
+		setva(l2, nr);
+	} else {
+		nrerrorrecovery(fi);
+		return;
+	}
+	if (msg_queue_len(&l2->i_queue) && (fi->state == ST_L2_7))
+		FsmEvent(fi, EV_L2_ACK_PULL, NULL);
+	if (test_and_clear_bit(FLG_ACK_PEND, &l2->flag))
+		enquiry_cr(l2, RR, RSP, 0);
+}
+
+static void
+l2_got_tei(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t	*l2 = fi->userdata;
+	msg_t	*msg = arg;
+	mISDNuser_head_t	*hh = (mISDNuser_head_t *)msg->data;
+
+	l2->tei = hh->dinfo;
+	free_msg(msg);
+	if (fi->state == ST_L2_3) {
+		establishlink(fi);
+		test_and_set_bit(FLG_L3_INIT, &l2->flag);
+	} else
+		FsmChangeState(fi, ST_L2_4);
+	if (msg_queue_len(&l2->ui_queue))
+		tx_ui(l2);
+}
+
+static void
+l2_st5_tout_200(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+
+	if (test_bit(FLG_LAPD, &l2->flag) &&
+		test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
+		FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
+	} else if (l2->rc == l2->N200) {
+		FsmChangeState(fi, ST_L2_4);
+		test_and_clear_bit(FLG_T200_RUN, &l2->flag);
+		msg_queue_purge(&l2->i_queue);
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'G');
+		if (test_bit(FLG_LAPB, &l2->flag))
+			l2down_create(l2, PH_DEACTIVATE | REQUEST, 0, 0, NULL);
+		st5_dl_release_l2l3(l2);
+	} else {
+		l2->rc++;
+		FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
+		send_uframe(l2, NULL, (test_bit(FLG_MOD128, &l2->flag) ?
+			SABME : SABM) | 0x10, CMD);
+	}
+}
+
+static void
+l2_st6_tout_200(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+
+	if (test_bit(FLG_LAPD, &l2->flag) &&
+		test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
+		FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
+	} else if (l2->rc == l2->N200) {
+		FsmChangeState(fi, ST_L2_4);
+		test_and_clear_bit(FLG_T200_RUN, &l2->flag);
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'H');
+		lapb_dl_release_l2l3(l2, CONFIRM);
+	} else {
+		l2->rc++;
+		FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200,
+			    NULL, 9);
+		send_uframe(l2, NULL, DISC | 0x10, CMD);
+	}
+}
+
+static void
+l2_st7_tout_200(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+
+	if (test_bit(FLG_LAPD, &l2->flag) &&
+		test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
+		FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
+		return;
+	}
+	test_and_clear_bit(FLG_T200_RUN, &l2->flag);
+	l2->rc = 0;
+	FsmChangeState(fi, ST_L2_8);
+	transmit_enquiry(l2);
+	l2->rc++;
+}
+
+static void
+l2_st8_tout_200(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+
+	if (test_bit(FLG_LAPD, &l2->flag) &&
+		test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
+		FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
+		return;
+	}
+	test_and_clear_bit(FLG_T200_RUN, &l2->flag);
+	if (l2->rc == l2->N200) {
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'I');
+		establishlink(fi);
+		test_and_clear_bit(FLG_L3_INIT, &l2->flag);
+	} else {
+		transmit_enquiry(l2);
+		l2->rc++;
+	}
+}
+
+static void
+l2_st7_tout_203(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+
+	if (test_bit(FLG_LAPD, &l2->flag) &&
+		test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
+		FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 9);
+		return;
+	}
+	FsmChangeState(fi, ST_L2_8);
+	transmit_enquiry(l2);
+	l2->rc = 0;
+}
+
+static void
+l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg, *omsg;
+	u_char header[MAX_HEADER_LEN];
+	int i;
+	int unsigned p1;
+
+	if (!cansend(l2))
+		return;
+
+	msg = msg_dequeue(&l2->i_queue);
+	if (!msg)
+		return;
+
+	if(test_bit(FLG_MOD128, &l2->flag))
+		p1 = (l2->vs - l2->va) % 128;
+	else
+		p1 = (l2->vs - l2->va) % 8;
+	p1 = (p1 + l2->sow) % l2->window;
+	if (l2->windowar[p1]) {
+		dprint(DBGM_L2, l2->nst->cardnr, "isdnl2 try overwrite ack queue entry %d\n",
+		       p1);
+		free_msg(l2->windowar[p1]);
+	}
+	l2->windowar[p1] = msg;
+	msg = msg_clone(msg);
+
+	if (!msg) {
+		free_msg(l2->windowar[p1]);
+		dprint(DBGM_L2, l2->nst->cardnr,"%s: no msg mem\n", __FUNCTION__);
+		return;
+	}
+
+	i = sethdraddr(l2, header, CMD);
+
+	if (test_bit(FLG_MOD128, &l2->flag)) {
+		header[i++] = l2->vs << 1;
+		header[i++] = l2->vr << 1;
+		l2->vs = (l2->vs + 1) % 128;
+	} else {
+		header[i++] = (l2->vr << 5) | (l2->vs << 1);
+		l2->vs = (l2->vs + 1) % 8;
+	}
+
+	p1 = msg_headroom(msg);
+	msg_pull(msg, mISDNUSER_HEAD_SIZE);
+	if (p1 >= i)
+		memcpy(msg_push(msg, i), header, i);
+	else {
+		dprint(DBGM_L2, l2->nst->cardnr,
+		"isdnl2 pull_iqueue msg header(%d/%d) too short\n", i, p1);
+		omsg = msg;
+		msg = alloc_msg(omsg->len + i + mISDNUSER_HEAD_SIZE);
+		if (!msg) {
+			free_msg(omsg);
+			dprint(DBGM_L2, l2->nst->cardnr,"%s: no msg mem\n", __FUNCTION__);
+			return;
+		}
+		msg_reserve(msg, mISDNUSER_HEAD_SIZE);
+		memcpy(msg_put(msg, i), header, i);
+		memcpy(msg_put(msg, omsg->len), omsg->data, omsg->len);
+		free_msg(omsg);
+	}
+	msg_push(msg, mISDNUSER_HEAD_SIZE);
+	l2down(l2, PH_DATA_REQ, DINFO_SKB, msg);
+	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
+	if (!test_and_set_bit(FLG_T200_RUN, &l2->flag)) {
+		FsmDelTimer(&l2->t203, 13);
+		FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 11);
+	}
+}
+
+static void
+l2_st8_got_super(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+	int PollFlag, rsp, rnr = 0;
+	unsigned int nr;
+
+	rsp = *msg->data & 0x2;
+	if (test_bit(FLG_ORIG, &l2->flag))
+		rsp = !rsp;
+
+	msg_pull(msg, l2addrsize(l2));
+
+	if (IsRNR(msg->data, l2)) {
+		set_peer_busy(l2);
+		rnr = 1;
+	} else
+		clear_peer_busy(l2);
+
+	if (test_bit(FLG_MOD128, &l2->flag)) {
+		PollFlag = (msg->data[1] & 0x1) == 0x1;
+		nr = msg->data[1] >> 1;
+	} else {
+		PollFlag = (msg->data[0] & 0x10);
+		nr = (msg->data[0] >> 5) & 0x7;
+	}
+	free_msg(msg);
+	if (rsp && PollFlag) {
+		if (legalnr(l2, nr)) {
+			if (rnr) {
+				restart_t200(l2, 15);
+			} else {
+				stop_t200(l2, 16);
+				FsmAddTimer(&l2->t203, l2->T203,
+					    EV_L2_T203, NULL, 5);
+				setva(l2, nr);
+			}
+			invoke_retransmission(l2, nr);
+			FsmChangeState(fi, ST_L2_7);
+			if (msg_queue_len(&l2->i_queue) && cansend(l2))
+				FsmEvent(fi, EV_L2_ACK_PULL, NULL);
+		} else
+			nrerrorrecovery(fi);
+	} else {
+		if (!rsp && PollFlag)
+			enquiry_response(l2);
+		if (legalnr(l2, nr)) {
+			setva(l2, nr);
+		} else
+			nrerrorrecovery(fi);
+	}
+}
+
+static void
+l2_got_FRMR(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	msg_pull(msg, l2addrsize(l2) + 1);
+
+	if (!(msg->data[0] & 1) || ((msg->data[0] & 3) == 1) ||		/* I or S */
+	    (IsUA(msg->data, l2) && (fi->state == ST_L2_7))) {
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'K');
+		establishlink(fi);
+		test_and_clear_bit(FLG_L3_INIT, &l2->flag);
+	}
+	free_msg(msg);
+}
+
+static void
+l2_st24_tei_remove(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	msg_queue_purge(&l2->ui_queue);
+	l2->tei = -1;
+	FsmChangeState(fi, ST_L2_1);
+	free_msg(msg);
+}
+
+static void
+l2_st3_tei_remove(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	msg_queue_purge(&l2->ui_queue);
+	l2->tei = -1;
+	msg_trim(msg, mISDNUSER_HEAD_SIZE);
+	if (l2up(l2, DL_RELEASE | INDICATION, CES(l2), msg))
+		free_msg(msg);
+	FsmChangeState(fi, ST_L2_1);
+}
+
+static void
+l2_st5_tei_remove(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	msg_queue_purge(&l2->i_queue);
+	msg_queue_purge(&l2->ui_queue);
+	freewin(l2);
+	l2->tei = -1;
+	stop_t200(l2, 17);
+	st5_dl_release_l2l3(l2);
+	FsmChangeState(fi, ST_L2_1);
+	free_msg(msg);
+}
+
+static void
+l2_st6_tei_remove(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	msg_queue_purge(&l2->ui_queue);
+	l2->tei = -1;
+	stop_t200(l2, 18);
+	if (l2up(l2, DL_RELEASE | CONFIRM, CES(l2), msg))
+		free_msg(msg);
+	FsmChangeState(fi, ST_L2_1);
+}
+
+static void
+l2_tei_remove(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	msg_queue_purge(&l2->i_queue);
+	msg_queue_purge(&l2->ui_queue);
+	freewin(l2);
+	l2->tei = -1;
+	stop_t200(l2, 17);
+	FsmDelTimer(&l2->t203, 19);
+	if (l2up(l2, DL_RELEASE | INDICATION, CES(l2), msg))
+		free_msg(msg);
+	FsmChangeState(fi, ST_L2_1);
+}
+
+static void
+l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+	
+	msg_queue_purge(&l2->i_queue);
+	msg_queue_purge(&l2->ui_queue);
+	if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag))
+		if (!l2up(l2, DL_RELEASE | INDICATION, CES(l2), msg))
+			return;
+	free_msg(msg);
+}
+
+static void
+l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	msg_queue_purge(&l2->i_queue);
+	msg_queue_purge(&l2->ui_queue);
+	freewin(l2);
+	stop_t200(l2, 19);
+	st5_dl_release_l2l3(l2);
+	FsmChangeState(fi, ST_L2_4);
+	free_msg(msg);
+}
+
+static void
+l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	msg_queue_purge(&l2->ui_queue);
+	stop_t200(l2, 20);
+	if (l2up(l2, DL_RELEASE | CONFIRM, CES(l2), msg))
+		free_msg(msg);
+	FsmChangeState(fi, ST_L2_4);
+}
+
+static void
+l2_persistant_da(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	msg_queue_purge(&l2->i_queue);
+	msg_queue_purge(&l2->ui_queue);
+	freewin(l2);
+	stop_t200(l2, 19);
+	FsmDelTimer(&l2->t203, 19);
+	if (l2up(l2, DL_RELEASE | INDICATION, CES(l2), msg))
+		free_msg(msg);
+	FsmChangeState(fi, ST_L2_4);
+}
+
+static void
+l2_set_own_busy(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	if(!test_and_set_bit(FLG_OWN_BUSY, &l2->flag)) {
+		enquiry_cr(l2, RNR, RSP, 0);
+		test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
+	}
+	if (msg)
+		free_msg(msg);
+}
+
+static void
+l2_clear_own_busy(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	msg_t *msg = arg;
+
+	if(!test_and_clear_bit(FLG_OWN_BUSY, &l2->flag)) {
+		enquiry_cr(l2, RR, RSP, 0);
+		test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
+	}
+	if (msg)
+		free_msg(msg);
+}
+
+static void
+l2_frame_error(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+
+	l2mgr(l2, MDL_ERROR | INDICATION, arg);
+}
+
+static void
+l2_frame_error_reest(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+
+	l2mgr(l2, MDL_ERROR | INDICATION, arg);
+	establishlink(fi);
+	test_and_clear_bit(FLG_L3_INIT, &l2->flag);
+}
+
+static struct FsmNode L2FnList[] =
+{
+	{ST_L2_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign},
+	{ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3},
+	{ST_L2_4, EV_L2_DL_ESTABLISH_REQ, l2_establish},
+	{ST_L2_5, EV_L2_DL_ESTABLISH_REQ, l2_discard_i_setl3},
+	{ST_L2_7, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish},
+	{ST_L2_8, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish},
+	{ST_L2_4, EV_L2_DL_RELEASE_REQ, l2_release},
+	{ST_L2_5, EV_L2_DL_RELEASE_REQ, l2_pend_rel},
+	{ST_L2_7, EV_L2_DL_RELEASE_REQ, l2_disconnect},
+	{ST_L2_8, EV_L2_DL_RELEASE_REQ, l2_disconnect},
+	{ST_L2_5, EV_L2_DL_DATA, l2_feed_i_if_reest},
+	{ST_L2_7, EV_L2_DL_DATA, l2_feed_i_pull},
+	{ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue},
+	{ST_L2_1, EV_L2_DL_UNITDATA, l2_queue_ui_assign},
+	{ST_L2_2, EV_L2_DL_UNITDATA, l2_queue_ui},
+	{ST_L2_3, EV_L2_DL_UNITDATA, l2_queue_ui},
+	{ST_L2_4, EV_L2_DL_UNITDATA, l2_send_ui},
+	{ST_L2_5, EV_L2_DL_UNITDATA, l2_send_ui},
+	{ST_L2_6, EV_L2_DL_UNITDATA, l2_send_ui},
+	{ST_L2_7, EV_L2_DL_UNITDATA, l2_send_ui},
+	{ST_L2_8, EV_L2_DL_UNITDATA, l2_send_ui},
+	{ST_L2_1, EV_L2_MDL_ASSIGN, l2_got_tei},
+	{ST_L2_2, EV_L2_MDL_ASSIGN, l2_got_tei},
+	{ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei},
+	{ST_L2_2, EV_L2_MDL_ERROR, l2_st24_tei_remove},
+	{ST_L2_3, EV_L2_MDL_ERROR, l2_st3_tei_remove},
+	{ST_L2_4, EV_L2_MDL_REMOVE, l2_st24_tei_remove},
+	{ST_L2_5, EV_L2_MDL_REMOVE, l2_st5_tei_remove},
+	{ST_L2_6, EV_L2_MDL_REMOVE, l2_st6_tei_remove},
+	{ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove},
+	{ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove},
+	{ST_L2_4, EV_L2_SABME, l2_start_multi},
+	{ST_L2_5, EV_L2_SABME, l2_send_UA},
+	{ST_L2_6, EV_L2_SABME, l2_send_DM},
+	{ST_L2_7, EV_L2_SABME, l2_restart_multi},
+	{ST_L2_8, EV_L2_SABME, l2_restart_multi},
+	{ST_L2_4, EV_L2_DISC, l2_send_DM},
+	{ST_L2_5, EV_L2_DISC, l2_send_DM},
+	{ST_L2_6, EV_L2_DISC, l2_send_UA},
+	{ST_L2_7, EV_L2_DISC, l2_stop_multi},
+	{ST_L2_8, EV_L2_DISC, l2_stop_multi},
+	{ST_L2_4, EV_L2_UA, l2_mdl_error_ua},
+	{ST_L2_5, EV_L2_UA, l2_connected},
+	{ST_L2_6, EV_L2_UA, l2_released},
+	{ST_L2_7, EV_L2_UA, l2_mdl_error_ua},
+	{ST_L2_8, EV_L2_UA, l2_mdl_error_ua},
+	{ST_L2_4, EV_L2_DM, l2_reestablish},
+	{ST_L2_5, EV_L2_DM, l2_st5_dm_release},
+	{ST_L2_6, EV_L2_DM, l2_st6_dm_release},
+	{ST_L2_7, EV_L2_DM, l2_mdl_error_dm},
+	{ST_L2_8, EV_L2_DM, l2_st8_mdl_error_dm},
+	{ST_L2_1, EV_L2_UI, l2_got_ui},
+	{ST_L2_2, EV_L2_UI, l2_got_ui},
+	{ST_L2_3, EV_L2_UI, l2_got_ui},
+	{ST_L2_4, EV_L2_UI, l2_got_ui},
+	{ST_L2_5, EV_L2_UI, l2_got_ui},
+	{ST_L2_6, EV_L2_UI, l2_got_ui},
+	{ST_L2_7, EV_L2_UI, l2_got_ui},
+	{ST_L2_8, EV_L2_UI, l2_got_ui},
+	{ST_L2_7, EV_L2_FRMR, l2_got_FRMR},
+	{ST_L2_8, EV_L2_FRMR, l2_got_FRMR},
+	{ST_L2_7, EV_L2_SUPER, l2_st7_got_super},
+	{ST_L2_8, EV_L2_SUPER, l2_st8_got_super},
+	{ST_L2_7, EV_L2_I, l2_got_iframe},
+	{ST_L2_8, EV_L2_I, l2_got_iframe},
+	{ST_L2_5, EV_L2_T200, l2_st5_tout_200},
+	{ST_L2_6, EV_L2_T200, l2_st6_tout_200},
+	{ST_L2_7, EV_L2_T200, l2_st7_tout_200},
+	{ST_L2_8, EV_L2_T200, l2_st8_tout_200},
+	{ST_L2_7, EV_L2_T203, l2_st7_tout_203},
+	{ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue},
+	{ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
+	{ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
+	{ST_L2_7, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy},
+	{ST_L2_8, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy},
+	{ST_L2_4, EV_L2_FRAME_ERROR, l2_frame_error},
+	{ST_L2_5, EV_L2_FRAME_ERROR, l2_frame_error},
+	{ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error},
+	{ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest},
+	{ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest},
+	{ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistant_da},
+	{ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove},
+	{ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove},
+	{ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistant_da},
+	{ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistant_da},
+	{ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistant_da},
+	{ST_L2_7, EV_L1_DEACTIVATE, l2_persistant_da},
+	{ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da},
+};
+
+#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode))
+
+static layer2_t *
+select_l2(net_stack_t *nst, int sapi, int tei) {
+	layer2_t	*l2;
+
+	l2 = nst->layer2;
+	while (l2) {
+		if ((l2->sapi == sapi) && (l2->tei == tei))
+			break;
+		l2 = l2->next;
+	}
+	return(l2);
+}
+
+static int
+ph_data_mux(net_stack_t *nst, iframe_t *frm, msg_t *msg)
+{
+	u_char		*datap;
+	layer2_t	*l2;
+	int		ret = -EINVAL;
+	int		psapi, ptei;
+	mISDNuser_head_t	*hh;
+	int		c = 0;
+
+	datap = msg_pull(msg, mISDN_HEADER_LEN);
+	if (msg->len <= 2) {
+		dprint(DBGM_L2, nst->cardnr, "%s: msg (%d) too short\n", __FUNCTION__,
+			msg->len);
+		msg_push(msg, mISDN_HEADER_LEN);
+		return(ret);
+	}
+	psapi = *datap++;
+	ptei = *datap++;
+	if ((psapi & 1) || !(ptei & 1)) {
+		dprint(DBGM_L2, nst->cardnr, "l2 D-channel frame wrong EA0/EA1\n");
+		msg_push(msg, mISDN_HEADER_LEN);
+		return(ret);
+	}
+	psapi >>= 2;
+	ptei >>= 1;
+	dprint(DBGM_L2, nst->cardnr, "%s: sapi(%d) tei(%d)\n", __FUNCTION__, psapi, ptei);
+	if (ptei == GROUP_TEI) {
+		if (psapi == TEI_SAPI) {
+			hh = (mISDNuser_head_t *)msg_push(msg, mISDNUSER_HEAD_SIZE);
+			hh->prim = MDL_UNITDATA | INDICATION;
+			if (nst->feature & FEATURE_NET_PTP) {
+				dprint(DBGM_L2, nst->cardnr, "%s: tei management not enabled for PTP\n", __FUNCTION__);
+				return(-EINVAL);
+			}
+			return(tei_mux(nst, msg));
+		} else {
+			dprint(DBGM_L2, nst->cardnr, "%s: unknown tei(%d) msg\n", __FUNCTION__,
+				ptei);
+		}
+	}
+	l2 = select_l2(nst, psapi, ptei);
+	if (!l2) {
+		dprint(DBGM_L2, nst->cardnr, "%s: no l2 for sapi(%d) tei(%d)\n", __FUNCTION__,
+			psapi, ptei);
+		return(-ENXIO);
+	}
+	if (!(*datap & 1)) {	/* I-Frame */
+		if(!(c = iframe_error(l2, msg)))
+			ret = FsmEvent(&l2->l2m, EV_L2_I, msg);
+	} else if (IsSFrame(datap, l2)) {	/* S-Frame */
+		if(!(c = super_error(l2, msg)))
+			ret = FsmEvent(&l2->l2m, EV_L2_SUPER, msg);
+	} else if (IsUI(datap,l2)) {
+		if(!(c = UI_error(l2, msg)))
+			ret = FsmEvent(&l2->l2m, EV_L2_UI, msg);
+	} else if (IsSABME(datap, l2)) {
+		if(!(c = unnum_error(l2, msg, CMD)))
+			ret = FsmEvent(&l2->l2m, EV_L2_SABME, msg);
+	} else if (IsUA(datap,l2)) {
+		if(!(c = unnum_error(l2, msg, RSP)))
+			ret = FsmEvent(&l2->l2m, EV_L2_UA, msg);
+	} else if (IsDISC(datap,l2)) {
+		if(!(c = unnum_error(l2, msg, CMD)))
+			ret = FsmEvent(&l2->l2m, EV_L2_DISC, msg);
+	} else if (IsDM(datap,l2)) {
+		if(!(c = unnum_error(l2, msg, RSP)))
+			ret = FsmEvent(&l2->l2m, EV_L2_DM, msg);
+	} else if (IsFRMR(datap,l2)) {
+		if(!(c = FRMR_error(l2, msg)))
+			ret = FsmEvent(&l2->l2m, EV_L2_FRMR, msg);
+	} else {
+		c = 'L';
+	}
+	if (c) {
+		dprint(DBGM_L2, l2->nst->cardnr, "l2 D-channel frame error %c\n",c);
+		FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *)(long)c);
+	}
+	if (ret)
+		free_msg(msg);
+	return(0);
+}
+
+int
+msg_mux(net_stack_t *nst, iframe_t *frm, msg_t *msg)
+{
+	layer2_t	*l2;
+	int		ret = -EINVAL;
+	msg_t		*nmsg;
+
+	dprint(DBGM_L2, nst->cardnr, "%s: msg len(%d)\n", __FUNCTION__, msg->len);
+	dprint(DBGM_L2, nst->cardnr, "%s: adr(%x) pr(%x) di(%x) len(%d)\n", __FUNCTION__,
+		frm->addr, frm->prim, frm->dinfo, frm->len);
+	l2 = nst->layer2;
+	while(l2) {
+		if (frm->prim == (PH_CONTROL | INDICATION)) {
+			if (frm->dinfo == HW_D_BLOCKED)
+				test_and_set_bit(FLG_DCHAN_BUSY, &l2->flag);
+			else if (frm->dinfo == HW_D_NOBLOCKED)
+				test_and_clear_bit(FLG_DCHAN_BUSY, &l2->flag);
+			l2 = l2->next;
+			continue;
+		}
+		if (l2->next) {
+			nmsg = msg_copy(msg);
+		} else
+			nmsg = msg;
+		ret = -EINVAL;
+		switch (frm->prim) {
+			case (PH_ACTIVATE | CONFIRM):
+			case (PH_ACTIVATE | INDICATION):
+				test_and_set_bit(FLG_L1_ACTIV, &l2->flag);
+				if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag))
+					ret = FsmEvent(&l2->l2m,
+						EV_L2_DL_ESTABLISH_REQ, nmsg);
+				break;
+			case (PH_DEACTIVATE | INDICATION):
+			case (PH_DEACTIVATE | CONFIRM):
+				test_and_clear_bit(FLG_L1_ACTIV, &l2->flag);
+				ret = FsmEvent(&l2->l2m, EV_L1_DEACTIVATE, nmsg);
+				break;
+			default:
+				l2m_debug(&l2->l2m, "l2 unknown pr %x", frm->prim);
+				break;
+		}
+		if (ret)
+			free_msg(nmsg);
+		ret = 0;
+		l2 = l2->next;
+	}
+	if (ret)
+		free_msg(msg);
+	return(0);
+}
+
+int
+l2muxer(net_stack_t *nst, msg_t *msg)
+{
+	iframe_t	*frm;
+	int		ret = -EINVAL;
+
+	frm = (iframe_t *)msg->data;
+	switch(frm->prim) {
+		case (PH_DATA_IND):
+			ret = ph_data_mux(nst, frm, msg);
+			break;
+		case (PH_DATA | CONFIRM):
+			ret = phd_conf(nst, frm, msg);
+			break;
+		case (PH_ACTIVATE | CONFIRM):
+		case (PH_ACTIVATE | INDICATION):
+		case (PH_CONTROL | INDICATION):
+		case (PH_DEACTIVATE | INDICATION):
+		case (PH_DEACTIVATE | CONFIRM):
+			ret = msg_mux(nst, frm, msg);
+			break;
+		default:
+			dprint(DBGM_L2, nst->cardnr, "%s: pr %x\n", __FUNCTION__, frm->prim);
+			break;
+	}
+	return(ret);
+}
+
+static int
+l2from_up(net_stack_t *nst, msg_t *msg) {
+	layer2_t	*l2;
+	mISDNuser_head_t	*hh;
+	int		ret = -EINVAL;
+
+	if (!msg)
+		return(ret);
+	hh = (mISDNuser_head_t *)msg->data;
+	if (msg->len < mISDN_FRAME_MIN)
+		return(ret);
+	dprint(DBGM_L2, nst->cardnr, "%s: prim(%x) dinfo(%x)\n", __FUNCTION__,
+		hh->prim, hh->dinfo);
+	l2 = select_l2(nst, SAPITEI(hh->dinfo));
+	if (!l2) {
+		dprint(DBGM_L2, nst->cardnr, "%s: no l2 for sapi(%d) tei(%d)\n", __FUNCTION__,
+			SAPITEI(hh->dinfo));
+		return(-ENXIO);
+	}
+	switch (hh->prim) {
+		case (DL_DATA | REQUEST):
+			ret = FsmEvent(&l2->l2m, EV_L2_DL_DATA, msg);
+			break;
+		case (DL_UNITDATA | REQUEST):
+			ret = FsmEvent(&l2->l2m, EV_L2_DL_UNITDATA, msg);
+			break;
+		case (DL_ESTABLISH | REQUEST):
+			if (test_bit(FLG_L1_ACTIV, &l2->flag)) {
+				if (test_bit(FLG_LAPD, &l2->flag) ||
+					test_bit(FLG_ORIG, &l2->flag)) {
+					ret = FsmEvent(&l2->l2m,
+						EV_L2_DL_ESTABLISH_REQ, msg);
+				}
+			} else {
+				if (test_bit(FLG_LAPD, &l2->flag) ||
+					test_bit(FLG_ORIG, &l2->flag)) {
+					test_and_set_bit(FLG_ESTAB_PEND,
+						&l2->flag);
+				}
+				ret = l2down(l2, PH_ACTIVATE | REQUEST, 0, msg);
+			}
+			break;
+		case (DL_RELEASE | REQUEST):
+			if (test_bit(FLG_LAPB, &l2->flag))
+				l2down_create(l2, PH_DEACTIVATE | REQUEST,
+					0, 0, NULL);
+			ret = FsmEvent(&l2->l2m, EV_L2_DL_RELEASE_REQ, msg);
+			break;
+		case (MDL_ASSIGN | REQUEST):
+			ret = FsmEvent(&l2->l2m, EV_L2_MDL_ASSIGN, msg);
+			break;
+		case (MDL_REMOVE | REQUEST):
+			ret = FsmEvent(&l2->l2m, EV_L2_MDL_REMOVE, msg);
+			break;
+		case (MDL_ERROR | RESPONSE):
+			ret = FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, msg);
+		case (MDL_STATUS | REQUEST):
+			l2up_create(l2, MDL_STATUS | CONFIRM, hh->dinfo, 1,
+				(void *)l2->tei);
+			break;
+		default:
+			l2m_debug(&l2->l2m, "l2 unknown pr %04x", hh->prim);
+	}
+	return(ret);
+}
+
+int
+tei_l2(layer2_t *l2, msg_t *msg)
+{
+	mISDNuser_head_t	*hh = (mISDNuser_head_t *)msg->data;
+	int		ret = -EINVAL;
+
+	if (!l2 || !msg)
+		return(ret);
+	dprint(DBGM_L2, l2->nst->cardnr, "%s: prim(%x)\n", __FUNCTION__, hh->prim);
+	if (msg->len < mISDN_FRAME_MIN)
+		return(ret);
+	switch(hh->prim) {
+	    case (MDL_UNITDATA | REQUEST):
+		ret = l2down(l2, PH_DATA_REQ, hh->dinfo, msg);
+		break;
+	    case (MDL_ASSIGN | REQUEST):
+		ret = FsmEvent(&l2->l2m, EV_L2_MDL_ASSIGN, msg);
+		break;
+	    case (MDL_REMOVE | REQUEST):
+		ret = FsmEvent(&l2->l2m, EV_L2_MDL_REMOVE, msg);
+		break;
+	    case (MDL_ERROR | RESPONSE):
+		ret = FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, msg);
+		break;
+	    case (MDL_FINDTEI | REQUEST):
+	    	ret = l2down_msg(l2, msg);
+		break;
+	}
+	return(ret);
+}
+
+static void
+l2m_debug(struct FsmInst *fi, char *fmt, ...)
+{
+	char	tbuf[128];
+	va_list args;
+
+	va_start(args, fmt);
+	vsprintf(tbuf, fmt, args);
+	dprint(DBGM_L2, fi->nst->cardnr, "L2 %s\n", tbuf);
+	va_end(args);
+}
+
+static void
+release_l2(layer2_t *l2)
+{
+	dprint(DBGM_L2, l2->nst->cardnr, "%s: sapi(%d) tei(%d) state(%d)\n", __FUNCTION__,
+		l2->sapi, l2->tei, l2->l2m.state);
+	FsmRemoveTimer(&l2->t200);
+	FsmRemoveTimer(&l2->t203);
+	msg_queue_purge(&l2->i_queue);
+	msg_queue_purge(&l2->ui_queue);
+	ReleaseWin(l2);
+	if (test_bit(FLG_LAPD, &l2->flag))
+		release_tei(l2->tm);
+	REMOVE_FROM_LISTBASE(l2, l2->nst->layer2);
+	free(l2);
+}
+
+#warning testing
+int
+tei0_active(layer2_t *l2)
+{
+	while(l2) {
+		dprint(DBGM_L2, l2->nst->cardnr, "checking l2 with tei=%d, sapi=%d\n", l2->tei, l2->sapi);
+		if (l2->tei == 0 && l2->sapi == 0)
+			break;
+		l2 = l2->next;
+	}
+	if (!l2)
+		return(0);
+	dprint(DBGM_L2, l2->nst->cardnr, "checking l2 with state=%d\n", l2->l2m.state);
+	if (l2->l2m.state >= ST_L2_7)
+		return(1);
+	return(0);
+
+}
+
+layer2_t *
+new_dl2(net_stack_t *nst, int tei) {
+	layer2_t *nl2;
+
+	if (!(nl2 = malloc(sizeof(layer2_t)))) {
+		dprint(DBGM_L2, nst->cardnr, "malloc layer2 failed\n");
+		return(NULL);
+	}
+	memset(nl2, 0, sizeof(layer2_t));
+	nl2->nst = nst;
+	nl2->debug = debug;
+	test_and_set_bit(FLG_LAPD, &nl2->flag);
+	test_and_set_bit(FLG_LAPD_NET, &nl2->flag);
+	test_and_set_bit(FLG_FIXED_TEI, &nl2->flag);
+	test_and_set_bit(FLG_MOD128, &nl2->flag);
+	nl2->sapi = 0;
+	nl2->tei = tei;
+	nl2->maxlen = MAX_DFRAME_LEN;
+	nl2->window = 1;
+	nl2->T200 = 1000;
+	nl2->N200 = 3;
+	nl2->T203 = 10000;
+	if (create_teimgr(nl2)) {
+		free(nl2);
+		return(NULL);
+	}
+	msg_queue_init(&nl2->i_queue);
+	msg_queue_init(&nl2->ui_queue);
+	InitWin(nl2);
+	nl2->l2m.fsm = nst->l2fsm;
+	nl2->l2m.state = ST_L2_4;
+	nl2->l2m.debug = debug;
+	nl2->l2m.nst = nl2->nst;
+	nl2->l2m.userdata = nl2;
+	nl2->l2m.userint = 0;
+	nl2->l2m.printdebug = l2m_debug;
+	FsmInitTimer(&nl2->l2m, &nl2->t200);
+	FsmInitTimer(&nl2->l2m, &nl2->t203);
+	APPEND_TO_LIST(nl2, nst->layer2);
+	return(nl2);
+}
+
+int Isdnl2Init(net_stack_t *nst)
+{
+	layer2_t	*l2;
+	msg_t		*msg;
+	struct		Fsm *l2f;
+
+	if (!(l2f = malloc(sizeof(struct Fsm))))
+		return(-ENOMEM);
+	nst->l2fsm = l2f;
+	memset(l2f, 0, sizeof(struct Fsm));
+	l2f->state_count = L2_STATE_COUNT;
+	l2f->event_count = L2_EVENT_COUNT;
+	l2f->strEvent = strL2Event;
+	l2f->strState = strL2State;
+	FsmNew(l2f, L2FnList, L2_FN_COUNT);
+	TEIInit(nst);
+	nst->l1_l2 = l2muxer;
+	nst->l3_l2 = l2from_up;
+	l2 = new_dl2(nst, 127);
+	if (!l2) {
+		dprint(DBGM_L2, l2->nst->cardnr, "%s: failed to create L2-instance with TEI 127\n", __FUNCTION__);
+		cleanup:
+		cleanup_Isdnl2(nst);
+		return(-ENOMEM);
+	}
+	l2 = new_dl2(nst, 0);
+	if (!l2) {
+		dprint(DBGM_L2, l2->nst->cardnr, "%s: failed to create L2-instance with TEI 0\n", __FUNCTION__);
+		goto cleanup;
+	}
+	if (!(nst->feature & FEATURE_NET_PTP)) {
+		if ((msg = create_link_msg(MDL_REMOVE | INDICATION, 127,
+			0, NULL, 0))) {
+			if (l2_tei(l2->tm, msg))
+				free_msg(msg);
+		}
+	}
+	return(0);
+}
+
+void cleanup_Isdnl2(net_stack_t *nst)
+{
+	if(nst->layer2) {
+		dprint(DBGM_L2, nst->cardnr, "%s: l2 list not empty\n", __FUNCTION__);
+		while(nst->layer2)
+			release_l2(nst->layer2);
+	}
+	TEIFree(nst);
+	FsmFree(nst->l2fsm);
+	free(nst->l2fsm);
+}

Added: misdn-user/trunk/i4lnet/net_l2.h
===================================================================
--- misdn-user/trunk/i4lnet/net_l2.h	                        (rev 0)
+++ misdn-user/trunk/i4lnet/net_l2.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,147 @@
+/* $Id: net_l2.h,v 1.3 2006/03/06 13:08:28 keil Exp $
+ *
+ * Layer 2 defines
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+#ifndef NET_L2_H
+#define NET_L2_H
+
+#include "mISDNlib.h"
+#include "isdn_net.h"
+#include "fsm.h"
+#ifdef MEMDBG
+#include "memdbg.h"
+#endif
+
+#define DINFO_SKB       -1
+
+#define MAX_WINDOW	8
+
+typedef struct _teimgr {
+	int		ri;
+	struct FsmInst	tei_m;
+	struct FsmTimer	t201;
+	int		T201;
+	int		debug;
+	int		val;
+	struct _layer2	*l2;
+} teimgr_t;
+
+struct _layer2 {
+	struct _layer2	*prev;
+	struct _layer2	*next;
+	int		sapi;
+	int		tei;
+	laddr_t		addr;
+	int		maxlen;
+	teimgr_t	*tm;
+	u_long		flag;
+	u_int		vs, va, vr;
+	int		rc;
+	u_int		window;
+	u_int		sow;
+	struct FsmInst	l2m;
+	struct FsmTimer	t200, t203;
+	int		T200, N200, T203;
+	int		debug;
+	msg_t	*windowar[MAX_WINDOW];
+	net_stack_t	*nst;
+	msg_queue_t i_queue;
+	msg_queue_t ui_queue;
+};
+
+#define SAPITEI(ces)	(ces>>8)&0xff, ces&0xff
+
+static inline int CES(layer2_t *l2) {
+	return(l2->tei | (l2->sapi << 8));
+}
+
+/* from mISDN_l2.c */
+extern int	tei0_active(layer2_t *l2);
+extern layer2_t	*new_dl2(net_stack_t *nst, int tei);
+extern int	tei_l2(layer2_t *l2, msg_t *msg);
+extern int	Isdnl2Init(net_stack_t *nst);
+extern void	cleanup_Isdnl2(net_stack_t *nst);
+
+
+/* from tei.c */
+extern int tei_mux(net_stack_t *nst, msg_t *msg);
+extern int l2_tei(teimgr_t *tm, msg_t *msg);
+extern int create_teimgr(layer2_t *l2);
+extern void release_tei(teimgr_t *tm);
+extern int TEIInit(net_stack_t *nst);
+extern void TEIFree(net_stack_t *nst);
+
+#define GROUP_TEI	127
+#define TEI_SAPI	63
+#define CTRL_SAPI	0
+
+#define RR	0x01
+#define RNR	0x05
+#define REJ	0x09
+#define SABME	0x6f
+#define SABM	0x2f
+#define DM	0x0f
+#define UI	0x03
+#define DISC	0x43
+#define UA	0x63
+#define FRMR	0x87
+#define XID	0xaf
+
+#define CMD	0
+#define RSP	1
+
+#define LC_FLUSH_WAIT 1
+
+#define FLG_LAPB	0
+#define FLG_LAPD	1
+#define FLG_ORIG	2
+#define FLG_MOD128	3
+#define FLG_PEND_REL	4
+#define FLG_L3_INIT	5
+#define FLG_T200_RUN	6
+#define FLG_ACK_PEND	7
+#define FLG_REJEXC	8
+#define FLG_OWN_BUSY	9
+#define FLG_PEER_BUSY	10
+#define FLG_DCHAN_BUSY	11
+#define FLG_L1_ACTIV	12
+#define FLG_ESTAB_PEND	13
+#define FLG_PTP		14
+#define FLG_FIXED_TEI	15
+#define FLG_L2BLOCK	16
+#define FLG_L1_BUSY	17
+#define FLG_LAPD_NET	18
+#define FLG_TEI_T201_1	19
+
+
+/* Simple replacement for the NON-ATOMIC routines which asm/bitops.h
+   was providing. */
+static inline int test_bit(int bit, unsigned long *word)
+{
+	return !!((*word) & (1<<bit));
+}
+static inline int test_and_clear_bit(int bit, unsigned long *word)
+{
+	int ret = !!((*word) & (1<<bit));
+	*word &= ~(1<<bit);
+	return ret;
+}
+static inline int test_and_set_bit(int bit, unsigned long *word)
+{
+	int ret = !!((*word) & (1<<bit));
+	*word |= 1<<bit;
+	return ret;
+}
+static inline void clear_bit(int bit, unsigned long *word)
+{
+	*word &= ~(1<<bit);
+}	
+static inline void set_bit(int bit, unsigned long *word)
+{
+	*word |= 1<<bit;
+}	
+#endif

Added: misdn-user/trunk/i4lnet/net_l3.c
===================================================================
--- misdn-user/trunk/i4lnet/net_l3.c	                        (rev 0)
+++ misdn-user/trunk/i4lnet/net_l3.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,3034 @@
+/* $Id: net_l3.c,v 1.15 2006/12/28 12:24:01 jolly Exp $
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ *		This file is (c) under GNU PUBLIC LICENSE
+ *		For changes and modifications please read
+ *		../../../Documentation/isdn/mISDN.cert
+ *
+ */
+
+#include <stdlib.h>
+#include "mISDNlib.h"
+#include "net_l2.h"
+#include "net_l3.h"
+#include "l3dss1.h"
+#include "helper.h"
+// #include "debug.h"
+
+const char *l3_revision = "$Revision: 1.15 $";
+
+#define PROTO_DIS_EURO	8
+
+#define L3_DEB_WARN	1
+#define L3_DEB_PROTERR	2
+#define	L3_DEB_STATE	4
+#define L3_DEB_PROC	8
+#define L3_DEB_CHECK	16
+
+enum {
+	ST_L3_LC_REL,
+	ST_L3_LC_ESTAB_WAIT,
+	ST_L3_LC_REL_DELAY, 
+	ST_L3_LC_REL_WAIT,
+	ST_L3_LC_ESTAB,
+};
+
+enum {
+	IMSG_END_PROC,
+	IMSG_END_PROC_M,
+	IMSG_L2_DATA,
+	IMSG_L4_DATA,
+	IMSG_TIMER_EXPIRED,
+	IMSG_MASTER_L2_DATA,
+	IMSG_PROCEEDING_IND,
+	IMSG_ALERTING_IND,
+	IMSG_CONNECT_IND,
+	IMSG_SEL_PROC,
+	IMSG_RELEASE_CHILDS,
+};
+
+static int send_proc(layer3_proc_t *proc, int op, void *arg);
+static int l3_msg(layer3_t *l3, u_int pr, int dinfo, void *arg);
+static int mISDN_l3up(layer3_proc_t *, msg_t *);
+static int l3down(layer3_t *l3, u_int prim, int dinfo, msg_t *msg);
+
+struct _l3_msg {
+	int	mt;
+	msg_t	*msg;
+};
+
+struct stateentry {
+	int state;
+	int primitive;
+	void (*rout) (layer3_proc_t *, int, void *);
+};
+
+#define SBIT(state)	(1<<state)
+#define ALL_STATES	0x03ffffff
+
+void
+display_NR_IE(u_char *p, char *head1, char *head2)
+{
+	int len;
+	char	txt[128];
+	char	*tp = txt;
+
+	len = *p++;
+	tp += sprintf(tp, "len(%d)", len);
+	if (len) {
+		len--;
+		tp += sprintf(tp, " plan(%x)", *p);
+		if (len && !(*p & 0x80)) {
+			len--;
+			p++;
+			tp += sprintf(tp, " pres(%x)", *p);
+		}
+		p++;
+		tp += sprintf(tp, " ");
+		while(len--)
+			tp += sprintf(tp, "%c", *p++);
+	}
+	dprint(DBGM_L3, -1, "%s%s %s\n", head1, head2, txt);
+}
+
+static void
+l3_debug(layer3_t *l3, char *fmt, ...)
+{
+	va_list args;
+	char buf[256], *p;
+
+	va_start(args, fmt);
+	p = buf;
+	p += sprintf(p, "l3 ");
+	p += vsprintf(p, fmt, args);
+	va_end(args);
+	dprint(DBGM_L3, l3->nst->cardnr, "%s\n", buf);
+}
+
+static int
+getcallref(u_char *p)
+{
+	int l, cr = 0;
+
+	p++;			/* prot discr */
+	l = 0xf & *p++;		/* callref length */
+	if (l > 2)		/* wrong callref only 1 or 2 octet*/
+		return(-2);
+	if (!l)			/* dummy CallRef */
+		return(-1);
+	if (l == 1) {		/* BRI */
+		cr = *p & 0x7f;
+		cr += (*p & 0x80) << 8;
+	} else {		/* PRI */
+		cr = *p++ << 8;
+		cr += *p;
+	}
+
+	return (cr);
+}
+                                                                                        
+void
+newl3state(layer3_proc_t *pc, int state)
+{
+	if (pc->l3 && pc->l3->debug & L3_DEB_STATE)
+		l3_debug(pc->l3, "newstate cr %d %d%s --> %d%s", 
+			 pc->callref & 0x7FFF,
+			 pc->state, pc->master ? "i" : "",
+			 state, pc->master ? "i" : "");
+	pc->state = state;
+}
+
+static void
+L3ExpireTimer(L3Timer_t *t)
+{
+	if (t->pc->l3->debug & L3_DEB_STATE)
+		l3_debug(t->pc->l3, "timer %p nr %x expired", t, t->nr);
+	send_proc(t->pc, IMSG_TIMER_EXPIRED, &t->nr);
+}
+
+void
+L3InitTimer(layer3_proc_t *pc, L3Timer_t *t)
+{
+	t->pc = pc;
+	t->tl.function = (void *) L3ExpireTimer;
+	t->tl.data = (long) t;
+	init_timer(&t->tl, pc->l3->nst);
+}
+
+void
+L3DelTimer(L3Timer_t *t)
+{
+	del_timer(&t->tl);
+}
+
+int
+L3AddTimer(L3Timer_t *t, int millisec, int timer_nr)
+{
+	if (timer_pending(&t->tl)) {
+		if (t->pc && t->pc->l3)
+			dprint(DBGM_L3, t->pc->l3->nst->cardnr, "L3AddTimer: timer already active!\n");
+		else
+			dprint(DBGM_L3, 0, "L3AddTimer: timer already active!\n");
+			
+		return -1;
+	}
+	init_timer(&t->tl, t->pc->l3->nst);
+	t->nr = timer_nr;
+	t->tl.expires = millisec;
+	add_timer(&t->tl);
+	return 0;
+}
+
+void
+StopAllL3Timer(layer3_proc_t *pc)
+{
+	L3DelTimer(&pc->timer1);
+	L3DelTimer(&pc->timer2);
+		
+	dprint(DBGM_L3, pc->l3->nst->cardnr, "%s: pc=%p del timer2\n", __FUNCTION__, pc);
+#warning also remove flags:
+	test_and_clear_bit(FLG_L3P_TIMER303_1, &pc->Flags);
+	test_and_clear_bit(FLG_L3P_TIMER308_1, &pc->Flags);
+	test_and_clear_bit(FLG_L3P_TIMER312, &pc->Flags);
+}
+
+void
+RemoveAllL3Timer(layer3_proc_t *pc)
+{
+	int ret;
+	
+	ret = remove_timer(&pc->timer1.tl);
+	if (ret)
+		dprint(DBGM_L3, pc->l3?pc->l3->nst->cardnr:0, "RemoveL3Timer1: ret %d\n", ret);
+	ret = remove_timer(&pc->timer2.tl);
+	dprint(DBGM_L3, pc->l3->nst->cardnr, "%s: pc=%p del timer2\n", __FUNCTION__, pc);
+	if (ret)
+		dprint(DBGM_L3, pc->l3->nst->cardnr, "RemoveL3Timer2: ret %d\n", ret);
+#warning also remove flags:
+	test_and_clear_bit(FLG_L3P_TIMER303_1, &pc->Flags);
+	test_and_clear_bit(FLG_L3P_TIMER308_1, &pc->Flags);
+	test_and_clear_bit(FLG_L3P_TIMER312, &pc->Flags);
+}
+
+static layer3_proc_t *
+create_proc(layer3_t *l3, int ces, int cr, layer3_proc_t *master)
+{
+	layer3_proc_t	*l3p;
+
+	l3p = malloc(sizeof(layer3_proc_t));
+	if (l3p) {
+		memset(l3p, 0, sizeof(layer3_proc_t));
+		l3p->l3 = l3;
+		l3p->ces = ces;
+		l3p->callref = cr;
+		l3p->master = master;
+		L3InitTimer(l3p, &l3p->timer1);
+		L3InitTimer(l3p, &l3p->timer2);
+		if (master) {
+			APPEND_TO_LIST(l3p, master->child);
+		}
+	}	
+	return(l3p);
+}
+
+static layer3_proc_t *
+find_proc(layer3_proc_t *master, int ces, int cr)
+{
+	layer3_proc_t	*p = master;
+	layer3_proc_t	*cp;
+
+	dprint(DBGM_L3, master?master->l3->nst->cardnr:0, "%s: ces(%x) cr(%x)\n", __FUNCTION__,
+		ces, cr);
+	while(p) {
+		dprint(DBGM_L3, p->l3->nst->cardnr, "%s: proc %p ces(%x) cr(%x)\n", __FUNCTION__,
+			p, p->ces, p->callref);
+		if ((p->ces == ces) && (p->callref == cr))
+			break;
+		if (p->child) {
+			cp = find_proc(p->child, ces, cr);
+			if (cp)
+				return(cp);
+		}
+		if (((p->ces & 0xffffff00) == 0xff00) && (p->callref == cr))
+			break;
+		p = p->next;
+	}
+	return(p);
+}
+
+u_char *
+findie(u_char * p, int size, u_char ie, int wanted_set)
+{
+	int l, codeset, maincodeset;
+	u_char *pend = p + size;
+
+	/* skip protocol discriminator, callref and message type */
+	p++;
+	l = (*p++) & 0xf;
+	p += l;
+	p++;
+	codeset = 0;
+	maincodeset = 0;
+	/* while there are bytes left... */
+	while (p < pend) {
+		if ((*p & 0xf0) == 0x90) {
+			codeset = *p & 0x07;
+			if (!(*p & 0x08))
+				maincodeset = codeset;
+		}
+		if (codeset == wanted_set) {
+			if (*p == ie) {
+				/* improved length check (Werner Cornelius) */
+				if (!(*p & 0x80)) {
+					if ((pend - p) < 2)
+						return(NULL);
+					if (*(p+1) > (pend - (p+2)))
+						return(NULL);
+					p++; /* points to len */
+				}
+				return (p);
+			} else if ((*p > ie) && !(*p & 0x80))
+				return (NULL);
+		}
+		if (!(*p & 0x80)) {
+			p++;
+			l = *p;
+			p += l;
+			codeset = maincodeset;
+		}
+		p++;
+	}
+	return (NULL);
+}
+
+u_char *
+find_and_copy_ie(u_char * p, int size, u_char ie, int wanted_set, msg_t *msg)
+{
+	u_char *iep, *mp;
+	int	l;
+
+	iep = findie(p, size, ie, wanted_set);
+	if (iep) {
+		l = 1;
+		if (!(ie & 0x80))
+			l += *iep;
+		mp = msg_put(msg, l);
+		memcpy(mp, iep, l);
+		iep = mp;
+	}
+	return(iep);
+}
+
+static void MsgStart(layer3_proc_t *pc, u_char mt) {
+	pc->op = &pc->obuf[0];
+	*pc->op++ = 8;
+	if (pc->callref == -1) { /* dummy cr */
+		*pc->op++ = 0;
+	} else {
+		if (pc->l3->nst->feature & FEATURE_NET_CRLEN2) {
+			*pc->op++ = 2;
+			*pc->op++ = (pc->callref >> 8) ^ 0x80;
+			*pc->op++ = pc->callref & 0xff;
+		} else {
+			*pc->op++ = 1;
+			*pc->op = pc->callref & 0x7f;
+			if (!(pc->callref & 0x8000))
+				*pc->op |= 0x80;
+			pc->op++;
+		}
+	}
+	*pc->op++ = mt;
+}
+
+static void AddvarIE(layer3_proc_t *pc, u_char ie, u_char *iep) {
+	u_char len = *iep;
+
+	*pc->op++ = ie;
+	*pc->op++ = *iep++;
+	while(len--)
+		*pc->op++ = *iep++;	
+}
+
+static int SendMsg(layer3_proc_t *pc, int state) {
+	int l;
+	int ret;
+	msg_t *msg;
+
+	l = pc->op - &pc->obuf[0];
+	if (!(msg = l3_alloc_msg(l)))
+		return(-ENOMEM);
+	memcpy(msg_put(msg, l), &pc->obuf[0], l);
+	dhexprint(DBGM_L3DATA, "l3 oframe:", &pc->obuf[0], l);
+	if (state != -1)
+		newl3state(pc, state);
+	if ((ret = l3_msg(pc->l3, DL_DATA | REQUEST, pc->ces, msg)))
+		free_msg(msg);
+	return(ret);
+}
+
+static int
+l3dss1_message(layer3_proc_t *pc, u_char mt)
+{
+	msg_t *msg;
+	u_char *p;
+	int ret;
+	int crlen = 1;
+
+	if (pc->l3->nst->feature & FEATURE_NET_CRLEN2)
+		crlen = 2;
+
+	if (!(msg = l3_alloc_msg(crlen+3)))
+		return(-ENOMEM);
+	p = msg_put(msg, crlen+3);
+	*p++ = 8;
+	*p++ = crlen;
+	if (crlen == 2) {
+		*p++ = (pc->callref >> 8) ^ 0x80;
+		*p++ = pc->callref & 0xff;
+	} else {
+		*p = pc->callref & 0x7f;
+		if (!(pc->callref & 0x8000))
+			*p |= 0x80;
+		p++;
+	}
+	*p++ = mt;
+	dhexprint(DBGM_L3DATA, "l3 oframe:", msg->data, 4);
+	if ((ret=l3_msg(pc->l3, DL_DATA | REQUEST, pc->ces, msg)))
+		free_msg(msg);
+	return(ret);
+}
+
+static void
+l3dss1_message_cause(layer3_proc_t *pc, u_char mt, u_char cause)
+{
+	MsgStart(pc, mt);
+	if (cause) {
+		*pc->op++ = IE_CAUSE;
+		*pc->op++ = 0x2;
+		*pc->op++ = 0x80 | CAUSE_LOC_PNET_LOCUSER;
+		*pc->op++ = 0x80 | cause;
+	}
+	SendMsg(pc, -1); 
+}
+
+static void
+l3dss1_status_send(layer3_proc_t *pc, u_char cause)
+{
+
+	MsgStart(pc, MT_STATUS);
+	*pc->op++ = IE_CAUSE;
+	*pc->op++ = 2;
+	*pc->op++ = 0x80 | CAUSE_LOC_USER;
+	*pc->op++ = 0x80 | cause;
+
+	*pc->op++ = IE_CALL_STATE;
+	*pc->op++ = 1;
+	*pc->op++ = pc->state & 0x3f;
+	SendMsg(pc, -1); 
+}
+
+static void
+l3dss1_msg_without_setup(layer3_proc_t *pc, u_char cause)
+{
+	/* This routine is called if here was no SETUP made (checks in dss1up and in
+	 * l3dss1_setup) and a RELEASE_COMPLETE have to be sent with an error code
+	 * MT_STATUS_ENQUIRE in the NULL state is handled too
+	 */
+	switch (cause) {
+		case 81:	/* invalid callreference */
+		case 88:	/* incomp destination */
+		case 96:	/* mandory IE missing */
+		case 100:       /* invalid IE contents */
+		case 101:	/* incompatible Callstate */
+			l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, cause);
+			break;
+		default:
+			dprint(DBGM_L3, pc->l3->nst->cardnr, "mISDN l3dss1_msg_without_setup wrong cause %d\n",
+				cause);
+	}
+	send_proc(pc, IMSG_END_PROC, NULL);
+}
+
+#if 0
+static int
+l3dss1_check_messagetype_validity(layer3_proc_t *pc, int mt, void *arg)
+{
+	switch (mt) {
+		case MT_ALERTING:
+		case MT_CALL_PROCEEDING:
+		case MT_CONNECT:
+		case MT_CONNECT_ACKNOWLEDGE:
+		case MT_DISCONNECT:
+		case MT_INFORMATION:
+		case MT_FACILITY:
+		case MT_NOTIFY:
+		case MT_PROGRESS:
+		case MT_RELEASE:
+		case MT_RELEASE_COMPLETE:
+		case MT_SETUP:
+		case MT_SETUP_ACKNOWLEDGE:
+		case MT_RESUME_ACKNOWLEDGE:
+		case MT_RESUME_REJECT:
+		case MT_SUSPEND_ACKNOWLEDGE:
+		case MT_SUSPEND_REJECT:
+		case MT_USER_INFORMATION:
+		case MT_RESTART:
+		case MT_RESTART_ACKNOWLEDGE:
+		case MT_CONGESTION_CONTROL:
+		case MT_STATUS:
+		case MT_STATUS_ENQUIRY:
+		case MT_HOLD:
+		case MT_RETRIEVE:
+		case MT_RESUME: /* RESUME only in user->net */
+		case MT_SUSPEND: /* SUSPEND only in user->net */
+			if (pc->l3->debug & L3_DEB_CHECK)
+				l3_debug(pc->l3, "l3dss1_check_messagetype_validity mt(%x) OK", mt);
+			break;
+		default:
+			if (pc->l3->debug & (L3_DEB_CHECK | L3_DEB_WARN))
+				l3_debug(pc->l3, "l3dss1_check_messagetype_validity mt(%x) fail", mt);
+			l3dss1_status_send(pc, CAUSE_MT_NOTIMPLEMENTED);
+			return(1);
+	}
+	return(0);
+}
+#endif
+
+static void
+l3dss1_std_ie_err(layer3_proc_t *pc, int ret) {
+
+	if (pc->l3->debug & L3_DEB_CHECK)
+		l3_debug(pc->l3, "check_infoelements ret %d", ret);
+	switch(ret) {
+		case 0: 
+			break;
+		case ERR_IE_COMPREHENSION:
+			l3dss1_status_send(pc, CAUSE_MANDATORY_IE_MISS);
+			break;
+		case ERR_IE_UNRECOGNIZED:
+			l3dss1_status_send(pc, CAUSE_IE_NOTIMPLEMENTED);
+			break;
+		case ERR_IE_LENGTH:
+			l3dss1_status_send(pc, CAUSE_INVALID_CONTENTS);
+			break;
+		case ERR_IE_SEQUENCE:
+		default:
+			break;
+	}
+}
+
+static u_char *
+l3dss1_get_channel_id(layer3_proc_t *pc, msg_t *omsg, msg_t *nmsg) {
+	u_char	*sp, *p;
+	int	l;
+
+	if ((sp = p = findie(omsg->data, omsg->len, IE_CHANNEL_ID, 0))) {
+		l = *p++;
+		if (pc->l3->nst->feature & FEATURE_NET_EXTCID) { /* PRI */
+			if (l < 3) {
+				if (pc->l3->debug & L3_DEB_WARN)
+					l3_debug(pc->l3, "wrong chid len %d", *p);
+				pc->err = -2;
+				return (NULL);
+			}
+			if ((*p & 0x60) != 0x20) {
+				if (pc->l3->debug & L3_DEB_WARN)
+					l3_debug(pc->l3, "wrong chid %x (for PRI interface)", *p);
+				pc->err = -3;
+				return (NULL);
+			}
+			p++;
+			if (*p & 0x10) {
+				if (pc->l3->debug & L3_DEB_WARN)
+					l3_debug(pc->l3, "wrong chid %x (channel map not supported)", *p);
+				pc->err = -4;
+				return (NULL);
+			}
+			p++;
+			pc->bc = *p & 0x7f;
+		} else { /* BRI */
+			if (l < 1) {
+				if (pc->l3->debug & L3_DEB_WARN)
+					l3_debug(pc->l3, "wrong chid len %d", *p);
+				pc->err = -2;
+				return (NULL);
+			}
+			if (*p & 0x60) {
+				if (pc->l3->debug & L3_DEB_WARN)
+					l3_debug(pc->l3, "wrong chid %x", *p);
+				pc->err = -3;
+				return (NULL);
+			}
+			pc->bc = *p & 3;
+		}
+		p = sp;
+		sp = msg_put(nmsg, 1 + *p);
+		memcpy(sp, p, 1 + *p);
+	} else
+		pc->err = -1;
+	return(sp);
+}
+
+static u_char *
+l3dss1_get_cause(layer3_proc_t *pc, msg_t *omsg, msg_t *nmsg) {
+	u_char l;
+	u_char *p, *sp;
+
+	if ((sp = p = findie(omsg->data, omsg->len, IE_CAUSE, 0))) {
+		l = *p++;
+		if (l>30) {
+			pc->err = 1;
+			return(NULL);
+		}
+		if (l)
+			l--;
+		else {
+			pc->err = 2;
+			return(NULL);
+		}
+		if (l && !(*p & 0x80)) {
+			l--;
+			p++; /* skip recommendation */
+		}
+		p++;
+		if (l) {
+			if (!(*p & 0x80)) {
+				pc->err = 3;
+				return(NULL);
+			}
+			pc->err = *p & 0x7F;
+		} else {
+			pc->err = 4;
+			return(NULL);
+		}
+		if (nmsg) {
+			p = sp;
+			sp = msg_put(nmsg, 1 + *p);
+			memcpy(sp, p, 1 + *p);
+		}
+	} else
+		pc->err = -1;
+	return(sp);
+}
+
+static void
+l3dss1_status_enq(layer3_proc_t *proc, int pr, void *arg)
+{
+}
+
+static void
+l3dss1_facility(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t		*umsg,*msg = arg;
+	FACILITY_t	*fac;
+
+	umsg = prep_l3data_msg(CC_FACILITY | INDICATION, 
+	pc->callref>0?pc->ces | (pc->callref << 16):-1, 
+	sizeof(FACILITY_t), msg->len, NULL);
+	if (!umsg)
+		return;
+	fac = (FACILITY_t *)(umsg->data + mISDNUSER_HEAD_SIZE);
+	fac->FACILITY =
+		find_and_copy_ie(msg->data, msg->len, IE_FACILITY, 0, umsg);
+	if (mISDN_l3up(pc, umsg))
+		free_msg(umsg);
+}
+
+static void
+l3dss1_userinfo(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t			*umsg,*msg = arg;
+	USER_INFORMATION_t	*ui;
+
+	umsg = prep_l3data_msg(CC_USER_INFORMATION | INDICATION, pc->ces |
+		(pc->callref << 16), sizeof(USER_INFORMATION_t), msg->len, NULL);
+	if (!umsg)
+		return;
+	ui = (USER_INFORMATION_t *)(umsg->data + mISDNUSER_HEAD_SIZE);
+	ui->USER_USER =
+		find_and_copy_ie(msg->data, msg->len, IE_USER_USER, 0, umsg);
+	if (mISDN_l3up(pc, umsg))
+		free_msg(umsg);
+}
+
+static void
+l3dss1_setup(layer3_proc_t *pc, int pr, void *arg)
+{
+	u_char	*p;
+	int	bcfound = 0;
+	msg_t	*umsg,*msg = arg;
+	int	err = 0;
+	SETUP_t	*setup;
+	
+	umsg = prep_l3data_msg(CC_SETUP | INDICATION, pc->ces |
+		(pc->callref << 16), sizeof(SETUP_t), msg->len, NULL);
+	if (!umsg)
+		return;
+	setup = (SETUP_t *)(umsg->data + mISDNUSER_HEAD_SIZE);
+	/*
+	 * Bearer Capabilities
+	 */
+	/* only the first occurence 'll be detected ! */
+	if ((p = setup->BEARER = find_and_copy_ie(msg->data, msg->len,
+		IE_BEARER, 0, umsg))) {
+		if ((p[0] < 2) || (p[0] > 11))
+			err = 1;
+		else {
+			switch (p[1] & 0x7f) {
+				case 0x00: /* Speech */
+				case 0x10: /* 3.1 Khz audio */
+				case 0x08: /* Unrestricted digital information */
+				case 0x09: /* Restricted digital information */
+				case 0x11:
+					/* Unrestr. digital information  with 
+					 * tones/announcements ( or 7 kHz audio
+					 */
+				case 0x18: /* Video */
+					break;
+				default:
+					err = 2;
+					break;
+			}
+			switch (p[2] & 0x7f) {
+				case 0x40: /* packed mode */
+				case 0x10: /* 64 kbit */
+				case 0x11: /* 2*64 kbit */
+				case 0x13: /* 384 kbit */
+				case 0x15: /* 1536 kbit */
+				case 0x17: /* 1920 kbit */
+					break;
+				default:
+					err = 3;
+					break;
+			}
+		}
+		if (err) {
+			if (pc->l3->debug & L3_DEB_WARN)
+				l3_debug(pc->l3, "setup with wrong bearer(l=%d:%x,%x)",
+					p[0], p[1], p[2]);
+			l3dss1_msg_without_setup(pc, CAUSE_INVALID_CONTENTS);
+			free_msg(umsg);
+			return;
+		} 
+	} else {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "setup without bearer capabilities");
+		/* ETS 300-104 1.3.3 */
+		l3dss1_msg_without_setup(pc, CAUSE_MANDATORY_IE_MISS);
+		free_msg(umsg);
+		return;
+	}
+	/*
+	 * Channel Identification
+	 */
+	if ((setup->CHANNEL_ID = l3dss1_get_channel_id(pc, msg, umsg))) {
+		if (pc->bc) {
+			bcfound++;
+		} else {
+			if (pc->l3->debug & L3_DEB_WARN)
+				l3_debug(pc->l3, "setup without bchannel, call waiting");
+			bcfound++;
+		} 
+	} else if (pc->err != -1) {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "setup with wrong chid ret %d", pc->err);
+	}
+	/* Now we are on none mandatory IEs */
+
+	setup->COMPLETE =
+		find_and_copy_ie(msg->data, msg->len, IE_COMPLETE, 0, umsg);
+	setup->FACILITY =
+		find_and_copy_ie(msg->data, msg->len, IE_FACILITY, 0, umsg);
+	setup->PROGRESS =
+		find_and_copy_ie(msg->data, msg->len, IE_PROGRESS, 0, umsg);
+	setup->NET_FAC =
+		find_and_copy_ie(msg->data, msg->len, IE_NET_FAC, 0, umsg);
+	setup->KEYPAD =
+		find_and_copy_ie(msg->data, msg->len, IE_KEYPAD, 0, umsg);
+	setup->SIGNAL =
+		find_and_copy_ie(msg->data, msg->len, IE_SIGNAL, 0, umsg);
+	setup->CALLED_PN =
+		find_and_copy_ie(msg->data, msg->len, IE_CALLED_PN, 0, umsg);
+	setup->CALLED_SUB =
+		find_and_copy_ie(msg->data, msg->len, IE_CALLED_SUB, 0, umsg);
+	setup->CALLING_PN =
+		find_and_copy_ie(msg->data, msg->len, IE_CALLING_PN, 0, umsg);
+	setup->CALLING_SUB =
+		find_and_copy_ie(msg->data, msg->len, IE_CALLING_SUB, 0, umsg);
+	setup->REDIR_NR =
+		find_and_copy_ie(msg->data, msg->len, IE_REDIR_NR, 0, umsg);
+	setup->LLC =
+		find_and_copy_ie(msg->data, msg->len, IE_LLC, 0, umsg);
+	setup->HLC =
+		find_and_copy_ie(msg->data, msg->len, IE_HLC, 0, umsg);
+	setup->USER_USER =
+		find_and_copy_ie(msg->data, msg->len, IE_USER_USER, 0, umsg);
+	setup->ces = pc->ces;
+	newl3state(pc, 1);
+	L3DelTimer(&pc->timer2);
+	dprint(DBGM_L3, pc->l3->nst->cardnr, "%s: pc=%p del timer2\n", __FUNCTION__, pc);
+	L3AddTimer(&pc->timer2, T_CTRL, 0x31f);
+	if (err) /* STATUS for none mandatory IE errors after actions are taken */
+		l3dss1_std_ie_err(pc, err);
+	if (mISDN_l3up(pc, umsg))
+		free_msg(umsg);
+}
+
+
+static void
+l3dss1_disconnect(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t		*umsg,*msg = arg;
+	DISCONNECT_t	*disc;
+
+	if (pc->state == 19) {
+	//	printf("We're in State 19, receive disconnect, so we stay here\n");
+		return ;
+	}
+
+
+	umsg = prep_l3data_msg(CC_DISCONNECT | INDICATION, pc->ces |
+		(pc->callref << 16), sizeof(DISCONNECT_t), msg->len, NULL);
+	if (!umsg)
+		return;
+	disc = (DISCONNECT_t *)(umsg->data + mISDNUSER_HEAD_SIZE);
+
+
+	StopAllL3Timer(pc);
+	newl3state(pc, 11);
+
+	if (!(disc->CAUSE = l3dss1_get_cause(pc, msg, umsg))) {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "DISC get_cause ret(%d)", pc->err);
+	} 
+	disc->FACILITY =
+		find_and_copy_ie(msg->data, msg->len, IE_FACILITY, 0, umsg);
+	disc->SIGNAL =
+		find_and_copy_ie(msg->data, msg->len, IE_SIGNAL, 0, umsg);
+	disc->USER_USER =
+		find_and_copy_ie(msg->data, msg->len, IE_USER_USER, 0, umsg);
+	if (mISDN_l3up(pc, umsg))
+		free_msg(umsg);
+}
+
+static void
+l3dss1_disconnect_i(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t		*umsg,*msg = arg;
+	DISCONNECT_t	*disc;
+	u_char		cause = 0;
+
+	umsg = prep_l3data_msg(CC_DISCONNECT | INDICATION, pc->ces |
+		(pc->callref << 16), sizeof(DISCONNECT_t), msg->len, NULL);
+	if (!umsg)
+		return;
+	disc = (DISCONNECT_t *)(umsg->data + mISDNUSER_HEAD_SIZE);
+	StopAllL3Timer(pc);
+	if (!(disc->CAUSE = l3dss1_get_cause(pc, msg, umsg))) {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "DISC get_cause ret(%d)", pc->err);
+		if (pc->err<0)
+			cause = CAUSE_MANDATORY_IE_MISS;
+		else if (pc->err>0)
+			cause = CAUSE_INVALID_CONTENTS;
+	}
+	disc->FACILITY =
+		find_and_copy_ie(msg->data, msg->len, IE_FACILITY, 0, umsg);
+	disc->SIGNAL =
+		find_and_copy_ie(msg->data, msg->len, IE_SIGNAL, 0, umsg);
+	disc->USER_USER =
+		find_and_copy_ie(msg->data, msg->len, IE_USER_USER, 0, umsg);
+	if (cause)
+		l3dss1_message_cause(pc, MT_RELEASE, cause);
+	else
+		l3dss1_message(pc, MT_RELEASE);
+	newl3state(pc, 19);
+	test_and_clear_bit(FLG_L3P_TIMER308_1, &pc->Flags);
+	L3AddTimer(&pc->timer1, T308, 0x308);
+	if (mISDN_l3up(pc, umsg))
+		free_msg(umsg);
+}
+
+static void
+l3dss1_information(layer3_proc_t *pc, int pr, void *arg) {
+	msg_t 		*umsg, *msg = arg;
+	INFORMATION_t	*info;
+
+	umsg = prep_l3data_msg(CC_INFORMATION | INDICATION, pc->ces |
+		(pc->callref << 16), sizeof(INFORMATION_t), msg->len, NULL);
+	if (!umsg)
+		return;
+	info = (INFORMATION_t *)(umsg->data + mISDNUSER_HEAD_SIZE);
+	info->COMPLETE =
+		find_and_copy_ie(msg->data, msg->len, IE_COMPLETE, 0, umsg);
+	info->KEYPAD =
+		find_and_copy_ie(msg->data, msg->len, IE_KEYPAD, 0, umsg);
+	info->SIGNAL =
+		find_and_copy_ie(msg->data, msg->len, IE_SIGNAL, 0, umsg);
+	info->CALLED_PN =
+		find_and_copy_ie(msg->data, msg->len, IE_CALLED_PN, 0, umsg);
+	if (pc->state == 2) { /* overlap receiving */
+		L3DelTimer(&pc->timer1);
+		L3AddTimer(&pc->timer1, T302, 0x302);
+	}
+	if (mISDN_l3up(pc, umsg))
+		free_msg(umsg);
+}
+
+static void
+l3dss1_release(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t		*umsg, *msg = arg;
+	RELEASE_t	*rel;
+	int 		cause=0;
+
+	umsg = prep_l3data_msg(CC_RELEASE | INDICATION, pc->ces |
+		(pc->callref << 16), sizeof(RELEASE_t), msg->len, NULL);
+	if (!umsg)
+		return;
+	rel = (RELEASE_t *)(umsg->data + mISDNUSER_HEAD_SIZE);
+	StopAllL3Timer(pc);
+	if (!(rel->CAUSE = l3dss1_get_cause(pc, msg, umsg))) {
+		if (pc->state != 12)
+			if (pc->l3->debug & L3_DEB_WARN)
+				l3_debug(pc->l3, "REL get_cause ret(%d)",
+					pc->err);
+		if ((pc->err<0) && (pc->state != 12))
+			cause = CAUSE_MANDATORY_IE_MISS;
+		else if (pc->err>0)
+			cause = CAUSE_INVALID_CONTENTS;
+	}
+	rel->FACILITY =
+		find_and_copy_ie(msg->data, msg->len, IE_FACILITY, 0, umsg);
+	rel->SIGNAL =
+		find_and_copy_ie(msg->data, msg->len, IE_SIGNAL, 0, umsg);
+	rel->USER_USER =
+		find_and_copy_ie(msg->data, msg->len, IE_USER_USER, 0, umsg);
+	if (cause)
+		l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, cause);
+	else
+		l3dss1_message(pc, MT_RELEASE_COMPLETE);
+	if (mISDN_l3up(pc, umsg))
+		free_msg(umsg);
+
+	/*
+		newl3state(pc, 0);
+		send_proc(pc, IMSG_END_PROC_M, NULL);
+	*/
+}
+
+static void
+l3dss1_release_i(layer3_proc_t *pc, int pr, void *arg)
+{
+
+	l3dss1_message(pc, MT_RELEASE_COMPLETE);
+	newl3state(pc, 0);
+	send_proc(pc, IMSG_END_PROC_M, NULL);
+}
+
+static void
+l3dss1_release_cmpl(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t			*umsg, *msg = arg;
+	RELEASE_COMPLETE_t	*relc;
+
+	umsg = prep_l3data_msg(CC_RELEASE_COMPLETE | INDICATION, pc->ces |
+		(pc->callref << 16), sizeof(RELEASE_COMPLETE_t), msg->len, NULL);
+	if (!umsg)
+		return;
+	relc = (RELEASE_COMPLETE_t *)(umsg->data + mISDNUSER_HEAD_SIZE);
+	StopAllL3Timer(pc);
+	newl3state(pc, 0);
+	if (!(relc->CAUSE = l3dss1_get_cause(pc, msg, umsg))) {
+		if (pc->err > 0)
+			if (pc->l3->debug & L3_DEB_WARN)
+				l3_debug(pc->l3, "RELCMPL get_cause err(%d)",
+					pc->err);
+	}
+	relc->FACILITY =
+		find_and_copy_ie(msg->data, msg->len, IE_FACILITY, 0, umsg);
+	relc->SIGNAL =
+		find_and_copy_ie(msg->data, msg->len, IE_SIGNAL, 0, umsg);
+	relc->USER_USER =
+		find_and_copy_ie(msg->data, msg->len, IE_USER_USER, 0, umsg);
+	if (mISDN_l3up(pc, umsg))
+		free_msg(umsg);
+	send_proc(pc, IMSG_END_PROC_M, NULL);
+}
+
+static void
+l3dss1_release_cmpl_i(layer3_proc_t *pc, int pr, void *arg)
+{
+	send_proc(pc, IMSG_END_PROC_M, NULL);
+}
+
+static void
+l3dss1_setup_acknowledge_i(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t			*umsg, *msg = arg;
+	SETUP_ACKNOWLEDGE_t	*sa;
+
+	dprint(DBGM_L3, pc->l3->nst->cardnr,"%s\n", __FUNCTION__);
+	if (!pc->master) {
+		L3DelTimer(&pc->timer1);
+		newl3state(pc, 25);
+		return;
+	}
+	umsg = prep_l3data_msg(CC_SETUP_ACKNOWLEDGE | INDICATION, pc->master->ces |
+		(pc->master->callref << 16), sizeof(SETUP_ACKNOWLEDGE_t), msg->len, NULL);
+	if (!umsg)
+		return;
+	sa = (SETUP_ACKNOWLEDGE_t *)(umsg->data + mISDNUSER_HEAD_SIZE);
+	L3DelTimer(&pc->timer1);	/* T304 */
+	newl3state(pc, 25);
+	sa->CHANNEL_ID =
+		find_and_copy_ie(msg->data, msg->len, IE_CHANNEL_ID, 0, umsg);
+	sa->FACILITY =
+		find_and_copy_ie(msg->data, msg->len, IE_FACILITY, 0, umsg);
+	sa->PROGRESS =
+		find_and_copy_ie(msg->data, msg->len, IE_PROGRESS, 0, umsg);
+	if (!mISDN_l3up(pc->master, umsg))
+		return;
+	free_msg(umsg);
+}
+
+static void
+l3dss1_proceeding_i(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t			*umsg, *msg = arg;
+	CALL_PROCEEDING_t	*proc;
+
+	dprint(DBGM_L3, pc->l3->nst->cardnr,"%s\n", __FUNCTION__);
+	if (!pc->master) {
+		L3DelTimer(&pc->timer1);
+		newl3state(pc, 9);
+		return;
+	}
+	umsg = prep_l3data_msg(CC_PROCEEDING | INDICATION, pc->master->ces |
+		(pc->master->callref << 16), sizeof(CALL_PROCEEDING_t), msg->len, NULL);
+	if (!umsg)
+		return;
+	proc = (CALL_PROCEEDING_t *)(umsg->data + mISDNUSER_HEAD_SIZE);
+	L3DelTimer(&pc->timer1);	/* T304 */
+	newl3state(pc, 9);
+	proc->CHANNEL_ID =
+		find_and_copy_ie(msg->data, msg->len, IE_CHANNEL_ID, 0, umsg);
+	proc->BEARER =
+		find_and_copy_ie(msg->data, msg->len, IE_BEARER, 0, umsg);
+	proc->FACILITY =
+		find_and_copy_ie(msg->data, msg->len, IE_FACILITY, 0, umsg);
+	proc->PROGRESS =
+		find_and_copy_ie(msg->data, msg->len, IE_PROGRESS, 0, umsg);
+	proc->HLC =
+		find_and_copy_ie(msg->data, msg->len, IE_HLC, 0, umsg);
+	if (!mISDN_l3up(pc->master, umsg))
+		return;
+	free_msg(umsg);
+}
+
+static void
+l3dss1_alerting_i(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t		*umsg, *msg = arg;
+	ALERTING_t	*al;
+
+	dprint(DBGM_L3, pc->l3->nst->cardnr,"%s\n", __FUNCTION__);
+	if (!pc->master) {
+		L3DelTimer(&pc->timer1);
+		newl3state(pc, 7);
+		return;
+	}
+	umsg = prep_l3data_msg(CC_ALERTING | INDICATION, pc->master->ces |
+		(pc->master->callref << 16), sizeof(ALERTING_t), msg->len, NULL);
+	if (!umsg)
+		return;
+	al = (ALERTING_t *)(umsg->data + mISDNUSER_HEAD_SIZE);
+	L3DelTimer(&pc->timer1);	/* T304 */
+	newl3state(pc, 7);
+	al->CHANNEL_ID =
+		find_and_copy_ie(msg->data, msg->len, IE_CHANNEL_ID, 0, umsg);
+	al->BEARER =
+		find_and_copy_ie(msg->data, msg->len, IE_BEARER, 0, umsg);
+	al->FACILITY =
+		find_and_copy_ie(msg->data, msg->len, IE_FACILITY, 0, umsg);
+	al->PROGRESS =
+		find_and_copy_ie(msg->data, msg->len, IE_PROGRESS, 0, umsg);
+	al->SIGNAL =
+		find_and_copy_ie(msg->data, msg->len, IE_SIGNAL, 0, umsg);
+	al->HLC =
+		find_and_copy_ie(msg->data, msg->len, IE_HLC, 0, umsg);
+	al->USER_USER =
+		find_and_copy_ie(msg->data, msg->len, IE_USER_USER, 0, umsg);
+	al->REDIR_DN =
+		find_and_copy_ie(msg->data, msg->len, IE_REDIR_DN, 0, umsg);
+	if (!mISDN_l3up(pc->master, umsg))
+		return;
+	free_msg(umsg);
+}
+
+#if 0
+static void
+l3dss1_call_proc(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t			*umsg, *msg = arg;
+	int			ret = 0;
+	u_char			cause;
+	CALL_PROCEEDING_t	*cp;
+
+	umsg = prep_l3data_msg(CC_PROCEEDING | INDICATION, pc->ces |
+		(pc->callref << 16), sizeof(CALL_PROCEEDING_t), msg->len, NULL);
+	if (!umsg)
+		return;
+	cp = (CALL_PROCEEDING_t *)(umsg->data + mISDNUSER_HEAD_SIZE);
+	if ((cp->CHANNEL_ID = l3dss1_get_channel_id(pc, msg, umsg))) {
+		if (!(pc->l3->nst->feature & FEATURE_NET_EXTCID)) { /* BRI */
+			if ((0 == pc->bc) || (3 == pc->bc)) {
+				if (pc->l3->debug & L3_DEB_WARN)
+					l3_debug(pc->l3, "setup answer with wrong chid %x", pc->bc);
+				l3dss1_status_send(pc, CAUSE_INVALID_CONTENTS);
+				free_msg(umsg);
+				return;
+			}
+		}
+	} else if (1 == pc->state) {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "setup answer wrong chid (ret %d)", pc->err);
+		if (pc->err == -1)
+			cause = CAUSE_MANDATORY_IE_MISS;
+		else
+			cause = CAUSE_INVALID_CONTENTS;
+		l3dss1_status_send(pc, cause);
+		free_msg(umsg);
+		return;
+	}
+	/* Now we are on none mandatory IEs */
+	cp->BEARER =
+		find_and_copy_ie(msg->data, msg->len, IE_BEARER, 0, umsg);
+	cp->FACILITY =
+		find_and_copy_ie(msg->data, msg->len, IE_FACILITY, 0, umsg);
+	cp->PROGRESS =
+		find_and_copy_ie(msg->data, msg->len, IE_PROGRESS, 0, umsg);
+	cp->DISPLAY =
+		find_and_copy_ie(msg->data, msg->len, IE_DISPLAY, 0, umsg);
+	cp->REDIR_DN =
+		find_and_copy_ie(msg->data, msg->len, IE_REDIR_DN, 0, umsg);
+	cp->HLC =
+		find_and_copy_ie(msg->data, msg->len, IE_HLC, 0, umsg);
+	L3DelTimer(&pc->timer1);
+	newl3state(pc, 3);
+	L3AddTimer(&pc->timer1, T310, 0x310);
+	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+		l3dss1_std_ie_err(pc, ret);
+	if (mISDN_l3up(pc, umsg))
+		free_msg(umsg);
+}
+#endif
+
+static void
+l3dss1_connect_i(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t		*umsg, *msg = arg;
+	CONNECT_t	*conn;
+
+	if (!pc->master) {
+		L3DelTimer(&pc->timer1);
+		newl3state(pc, 8);
+		return;
+	}
+	umsg = prep_l3data_msg(CC_CONNECT | INDICATION, pc->master->ces |
+		(pc->master->callref << 16), sizeof(CONNECT_t), msg->len, NULL);
+	if (!umsg)
+		return;
+	conn = (CONNECT_t *)(umsg->data + mISDNUSER_HEAD_SIZE);
+	L3DelTimer(&pc->timer1);	/* T310 */
+	newl3state(pc, 8);
+	conn->BEARER =
+		find_and_copy_ie(msg->data, msg->len, IE_BEARER, 0, umsg);
+	conn->FACILITY =
+		find_and_copy_ie(msg->data, msg->len, IE_FACILITY, 0, umsg);
+	conn->PROGRESS =
+		find_and_copy_ie(msg->data, msg->len, IE_PROGRESS, 0, umsg);
+	conn->DISPLAY =
+		find_and_copy_ie(msg->data, msg->len, IE_DISPLAY, 0, umsg);
+	conn->DATE =
+		find_and_copy_ie(msg->data, msg->len, IE_DATE, 0, umsg);
+	conn->SIGNAL =
+		find_and_copy_ie(msg->data, msg->len, IE_SIGNAL, 0, umsg);
+	conn->CONNECT_PN =
+		find_and_copy_ie(msg->data, msg->len, IE_CONNECT_PN, 0, umsg);
+	conn->CONNECT_SUB =
+		find_and_copy_ie(msg->data, msg->len, IE_CONNECT_SUB, 0, umsg);
+	conn->HLC =
+		find_and_copy_ie(msg->data, msg->len, IE_HLC, 0, umsg);
+	conn->LLC =
+		find_and_copy_ie(msg->data, msg->len, IE_LLC, 0, umsg);
+	conn->USER_USER =
+		find_and_copy_ie(msg->data, msg->len, IE_USER_USER, 0, umsg);
+	conn->ces = pc->ces;
+	if (send_proc(pc, IMSG_CONNECT_IND, umsg))
+		free_msg(umsg); 
+}
+
+static void
+l3dss1_hold(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t		*umsg, *msg = arg;
+	HOLD_t		*hold;
+
+	if (!(pc->l3->nst->feature & FEATURE_NET_HOLD)) {
+		l3dss1_message_cause(pc, MT_HOLD_REJECT, CAUSE_MT_NOTIMPLEMENTED);
+		return;
+	}
+	dprint(DBGM_L3, pc->l3->nst->cardnr,"%s\n", __FUNCTION__);
+	if (pc->hold_state == HOLDAUX_HOLD_IND)
+		return;
+	if (pc->hold_state != HOLDAUX_IDLE) {
+		l3dss1_message_cause(pc, MT_HOLD_REJECT, CAUSE_NOTCOMPAT_STATE);
+		return;
+	}
+	pc->hold_state = HOLDAUX_HOLD_IND; 
+
+	umsg = prep_l3data_msg(CC_HOLD | INDICATION, pc->ces |
+		(pc->callref << 16), sizeof(HOLD_t), msg->len, NULL);
+	if (!umsg)
+		return;
+	hold = (HOLD_t *)(umsg->data + mISDNUSER_HEAD_SIZE);
+	if (mISDN_l3up(pc, umsg))
+		free_msg(umsg);
+}
+
+static void
+l3dss1_retrieve(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t		*umsg, *msg = arg;
+	RETRIEVE_t	*retr;
+
+	if (!(pc->l3->nst->feature & FEATURE_NET_HOLD)) {
+		l3dss1_message_cause(pc, MT_RETRIEVE_REJECT, CAUSE_MT_NOTIMPLEMENTED);
+		return;
+	}
+	dprint(DBGM_L3, pc->l3->nst->cardnr,"%s\n", __FUNCTION__);
+	if (pc->hold_state == HOLDAUX_RETR_IND)
+		return;
+	if (pc->hold_state != HOLDAUX_HOLD) {
+		l3dss1_message_cause(pc, MT_RETRIEVE_REJECT, CAUSE_NOTCOMPAT_STATE);
+		return;
+	}
+	pc->hold_state = HOLDAUX_RETR_IND;
+
+	umsg = prep_l3data_msg(CC_RETRIEVE | INDICATION, pc->ces |
+		(pc->callref << 16), sizeof(RETRIEVE_t), msg->len, NULL);
+	if (!umsg)
+		return;
+	retr = (RETRIEVE_t *)(umsg->data + mISDNUSER_HEAD_SIZE);
+	retr->CHANNEL_ID =
+		find_and_copy_ie(msg->data, msg->len, IE_CHANNEL_ID, 0, umsg);
+	if (mISDN_l3up(pc, umsg))
+		free_msg(umsg);
+}
+
+static void
+l3dss1_suspend(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t		*umsg, *msg = arg;
+	SUSPEND_t	*susp;
+
+	dprint(DBGM_L3, pc->l3->nst->cardnr,"%s\n", __FUNCTION__);
+	umsg = prep_l3data_msg(CC_SUSPEND | INDICATION, pc->ces |
+		(pc->callref << 16), sizeof(SUSPEND_t), msg->len, NULL);
+	if (!umsg)
+		return;
+	susp = (SUSPEND_t *)(umsg->data + mISDNUSER_HEAD_SIZE);
+	susp->CALL_ID =
+		find_and_copy_ie(msg->data, msg->len, IE_CALL_ID, 0, umsg);
+	susp->FACILITY =
+		find_and_copy_ie(msg->data, msg->len, IE_FACILITY, 0, umsg);
+	newl3state(pc, 15);
+	if (mISDN_l3up(pc, umsg))
+		free_msg(umsg);
+}
+
+static void
+l3dss1_resume(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t		*umsg, *msg = arg;
+	RESUME_t	*res;
+
+	dprint(DBGM_L3, pc->l3->nst->cardnr,"%s\n", __FUNCTION__);
+	umsg = prep_l3data_msg(CC_RESUME | INDICATION, pc->ces |
+		(pc->callref << 16), sizeof(RESUME_t), msg->len, NULL);
+	if (!umsg)
+		return;
+	res = (RESUME_t *)(umsg->data + mISDNUSER_HEAD_SIZE);
+	res->CALL_ID =
+		find_and_copy_ie(msg->data, msg->len, IE_CALL_ID, 0, umsg);
+	res->FACILITY =
+		find_and_copy_ie(msg->data, msg->len, IE_FACILITY, 0, umsg);
+	res->ces = pc->ces;
+	newl3state(pc, 17);
+	if (mISDN_l3up(pc, umsg))
+		free_msg(umsg);
+}
+
+static struct stateentry datastatelist[] =
+{
+	{ALL_STATES,
+		MT_STATUS_ENQUIRY, l3dss1_status_enq},
+	{ALL_STATES,
+		MT_FACILITY, l3dss1_facility},
+	{SBIT(19),
+		MT_STATUS, l3dss1_release_cmpl},
+	{SBIT(0),
+		MT_SETUP, l3dss1_setup},
+	{SBIT(6) | SBIT(7)  | SBIT(9) | SBIT(25),
+		MT_SETUP_ACKNOWLEDGE, l3dss1_setup_acknowledge_i},
+	{SBIT(6) | SBIT(7)  | SBIT(9) | SBIT(25),
+		MT_CALL_PROCEEDING, l3dss1_proceeding_i},
+	{SBIT(6) | SBIT(7)  | SBIT(9) | SBIT(25),
+		MT_ALERTING, l3dss1_alerting_i},
+	{SBIT(6) | SBIT(7)  | SBIT(9) | SBIT(25),
+		MT_CONNECT, l3dss1_connect_i},
+	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(10) | SBIT(19),
+		MT_DISCONNECT, l3dss1_disconnect},
+	{SBIT(7) | SBIT(8) | SBIT(9) | SBIT(25),
+		MT_DISCONNECT, l3dss1_disconnect_i},
+	{SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) |
+	 SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
+		MT_INFORMATION, l3dss1_information},
+	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(10) |
+	 SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17),
+		MT_RELEASE, l3dss1_release},
+	{SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(19) | SBIT(25),
+		MT_RELEASE, l3dss1_release_i},
+	{SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(10) |
+	 SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19),
+		MT_RELEASE_COMPLETE, l3dss1_release_cmpl},
+	{SBIT(4) | SBIT(7) | SBIT(10),
+		MT_USER_INFORMATION, l3dss1_userinfo},
+	{SBIT(7) | SBIT(8) | SBIT(9) | SBIT(25),
+		MT_RELEASE_COMPLETE, l3dss1_release_cmpl_i},
+	{SBIT(3) | SBIT(4) | SBIT(10),
+		MT_HOLD, l3dss1_hold},
+	{SBIT(3) | SBIT(4) | SBIT(10) | SBIT(12),
+		MT_RETRIEVE, l3dss1_retrieve},
+	{SBIT(10),
+		MT_SUSPEND, l3dss1_suspend},
+	{SBIT(0),
+		MT_RESUME, l3dss1_resume},
+};
+
+#define DATASLLEN \
+	(sizeof(datastatelist) / sizeof(struct stateentry))
+
+static layer3_proc_t
+*create_child_proc(layer3_proc_t *pc, int mt, msg_t *msg, int state) {
+	mISDNuser_head_t	*hh;
+	struct _l3_msg	l3m;
+	layer3_proc_t	*p3i;
+
+	hh = (mISDNuser_head_t *)msg->data;
+	msg_pull(msg, mISDNUSER_HEAD_SIZE);
+	p3i = create_proc(pc->l3, hh->dinfo, pc->callref, pc);
+	if (!p3i) {
+		l3_debug(pc->l3, "cannot create child\n");
+		return(NULL);
+	}
+	p3i->state = pc->state;
+	if (pc->state != -1)
+		newl3state(pc, state);
+	l3m.mt = mt;
+	l3m.msg = msg;
+	send_proc(p3i, IMSG_L2_DATA, &l3m);
+	return(p3i);
+}                                                   
+
+static void
+l3dss1_setup_acknowledge_m(layer3_proc_t *pc, int pr, void *arg)
+{
+	dprint(DBGM_L3, pc->l3->nst->cardnr,"%s\n", __FUNCTION__);
+	L3DelTimer(&pc->timer1);
+	create_child_proc(pc, pr, arg, 25);
+}
+
+static void
+l3dss1_proceeding_m(layer3_proc_t *pc, int pr, void *arg)
+{
+	dprint(DBGM_L3, pc->l3->nst->cardnr,"%s\n", __FUNCTION__);
+	L3DelTimer(&pc->timer1);
+	create_child_proc(pc, pr, arg, 9);
+}
+
+static void
+l3dss1_alerting_m(layer3_proc_t *pc, int pr, void *arg)
+{
+	dprint(DBGM_L3, pc->l3->nst->cardnr,"%s\n", __FUNCTION__);
+	L3DelTimer(&pc->timer1);
+	create_child_proc(pc, pr, arg, 7);
+}
+
+static void
+l3dss1_connect_m(layer3_proc_t *pc, int pr, void *arg)
+{
+	dprint(DBGM_L3, pc->l3->nst->cardnr,"%s\n", __FUNCTION__);
+	L3DelTimer(&pc->timer1);
+	create_child_proc(pc, pr, arg, 8);
+}
+
+static void
+l3dss1_release_m(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t	*msg = arg;
+	msg_pull(msg, mISDNUSER_HEAD_SIZE);
+	l3dss1_release_i(pc, pr, msg);
+}
+
+static void
+l3dss1_release_mx(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t	*msg = arg;
+
+	msg_pull(msg, mISDNUSER_HEAD_SIZE);
+	l3dss1_release(pc, pr, msg);
+}
+
+static void
+l3dss1_release_cmpl_m(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t	*msg = arg;
+	u_char	*p;
+
+	if (pc->state == 6) {
+		msg_pull(msg, mISDNUSER_HEAD_SIZE);
+		if ((p = l3dss1_get_cause(pc, msg, NULL))) {
+			dprint(DBGM_L3, pc->l3->nst->cardnr,"%s cause (%d/%d)\n", __FUNCTION__,
+				pc->cause, pc->err);
+			switch(pc->cause) {
+				case CAUSE_USER_BUSY:
+					break;
+				case CAUSE_CALL_REJECTED:
+					if (pc->err == CAUSE_USER_BUSY)
+						pc->cause = pc->err;
+					break;
+				default:
+					pc->cause = pc->err;
+			}
+		}
+		test_and_set_bit(FLG_L3P_GOTRELCOMP, &pc->Flags);
+	}
+}
+
+static void
+l3dss1_release_cmpl_mx(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t	*msg = arg;
+
+	msg_pull(msg, mISDNUSER_HEAD_SIZE);
+	l3dss1_release_cmpl(pc, pr, msg);
+}
+
+static void
+l3dss1_information_mx(layer3_proc_t *pc, int pr, void *arg)
+{
+	msg_t	*msg = arg;
+
+	msg_pull(msg, mISDNUSER_HEAD_SIZE);
+	l3dss1_information(pc, pr, msg);
+}
+
+static struct stateentry mdatastatelist[] =
+{
+	{SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25),
+		MT_SETUP_ACKNOWLEDGE, l3dss1_setup_acknowledge_m},
+	{SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25),
+		MT_CALL_PROCEEDING, l3dss1_proceeding_m},
+	{SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25),
+		MT_ALERTING, l3dss1_alerting_m},
+	{SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25),
+		MT_CONNECT, l3dss1_connect_m},
+	{SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) |
+	 SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
+		MT_INFORMATION, l3dss1_information_mx},
+	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(10) | SBIT(11) |
+	 SBIT(12) | SBIT(15) | SBIT(17),
+		MT_RELEASE, l3dss1_release_mx},
+	{SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(22) | SBIT(25),
+		MT_RELEASE, l3dss1_release_m},
+	{SBIT(19),  MT_RELEASE, l3dss1_release_cmpl},
+	{SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(10) |
+	 SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19),
+		MT_RELEASE_COMPLETE, l3dss1_release_cmpl_mx},
+	{SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(22) | SBIT(25),
+		MT_RELEASE_COMPLETE, l3dss1_release_cmpl_m},
+};
+
+#define MDATASLLEN \
+	(sizeof(mdatastatelist) / sizeof(struct stateentry))
+                                                   
+static void
+l3dss1_setup_ack_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	SETUP_ACKNOWLEDGE_t *setup_ack = arg;
+
+	if (setup_ack) {
+		MsgStart(pc, MT_SETUP_ACKNOWLEDGE);
+		if (setup_ack->CHANNEL_ID) {
+			if (setup_ack->CHANNEL_ID[0] == 1)
+				pc->bc = setup_ack->CHANNEL_ID[1] & 3;
+			AddvarIE(pc, IE_CHANNEL_ID, setup_ack->CHANNEL_ID);
+		}
+		if (setup_ack->FACILITY)
+			AddvarIE(pc, IE_FACILITY, setup_ack->FACILITY);
+		if (setup_ack->PROGRESS)
+			AddvarIE(pc, IE_PROGRESS, setup_ack->PROGRESS);
+		if (setup_ack->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, setup_ack->DISPLAY);
+		SendMsg(pc, 2);
+	} else {
+		newl3state(pc, 2);
+		l3dss1_message(pc, MT_SETUP_ACKNOWLEDGE);
+	}
+	L3DelTimer(&pc->timer1);
+	L3AddTimer(&pc->timer1, T302, 0x302);
+}
+
+static void
+l3dss1_proceed_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	CALL_PROCEEDING_t *cproc = arg;
+
+	L3DelTimer(&pc->timer1);
+	if (cproc) {
+		MsgStart(pc, MT_CALL_PROCEEDING);
+		if (cproc->BEARER)
+			AddvarIE(pc, IE_BEARER, cproc->BEARER);
+		if (cproc->CHANNEL_ID) {
+			if (cproc->CHANNEL_ID[0] == 1)
+				pc->bc = cproc->CHANNEL_ID[1] & 3;
+			AddvarIE(pc, IE_CHANNEL_ID, cproc->CHANNEL_ID);
+		}
+		if (cproc->FACILITY)
+			AddvarIE(pc, IE_FACILITY, cproc->FACILITY);
+		if (cproc->PROGRESS)
+			AddvarIE(pc, IE_PROGRESS, cproc->PROGRESS);
+		if (cproc->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, cproc->DISPLAY);
+		if (cproc->REDIR_DN)
+			AddvarIE(pc, IE_REDIR_DN, cproc->REDIR_DN);
+		if (cproc->HLC)
+			AddvarIE(pc, IE_HLC, cproc->HLC);
+		SendMsg(pc, 3);
+	} else {
+		newl3state(pc, 3);
+		l3dss1_message(pc, MT_CALL_PROCEEDING);
+	}
+}
+
+static void
+l3dss1_alert_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	ALERTING_t *alert = arg;
+
+	if (alert) {
+		MsgStart(pc, MT_ALERTING);
+		if (alert->BEARER)
+			AddvarIE(pc, IE_BEARER, alert->BEARER);
+		if (alert->CHANNEL_ID) {
+			if (alert->CHANNEL_ID[0] == 1)
+				pc->bc = alert->CHANNEL_ID[1] & 3;
+			AddvarIE(pc, IE_CHANNEL_ID, alert->CHANNEL_ID);
+		}
+		if (alert->FACILITY)
+			AddvarIE(pc, IE_FACILITY, alert->FACILITY);
+		if (alert->PROGRESS)
+			AddvarIE(pc, IE_PROGRESS, alert->PROGRESS);
+		if (alert->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, alert->DISPLAY);
+		if (alert->HLC)
+			AddvarIE(pc, IE_HLC, alert->HLC);
+		if (alert->USER_USER)
+			AddvarIE(pc, IE_USER_USER, alert->USER_USER);
+		if (alert->REDIR_DN)
+			AddvarIE(pc, IE_REDIR_DN, alert->REDIR_DN);
+		SendMsg(pc, 4);
+	} else {
+		newl3state(pc, 4);
+		l3dss1_message(pc, MT_ALERTING);
+	}
+	L3DelTimer(&pc->timer1);
+}
+
+static void
+l3dss1_setup_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	SETUP_t	*setup = arg;
+	msg_t	*msg;
+	int	l;
+
+	MsgStart(pc, MT_SETUP);
+	if (setup->COMPLETE)
+		*pc->op++ = IE_COMPLETE;
+	if (setup->BEARER)
+		AddvarIE(pc, IE_BEARER, setup->BEARER);
+	if (setup->CHANNEL_ID) {
+		if (setup->CHANNEL_ID[0] == 1)
+			pc->bc = setup->CHANNEL_ID[1] & 3;
+		AddvarIE(pc, IE_CHANNEL_ID, setup->CHANNEL_ID);
+	}
+	if (setup->FACILITY)
+		AddvarIE(pc, IE_FACILITY, setup->FACILITY);
+	if (setup->PROGRESS)
+		AddvarIE(pc, IE_PROGRESS, setup->PROGRESS);
+	if (setup->NET_FAC)
+		AddvarIE(pc, IE_NET_FAC, setup->NET_FAC);
+	if (setup->DISPLAY)
+		AddvarIE(pc, IE_DISPLAY, setup->DISPLAY);
+	if (setup->KEYPAD)
+		AddvarIE(pc, IE_KEYPAD, setup->KEYPAD);
+	if (setup->CALLING_PN)
+		AddvarIE(pc, IE_CALLING_PN, setup->CALLING_PN);
+	if (setup->CALLING_SUB)
+		AddvarIE(pc, IE_CALLING_SUB, setup->CALLING_SUB);
+	if (setup->CALLED_PN)
+		AddvarIE(pc, IE_CALLED_PN, setup->CALLED_PN);
+	if (setup->CALLED_SUB)
+		AddvarIE(pc, IE_CALLED_SUB, setup->CALLED_SUB);
+	if (setup->LLC)
+		AddvarIE(pc, IE_LLC, setup->LLC);
+	if (setup->HLC)
+		AddvarIE(pc, IE_HLC, setup->HLC);
+	if (setup->USER_USER)
+		AddvarIE(pc, IE_USER_USER, setup->USER_USER);
+	
+	l = pc->op - &pc->obuf[0];
+	if (!(msg = l3_alloc_msg(l)))
+		return;
+	memcpy(msg_put(msg, l), &pc->obuf[0], l);
+	newl3state(pc, 6);
+	dhexprint(DBGM_L3DATA, "l3 oframe:", &pc->obuf[0], l);
+	if (pc->l3->nst->feature & FEATURE_NET_PTP) {
+		dprint(DBGM_L3, pc->l3->nst->cardnr, "%s: proc(%p) sending SETUP to CES 0\n", __FUNCTION__, pc);
+		if (l3_msg(pc->l3, DL_DATA | REQUEST, 0, msg))
+			free_msg(msg);
+	} else {
+		dprint(DBGM_L3, pc->l3->nst->cardnr, "%s: proc(%p) sending SETUP to broadcast CES\n", __FUNCTION__, pc);
+		if (l3_msg(pc->l3, DL_UNITDATA | REQUEST, 127, msg))
+			free_msg(msg);
+	}
+	L3DelTimer(&pc->timer1);
+	test_and_clear_bit(FLG_L3P_TIMER303_1, &pc->Flags);
+	L3AddTimer(&pc->timer1, T303, 0x303);
+	L3DelTimer(&pc->timer2);
+	if (!(pc->l3->nst->feature & FEATURE_NET_PTP)) {
+		test_and_set_bit(FLG_L3P_TIMER312, &pc->Flags);
+		L3AddTimer(&pc->timer2, T312, 0x312);
+	}
+}
+
+static void
+l3dss1_disconnect_req(layer3_proc_t *pc, int pr, void *arg);
+
+static void
+l3dss1_connect_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	CONNECT_t *conn = arg;
+
+	L3DelTimer(&pc->timer1);
+	if (conn && conn->CHANNEL_ID) {
+		if (conn->CHANNEL_ID[0] == 1)
+			pc->bc = conn->CHANNEL_ID[1] & 3;
+	}
+	if (conn) {
+		MsgStart(pc, MT_CONNECT);
+		if (conn->BEARER)
+			AddvarIE(pc, IE_BEARER, conn->BEARER);
+		if (conn->CHANNEL_ID)
+			AddvarIE(pc, IE_CHANNEL_ID, conn->CHANNEL_ID);
+		if (conn->FACILITY)
+			AddvarIE(pc, IE_FACILITY, conn->FACILITY);
+		if (conn->PROGRESS)
+			AddvarIE(pc, IE_PROGRESS, conn->PROGRESS);
+		if (conn->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, conn->DISPLAY);
+		if (conn->DATE)
+			AddvarIE(pc, IE_DATE, conn->DATE);
+		if (conn->CONNECT_PN)
+			AddvarIE(pc, IE_CONNECT_PN, conn->CONNECT_PN);
+		if (conn->CONNECT_SUB)
+			AddvarIE(pc, IE_CONNECT_SUB, conn->CONNECT_SUB);
+		if (conn->LLC)
+			AddvarIE(pc, IE_LLC, conn->LLC);
+		if (conn->HLC)
+			AddvarIE(pc, IE_HLC, conn->HLC);
+		if (conn->USER_USER)
+			AddvarIE(pc, IE_USER_USER, conn->USER_USER);
+		SendMsg(pc, 10);
+	} else {
+		newl3state(pc, 10);
+		l3dss1_message(pc, MT_CONNECT);
+	}
+}
+
+static void
+l3dss1_connect_res(layer3_proc_t *pc, int pr, void *arg)
+{
+	CONNECT_ACKNOWLEDGE_t	*connack = arg;
+	int			cause;
+
+	L3DelTimer(&pc->timer1);
+	send_proc(pc, IMSG_SEL_PROC, NULL);
+	if (connack && connack->CHANNEL_ID) {
+		if (connack->CHANNEL_ID[0] == 1)
+			pc->bc = connack->CHANNEL_ID[1] & 3;
+	}
+#if 0
+	if (!pc->bc) {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "D-chan connect for waiting call");
+		l3dss1_disconnect_req(pc, pr, NULL);
+		return;
+	}
+#endif
+	if (connack) {
+		MsgStart(pc, MT_CONNECT_ACKNOWLEDGE);
+		if (connack->CHANNEL_ID)
+			AddvarIE(pc, IE_CHANNEL_ID, connack->CHANNEL_ID);
+		if (connack->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, connack->DISPLAY);
+		if (connack->SIGNAL)
+			AddvarIE(pc, IE_SIGNAL, connack->SIGNAL);
+		SendMsg(pc, 10);
+	} else {
+		newl3state(pc, 10);
+		l3dss1_message(pc, MT_CONNECT_ACKNOWLEDGE);
+	}
+	cause = CAUSE_NONSELECTED_USER;
+	send_proc(pc, IMSG_RELEASE_CHILDS, &cause);
+}
+
+static void
+l3dss1_disconnect_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	DISCONNECT_t *disc = arg;
+
+	StopAllL3Timer(pc);
+	if (disc) {
+		MsgStart(pc, MT_DISCONNECT);
+		if (disc->CAUSE){ 
+			AddvarIE(pc, IE_CAUSE, disc->CAUSE);
+		} else {
+			*pc->op++ = IE_CAUSE;
+			*pc->op++ = 2;
+			*pc->op++ = 0x80 | CAUSE_LOC_PNET_LOCUSER;
+			*pc->op++ = 0x80 | CAUSE_NORMALUNSPECIFIED;
+		}
+		if (disc->FACILITY)
+			AddvarIE(pc, IE_FACILITY, disc->FACILITY);
+		if (disc->PROGRESS)
+			AddvarIE(pc, IE_PROGRESS, disc->PROGRESS);
+		if (disc->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, disc->DISPLAY);
+		if (disc->USER_USER)
+			AddvarIE(pc, IE_USER_USER, disc->USER_USER);
+		SendMsg(pc, 12);
+	} else {
+		newl3state(pc, 12);
+		l3dss1_message_cause(pc, MT_DISCONNECT, CAUSE_NORMALUNSPECIFIED);
+	}
+	L3AddTimer(&pc->timer1, T305, 0x305);
+}
+
+static void
+l3dss1_facility_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	FACILITY_t *fac = arg;
+
+	if (fac) {
+		MsgStart(pc, MT_FACILITY);
+		if (fac->FACILITY)
+			AddvarIE(pc, IE_FACILITY, fac->FACILITY);
+		else
+			return;
+		if (fac->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, fac->DISPLAY);
+		SendMsg(pc, -1);
+	}
+}
+
+static void
+l3dss1_userinfo_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	USER_INFORMATION_t *ui = arg;
+
+	if (ui) {
+		MsgStart(pc, MT_USER_INFORMATION);
+ 		if (ui->USER_USER)
+			AddvarIE(pc, IE_USER_USER, ui->USER_USER);
+		else
+			return;
+		SendMsg(pc, -1);
+	}
+}
+
+static void
+l3dss1_information_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	INFORMATION_t *info = arg;
+	msg_t   *msg;
+	int     l;
+
+	if (pc->state == 25 && !(pc->l3->nst->feature & FEATURE_NET_PTP))
+		return;
+	
+	if (info) {
+		MsgStart(pc, MT_INFORMATION);
+ 		if (info->COMPLETE)
+			*pc->op++ = IE_COMPLETE;
+		if (info->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, info->DISPLAY);
+		if (info->KEYPAD)
+			AddvarIE(pc, IE_KEYPAD, info->KEYPAD);
+		if (info->SIGNAL)
+			AddvarIE(pc, IE_SIGNAL, info->SIGNAL);
+		if (info->CALLED_PN)
+			AddvarIE(pc, IE_CALLED_PN, info->CALLED_PN);
+		if (pc->state != 25)
+			SendMsg(pc, -1);
+		else {
+			l = pc->op - &pc->obuf[0];
+			if (!(msg = l3_alloc_msg(l)))
+				return;
+			memcpy(msg_put(msg, l), &pc->obuf[0], l);
+			dhexprint(DBGM_L3DATA, "l3 oframe:", &pc->obuf[0], l);
+			dprint(DBGM_L3, pc->l3->nst->cardnr, "%s: proc(%p) sending INFORMATION to CES 0 during state 25 (OVERLAP)\n", __FUNCTION__, pc);
+			if (l3_msg(pc->l3, DL_DATA | REQUEST, 0, msg))
+				free_msg(msg);
+		}
+	}
+}
+
+static void
+l3dss1_progress_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	PROGRESS_t *prog = arg;
+
+	if (prog) {
+		MsgStart(pc, MT_INFORMATION);
+		if (prog->BEARER)
+			AddvarIE(pc, IE_BEARER, prog->BEARER);
+		if (prog->CAUSE)
+			AddvarIE(pc, IE_CAUSE, prog->CAUSE);
+		if (prog->FACILITY)
+			AddvarIE(pc, IE_FACILITY, prog->FACILITY);
+		if (prog->PROGRESS)
+			AddvarIE(pc, IE_PROGRESS, prog->PROGRESS);
+		else
+			return;
+		if (prog->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, prog->DISPLAY);
+		if (prog->HLC)
+			AddvarIE(pc, IE_HLC, prog->HLC);
+		SendMsg(pc, -1);
+	}
+}
+
+static void
+l3dss1_notify_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	NOTIFY_t *noti = arg;
+
+	if (noti) {
+		MsgStart(pc, MT_INFORMATION);
+		if (noti->BEARER)
+			AddvarIE(pc, IE_BEARER, noti->BEARER);
+		if (noti->NOTIFY)
+			AddvarIE(pc, IE_NOTIFY, noti->NOTIFY);
+		else
+			return;
+		if (noti->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, noti->DISPLAY);
+		if (noti->REDIR_DN)
+			AddvarIE(pc, IE_REDIR_DN, noti->REDIR_DN);
+		SendMsg(pc, -1);
+	}
+}
+
+static void
+l3dss1_disconnect_req_out(layer3_proc_t *pc, int pr, void *arg)
+{
+	DISCONNECT_t	*disc = arg;
+	int		cause;
+
+	if (pc->master) { /* child */
+		l3dss1_disconnect_req_out(pc->master, pr, arg);
+		return;
+	}
+	L3DelTimer(&pc->timer1);
+	if (disc) {
+		if (disc->CAUSE){
+			cause = disc->CAUSE[2] & 0x7f;
+		} else {
+			cause = CAUSE_NORMALUNSPECIFIED;
+		}
+	}
+	send_proc(pc, IMSG_RELEASE_CHILDS, &cause);
+	if (test_bit(FLG_L3P_TIMER312, &pc->Flags)) {
+		newl3state(pc, 22);
+	} else {
+		if_link(pc->l3->nst->manager, (ifunc_t)pc->l3->nst->l3_manager,
+			CC_RELEASE | CONFIRM, pc->ces |
+			(pc->callref << 16), 0, NULL, 0);
+		newl3state(pc, 0);
+		if (!pc->child)
+			send_proc(pc, IMSG_END_PROC_M, NULL);
+	}
+}
+
+static void
+l3dss1_release_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	RELEASE_t *rel = arg;
+	
+	StopAllL3Timer(pc);
+	if (rel) {
+		MsgStart(pc, MT_RELEASE);
+		if (rel->CAUSE)
+			AddvarIE(pc, IE_CAUSE, rel->CAUSE);
+		if (rel->FACILITY)
+			AddvarIE(pc, IE_FACILITY, rel->FACILITY);
+		if (rel->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, rel->DISPLAY);
+		if (rel->USER_USER)
+			AddvarIE(pc, IE_USER_USER, rel->USER_USER);
+		SendMsg(pc, 19);
+	} else {
+		newl3state(pc, 19);
+		l3dss1_message(pc, MT_RELEASE);
+	}
+	test_and_clear_bit(FLG_L3P_TIMER308_1, &pc->Flags);
+	L3AddTimer(&pc->timer1, T308, 0x308);
+}
+
+static void
+l3dss1_release_cmpl_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	RELEASE_COMPLETE_t *rcmpl = arg;
+
+	StopAllL3Timer(pc);
+	if (rcmpl) {
+		MsgStart(pc, MT_RELEASE_COMPLETE);
+		if (rcmpl->CAUSE)
+			AddvarIE(pc, IE_CAUSE, rcmpl->CAUSE);
+		if (rcmpl->FACILITY)
+			AddvarIE(pc, IE_FACILITY, rcmpl->FACILITY);
+		if (rcmpl->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, rcmpl->DISPLAY);
+		if (rcmpl->USER_USER) 
+			AddvarIE(pc, IE_USER_USER, rcmpl->USER_USER);
+		SendMsg(pc, 0);
+	} else {
+		newl3state(pc, 0);
+		l3dss1_message(pc, MT_RELEASE_COMPLETE);
+	}
+	send_proc(pc, IMSG_END_PROC_M, NULL);
+}
+
+static void
+l3dss1_t302(layer3_proc_t *pc, int pr, void *arg)
+{
+	{
+		int t = 0x302;
+
+		StopAllL3Timer(pc);
+		if_link(pc->l3->nst->manager, (ifunc_t)pc->l3->nst->l3_manager,
+			CC_TIMEOUT | INDICATION,pc->ces | (pc->callref << 16),
+			sizeof(int), &t, 0);
+	}
+}
+
+static void
+l3dss1_t303(layer3_proc_t *pc, int pr, void *arg)
+{
+	int			l;
+	msg_t			*msg;
+	RELEASE_COMPLETE_t	*relc;
+
+	L3DelTimer(&pc->timer1);
+	if (test_bit(FLG_L3P_GOTRELCOMP, &pc->Flags)) {
+		StopAllL3Timer(pc);
+		msg = prep_l3data_msg(CC_RELEASE_COMPLETE | INDICATION,
+			pc->ces | (pc->callref << 16),
+			sizeof(RELEASE_COMPLETE_t), 3, NULL);
+		if (!msg)
+			return;
+		relc = (RELEASE_COMPLETE_t *)(msg->data + mISDNUSER_HEAD_SIZE);
+		newl3state(pc, 0);
+		relc->CAUSE = msg_put(msg, 3);
+		relc->CAUSE[0] = 2;
+		relc->CAUSE[1] = 0x80;
+		if (pc->cause)
+			relc->CAUSE[2] = pc->cause | 0x80;
+		else
+			relc->CAUSE[2] = CAUSE_NORMALUNSPECIFIED | 0x80;
+		if (mISDN_l3up(pc, msg))
+			free_msg(msg);
+		send_proc(pc, IMSG_END_PROC_M, NULL);
+		return;
+	}
+	if (!test_and_set_bit(FLG_L3P_TIMER303_1, &pc->Flags)) {
+		if (pc->obuf[3] == MT_SETUP) {
+			l = pc->op - &pc->obuf[0];
+			dhexprint(DBGM_L3DATA, "l3 oframe:", &pc->obuf[0], l);
+			if ((msg = l3_alloc_msg(l))) {
+				memcpy(msg_put(msg, l), &pc->obuf[0], l);
+
+				if (pc->l3->nst->feature & FEATURE_NET_PTP) {
+					dprint(DBGM_L3, pc->l3->nst->cardnr, "%s: proc(%p) sending SETUP to CES 0\n", __FUNCTION__, pc);
+					if (l3_msg(pc->l3, DL_DATA | REQUEST, 0, msg))
+						free_msg(msg);
+				} else {
+					dprint(DBGM_L3, pc->l3->nst->cardnr, "%s: proc(%p) sending SETUP to broadcast CES\n", __FUNCTION__, pc);
+					if (l3_msg(pc->l3, DL_UNITDATA | REQUEST, 127, msg))
+						free_msg(msg);
+				}
+			}
+
+			L3DelTimer(&pc->timer2);
+dprint(DBGM_L3, pc->l3->nst->cardnr, "%s: pc=%p del timer2\n", __FUNCTION__, pc);
+			if (!(pc->l3->nst->feature & FEATURE_NET_PTP)) {
+				L3AddTimer(&pc->timer2, T312, 0x312);
+				test_and_set_bit(FLG_L3P_TIMER312,
+					&pc->Flags);
+			}
+
+			L3AddTimer(&pc->timer1, T303, 0x303);
+			return;
+		}
+	}
+	msg = prep_l3data_msg(CC_RELEASE_COMPLETE | INDICATION,
+		pc->ces | (pc->callref << 16),
+		sizeof(RELEASE_COMPLETE_t), 3, NULL);
+	if (!msg)
+		return;
+	relc = (RELEASE_COMPLETE_t *)(msg->data + mISDNUSER_HEAD_SIZE);
+	relc->CAUSE = msg_put(msg, 3);
+	relc->CAUSE[0] = 2;
+	relc->CAUSE[1] = 0x85;
+	relc->CAUSE[2] = CAUSE_NOUSER_RESPONDING | 0x80;
+	if (mISDN_l3up(pc, msg))
+		free_msg(msg);
+	newl3state(pc, 22);
+}
+
+static void
+l3dss1_t305(layer3_proc_t *pc, int pr, void *arg)
+{
+#warning: mut we dat sendn? :  int t = 0x305;
+
+	StopAllL3Timer(pc);
+
+
+	newl3state(pc, 19);
+		l3dss1_message(pc, MT_RELEASE);
+	test_and_clear_bit(FLG_L3P_TIMER308_1, &pc->Flags);
+	L3AddTimer(&pc->timer1, T308, 0x308);
+}
+
+static void
+l3dss1_t308(layer3_proc_t *pc, int pr, void *arg)
+{
+	if (!test_and_set_bit(FLG_L3P_TIMER308_1, &pc->Flags)) {
+		newl3state(pc, 19);
+		L3DelTimer(&pc->timer1);
+		l3dss1_message(pc, MT_RELEASE);
+		L3AddTimer(&pc->timer1, T308, 0x308);
+	} else {
+		int t = 0x308;
+
+		StopAllL3Timer(pc);
+		newl3state(pc, 0);
+		if_link(pc->l3->nst->manager, (ifunc_t)pc->l3->nst->l3_manager,
+			CC_TIMEOUT | INDICATION,pc->ces | (pc->callref << 16),
+			sizeof(int), &t, 0);
+		send_proc(pc, IMSG_END_PROC_M, NULL);
+	}
+}
+
+static void
+l3dss1_t312(layer3_proc_t *pc, int pr, void *arg)
+{
+	int t = 0x312;
+
+	test_and_clear_bit(FLG_L3P_TIMER312, &pc->Flags);
+	L3DelTimer(&pc->timer2);
+dprint(DBGM_L3, pc->l3->nst->cardnr, "%s: pc=%p del timer2\n", __FUNCTION__, pc);
+	l3_debug(pc->l3, "%s: state %d", __FUNCTION__, pc->state);
+	if (pc->state == 22 || pc->state == 25 || pc->state == 9 || pc->state == 7) {
+		StopAllL3Timer(pc);
+		if (!pc->child) {
+			if_link(pc->l3->nst->manager, (ifunc_t)pc->l3->nst->l3_manager,
+				CC_TIMEOUT | INDICATION,pc->ces |
+				(pc->callref << 16), sizeof(int), &t, 0);
+			send_proc(pc, IMSG_END_PROC_M, NULL);
+		}
+	}
+}
+
+static void
+l3dss1_holdack_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	HOLD_ACKNOWLEDGE_t *hack = arg;
+
+	if (pc->hold_state != HOLDAUX_HOLD_IND)
+		return;
+	pc->hold_state = HOLDAUX_HOLD; 
+	if (hack) {
+		MsgStart(pc, MT_HOLD_ACKNOWLEDGE);
+		if (hack->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, hack->DISPLAY);
+		SendMsg(pc, -1);
+	} else {
+		l3dss1_message(pc, MT_HOLD_ACKNOWLEDGE);
+	}
+}
+
+static void
+l3dss1_holdrej_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	HOLD_REJECT_t *hrej = arg;
+
+	if (pc->hold_state != HOLDAUX_HOLD_IND)
+		return;
+	pc->hold_state = HOLDAUX_IDLE; 
+	MsgStart(pc, MT_HOLD_REJECT);
+	if (hrej) {
+		if (hrej->CAUSE)
+			AddvarIE(pc, IE_CAUSE, hrej->CAUSE);
+		else {
+			*pc->op++ = IE_CAUSE;
+			*pc->op++ = 2;
+			*pc->op++ = 0x80;
+			*pc->op++ = 0x80 | 0x47;
+		}
+		if (hrej->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, hrej->DISPLAY);
+	} else {
+		*pc->op++ = IE_CAUSE;
+		*pc->op++ = 2;
+		*pc->op++ = 0x80;
+		*pc->op++ = 0x80 | 0x47;
+	}
+	SendMsg(pc, -1);
+}
+
+static void
+l3dss1_retrack_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	RETRIEVE_ACKNOWLEDGE_t *rack = arg;
+
+	if (pc->hold_state != HOLDAUX_RETR_IND)
+		return;
+	pc->hold_state = HOLDAUX_IDLE;
+	if (rack) {
+		MsgStart(pc, MT_RETRIEVE_ACKNOWLEDGE);
+		if (rack->CHANNEL_ID)
+			AddvarIE(pc, IE_CHANNEL_ID, rack->CHANNEL_ID);
+		if (rack->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, rack->DISPLAY);
+		SendMsg(pc, -1);
+	} else {
+		l3dss1_message(pc, MT_RETRIEVE_ACKNOWLEDGE);
+	}
+}
+
+static void
+l3dss1_retrrej_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	RETRIEVE_REJECT_t *rrej = arg;
+
+	if (pc->hold_state != HOLDAUX_RETR_IND)
+		return;
+	pc->hold_state = HOLDAUX_HOLD; 
+	MsgStart(pc, MT_RETRIEVE_REJECT);
+	if (rrej) {
+		if (rrej->CAUSE)
+			AddvarIE(pc, IE_CAUSE, rrej->CAUSE);
+		else {
+			*pc->op++ = IE_CAUSE;
+			*pc->op++ = 2;
+			*pc->op++ = 0x80;
+			*pc->op++ = 0x80 | 0x47;
+		}
+		if (rrej->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, rrej->DISPLAY);
+	} else {
+		*pc->op++ = IE_CAUSE;
+		*pc->op++ = 2;
+		*pc->op++ = 0x80;
+		*pc->op++ = 0x80 | 0x47;
+	}
+	SendMsg(pc, -1);
+}
+
+static void
+l3dss1_suspack_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	SUSPEND_ACKNOWLEDGE_t *sack = arg;
+
+	StopAllL3Timer(pc);
+	if (sack) {
+		MsgStart(pc, MT_SUSPEND_ACKNOWLEDGE);
+		if (sack->FACILITY)
+			AddvarIE(pc, IE_FACILITY, sack->FACILITY);
+		if (sack->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, sack->DISPLAY);
+		SendMsg(pc, 0);
+	} else {
+		l3dss1_message(pc, MT_SUSPEND_ACKNOWLEDGE);
+	}
+	newl3state(pc, 0);
+	send_proc(pc, IMSG_END_PROC_M, NULL);
+}
+
+static void
+l3dss1_susprej_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	SUSPEND_REJECT_t *srej = arg;
+
+	MsgStart(pc, MT_SUSPEND_REJECT);
+	if (srej) {
+		if (srej->CAUSE)
+			AddvarIE(pc, IE_CAUSE, srej->CAUSE);
+		else {
+			*pc->op++ = IE_CAUSE;
+			*pc->op++ = 2;
+			*pc->op++ = 0x80;
+			*pc->op++ = 0x80 | 0x47;
+		}
+		if (srej->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, srej->DISPLAY);
+	} else {
+		*pc->op++ = IE_CAUSE;
+		*pc->op++ = 2;
+		*pc->op++ = 0x80;
+		*pc->op++ = 0x80 | 0x47;
+	}
+	SendMsg(pc, -1);
+	newl3state(pc, 10);
+}
+
+static void
+l3dss1_resack_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	RESUME_ACKNOWLEDGE_t *rack = arg;
+
+	StopAllL3Timer(pc);
+	if (rack) {
+		MsgStart(pc, MT_RESUME_ACKNOWLEDGE);
+		if (rack->CHANNEL_ID)
+			AddvarIE(pc, IE_CHANNEL_ID, rack->CHANNEL_ID);
+		if (rack->FACILITY)
+			AddvarIE(pc, IE_FACILITY, rack->FACILITY);
+		if (rack->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, rack->DISPLAY);
+		SendMsg(pc, 0);
+	} else {
+		l3dss1_message(pc, MT_RESUME_ACKNOWLEDGE);
+	}
+	newl3state(pc, 10);
+}
+
+static void
+l3dss1_resrej_req(layer3_proc_t *pc, int pr, void *arg)
+{
+	RESUME_REJECT_t *rrej = arg;
+
+	MsgStart(pc, MT_RESUME_REJECT);
+	if (rrej) {
+		if (rrej->CAUSE)
+			AddvarIE(pc, IE_CAUSE, rrej->CAUSE);
+		else {
+			*pc->op++ = IE_CAUSE;
+			*pc->op++ = 2;
+			*pc->op++ = 0x80;
+			*pc->op++ = 0x80 | 0x47;
+		}
+		if (rrej->DISPLAY)
+			AddvarIE(pc, IE_DISPLAY, rrej->DISPLAY);
+	} else {
+		*pc->op++ = IE_CAUSE;
+		*pc->op++ = 2;
+		*pc->op++ = 0x80;
+		*pc->op++ = 0x80 | 0x47;
+	}
+	SendMsg(pc, -1);
+	newl3state(pc, 0);
+	send_proc(pc, IMSG_END_PROC_M, NULL);
+}
+
+/* *INDENT-OFF* */
+static struct stateentry downstatelist[] =
+{
+#if 0
+	{SBIT(0),
+	 CC_RESUME | REQUEST, l3dss1_resume_req},
+	{SBIT(12),
+	 CC_RELEASE | REQUEST, l3dss1_release_req},
+	{ALL_STATES,
+	 CC_RESTART | REQUEST, l3dss1_restart},
+	{SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25),
+	 CC_CONNECT | REQUEST, l3dss1_connect_req},
+	{SBIT(10),
+	 CC_SUSPEND | REQUEST, l3dss1_suspend_req},
+#endif
+	{ALL_STATES,
+		CC_RELEASE_COMPLETE | REQUEST, l3dss1_release_cmpl_req},
+	{SBIT(0),
+	 CC_SETUP | REQUEST, l3dss1_setup_req},
+	{SBIT(1),
+	 CC_SETUP_ACKNOWLEDGE | REQUEST, l3dss1_setup_ack_req},
+	{SBIT(1) | SBIT(2),
+	 CC_PROCEEDING | REQUEST, l3dss1_proceed_req},
+	{SBIT(2) | SBIT(3),
+	 CC_ALERTING | REQUEST, l3dss1_alert_req},
+	{SBIT(2) | SBIT(3) | SBIT(4),
+	 CC_CONNECT | REQUEST, l3dss1_connect_req},
+	{SBIT(8),
+	 CC_CONNECT | RESPONSE, l3dss1_connect_res},
+	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(10),
+	 CC_DISCONNECT | REQUEST, l3dss1_disconnect_req},
+	{ SBIT(2) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(25),
+	 CC_DISCONNECT | REQUEST, l3dss1_disconnect_req_out},
+	{ SBIT(2) | SBIT(11)
+#warning bitte beachte folgendes:
+/*
+andreas:
+es ist nur erlaubt, im state 11 einen release zu schicken!
+dennoch verwende der stack den release scheinbar, um einen prozess
+zu releasen, wie es z.b. in l3dss1_disconnect_req_out geschieht.
+der process befindet sich zu diesem zeitpunk noch im state 7, 9 oder 25.
+wenn man den (Layer 4) state auf 11 ändern würde, braucht mann die folgende
+zeile nicht: (bitte nachdenken, ob dies korrekt ist)
+
+karsten:
+Nein glaube ich nicht. CC_RELEASE |= CC_RELEASE_CR muss aber mal ein paar Tests
+machen
+
+andreas:
+solltest du was ändern, bitte vorher mit mit sprechen, da bei mir alles soweit fabelhaft läuft un ich layer 4 eventuell anpassen muss.
+*/
+	| SBIT(12) | SBIT(7) | SBIT(9) | SBIT(25)
+	 ,CC_RELEASE | REQUEST, l3dss1_release_req},
+/*
+andreas:
+wenn ein CC_DISCONNECT gesendet wird (state 7 = klingeling), dann bekommt man nur einen RELEASE_CR, aber keinen vorherigen RELEASE 
+
+karsten:
+muss ich auch testen, keine Zeit
+
+andreas:
+solltest du was ändern, bitte vorher mit mit sprechen, da bei mir alles soweit fabelhaft läuft un ich layer 4 eventuell anpassen muss.
+*/
+	{ALL_STATES,
+	 CC_FACILITY | REQUEST, l3dss1_facility_req},
+	{SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10),
+	 CC_USER_INFORMATION | REQUEST, l3dss1_userinfo_req},
+	{SBIT(2) | SBIT(3) | SBIT(4) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(25),
+	 CC_INFORMATION | REQUEST, l3dss1_information_req},
+	{SBIT(2) | SBIT(3) | SBIT(4),
+	 CC_PROGRESS | REQUEST, l3dss1_progress_req},
+	{SBIT(10) | SBIT(15),
+	 CC_NOTIFY | REQUEST, l3dss1_notify_req},
+	{SBIT(2),
+	 CC_T302, l3dss1_t302},
+	{SBIT(12),
+	 CC_T305, l3dss1_t305},
+	{SBIT(6),
+	 CC_T303, l3dss1_t303},
+	{SBIT(19),
+	 CC_T308, l3dss1_t308},
+	{ALL_STATES,
+	 CC_T312, l3dss1_t312},
+	{SBIT(3) | SBIT(4) | SBIT(10) | SBIT(12),
+	 CC_HOLD_ACKNOWLEDGE | REQUEST, l3dss1_holdack_req},
+	{SBIT(3) | SBIT(4) | SBIT(10) | SBIT(12),
+	 CC_HOLD_REJECT | REQUEST, l3dss1_holdrej_req},
+	{SBIT(3) | SBIT(4) | SBIT(10) | SBIT(12),
+	 CC_RETRIEVE_ACKNOWLEDGE | REQUEST, l3dss1_retrack_req},
+	{SBIT(3) | SBIT(4) | SBIT(10) | SBIT(12),
+	 CC_RETRIEVE_REJECT | REQUEST, l3dss1_retrrej_req},
+	{SBIT(15),
+	 CC_SUSPEND_ACKNOWLEDGE | REQUEST, l3dss1_suspack_req},
+	{SBIT(15),
+	 CC_SUSPEND_REJECT | REQUEST, l3dss1_susprej_req},
+	{SBIT(17),
+	 CC_RESUME_ACKNOWLEDGE | REQUEST, l3dss1_resack_req},
+	{SBIT(17),
+	 CC_RESUME_REJECT | REQUEST, l3dss1_resrej_req},
+};
+
+#define DOWNSLLEN \
+	(sizeof(downstatelist) / sizeof(struct stateentry))
+
+static int
+imsg_intrelease(layer3_proc_t *master, layer3_proc_t *child)
+{
+	int	cause;
+
+	if ((!master) || (!child))
+		return(-EINVAL);
+	dprint(DBGM_L3, master->l3->nst->cardnr, "%s: m/c(%x/%x) state(%d/%d) m->c(%p)\n", __FUNCTION__,
+		master->ces, child->ces, master->state, child->state,
+		master->child);
+	switch (master->state) {
+		case 0:
+			if (!master->child) {
+				send_proc(master, IMSG_END_PROC, master);
+			}
+			break;
+		case 6:
+		case 10:
+			break;
+		case 19:
+			send_proc(master, IMSG_END_PROC, NULL);
+			break;
+		case 7:
+		case 9:
+		case 25:
+			if (master->child ||
+				test_bit(FLG_L3P_TIMER312, &master->Flags)) {
+	dprint(DBGM_L3, master->l3->nst->cardnr, "%s: JOLLY child=%p, flg=%d\n", __FUNCTION__, master->child, test_bit(FLG_L3P_TIMER312, &master->Flags));
+			} else {
+				send_proc(master, IMSG_END_PROC, NULL);
+			}
+			break;
+		case 8:
+			if (master->selces == child->ces) {
+				cause = CAUSE_NONSELECTED_USER;
+				send_proc(master, IMSG_RELEASE_CHILDS, &cause);
+				if (test_bit(FLG_L3P_TIMER312, &master->Flags)) {
+					newl3state(master, 22);
+				} else {
+					if (!master->child)
+						send_proc(master,
+							IMSG_END_PROC, NULL);
+				}
+			}
+			break;
+		case 22:
+			if (!master->child) {
+				send_proc(master, IMSG_END_PROC, NULL);
+			}
+			break;
+	}
+	return(0);
+}
+
+static int
+send_proc(layer3_proc_t *proc, int op, void *arg)
+{
+	int		i;
+	layer3_proc_t	*selp;
+	struct _l3_msg	*l3m = arg;
+	struct _l3_msg	l3msg;
+
+	if (proc->l3 && proc->l3->debug & L3_DEB_PROC)
+		l3_debug(proc->l3, "%s: proc(%x,%d) op(%d)", __FUNCTION__,
+			proc->ces, proc->callref, op);  
+	switch(op) {
+		case IMSG_END_PROC:
+		case IMSG_END_PROC_M:
+			RemoveAllL3Timer(proc);
+			if (!proc->master && !arg) {
+				if_link(proc->l3->nst->manager,
+					(ifunc_t)proc->l3->nst->l3_manager,
+					CC_RELEASE_CR | INDICATION,
+					proc->ces | (proc->callref << 16),
+					sizeof(int), &proc->err, 0);
+			}
+			while (proc->child)
+				send_proc(proc->child, IMSG_END_PROC, NULL);
+			if (proc->next)
+				proc->next->prev = proc->prev;
+			if (proc->prev)
+				proc->prev->next = proc->next;
+			if (proc->l3 && (proc == proc->l3->proc) )
+				proc->l3->proc = proc->next;
+			if (proc->master) {
+				if (proc->master->child == proc)
+					proc->master->child = proc->next;
+				if (op == IMSG_END_PROC_M)
+					imsg_intrelease(proc->master, proc);
+			}
+			free(proc);
+			break;
+		case IMSG_L2_DATA:
+			for (i = 0; i < DATASLLEN; i++)
+				if ((l3m->mt == datastatelist[i].primitive) &&
+					((1 << proc->state) & datastatelist[i].state))
+				break;
+			if (i == DATASLLEN) {
+				if (proc->l3->debug & L3_DEB_STATE) {
+					l3_debug(proc->l3, "dss1 state %d mt %#x unhandled",
+						proc->state, l3m->mt);
+				}
+				if ((MT_RELEASE_COMPLETE != l3m->mt) && (MT_RELEASE != l3m->mt)) {
+		//			l3dss1_status_send(proc, CAUSE_NOTCOMPAT_STATE);
+				}
+			} else {
+				if (proc->l3->debug & L3_DEB_STATE) {
+					l3_debug(proc->l3, "dss1 state %d mt %x",
+						proc->state, l3m->mt);
+				}
+				datastatelist[i].rout(proc, l3m->mt, l3m->msg);
+			}
+			break;
+		case IMSG_MASTER_L2_DATA:
+			for (i = 0; i < MDATASLLEN; i++)
+				if ((l3m->mt == mdatastatelist[i].primitive) &&
+					((1 << proc->state) & mdatastatelist[i].state))
+				break;
+			if (i == MDATASLLEN) {
+				if (proc->l3->debug & L3_DEB_STATE) {
+					l3_debug(proc->l3, "dss1 state %d mt %#x unhandled",
+						proc->state, l3m->mt);
+				}
+				if ((MT_RELEASE_COMPLETE != l3m->mt) && (MT_RELEASE != l3m->mt)) {
+		//			l3dss1_status_send(proc, CAUSE_NOTCOMPAT_STATE);
+				}
+			} else {
+				if (proc->l3->debug & L3_DEB_STATE) {
+					l3_debug(proc->l3, "dss1 state %d mt %x",
+						proc->state, l3m->mt);
+				}
+				mdatastatelist[i].rout(proc, l3m->mt, l3m->msg);
+			}
+			break;
+		case IMSG_TIMER_EXPIRED:
+			i = *((int *)arg);
+			l3_debug(proc->l3, "%s: timer %x", __FUNCTION__, i);
+			l3m = &l3msg;
+			l3m->mt = CC_TIMER | (i<<8);
+			l3m->msg = NULL;
+		case IMSG_L4_DATA:
+			for (i = 0; i < DOWNSLLEN; i++)
+				if ((l3m->mt == downstatelist[i].primitive) &&
+					((1 << proc->state) & downstatelist[i].state))
+				break;
+			if (i == DOWNSLLEN) {
+				if (proc->l3->debug & L3_DEB_STATE) {
+					l3_debug(proc->l3, "dss1 state %d L4 %#x unhandled",
+						proc->state, l3m->mt);
+				}
+			} else {
+				if (proc->l3->debug & L3_DEB_STATE) {
+					l3_debug(proc->l3, "dss1 state %d L4 %x",
+						proc->state, l3m->mt);
+				}
+				if (l3m->msg)
+					downstatelist[i].rout(proc, l3m->mt,
+						l3m->msg->data);
+				else
+					downstatelist[i].rout(proc, l3m->mt,
+						NULL);
+			}
+			break;
+		case IMSG_CONNECT_IND:
+			selp = proc;
+			proc = proc->master;
+			if (!proc)
+				return(-EINVAL);
+			proc->selces = selp->ces;
+			newl3state(proc, 8);
+			return(mISDN_l3up(proc, arg));
+		case IMSG_SEL_PROC:
+			selp = find_proc(proc->child, proc->selces,
+				proc->callref);
+			i = proc->selces | (proc->callref << 16);
+			if_link(proc->l3->nst->manager, 
+				(ifunc_t)proc->l3->nst->l3_manager,
+				CC_NEW_CR | INDICATION, proc->ces |
+				(proc->callref << 16), sizeof(int), &i, 0);
+			proc->ces = proc->selces;
+			send_proc(selp, IMSG_END_PROC, NULL);
+			break;
+		case IMSG_RELEASE_CHILDS:
+			{
+				RELEASE_t	*rel;
+				char		cause[3];
+
+				cause[0] = 2;
+				cause[1] = CAUSE_LOC_PNET_LOCUSER | 0x80;
+				cause[2] = *((int *)arg) | 0x80;
+				l3msg.mt = CC_RELEASE | REQUEST;
+				l3msg.msg = alloc_msg(sizeof(RELEASE_t));
+				if (!l3msg.msg)
+					return(-ENOMEM);
+				rel = (RELEASE_t *)msg_put(l3msg.msg,
+					sizeof(RELEASE_t));
+				memset(rel, 0, sizeof(RELEASE_t));
+				rel->CAUSE = cause;
+				selp = proc->child;
+				while(selp) {
+					layer3_proc_t *next = selp->next;
+
+					send_proc(selp, IMSG_L4_DATA, &l3msg);
+					selp = next;
+				}
+				free_msg(l3msg.msg);
+			}
+			break;
+	}
+	return(0);
+}
+
+static int
+dl_data_mux(layer3_t *l3, mISDNuser_head_t *hh, msg_t *msg)
+{
+	layer3_proc_t	*proc;
+	int		ret = -EINVAL;
+	int		cr;
+	struct _l3_msg	l3m;
+
+	if (!l3)
+		return(ret);
+	dprint(DBGM_L3, l3->nst->cardnr, "%s: len(%d)\n", __FUNCTION__, msg->len);
+	dhexprint(DBGM_L3DATA, "l3 iframe:", msg->data, msg->len);
+	if (msg->len < 3) {
+		l3_debug(l3, "dss1 frame too short(%d)", msg->len);
+		free_msg(msg);
+		return(0);
+	}
+	if (msg->data[0] != PROTO_DIS_EURO) { 
+		if (l3->debug & L3_DEB_PROTERR) {
+			l3_debug(l3, "dss1%sunexpected discriminator %x message len %d",
+				(hh->prim == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
+				msg->data[0], msg->len);
+		}
+		free_msg(msg); 
+		return(0);
+	}
+	dprint(DBGM_L3, l3->nst->cardnr, "%s: dis(%x)\n", __FUNCTION__, msg->data[0]);
+	cr = getcallref(msg->data);
+	dprint(DBGM_L3, l3->nst->cardnr, "%s: cr(%x)\n", __FUNCTION__, cr);
+	if (msg->len < ((msg->data[1] & 0x0f) + 3)) {
+		l3_debug(l3, "dss1 frame too short(%d)", msg->len);
+		free_msg(msg);
+		return(0);
+	}
+	l3m.msg = msg;
+	l3m.mt = msg->data[msg->data[1] + 2];
+	if (cr == -2) {  /* wrong Callref */
+		if (l3->debug & L3_DEB_WARN)
+			l3_debug(l3, "dss1 wrong Callref");
+		free_msg(msg);
+		return(0);
+	} else if (cr == -1) {  /* Dummy Callref */
+		if (l3m.mt == MT_FACILITY) {
+			layer3_proc_t dummy;
+			memset( &dummy, 0, sizeof(layer3_proc_t));
+			dummy.l3 = l3;
+			dummy.ces = 0;
+			dummy.callref = -1;
+			l3dss1_facility(&dummy, hh->prim, msg);
+		}
+		else if (l3->debug & L3_DEB_WARN)
+			l3_debug(l3, "dss1 dummy Callref (no facility msg)");
+		free_msg(msg);
+		return(0);
+	} else if ((((msg->data[1] & 0x0f) == 1) && (0==(cr & 0x7f))) ||
+		(((msg->data[1] & 0x0f) == 2) && (0==(cr & 0x7fff)))) {
+		/* Global CallRef */
+		if (l3->debug & L3_DEB_STATE)
+			l3_debug(l3, "dss1 Global CallRef");
+//		global_handler(l3, l3m.mt, msg);
+		free_msg(msg);
+		return(0);
+	}
+	dprint(DBGM_L3, l3->nst->cardnr, "%s: mt(%x)\n", __FUNCTION__, l3m.mt);
+	proc = find_proc(l3->proc, hh->dinfo, cr);
+	dprint(DBGM_L3, l3->nst->cardnr, "%s: proc(%p)\n", __FUNCTION__, proc);
+	if (!proc) {
+		if (l3m.mt == MT_SETUP || l3m.mt == MT_RESUME) {
+			/* Setup/Resume creates a new transaction process */
+			if (msg->data[2] & 0x80) {
+				/* Setup/Resume with wrong CREF flag */
+				if (l3->debug & L3_DEB_STATE)
+					l3_debug(l3, "dss1 wrong CRef flag");
+				free_msg(msg);
+				return(0);
+			}
+			dprint(DBGM_L3, l3->nst->cardnr, "%s: %s\n", __FUNCTION__, (l3m.mt==MT_SETUP)?"MT_SETUP":"MT_RESUME");
+			if (!(proc = create_proc(l3, hh->dinfo, cr, NULL))) {
+				/* May be to answer with RELEASE_COMPLETE and
+				 * CAUSE 0x2f "Resource unavailable", but this
+				 * need a new_l3_process too ... arghh
+				 */
+				free_msg(msg);
+				return(0);
+			}
+			dprint(DBGM_L3, l3->nst->cardnr, "%s: proc(%p)\n", __FUNCTION__, proc);
+			APPEND_TO_LIST(proc, l3->proc);
+		} else {
+			dprint(DBGM_L3, l3->nst->cardnr, "%s: mt(%x) do not create proc\n", __FUNCTION__,
+				l3m.mt);
+			// TODO: it happens that a response to an outgoing setup is received after connect of another terminal. in this case we must release.
+			free_msg(msg);
+			return(0);
+		}
+	}
+	if ((proc->ces & 0xffffff00) == 0xff00) {
+		dprint(DBGM_L3, l3->nst->cardnr, "%s: master state %d found\n", __FUNCTION__,
+			proc->state);
+		msg_push(msg, mISDNUSER_HEAD_SIZE);
+		send_proc(proc, IMSG_MASTER_L2_DATA, &l3m);
+	} else
+		send_proc(proc, IMSG_L2_DATA, &l3m);
+	free_msg(msg);
+	return(0);
+}
+
+int
+l3_muxer(net_stack_t *nst, msg_t *msg)
+{
+	mISDNuser_head_t	*hh;
+	int		ret = -EINVAL;
+
+	hh = (mISDNuser_head_t *)msg->data;
+	dprint(DBGM_L3, nst->cardnr, "%s: msg len(%d)\n", __FUNCTION__, msg->len);
+	dprint(DBGM_L3, nst->cardnr, "%s: pr(%x) di(%x)\n", __FUNCTION__,
+		hh->prim, hh->dinfo);
+	msg_pull(msg, mISDNUSER_HEAD_SIZE);
+	if (hh->prim == (DL_DATA | INDICATION)) {
+		ret = dl_data_mux(nst->layer3, hh, msg); 
+	} else {
+		ret = l3_msg(nst->layer3, hh->prim, hh->dinfo, msg);
+	}
+	if (ret)
+		free_msg(msg);
+	ret = 0;
+	return(ret);
+}
+
+static int
+manager_l3(net_stack_t *nst, msg_t *msg)
+{
+	mISDNuser_head_t	*hh;
+	layer3_proc_t	*proc;
+	struct _l3_msg	l3m;
+
+	hh = (mISDNuser_head_t *)msg->data;
+	dprint(DBGM_L3, nst->cardnr, "%s: msg len(%d)\n", __FUNCTION__, msg->len);
+	dprint(DBGM_L3, nst->cardnr, "%s: pr(%x) di(%x)\n", __FUNCTION__,
+		hh->prim, hh->dinfo);
+	msg_pull(msg, mISDNUSER_HEAD_SIZE);
+	proc = find_proc(nst->layer3->proc, hh->dinfo & 0xffff,
+		(hh->dinfo>>16)& 0xffff);
+	if (!proc) {
+		switch (hh->prim) {
+			case CC_SETUP | REQUEST:
+			{
+				int l4id;
+				nst->layer3->next_cr++;
+				if (nst->feature & FEATURE_NET_CRLEN2) {
+					if (nst->layer3->next_cr>32766)
+						nst->layer3->next_cr = 1;
+				} else {
+					if (nst->layer3->next_cr>126)
+						nst->layer3->next_cr = 1;
+				}
+				proc = create_proc(nst->layer3, hh->dinfo & 0xffff,
+					nst->layer3->next_cr | 0x8000, NULL);
+				if (!proc) {
+					dprint(DBGM_L3, nst->cardnr, "%s: pr(%x) failed to create proc.\n",
+						__FUNCTION__, hh->prim);
+					free_msg(msg);
+					return(0);
+				}
+				dprint(DBGM_L3, nst->cardnr, "%s: proc(%p)\n", __FUNCTION__, proc);
+#warning testing
+#if 0
+printf("check for tei 0 active\n");
+		l2 = nst->layer2;
+		while(l2) {
+			if (l2->tei == 0 && l2->sapi == 0)
+				break;
+			l2 = l2->next;
+		}
+		if (l2) if (l2->state == ST_L2_4) {
+			p3i = create_proc(proc->l3, 0, proc->callref, proc);
+			if (!p3i) {
+				l3_debug(proc->l3, "cannot create child\n");
+				return(NULL);
+			}
+			proc = p3i;
+			
+			dprint(DBGM_L3, nst->cardnr, "%s: TEI 0 is active, so we created proc(%p)\n", __FUNCTION__, proc);
+			
+		}
+#endif
+			
+
+				APPEND_TO_LIST(proc, nst->layer3->proc);
+				l4id = proc->ces | (proc->callref << 16);
+				if_link(nst->manager, (ifunc_t)nst->l3_manager, CC_SETUP | CONFIRM, hh->dinfo, sizeof(int), &l4id, 0);
+				}
+			break;
+			case DL_ESTABLISH | REQUEST: 
+				if (nst->feature & FEATURE_NET_PTP) {
+					l3down(nst->layer3, DL_ESTABLISH | REQUEST, 0, NULL);
+					free_msg(msg);
+					return 0;
+				}
+			break;
+			default:
+			break;
+		}
+	}
+	if (!proc) {
+		dprint(DBGM_L3, nst->cardnr, "%s: pr(%x) no proc id %x found\n", __FUNCTION__,
+			hh->prim, hh->dinfo);
+		free_msg(msg);
+		return(0);
+	}
+	l3m.mt = hh->prim;
+	if (msg->len)
+		l3m.msg = msg;
+	else {
+		dprint(DBGM_L3, nst->cardnr, "%s: pr(%x) id(%x) zero param\n", __FUNCTION__,
+			hh->prim, hh->dinfo);
+		l3m.msg = NULL;
+	}
+	send_proc(proc, IMSG_L4_DATA, &l3m);
+	free_msg(msg);
+	return(0);
+}
+
+static void
+release_l3(layer3_t *l3) {
+	dprint(DBGM_L3, l3->nst->cardnr, "%s(%p)\n", __FUNCTION__, l3);
+	while(l3->proc) {
+		dprint(DBGM_L3, l3->nst->cardnr, "%s: rel_proc ces(%x)\n", __FUNCTION__,
+			l3->proc->ces);
+		send_proc(l3->proc, IMSG_END_PROC, NULL);
+	}
+	msg_queue_purge(&l3->squeue0);
+	REMOVE_FROM_LISTBASE(l3, l3->nst->layer3);
+	free(l3);
+}
+
+static int
+mISDN_l3up(layer3_proc_t *l3p, msg_t *msg)
+{
+	int err = -EINVAL;
+
+	if (!l3p || !l3p->l3 || !l3p->l3->nst)
+		return(-EINVAL);
+	if (l3p->l3->nst->l3_manager)
+		err = l3p->l3->nst->l3_manager(l3p->l3->nst->manager, msg);
+	if (err)
+		dprint(DBGM_L3, l3p->l3->nst->cardnr, "%s: error %d\n", __FUNCTION__, err);
+	return(err);
+}
+
+static int
+l3down(layer3_t *l3, u_int prim, int dinfo, msg_t *msg) {
+	int err = -EINVAL;
+
+	if (!msg)
+		err = if_link(l3->nst, l3->nst->l3_l2, prim, dinfo, 0, NULL, 0);
+	else
+		err = if_addhead(l3->nst, l3->nst->l3_l2, prim, dinfo, msg);
+	return(err);
+}
+
+static void
+send_squeue(layer3_t *l3, msg_queue_t *squeue)
+{
+	msg_t	*msg;
+
+	while((msg = msg_dequeue(&l3->squeue0))) {
+		if (l3->nst->l3_l2(l3->nst, msg))
+			free_msg(msg);
+	}
+}
+
+#warning testing
+static int
+remove_proc(layer3_proc_t **procp, int ces)
+{
+	int found = 1;
+	int any = 0;
+	layer3_proc_t *proc;
+
+	if (ces > 126)
+		return(0);
+
+	while(found) {
+		found = 0;
+		proc = *procp;
+		while(proc) {
+			dprint(DBGM_L3, proc->l3->nst->cardnr, "%s: comparing %s proc(%x) ces(%x)\n", __FUNCTION__,
+				(proc->master)?"child":"master", proc, proc->ces);
+			if (proc->ces == ces) {
+				dprint(DBGM_L3, proc->l3->nst->cardnr, "%s: found proc(%x)\n", __FUNCTION__,
+					 proc);
+				if (proc->master)
+					send_proc(proc, IMSG_END_PROC_M, NULL);
+				else
+					send_proc(proc, IMSG_END_PROC, NULL);
+				any = 1;
+				found = 1;
+				break;
+			}
+			if (proc->child) {
+				if (remove_proc(&proc->child, ces)) {
+					any = 1;
+					found = 1;
+					break;
+				}
+			}
+			proc = proc->next;
+		}
+	}
+	return(any);
+}
+
+#warning l2_state makes no sense in multipoint environment. shouldnt we use something like l2_state[ces] ?
+static int
+l3_msg(layer3_t *l3, u_int pr, int dinfo, void *arg)
+{
+	msg_t	*msg = arg, *lmsg = NULL;
+#warning testing
+	int	ces = dinfo & 0xffff;
+	dprint(DBGM_L3, l3->nst->cardnr, "%s: pr(%x) di(%x) arg(%p)\n", __FUNCTION__,
+		pr, dinfo, arg);
+
+	if (l3->nst->feature & FEATURE_NET_PTP) dinfo=0;
+
+	switch (pr) {
+		case (DL_UNITDATA | REQUEST):
+			return(l3down(l3, pr, dinfo, arg));
+		case (DL_DATA | REQUEST):
+			if (l3->l2_state0 == ST_L3_LC_ESTAB || ces > 0) {
+				return(l3down(l3, pr, dinfo, arg));
+			} else {
+				if (ces == 0) {
+					mISDN_addhead(pr, dinfo, msg);
+					msg_queue_tail(&l3->squeue0, msg);
+					l3->l2_state0 = ST_L3_LC_ESTAB_WAIT;
+					l3down(l3, DL_ESTABLISH | REQUEST, dinfo, NULL);
+					return(0);
+				}
+			}
+			break;
+		case (DL_DATA | CONFIRM):
+			break;
+		case (DL_ESTABLISH | REQUEST):
+			if (ces == 0) {
+				if (l3->l2_state0 != ST_L3_LC_ESTAB) {
+					l3down(l3, pr, dinfo, NULL);
+					l3->l2_state0 = ST_L3_LC_ESTAB_WAIT;
+				}
+			}
+			break;
+		case (DL_ESTABLISH | CONFIRM):
+			if (ces == 0) {
+				if (l3->l2_state0 != ST_L3_LC_REL_WAIT) {
+					l3->l2_state0 = ST_L3_LC_ESTAB;
+					send_squeue(l3, &l3->squeue0);
+				}
+			}
+			if (!l3->nst->l3_manager)
+				break;
+			if (!(lmsg = create_link_msg(pr, dinfo, 0, NULL, 0)))
+				break;
+			if (l3->nst->l3_manager(l3->nst->manager, lmsg))
+				free_msg(lmsg);
+			break;
+		case (DL_ESTABLISH | INDICATION):
+			if (ces == 0) {
+				if (l3->l2_state0 == ST_L3_LC_REL) {
+					l3->l2_state0 = ST_L3_LC_ESTAB;
+					send_squeue(l3, &l3->squeue0);
+				}
+			}
+			if (!l3->nst->l3_manager)
+				break;
+			if (!(lmsg = create_link_msg(pr, dinfo, 0, NULL, 0)))
+				break;
+			if (l3->nst->l3_manager(l3->nst->manager, lmsg))
+				free_msg(lmsg);
+			break;
+		case (DL_RELEASE | INDICATION):
+#warning du musst alle processe releasen CC_RELEASE!!! dies geschieht z.b. wenn man das telefon vom s0-bus abnimmt und der layer-2 dadurch zusammen bricht.
+#warning geschieht dies auch im TE-mode?
+#warning TODO DL_RELEASE | INDICATION handling; inclusiv special state 10 (T309)
+			if (ces == 0) {
+				if (l3->l2_state0 == ST_L3_LC_ESTAB) {
+					l3->l2_state0 = ST_L3_LC_REL;
+				}
+			}
+			if (!l3->nst->l3_manager)
+				break;
+			if (!(lmsg = create_link_msg(pr, dinfo, 0, NULL, 0)))
+				break;
+			if (l3->nst->l3_manager(l3->nst->manager, lmsg))
+				free_msg(lmsg);
+			remove_proc(&l3->proc, dinfo);
+			break;
+		case (DL_RELEASE | CONFIRM):
+			if (ces == 0) {
+				if (l3->l2_state0 == ST_L3_LC_REL_WAIT) {
+					l3->l2_state0 = ST_L3_LC_REL;
+				}
+			}
+			if (!l3->nst->l3_manager)
+				break;
+			if (!(lmsg = create_link_msg(pr, dinfo, 0, NULL, 0)))
+				break;
+			if (l3->nst->l3_manager(l3->nst->manager, lmsg))
+				free_msg(lmsg);
+			remove_proc(&l3->proc, dinfo);
+			break;
+		case (DL_RELEASE | REQUEST):
+			if (ces == 0) {
+				if (l3->l2_state0 == ST_L3_LC_ESTAB) {
+					l3down(l3, pr, dinfo, NULL);
+					l3->l2_state0 = ST_L3_LC_REL_WAIT;
+				}
+			}
+			break;
+	}
+	if (msg)
+		free_msg(msg);
+	return(0);
+}
+
+int Isdnl3Init(net_stack_t *nst)
+{
+	layer3_t *l3;
+
+	l3 = malloc(sizeof(layer3_t));
+	if (!l3)
+		return(-ENOMEM);
+	memset(l3, 0, sizeof(layer3_t));
+	l3->nst = nst;
+	nst->l2_l3 = l3_muxer;
+	nst->manager_l3 = manager_l3;
+	l3->debug = 0xff;
+#warning testing
+	msg_queue_init(&l3->squeue0);
+	l3->l2_state0 = ST_L3_LC_REL;
+	APPEND_TO_LIST(l3, nst->layer3);
+	return(0);
+}
+
+void cleanup_Isdnl3(net_stack_t *nst)
+{
+	if (nst->layer3) {
+		dprint(DBGM_L3, nst->cardnr, "%s: l3 list not empty\n", __FUNCTION__);
+		while(nst->layer3)
+			release_l3(nst->layer3);
+	}
+}

Added: misdn-user/trunk/i4lnet/net_l3.h
===================================================================
--- misdn-user/trunk/i4lnet/net_l3.h	                        (rev 0)
+++ misdn-user/trunk/i4lnet/net_l3.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,290 @@
+/* $Id: net_l3.h,v 1.4 2006/12/28 12:24:01 jolly Exp $
+ *
+ * Layer 3 defines
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+#ifndef NET_L3_H
+#define NET_L3_H
+
+#include "isdn_net.h"
+
+typedef struct _layer3_proc	layer3_proc_t;
+typedef struct _L3Timer L3Timer_t;
+
+struct _L3Timer {
+	layer3_proc_t		*pc;
+	itimer_t		tl;
+	int			nr;
+};
+
+struct _layer3_proc {
+	layer3_proc_t	*prev;
+	layer3_proc_t	*next;
+	layer3_proc_t	*child;
+	layer3_proc_t	*master;
+	layer3_t	*l3;
+	int		callref;
+	int		ces;
+	int		selces;
+	int		state;
+	u_long		Flags;
+	L3Timer_t	timer1;
+	L3Timer_t	timer2;
+	int		bc;
+	int             err;
+	int		cause;
+	int		hold_state;
+	u_char		obuf[MAX_DFRAME_LEN];
+	u_char		*op;
+};
+
+#define FLG_L3P_TIMER312	1
+#define FLG_L3P_TIMER303_1	2
+#define FLG_L3P_TIMER308_1	3
+#define FLG_L3P_GOTRELCOMP	4
+
+struct _layer3 {
+	layer3_t	*prev;
+	layer3_t	*next;
+	msg_queue_t	squeue0;
+	int		l2_state0;
+	int		next_cr;
+	int		debug;
+	net_stack_t	*nst;
+	layer3_proc_t	*proc;
+};
+
+static inline msg_t *l3_alloc_msg(int size)
+{
+	msg_t	*msg;
+
+	msg = alloc_msg(size+MAX_HEADER_LEN);
+	if (msg)
+		msg_reserve(msg, MAX_HEADER_LEN);
+	return(msg);
+}
+
+extern	int	Isdnl3Init(net_stack_t *);
+extern	void	cleanup_Isdnl3(net_stack_t *);
+extern	void	display_NR_IE(u_char *, char *, char *);
+
+/* l3 pointer arrays */
+
+typedef struct _ALERTING {
+	u_char *BEARER;
+	u_char *CHANNEL_ID;
+	u_char *FACILITY;
+	u_char *PROGRESS;
+	u_char *DISPLAY;
+	u_char *SIGNAL;
+	u_char *HLC;
+	u_char *USER_USER;
+	u_char *REDIR_DN;
+} ALERTING_t;
+
+typedef struct _CALL_PROCEEDING {
+	u_char *BEARER;
+	u_char *CHANNEL_ID;
+	u_char *FACILITY;
+	u_char *PROGRESS;
+	u_char *DISPLAY;
+	u_char *REDIR_DN;
+	u_char *HLC;
+} CALL_PROCEEDING_t;
+
+typedef struct _CONNECT {
+	u_char *BEARER;
+	u_char *CHANNEL_ID;
+	u_char *FACILITY;
+	u_char *PROGRESS;
+	u_char *DISPLAY;
+	u_char *DATE;
+	u_char *SIGNAL;
+	u_char *CONNECT_PN;
+	u_char *CONNECT_SUB;
+	u_char *LLC;
+	u_char *HLC;
+	u_char *USER_USER;
+	int ces;
+} CONNECT_t;
+
+typedef struct _CONNECT_ACKNOWLEDGE {
+	u_char *CHANNEL_ID;
+	u_char *DISPLAY;
+	u_char *SIGNAL;
+} CONNECT_ACKNOWLEDGE_t;
+
+typedef struct _DISCONNECT {
+	u_char *CAUSE;
+	u_char *FACILITY;
+	u_char *PROGRESS;
+	u_char *DISPLAY;
+	u_char *SIGNAL;
+	u_char *USER_USER;
+} DISCONNECT_t;
+
+typedef struct _INFORMATION {
+	u_char *COMPLETE;
+	u_char *DISPLAY;
+	u_char *KEYPAD;
+	u_char *SIGNAL;
+	u_char *CALLED_PN;
+} INFORMATION_t;
+
+typedef struct _NOTIFY {
+	u_char *BEARER;
+	u_char *NOTIFY;
+	u_char *DISPLAY;
+	u_char *REDIR_DN;
+} NOTIFY_t;
+
+typedef struct _PROGRESS {
+	u_char *BEARER;
+	u_char *CAUSE;
+	u_char *FACILITY;
+	u_char *PROGRESS;
+	u_char *DISPLAY;
+	u_char *HLC;
+} PROGRESS_t;
+
+typedef struct _RELEASE {
+	u_char *CAUSE;
+	u_char *FACILITY;
+	u_char *DISPLAY;
+	u_char *SIGNAL;
+	u_char *USER_USER;
+} RELEASE_t;
+
+typedef struct _RELEASE_COMPLETE {
+	u_char *CAUSE;
+	u_char *FACILITY;
+	u_char *DISPLAY;
+	u_char *SIGNAL;
+	u_char *USER_USER;
+} RELEASE_COMPLETE_t;
+
+typedef struct _RESUME {
+	u_char *CALL_ID;
+	u_char *FACILITY;
+	int ces;
+} RESUME_t;
+
+typedef struct _RESUME_ACKNOWLEDGE {
+	u_char *CHANNEL_ID;
+	u_char *FACILITY;
+	u_char *DISPLAY;
+} RESUME_ACKNOWLEDGE_t;
+
+typedef struct _RESUME_REJECT {
+	u_char *CAUSE;
+	u_char *DISPLAY;
+} RESUME_REJECT_t;
+
+typedef struct _SETUP {
+	u_char *COMPLETE;
+	u_char *BEARER;
+	u_char *CHANNEL_ID;
+	u_char *FACILITY;
+	u_char *PROGRESS;
+	u_char *NET_FAC;
+	u_char *DISPLAY;
+	u_char *KEYPAD;
+	u_char *SIGNAL;
+	u_char *CALLING_PN;
+	u_char *CALLING_SUB;
+	u_char *CALLED_PN;
+	u_char *CALLED_SUB;
+	u_char *REDIR_NR;
+	u_char *LLC;
+	u_char *HLC;
+	u_char *USER_USER;
+	int ces;
+} SETUP_t;
+
+typedef struct _SETUP_ACKNOWLEDGE {
+	u_char *CHANNEL_ID;
+	u_char *FACILITY;
+	u_char *PROGRESS;
+	u_char *DISPLAY;
+	u_char *SIGNAL;
+} SETUP_ACKNOWLEDGE_t;
+
+typedef struct _STATUS {
+	u_char *CAUSE;
+	u_char *CALL_STATE;
+	u_char *DISPLAY;
+} STATUS_t;
+
+typedef struct _STATUS_ENQUIRY {
+	u_char *DISPLAY;
+} STATUS_ENQUIRY_t;
+
+typedef struct _SUSPEND {
+	u_char *CALL_ID;
+	u_char *FACILITY;
+} SUSPEND_t;
+
+typedef struct _SUSPEND_ACKNOWLEDGE {
+	u_char *FACILITY;
+	u_char *DISPLAY;
+} SUSPEND_ACKNOWLEDGE_t;
+
+typedef struct _SUSPEND_REJECT {
+	u_char *CAUSE;
+	u_char *DISPLAY;
+} SUSPEND_REJECT_t;
+
+typedef struct _CONGESTION_CONTROL {
+	u_char *CONGESTION;
+	u_char *CAUSE;
+	u_char *DISPLAY;
+} CONGESTION_CONTROL_t;
+
+typedef struct _USER_INFORMATION {
+	u_char *MORE_DATA;
+	u_char *USER_USER;
+} USER_INFORMATION_t;
+
+typedef struct _RESTART {
+	u_char *CHANNEL_ID;
+	u_char *DISPLAY;
+	u_char *RESTART_IND;
+} RESTART_t;
+
+typedef struct _FACILITY {
+	u_char *FACILITY;
+	u_char *DISPLAY;
+} FACILITY_t;
+
+typedef struct _HOLD {
+	u_char *DISPLAY;
+} HOLD_t;
+
+typedef struct _HOLD_ACKNOWLEDGE {
+	u_char *CHANNEL_ID;
+	u_char *DISPLAY;
+} HOLD_ACKNOWLEDGE_t;
+
+typedef struct _HOLD_REJECT {
+	u_char *CAUSE;
+	u_char *DISPLAY;
+} HOLD_REJECT_t;
+
+typedef struct _RETRIEVE {
+	u_char *CHANNEL_ID;
+} RETRIEVE_t;
+
+typedef struct _RETRIEVE_ACKNOWLEDGE {
+	u_char *CHANNEL_ID;
+	u_char *DISPLAY;
+} RETRIEVE_ACKNOWLEDGE_t;
+
+typedef struct _RETRIEVE_REJECT {
+	u_char *CAUSE;
+	u_char *DISPLAY;
+} RETRIEVE_REJECT_t;
+
+#endif

Added: misdn-user/trunk/i4lnet/nettst.c
===================================================================
--- misdn-user/trunk/i4lnet/nettst.c	                        (rev 0)
+++ misdn-user/trunk/i4lnet/nettst.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,320 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <time.h>
+#include "isdn_net.h"
+#include "net_l2.h"
+#include "net_l3.h"
+#include "net_l4.h"
+#include "l3dss1.h"
+#include "helper.h"
+#include "bchannel.h"
+#include "tone.h"
+
+net_stack_t	kern_if;
+
+itimer_t	timer1;
+
+static void
+do_cleanup(net_stack_t *nst)
+{
+	fprintf(stderr, "%s\n", __FUNCTION__);
+	cleanup_Isdnl4(nst);
+	cleanup_Isdnl3(nst);
+	cleanup_Isdnl2(nst);
+	do_net_stack_cleanup(nst);
+}
+
+static void
+term_handler(int sig)
+{
+	pthread_t	tid;
+
+	tid = pthread_self();
+	fprintf(stderr,"signal %d received from thread %ld\n", sig, tid);
+	test_and_set_bit(FLG_KIF_TERMINATION, &kern_if.flag);
+	sem_post(&kern_if.network);
+}
+
+static int
+man_down(net_stack_t *nst, msg_t *msg)
+{
+	msg_queue_tail(&nst->wqueue, msg);
+	sem_post(&nst->network);
+	return(0);
+}
+
+static int
+do_disconnect(layer4_t *l4)
+{
+	l4->cause_loc = CAUSE_LOC_PNET_LOCUSER;
+	l4->cause_val = CAUSE_NORMAL_CLEARING;
+	l4->progress = PROGRESS_TONE;
+	if_link(l4->nst, man_down, MAN_CLEAR_CALL | REQUEST,
+		l4->channel, 0, NULL, 0);
+	return(0);
+}
+
+static int
+do_connect(layer4_t *l4)
+{
+	if_link(l4->nst, man_down, MAN_CONNECT | REQUEST,
+		l4->channel, 0, NULL, 0);
+	return(0);
+}
+
+static int
+do_alert(layer4_t *l4)
+{
+	if_link(l4->nst, man_down, MAN_ALERT | REQUEST,
+		l4->channel, 0, NULL, 0);
+	return(0);
+}
+
+static int
+clear_call(layer4_t *l4)
+{
+	if (l4->sdata) {
+		layer4_t *peer = l4->sdata;
+		
+		if (l4->cause_val) {
+			peer->cause_loc = l4->cause_loc;
+			peer->cause_val = l4->cause_val;
+		} else {
+			peer->cause_loc = CAUSE_LOC_PNET_LOCUSER;
+			peer->cause_val = CAUSE_NORMALUNSPECIFIED;
+		}
+		peer->progress = PROGRESS_TONE;
+		peer->sbuf = NULL;
+		peer->sdata = NULL;
+		peer->rdata = NULL;
+		if (peer->nst)
+			if_link(peer->nst, man_down, MAN_CLEAR_CALL |
+				REQUEST, peer->channel, 0, NULL, 0);
+	}
+	l4->sdata = NULL;
+	l4->rdata = NULL;
+	l4->sbuf = NULL;
+	return(0);
+}
+
+static int
+alert_call(layer4_t *l4)
+{
+	if (l4->sdata)
+		do_alert(l4->sdata);
+	return(0);
+}
+
+static int
+connect_call(layer4_t *l4)
+{
+	strcpy(l4->display,"connect ack");
+	if_link(l4->nst, man_down, MAN_CONNECT | RESPONSE,
+		l4->channel, 0, NULL, 0);
+	del_timer(&timer1);
+	if (l4->sdata)
+		do_connect(l4->sdata);
+	return(0);
+}
+
+static int
+route_call(layer4_t *l4)
+{
+	layer4_t	*newl4;
+
+	fprintf(stderr, "%s: msn ", __FUNCTION__);
+	display_NR_IE(l4->msn);
+	fprintf(stderr, "%s:  nr ", __FUNCTION__);
+	display_NR_IE(l4->nr);
+	if (l4->usednr->typ == NR_TYPE_INTERN) {
+		newl4 = get_free_channel(&kern_if, -1, NULL);
+		if (!newl4) {
+			l4->cause_loc = CAUSE_LOC_PNET_LOCUSER;
+			l4->cause_val = CAUSE_USER_BUSY;
+			l4->progress = PROGRESS_TONE;
+			if_link(l4->nst, man_down, MAN_CLEAR_CALL | REQUEST,
+				l4->channel, 0, NULL, 0);
+			return(0);
+		}
+		l4->sdata = newl4;
+		l4->rdata = newl4;
+		newl4->sdata = l4;
+		newl4->rdata = l4;
+		l4->sbuf = &newl4->rbuf;
+		newl4->sbuf = &l4->rbuf;
+		newl4->msn[0] = l4->usednr->len +1;
+		newl4->msn[1] = 0x81;
+		memcpy(&newl4->msn[2], l4->usednr->nr, l4->usednr->len);
+		if (l4->msn[0])
+			memcpy(newl4->nr, l4->msn, l4->msn[0] + 1);
+		newl4->l1_prot = ISDN_PID_L1_B_64TRANS;
+		if_link(newl4->nst, man_down, MAN_SETUP | REQUEST,
+			newl4->channel, 0, NULL, 0);
+	} else if (l4->usednr->typ == NR_TYPE_AUDIO) {
+		l4->sdata = NULL;
+		l4->rdata = NULL;
+		strcpy(l4->display,"connect to AUDIO");
+		do_connect(l4);
+		l4->display[0] = 0;
+		deactivate_bchannel(l4);
+		setup_bchannel_rawdev(l4);
+		activate_bchannel(l4);
+	} else if (l4->usednr->typ == NR_TYPE_VOIP) {
+		l4->sdata = NULL;
+		l4->rdata = NULL;
+		sprintf(l4->display,"calling %s", l4->usednr->name);
+		do_alert(l4);
+		sprintf(l4->display,"connect to %s", l4->usednr->name);
+		do_connect(l4);
+		l4->display[0] = 0;
+		deactivate_bchannel(l4);
+		setup_bchannel_rawdev(l4);
+		activate_bchannel(l4);
+	}
+	return(0);
+}
+
+static int
+manager(net_stack_t *nst, msg_t *msg) {
+	mISDNuser_head_t	*hh;
+	layer4_t	*l4;
+
+	if (!msg)
+		return(-EINVAL);
+	hh = (mISDNuser_head_t *)msg->data;
+	msg_pull(msg, mISDN_HEAD_SIZE);
+	fprintf(stderr, "%s: prim(%x) msg->len(%d)\n", __FUNCTION__,
+		hh->prim, msg->len);
+	if (hh->dinfo == 1) {
+		l4 = &nst->layer4[0];
+	} else if (hh->dinfo == 2) {
+		l4 = &nst->layer4[1];
+	} else {
+		return(-EINVAL);
+	}
+	switch(hh->prim) {
+		case MAN_SETUP | INDICATION:
+			fprintf(stderr, "%s: setup id(%x)\n", __FUNCTION__,
+				hh->dinfo);
+			route_call(l4);
+			break;
+		case MAN_ALERT | INDICATION:
+			fprintf(stderr, "%s: connect id(%x)\n", __FUNCTION__,
+				hh->dinfo);
+			alert_call(l4);
+			break;
+		case MAN_CONNECT | INDICATION:
+			fprintf(stderr, "%s: connect id(%x)\n", __FUNCTION__,
+				hh->dinfo);
+			connect_call(l4);
+			break;
+		case MAN_CLEAR_CALL | INDICATION:
+			fprintf(stderr, "%s: clear call id(%x)\n", __FUNCTION__,
+				hh->dinfo);
+			clear_call(l4);
+			break;
+		default:
+			fprintf(stderr, "%s: unhandled prim(%x) msg->len(%d)\n", __FUNCTION__,
+				hh->prim, msg->len);
+			break;
+	}
+	free_msg(msg);
+	return(0);
+}
+
+
+int main(argc,argv)
+int argc;
+char *argv[];
+
+{
+	int		ret, *retp;
+	nr_list_t	*nr1,*nr2,*nr3,*nr4,*nr5;
+	layer4_t	*l4;
+	if_action_t	mISDNrd,*hrd;
+
+	
+	nr1 = malloc(sizeof(nr_list_t));
+	nr2 = malloc(sizeof(nr_list_t));
+	nr3 = malloc(sizeof(nr_list_t));
+	nr4 = malloc(sizeof(nr_list_t));
+	nr5 = malloc(sizeof(nr_list_t));
+	memset(nr1, 0, sizeof(nr_list_t));
+	memset(nr2, 0, sizeof(nr_list_t));
+	memset(nr3, 0, sizeof(nr_list_t));
+	memset(nr4, 0, sizeof(nr_list_t));
+	memset(nr5, 0, sizeof(nr_list_t));
+	nr1->len = 5;
+	strcpy(nr1->nr,"12345");
+	nr1->typ = NR_TYPE_INTERN;
+	nr2->len = 4;
+	strcpy(nr2->nr,"4566");
+	nr2->typ = NR_TYPE_INTERN;
+	nr3->len = 3;
+	strcpy(nr3->nr,"789");
+	nr3->typ = NR_TYPE_AUDIO;
+	nr4->len = 3;
+	strcpy(nr4->nr,"147");
+	strcpy(nr4->name, "pingi2");
+	nr4->typ = NR_TYPE_VOIP;
+	nr5->len = 3;
+	strcpy(nr5->nr,"258");
+	strcpy(nr5->name, "pingi2");
+	nr5->typ = NR_TYPE_VOIP;
+	msg_init();
+	ret = do_net_stack_setup(&kern_if);
+	if (ret) {
+		fprintf(stderr, "error in do_net_stack_setup %d\n", ret);
+		return(0);
+	}
+	APPEND_TO_LIST(nr1, kern_if.nrlist);
+	APPEND_TO_LIST(nr2, kern_if.nrlist);
+	APPEND_TO_LIST(nr3, kern_if.nrlist);
+	APPEND_TO_LIST(nr4, kern_if.nrlist);
+	APPEND_TO_LIST(nr5, kern_if.nrlist);
+	Isdnl2Init(&kern_if);
+	Isdnl3Init(&kern_if);
+	Isdnl4Init(&kern_if);
+	kern_if.l4_mgr = manager;
+	init_bhandler(&kern_if);
+	memset(&timer1, 0, sizeof(itimer_t));
+	signal(SIGTERM, term_handler);
+	signal(SIGINT, term_handler);
+	signal(SIGPIPE, term_handler);
+	if (argc>1) {
+		l4 = get_free_channel(&kern_if, -1, NULL);
+		if (l4) {
+			l4->msn[0] = 4;
+			l4->msn[1] = 0x81;
+			l4->msn[2] = '8';
+			l4->msn[3] = '8';
+			l4->msn[4] = '8';
+			
+			l4->nr[0] = 4;
+			l4->nr[1] = 0x81;
+			l4->nr[2] = '1';
+			l4->nr[3] = '2';
+			l4->nr[4] = '3';
+			l4->l1_prot = ISDN_PID_L1_B_64TRANS;
+			if_link(l4->nst, man_down, MAN_SETUP | REQUEST,
+				l4->channel, 0, NULL, 0);
+			del_timer(&timer1);
+			timer1.function = (void *)do_disconnect;
+			timer1.data = (long)l4;
+			init_timer(&timer1, &kern_if);
+			timer1.expires = 8000;
+			add_timer(&timer1);
+		}
+	}
+	hrd = &mISDNrd;
+	memset(hrd, 0, sizeof(if_action_t));
+	hrd->nst = &kern_if;
+	hrd->fd = kern_if.device;
+	hrd->function = do_net_read;
+	APPEND_TO_LIST(hrd, kern_if.rd);
+	retp = do_netthread(&kern_if);
+	fprintf(stderr, "do_main_loop returns(%p)\n", retp);
+	do_cleanup(&kern_if);
+	return(0);
+}

Added: misdn-user/trunk/i4lnet/sndloop.c
===================================================================
--- misdn-user/trunk/i4lnet/sndloop.c	                        (rev 0)
+++ misdn-user/trunk/i4lnet/sndloop.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,145 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <linux/soundcard.h>
+
+unsigned char ulaw_to_Alaw[256] = {
+     0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
+     0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
+     0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
+     0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
+     0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02,
+     0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x1a,
+     0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12,
+     0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x6b,
+     0x68, 0x69, 0x6e, 0x6f, 0x6c, 0x6d, 0x62, 0x63,
+     0x60, 0x61, 0x66, 0x67, 0x64, 0x65, 0x7b, 0x79,
+     0x7e, 0x7f, 0x7c, 0x7d, 0x72, 0x73, 0x70, 0x71,
+     0x76, 0x77, 0x74, 0x75, 0x4b, 0x49, 0x4f, 0x4d,
+     0x42, 0x43, 0x40, 0x41, 0x46, 0x47, 0x44, 0x45,
+     0x5a, 0x5b, 0x58, 0x59, 0x5e, 0x5f, 0x5c, 0x5d,
+     0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51,
+     0x56, 0x56, 0x57, 0x57, 0x54, 0x54, 0x55, 0xd5,
+     0xaa, 0xab, 0xa8, 0xa9, 0xae, 0xaf, 0xac, 0xad,
+     0xa2, 0xa3, 0xa0, 0xa1, 0xa6, 0xa7, 0xa4, 0xa5,
+     0xba, 0xbb, 0xb8, 0xb9, 0xbe, 0xbf, 0xbc, 0xbd,
+     0xb2, 0xb3, 0xb0, 0xb1, 0xb6, 0xb7, 0xb4, 0xb5,
+     0x8b, 0x88, 0x89, 0x8e, 0x8f, 0x8c, 0x8d, 0x82,
+     0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85, 0x9a,
+     0x9b, 0x98, 0x99, 0x9e, 0x9f, 0x9c, 0x9d, 0x92,
+     0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, 0xeb,
+     0xe8, 0xe9, 0xee, 0xef, 0xec, 0xed, 0xe2, 0xe3,
+     0xe0, 0xe1, 0xe6, 0xe7, 0xe4, 0xe5, 0xfb, 0xf9,
+     0xfe, 0xff, 0xfc, 0xfd, 0xf2, 0xf3, 0xf0, 0xf1,
+     0xf6, 0xf7, 0xf4, 0xf5, 0xcb, 0xc9, 0xcf, 0xcd,
+     0xc2, 0xc3, 0xc0, 0xc1, 0xc6, 0xc7, 0xc4, 0xc5,
+     0xda, 0xdb, 0xd8, 0xd9, 0xde, 0xdf, 0xdc, 0xdd,
+     0xd2, 0xd2, 0xd3, 0xd3, 0xd0, 0xd0, 0xd1, 0xd1,
+     0xd6, 0xd6, 0xd7, 0xd7, 0xd4, 0xd4, 0xd5, 0xd5,
+    
+};
+
+unsigned char Alaw_to_ulaw[256] = {
+     0x29, 0x2a, 0x27, 0x28, 0x2d, 0x2e, 0x2b, 0x2c,
+     0x21, 0x22, 0x1f, 0x20, 0x25, 0x26, 0x23, 0x24,
+     0x39, 0x3a, 0x37, 0x38, 0x3d, 0x3e, 0x3b, 0x3c,
+     0x31, 0x32, 0x2f, 0x30, 0x35, 0x36, 0x33, 0x34,
+     0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
+     0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
+     0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
+     0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
+     0x62, 0x63, 0x60, 0x61, 0x66, 0x67, 0x64, 0x65,
+     0x5d, 0x5d, 0x5c, 0x5c, 0x5f, 0x5f, 0x5e, 0x5e,
+     0x74, 0x76, 0x70, 0x72, 0x7c, 0x7e, 0x78, 0x7a,
+     0x6a, 0x6b, 0x68, 0x69, 0x6e, 0x6f, 0x6c, 0x6d,
+     0x48, 0x49, 0x46, 0x47, 0x4c, 0x4d, 0x4a, 0x4b,
+     0x40, 0x41, 0x3f, 0x3f, 0x44, 0x45, 0x42, 0x43,
+     0x56, 0x57, 0x54, 0x55, 0x5a, 0x5b, 0x58, 0x59,
+     0x4f, 0x4f, 0x4e, 0x4e, 0x52, 0x53, 0x50, 0x51,
+     0xa9, 0xaa, 0xa7, 0xa8, 0xad, 0xae, 0xab, 0xac,
+     0xa1, 0xa2, 0x9f, 0xa0, 0xa5, 0xa6, 0xa3, 0xa4,
+     0xb9, 0xba, 0xb7, 0xb8, 0xbd, 0xbe, 0xbb, 0xbc,
+     0xb1, 0xb2, 0xaf, 0xb0, 0xb5, 0xb6, 0xb3, 0xb4,
+     0x8a, 0x8b, 0x88, 0x89, 0x8e, 0x8f, 0x8c, 0x8d,
+     0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85,
+     0x9a, 0x9b, 0x98, 0x99, 0x9e, 0x9f, 0x9c, 0x9d,
+     0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95,
+     0xe2, 0xe3, 0xe0, 0xe1, 0xe6, 0xe7, 0xe4, 0xe5,
+     0xdd, 0xdd, 0xdc, 0xdc, 0xdf, 0xdf, 0xde, 0xde,
+     0xf4, 0xf6, 0xf0, 0xf2, 0xfc, 0xfe, 0xf8, 0xfa,
+     0xea, 0xeb, 0xe8, 0xe9, 0xee, 0xef, 0xec, 0xed,
+     0xc8, 0xc9, 0xc6, 0xc7, 0xcc, 0xcd, 0xca, 0xcb,
+     0xc0, 0xc1, 0xbf, 0xbf, 0xc4, 0xc5, 0xc2, 0xc3,
+     0xd6, 0xd7, 0xd4, 0xd5, 0xda, 0xdb, 0xd8, 0xd9,
+     0xcf, 0xcf, 0xce, 0xce, 0xd2, 0xd3, 0xd0, 0xd1,
+};
+
+
+int main(argc,argv)
+int argc;
+char *argv[];
+{
+	int	audio_out;
+	int	mISDN_in;
+	int	format;
+	int	cnt, wcnt, i;
+	int	n,sel;
+	fd_set  fdr;
+	unsigned char buf[128];
+
+	if (argc<=1)
+		exit(1);
+	audio_out = open("/dev/audio", O_WRONLY | O_NONBLOCK);
+	if (0 > audio_out) {
+		fprintf(stderr, "cannot open /dev/audio for write:%s\n",
+			strerror(errno));
+		exit(1);
+	}
+	mISDN_in = open(argv[1], O_RDONLY | O_NONBLOCK);
+	if (0 > mISDN_in) {
+		close(audio_out);
+		fprintf(stderr, "cannot open %s for read:%s\n",
+			argv[1], strerror(errno));
+		exit(1);
+	}
+	format = AFMT_MU_LAW;
+	fprintf(stdout, "audio format %x\n", format);
+	if (ioctl(audio_out, SNDCTL_DSP_SETFMT, &format) == -1) {
+		fprintf(stderr, "ioctl SNDCTL_DSP_SETFMT %s\n",
+			strerror(errno));
+	} else
+		fprintf(stdout, "audio format %x\n", format);
+	while(1) {
+		cnt = read(mISDN_in, buf, 128);
+		fprintf(stdout,	"mISDN_in %d bytes\n", cnt);
+		if (cnt>0) {
+			for (i=0;i<cnt;i++)
+				buf[i] = Alaw_to_ulaw[buf[i]];
+			wcnt = write(audio_out, buf, cnt);
+			fprintf(stdout, "audio_out%d bytes\n", wcnt);
+		} else if (errno == EAGAIN) {
+			FD_ZERO(&fdr);
+			FD_SET(mISDN_in, &fdr);
+			n = mISDN_in;
+			n++;
+			sel = select(n, &fdr, NULL, NULL, NULL);
+			if (sel<1) {
+				fprintf(stdout, "sel %d : %s\n",
+					sel, strerror(errno)); 
+				break;
+			}
+		} else {
+			fprintf(stdout, "mISDN_in: %s\n",
+				strerror(errno));
+			break;
+		}
+	}
+	close(audio_out);
+	close(mISDN_in);
+}

Added: misdn-user/trunk/i4lnet/sndloop2.c
===================================================================
--- misdn-user/trunk/i4lnet/sndloop2.c	                        (rev 0)
+++ misdn-user/trunk/i4lnet/sndloop2.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,145 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <linux/soundcard.h>
+
+unsigned char ulaw_to_Alaw[256] = {
+     0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
+     0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
+     0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
+     0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
+     0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02,
+     0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x1a,
+     0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12,
+     0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x6b,
+     0x68, 0x69, 0x6e, 0x6f, 0x6c, 0x6d, 0x62, 0x63,
+     0x60, 0x61, 0x66, 0x67, 0x64, 0x65, 0x7b, 0x79,
+     0x7e, 0x7f, 0x7c, 0x7d, 0x72, 0x73, 0x70, 0x71,
+     0x76, 0x77, 0x74, 0x75, 0x4b, 0x49, 0x4f, 0x4d,
+     0x42, 0x43, 0x40, 0x41, 0x46, 0x47, 0x44, 0x45,
+     0x5a, 0x5b, 0x58, 0x59, 0x5e, 0x5f, 0x5c, 0x5d,
+     0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51,
+     0x56, 0x56, 0x57, 0x57, 0x54, 0x54, 0x55, 0xd5,
+     0xaa, 0xab, 0xa8, 0xa9, 0xae, 0xaf, 0xac, 0xad,
+     0xa2, 0xa3, 0xa0, 0xa1, 0xa6, 0xa7, 0xa4, 0xa5,
+     0xba, 0xbb, 0xb8, 0xb9, 0xbe, 0xbf, 0xbc, 0xbd,
+     0xb2, 0xb3, 0xb0, 0xb1, 0xb6, 0xb7, 0xb4, 0xb5,
+     0x8b, 0x88, 0x89, 0x8e, 0x8f, 0x8c, 0x8d, 0x82,
+     0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85, 0x9a,
+     0x9b, 0x98, 0x99, 0x9e, 0x9f, 0x9c, 0x9d, 0x92,
+     0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, 0xeb,
+     0xe8, 0xe9, 0xee, 0xef, 0xec, 0xed, 0xe2, 0xe3,
+     0xe0, 0xe1, 0xe6, 0xe7, 0xe4, 0xe5, 0xfb, 0xf9,
+     0xfe, 0xff, 0xfc, 0xfd, 0xf2, 0xf3, 0xf0, 0xf1,
+     0xf6, 0xf7, 0xf4, 0xf5, 0xcb, 0xc9, 0xcf, 0xcd,
+     0xc2, 0xc3, 0xc0, 0xc1, 0xc6, 0xc7, 0xc4, 0xc5,
+     0xda, 0xdb, 0xd8, 0xd9, 0xde, 0xdf, 0xdc, 0xdd,
+     0xd2, 0xd2, 0xd3, 0xd3, 0xd0, 0xd0, 0xd1, 0xd1,
+     0xd6, 0xd6, 0xd7, 0xd7, 0xd4, 0xd4, 0xd5, 0xd5,
+    
+};
+
+unsigned char Alaw_to_ulaw[256] = {
+     0x29, 0x2a, 0x27, 0x28, 0x2d, 0x2e, 0x2b, 0x2c,
+     0x21, 0x22, 0x1f, 0x20, 0x25, 0x26, 0x23, 0x24,
+     0x39, 0x3a, 0x37, 0x38, 0x3d, 0x3e, 0x3b, 0x3c,
+     0x31, 0x32, 0x2f, 0x30, 0x35, 0x36, 0x33, 0x34,
+     0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
+     0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
+     0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
+     0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
+     0x62, 0x63, 0x60, 0x61, 0x66, 0x67, 0x64, 0x65,
+     0x5d, 0x5d, 0x5c, 0x5c, 0x5f, 0x5f, 0x5e, 0x5e,
+     0x74, 0x76, 0x70, 0x72, 0x7c, 0x7e, 0x78, 0x7a,
+     0x6a, 0x6b, 0x68, 0x69, 0x6e, 0x6f, 0x6c, 0x6d,
+     0x48, 0x49, 0x46, 0x47, 0x4c, 0x4d, 0x4a, 0x4b,
+     0x40, 0x41, 0x3f, 0x3f, 0x44, 0x45, 0x42, 0x43,
+     0x56, 0x57, 0x54, 0x55, 0x5a, 0x5b, 0x58, 0x59,
+     0x4f, 0x4f, 0x4e, 0x4e, 0x52, 0x53, 0x50, 0x51,
+     0xa9, 0xaa, 0xa7, 0xa8, 0xad, 0xae, 0xab, 0xac,
+     0xa1, 0xa2, 0x9f, 0xa0, 0xa5, 0xa6, 0xa3, 0xa4,
+     0xb9, 0xba, 0xb7, 0xb8, 0xbd, 0xbe, 0xbb, 0xbc,
+     0xb1, 0xb2, 0xaf, 0xb0, 0xb5, 0xb6, 0xb3, 0xb4,
+     0x8a, 0x8b, 0x88, 0x89, 0x8e, 0x8f, 0x8c, 0x8d,
+     0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85,
+     0x9a, 0x9b, 0x98, 0x99, 0x9e, 0x9f, 0x9c, 0x9d,
+     0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95,
+     0xe2, 0xe3, 0xe0, 0xe1, 0xe6, 0xe7, 0xe4, 0xe5,
+     0xdd, 0xdd, 0xdc, 0xdc, 0xdf, 0xdf, 0xde, 0xde,
+     0xf4, 0xf6, 0xf0, 0xf2, 0xfc, 0xfe, 0xf8, 0xfa,
+     0xea, 0xeb, 0xe8, 0xe9, 0xee, 0xef, 0xec, 0xed,
+     0xc8, 0xc9, 0xc6, 0xc7, 0xcc, 0xcd, 0xca, 0xcb,
+     0xc0, 0xc1, 0xbf, 0xbf, 0xc4, 0xc5, 0xc2, 0xc3,
+     0xd6, 0xd7, 0xd4, 0xd5, 0xda, 0xdb, 0xd8, 0xd9,
+     0xcf, 0xcf, 0xce, 0xce, 0xd2, 0xd3, 0xd0, 0xd1,
+};
+
+//#define AUDIOF	"/usr/share/sounds/au/linus-english.au"
+#define AUDIOF "/dev/audio"
+int main(argc,argv)
+int argc;
+char *argv[];
+{
+	int	audio_in;
+	int	mISDN_out;
+	int	format;
+	int	cnt, wcnt, i;
+	int	n,sel;
+	fd_set  fdw;
+	unsigned char buf[128];
+
+	if (argc<=1)
+		exit(1);
+	audio_in = open(AUDIOF, O_RDONLY);
+	if (0 > audio_in) {
+		fprintf(stderr, "cannot open " AUDIOF " for read:%s\n",
+			strerror(errno));
+		exit(1);
+	}
+	mISDN_out = open(argv[1], O_WRONLY | O_NONBLOCK);
+	if (0 > mISDN_out) {
+		close(audio_in);
+		fprintf(stderr, "cannot open %s for write:%s\n",
+			argv[1], strerror(errno));
+		exit(1);
+	}
+	while(1) {
+		cnt = read(audio_in, buf, 128);
+		fprintf(stdout,	"audio_in %d bytes\n", cnt);
+		if (cnt>0) {
+			for (i=0;i<cnt;i++)
+				buf[i] = ulaw_to_Alaw[buf[i]];
+			wcnt = write(mISDN_out, buf, cnt);
+			fprintf(stdout, "mISDN_out%d bytes\n", wcnt);
+			if (wcnt>0) {
+				fprintf(stdout, "mISDN_out%d bytes\n", wcnt);
+			} else if (errno == EAGAIN) {
+				FD_ZERO(&fdw);
+				FD_SET(mISDN_out, &fdw);
+				n = mISDN_out;
+				n++;
+				sel = select(n, NULL, &fdw, NULL, NULL);
+				if (sel<1) {
+					fprintf(stdout, "sel %d : %s\n",
+						sel, strerror(errno)); 
+					break;
+				}
+			} else {
+				fprintf(stdout, "mISDN_out: %s\n",
+					strerror(errno));
+			}
+		} else {
+			fprintf(stdout, "audio_in: %s\n",
+				strerror(errno));
+			break;
+		}
+	}
+	close(audio_in);
+	close(mISDN_out);
+}

Added: misdn-user/trunk/i4lnet/tei.c
===================================================================
--- misdn-user/trunk/i4lnet/tei.c	                        (rev 0)
+++ misdn-user/trunk/i4lnet/tei.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,443 @@
+/* $Id: tei.c,v 1.5 2006/07/18 13:50:03 crich Exp $
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ *		This file is (c) under GNU PUBLIC LICENSE
+ *		For changes and modifications please read
+ *		../../../Documentation/isdn/mISDN.cert
+ *
+ */
+#define __NO_VERSION__
+#include <stdlib.h>
+#include "net_l2.h"
+// #include "helper.h"
+// #include "debug.h"
+// #include <linux/random.h>
+
+const char *tei_revision = "$Revision: 1.5 $";
+
+#define ID_REQUEST	1
+#define ID_ASSIGNED	2
+#define ID_DENIED	3
+#define ID_CHK_REQ	4
+#define ID_CHK_RES	5
+#define ID_REMOVE	6
+#define ID_VERIFY	7
+
+#define TEI_ENTITY_ID	0xf
+
+enum {
+	ST_TEI_NOP,
+	ST_TEI_REMOVE,
+	ST_TEI_IDVERIFY,
+};
+
+#define TEI_STATE_COUNT (ST_TEI_IDVERIFY+1)
+
+static char *strTeiState[] =
+{
+	"ST_TEI_NOP",
+	"ST_TEI_REMOVE",
+	"ST_TEI_IDVERIFY",
+};
+
+enum {
+	EV_IDREQ,
+	EV_ASSIGN,
+	EV_ASSIGN_REQ,
+	EV_CHECK_RES,
+	EV_CHECK_REQ,
+	EV_REMOVE,
+	EV_VERIFY,
+	EV_T201,
+};
+
+#define TEI_EVENT_COUNT (EV_T201+1)
+
+static char *strTeiEvent[] =
+{
+	"EV_IDREQ",
+	"EV_ASSIGN",
+	"EV_ASSIGN_REQ",
+	"EV_CHECK_RES",
+	"EV_CHECK_REQ",
+	"EV_REMOVE",
+	"EV_VERIFY",
+	"EV_T201",
+};
+
+static layer2_t
+*new_tei_req(net_stack_t *nst)
+{
+	layer2_t	*l2;
+	int		tei;
+
+	for (tei=64;tei<127;tei++) {
+		l2 = nst->layer2;
+		while(l2) {
+			if (l2->tei == tei)
+				break;
+			l2 = l2->next;
+		}
+		if (!l2)
+			break;
+	}
+	if (tei==127) /* all tei in use */
+		return(NULL);
+	l2 = new_dl2(nst, tei);
+	return(l2);
+}
+
+unsigned int
+random_ri(void)
+{
+	long int x;
+
+	x = random();
+	return (x & 0xffff);
+}
+
+static layer2_t *
+find_tei(net_stack_t *nst, int tei)
+{
+	layer2_t	*l2;
+
+	l2 = nst->layer2;
+	while(l2) {
+		if (l2->tei == tei)
+			break;
+		l2 = l2->next;
+	}
+	return(l2);
+}
+
+static void
+put_tei_msg(teimgr_t *tm, u_char m_id, unsigned int ri, u_char tei)
+{
+	msg_t *msg;
+	u_char bp[8];
+
+	bp[0] = (TEI_SAPI << 2);
+	if (test_bit(FLG_LAPD_NET, &tm->l2->flag))
+		bp[0] |= 2; /* CR:=1 for net command */
+	bp[1] = (GROUP_TEI << 1) | 0x1;
+	bp[2] = UI;
+	bp[3] = TEI_ENTITY_ID;
+	bp[4] = ri >> 8;
+	bp[5] = ri & 0xff;
+	bp[6] = m_id;
+	bp[7] = (tei << 1) | 1;
+	msg = create_link_msg(MDL_UNITDATA | REQUEST, DINFO_SKB, 8, bp, 0);
+	if (!msg) {
+		dprint(DBGM_TEI, -1, "mISDN: No msg for TEI manager\n");
+		return;
+	}
+	if (tei_l2(tm->l2, msg))
+		free_msg(msg);
+}
+
+static void
+tei_assign_req(struct FsmInst *fi, int event, void *arg)
+{
+	teimgr_t *tm = fi->userdata;
+	u_char *dp = arg;
+
+	if (tm->l2->tei == -1) {
+		tm->tei_m.printdebug(&tm->tei_m,
+			"net tei assign request without tei");
+		return;
+	}
+	tm->ri = ((unsigned int) *dp++ << 8);
+	tm->ri += *dp++;
+	if (tm->debug)
+		tm->tei_m.printdebug(&tm->tei_m,
+			"net assign request ri %d teim %d", tm->ri, *dp);
+	put_tei_msg(tm, ID_ASSIGNED, tm->ri, tm->l2->tei);
+	FsmChangeState(fi, ST_TEI_NOP);
+}
+
+static void
+tei_id_chk_res(struct FsmInst *fi, int event, void *arg)
+{
+	teimgr_t *tm = fi->userdata;
+	int	*ri = arg;
+
+	
+	if (tm->debug)
+		tm->tei_m.printdebug(fi, "identity %d check response ri %x/%x",
+			tm->l2->tei, *ri, tm->ri);
+	if (tm->ri != -1) {
+		FsmDelTimer(&tm->t201, 4);
+		tm->tei_m.printdebug(fi, "duplicat %d response", tm->l2->tei);
+		tm->val = tm->l2->tei;
+		put_tei_msg(tm, ID_REMOVE, 0, tm->val);
+		FsmAddTimer(&tm->t201, tm->T201, EV_T201, NULL, 2);
+		FsmChangeState(&tm->tei_m, ST_TEI_REMOVE);
+	} else
+		tm->ri = *ri;
+}
+
+static void
+tei_id_remove(struct FsmInst *fi, int event, void *arg)
+{
+	teimgr_t	*tm = fi->userdata;
+	int		*tei = arg;
+
+	if (tm->debug)
+		tm->tei_m.printdebug(fi, "identity remove tei %d/%d", *tei, tm->l2->tei);
+	tm->val = *tei;
+	put_tei_msg(tm, ID_REMOVE, 0, tm->val);
+	FsmAddTimer(&tm->t201, tm->T201, EV_T201, NULL, 2);
+	FsmChangeState(&tm->tei_m, ST_TEI_REMOVE);
+}
+
+static void
+tei_id_verify(struct FsmInst *fi, int event, void *arg)
+{
+	teimgr_t *tm = fi->userdata;
+
+	if (tm->debug)
+		tm->tei_m.printdebug(fi, "id verify request for tei %d",
+			tm->l2->tei);
+	tm->ri = -1;
+	put_tei_msg(tm, ID_CHK_REQ, 0, tm->l2->tei);
+	FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY);
+	test_and_set_bit(FLG_TEI_T201_1, &tm->l2->flag);
+	FsmAddTimer(&tm->t201, tm->T201, EV_T201, NULL, 2);
+}
+
+static void
+tei_id_remove_tout(struct FsmInst *fi, int event, void *arg)
+{
+	teimgr_t *tm = fi->userdata;
+
+	if (tm->debug)
+		tm->tei_m.printdebug(fi, "remove req(2) tei %d",
+			tm->l2->tei);
+	put_tei_msg(tm, ID_REMOVE, 0, tm->val);
+	FsmChangeState(fi, ST_TEI_NOP);
+}
+
+static void
+tei_id_ver_tout(struct FsmInst *fi, int event, void *arg)
+{
+	teimgr_t *tm = fi->userdata;
+
+	if (tm->debug)
+		tm->tei_m.printdebug(fi, "verify tout tei %d",
+			tm->l2->tei);
+	if (test_and_clear_bit(FLG_TEI_T201_1, &tm->l2->flag)) {
+		put_tei_msg(tm, ID_CHK_REQ, 0, tm->l2->tei);
+		tm->ri = -1;
+		FsmAddTimer(&tm->t201, tm->T201, EV_T201, NULL, 3);
+	} else {
+		FsmChangeState(fi, ST_TEI_NOP);
+		if (tm->ri == -1) {
+			tm->tei_m.printdebug(fi, "tei %d check no response",
+				tm->l2->tei);
+			// remove tei
+		} else
+			tm->tei_m.printdebug(fi, "tei %d check ok",
+				tm->l2->tei);
+	}
+}
+
+int
+l2_tei(teimgr_t *tm, msg_t *msg)
+{
+	mISDNuser_head_t	*hh;
+	int		ret = -EINVAL;
+
+	if (!tm || !msg)
+		return(ret);
+	hh = (mISDNuser_head_t *)msg->data;
+	dprint(DBGM_TEI, -1, "%s: prim(%x)\n", __FUNCTION__, hh->prim);
+	if (msg->len < mISDN_FRAME_MIN)
+		return(ret);
+	switch(hh->prim) {
+	    case (MDL_REMOVE | INDICATION):
+		FsmEvent(&tm->tei_m, EV_REMOVE, &hh->dinfo);
+		break;
+	    case (MDL_ERROR | REQUEST):
+	    	if (!test_bit(FLG_FIXED_TEI, &tm->l2->flag))
+			FsmEvent(&tm->tei_m, EV_VERIFY, NULL);
+		break;
+	}
+	free_msg(msg);
+	return(0);
+}
+
+static void
+tei_debug(struct FsmInst *fi, char *fmt, ...)
+{
+	teimgr_t	*tm = fi->userdata;
+	char		tbuf[128];
+	va_list 	args;
+
+	va_start(args, fmt);
+	vsprintf(tbuf, fmt, args);
+	dprint(DBGM_L2, -1, "tei%d %s\n", tm->l2->tei, tbuf);
+	va_end(args);
+}
+
+static struct FsmNode TeiFnList[] =
+{
+	{ST_TEI_NOP, EV_ASSIGN_REQ, tei_assign_req},
+	{ST_TEI_NOP, EV_VERIFY, tei_id_verify},
+	{ST_TEI_NOP, EV_REMOVE, tei_id_remove},
+	{ST_TEI_REMOVE, EV_T201, tei_id_remove_tout},
+	{ST_TEI_IDVERIFY, EV_T201, tei_id_ver_tout},
+	{ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove},
+	{ST_TEI_IDVERIFY, EV_CHECK_RES, tei_id_chk_res},
+};
+
+#define TEI_FN_COUNT (sizeof(TeiFnList)/sizeof(struct FsmNode))
+
+void
+release_tei(teimgr_t *tm)
+{
+	FsmDelTimer(&tm->t201, 1);
+	free(tm);
+}
+
+int
+create_teimgr(layer2_t *l2) {
+	teimgr_t *ntei;
+
+	if (!l2) {
+		eprint("create_tei no layer2\n");
+		return(-EINVAL);
+	}
+	if (!(ntei = malloc(sizeof(teimgr_t)))) {
+		eprint("kmalloc teimgr failed\n");
+		return(-ENOMEM);
+	}
+	memset(ntei, 0, sizeof(teimgr_t));
+	ntei->l2 = l2;
+	ntei->T201 = 1000;	/* T201  1000 milliseconds */
+	ntei->debug = l2->debug;
+	ntei->tei_m.nst = l2->nst;
+	ntei->tei_m.debug = l2->debug;
+	ntei->tei_m.userdata = ntei;
+	ntei->tei_m.printdebug = tei_debug;
+	ntei->tei_m.fsm = l2->nst->teifsm;
+	ntei->tei_m.state = ST_TEI_NOP;
+	FsmInitTimer(&ntei->tei_m, &ntei->t201);
+	l2->tm = ntei;
+	return(0);
+}
+
+int
+tei_mux(net_stack_t *nst, msg_t *msg)
+{
+	mISDNuser_head_t	*hh;
+	u_char		*dp;
+	int 		mt;
+	layer2_t	*l2;
+	unsigned int	ri, ai;
+
+	hh = (mISDNuser_head_t *)msg->data;
+	dprint(DBGM_TEI, -1, "%s: prim(%x) len(%d)\n", __FUNCTION__,
+		hh->prim, msg->len);
+	if (msg->len < mISDN_FRAME_MIN)
+		return(-EINVAL);
+	if (hh->prim != (MDL_UNITDATA | INDICATION)) {
+		wprint("%s: prim(%x) unhandled\n", __FUNCTION__,
+			hh->prim);
+		return(-EINVAL);
+	}
+	msg_pull(msg, mISDNUSER_HEAD_SIZE);
+	if (msg->len < 8) {
+		wprint("short tei mgr frame %d/8\n", msg->len);
+		return(-EINVAL);
+	}
+	dp = msg->data + 2;
+	if ((*dp & 0xef) != UI) {
+		wprint("tei mgr frame is not ui %x\n", *dp);
+		return(-EINVAL);
+	}
+	dp++;
+	if (*dp++ != TEI_ENTITY_ID) {
+		/* wrong management entity identifier, ignore */
+		dp--;
+		wprint("tei handler wrong entity id %x\n", *dp);
+		return(-EINVAL);
+	} else {
+		mt = *(dp+2);
+		ri = ((unsigned int) *dp++ << 8);
+		ri += *dp++;
+		dp++;
+		ai = (unsigned int) *dp++;
+		ai >>= 1;
+		dprint(DBGM_TEI, -1, "tei handler mt %x ri(%x) ai(%d)\n",
+			mt, ri, ai);
+		if (mt == ID_REQUEST) {
+			if (ai != 127) {
+				wprint("%s: ID_REQUEST ai(%d) not 127\n", __FUNCTION__,
+					ai);
+				return(-EINVAL);
+			}
+			l2 = new_tei_req(nst);
+			if (!l2) {
+				wprint("%s: no free tei\n", __FUNCTION__);
+				return(-EBUSY);
+			}
+			l2->tm->ri = ri;
+			put_tei_msg(l2->tm, ID_ASSIGNED, ri, l2->tei);
+			free_msg(msg);
+			return(0);
+		}
+		l2 = find_tei(nst, ai);
+		if (mt == ID_VERIFY) {
+			if (l2) {
+				FsmEvent(&l2->tm->tei_m, EV_VERIFY, &ai);
+			} else {
+				l2 = find_tei(nst, 127);
+				if (!l2) {
+					wprint("%s: no 127 manager\n", __FUNCTION__);
+					return(-EINVAL);
+				}
+				FsmEvent(&l2->tm->tei_m, EV_REMOVE, &ai);
+			}
+		} else if (mt == ID_CHK_RES) {
+			if (l2) {
+				FsmEvent(&l2->tm->tei_m, EV_CHECK_RES, &ri);
+			} else {
+				l2 = find_tei(nst, 127);
+				if (!l2) {
+					wprint("%s: no 127 manager\n", __FUNCTION__);
+					return(-EINVAL);
+				}
+				FsmEvent(&l2->tm->tei_m, EV_REMOVE, &ai);
+			}
+		} else {
+			wprint("%s: wrong mt %x", __FUNCTION__, mt);
+			return(-EINVAL);
+		}
+	}
+	free_msg(msg);
+	return(0);
+}
+
+
+
+int TEIInit(net_stack_t *nst)
+{
+	struct Fsm *teif;
+
+	if (!(teif = malloc(sizeof(struct Fsm))))
+		return(1);
+	nst->teifsm = teif;
+	memset(teif, 0, sizeof(struct Fsm));
+	teif->state_count = TEI_STATE_COUNT;
+	teif->event_count = TEI_EVENT_COUNT;
+	teif->strEvent = strTeiEvent;
+	teif->strState = strTeiState;
+	FsmNew(teif, TeiFnList, TEI_FN_COUNT);
+	return(0);
+}
+
+void TEIFree(net_stack_t *nst)
+{
+	FsmFree(nst->teifsm);
+}

Added: misdn-user/trunk/i4lnet/tone.c
===================================================================
--- misdn-user/trunk/i4lnet/tone.c	                        (rev 0)
+++ misdn-user/trunk/i4lnet/tone.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,147 @@
+#include <stdio.h>
+#include "isdn_net.h"
+#include "tone.h"
+#include "bchannel.h"
+
+/* 
+ * These are 10 periods (24 ms) of the 425 Hz tone used by most inband
+ * signals.
+ * Its quiet not exacly 425 Hz, but 416,66667, which fit very well
+ * the 15% tolerance
+ */
+
+const unsigned char tone_425[TONE_425_SIZE] = {
+ 0xd5, 0x81, 0xb6, 0xbf, 0xbb, 0xba, 0xb8, 0xb2,
+ 0x8a, 0x9d, 0x15, 0x0e, 0x33, 0x39, 0x3a, 0x3b,
+ 0x3e, 0x31, 0x0d, 0x65, 0x85, 0xb4, 0xbd, 0xb8,
+ 0xba, 0xb8, 0xbd, 0xb4, 0x85, 0x65, 0x0d, 0x31,
+ 0x3e, 0x3b, 0x3a, 0x39, 0x33, 0x0e, 0x15, 0x9d,
+ 0x8a, 0xb2, 0xb8, 0xba, 0xbb, 0xbf, 0xb6, 0x81,
+ 0xd5, 0x01, 0x36, 0x3f, 0x3b, 0x3a, 0x38, 0x32,
+ 0x0a, 0x1d, 0x95, 0x8e, 0xb3, 0xb9, 0xba, 0xbb,
+ 0xbe, 0xb1, 0x8d, 0xe5, 0x05, 0x34, 0x3d, 0x38,
+ 0x3a, 0x38, 0x3d, 0x34, 0x05, 0xe5, 0x8d, 0xb1,
+ 0xbe, 0xbb, 0xba, 0xb9, 0xb3, 0x8e, 0x95, 0x1d,
+ 0x0a, 0x32, 0x38, 0x3a, 0x3b, 0x3f, 0x36, 0x01,
+ 0xd5, 0x81, 0xb6, 0xbf, 0xbb, 0xba, 0xb8, 0xb2,
+ 0x8a, 0x9d, 0x15, 0x0e, 0x33, 0x39, 0x3a, 0x3b,
+ 0x3e, 0x31, 0x0d, 0x65, 0x85, 0xb4, 0xbd, 0xb8,
+ 0xba, 0xb8, 0xbd, 0xb4, 0x85, 0x65, 0x0d, 0x31,
+ 0x3e, 0x3b, 0x3a, 0x39, 0x33, 0x0e, 0x15, 0x9d,
+ 0x8a, 0xb2, 0xb8, 0xba, 0xbb, 0xbf, 0xb6, 0x81,
+ 0xd5, 0x01, 0x36, 0x3f, 0x3b, 0x3a, 0x38, 0x32,
+ 0x0a, 0x1d, 0x95, 0x8e, 0xb3, 0xb9, 0xba, 0xbb,
+ 0xbe, 0xb1, 0x8d, 0xe5, 0x05, 0x34, 0x3d, 0x38,
+ 0x3a, 0x38, 0x3d, 0x34, 0x05, 0xe5, 0x8d, 0xb1,
+ 0xbe, 0xbb, 0xba, 0xb9, 0xb3, 0x8e, 0x95, 0x1d,
+ 0x0a, 0x32, 0x38, 0x3a, 0x3b, 0x3f, 0x36, 0x01
+};
+
+/* 
+ * These are 10 ms of silence
+ */
+
+const unsigned char tone_SILENCE[TONE_SILENCE_SIZE] = {
+ 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
+ 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
+ 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
+ 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
+ 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
+ 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
+ 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
+ 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
+ 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
+ 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5
+};
+
+int tone_handler(bchannel_t *bc) {
+	const unsigned char	*tp;
+	int			len;
+
+	dprint(DBGM_TONE, -1, "%s:ch%d Flags %x\n", __FUNCTION__,
+		bc->channel, bc->Flags);
+	if (bc->bstate != BC_BSTATE_ACTIV)
+		return(1);
+	if (bc->smsg)
+		return(2);
+	if (!(bc->Flags & FLG_BC_TONE))
+		return(3);
+	if (bc->Flags & FLG_BC_TONE_DIAL) {
+		tp = tone_425;
+		len = TONE_425_SIZE;
+	} else if (bc->Flags & FLG_BC_TONE_ALERT) {
+		if (bc->Flags & FLG_BC_TONE_SILENCE) {
+			if (bc->ttime > TONE_ALERT_SILENCE_TIME) {
+				bc->ttime = 0;
+				tp = tone_425;
+				len = TONE_425_SIZE;
+				bc->Flags &= ~FLG_BC_TONE_SILENCE;
+			} else {
+				tp = tone_SILENCE;
+				len = TONE_SILENCE_SIZE;
+			}
+		} else {
+			if (bc->ttime > TONE_ALERT_TIME) {
+				bc->ttime = 0;
+				tp = tone_SILENCE;
+				len = TONE_SILENCE_SIZE;
+				bc->Flags |= FLG_BC_TONE_SILENCE;
+			} else {
+				tp = tone_425;
+				len = TONE_425_SIZE;
+			}
+		}
+	} else if (bc->Flags & FLG_BC_TONE_BUSY) {
+		if (bc->Flags & FLG_BC_TONE_SILENCE) {
+			if (bc->ttime > TONE_BUSY_SILENCE_TIME) {
+				bc->ttime = 0;
+				tp = tone_425;
+				len = TONE_425_SIZE;
+				bc->Flags &= ~FLG_BC_TONE_SILENCE;
+			} else {
+				tp = tone_SILENCE;
+				len = TONE_SILENCE_SIZE;
+			}
+		} else {
+			if (bc->ttime > TONE_BUSY_TIME) {
+				bc->ttime = 0;
+				tp = tone_SILENCE;
+				len = TONE_SILENCE_SIZE;
+				bc->Flags |= FLG_BC_TONE_SILENCE;
+			} else {
+				tp = tone_425;
+				len = TONE_425_SIZE;
+			}
+		}
+	} else if (bc->Flags & FLG_BC_TONE_SILENCE) {
+		tp = tone_SILENCE;
+		len = TONE_SILENCE_SIZE;
+	} else
+		return(4);
+	if (len > ibuf_freecount(bc->sbuf)) {
+		dprint(DBGM_TONE, -1, "%s:ch%d not sbuf %d/%d\n", __FUNCTION__,
+			bc->channel, len, ibuf_freecount(bc->sbuf));
+		return(5);
+	}
+	if (bc->sbuf) {
+		bc->ttime += len*125;
+		ibuf_memcpy_w(bc->sbuf, (unsigned char *)tp, len);
+		sem_post(bc->sbuf->rsem);
+	}
+	return(0);
+}
+
+int
+set_tone(bchannel_t *bc, int tone)
+{
+	bc->Flags &= ~FLG_BC_TONE;
+	bc->Flags |= tone;
+	bc->ttime = 0;
+	if (tone) {
+		if (bc->sbuf) {
+			bc->sbuf->rsem = &bc->work;
+			bc->sbuf->wsem = &bc->work;
+		}
+	}
+	return(bc->Flags & FLG_BC_TONE);
+}

Added: misdn-user/trunk/include/bchannel.h
===================================================================
--- misdn-user/trunk/include/bchannel.h	                        (rev 0)
+++ misdn-user/trunk/include/bchannel.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,37 @@
+#ifndef BCHANNEL_H
+#define BCHANNEL_H
+
+enum {
+	BC_CSTATE_NULL,
+	BC_CSTATE_ICALL,
+	BC_CSTATE_OCALL,
+	BC_CSTATE_OVERLAP_REC,
+	BC_CSTATE_PROCEED,
+	BC_CSTATE_ALERTING,
+	BC_CSTATE_ACTIV,
+	BC_CSTATE_DISCONNECT,
+	BC_CSTATE_DISCONNECTED,
+	BC_CSTATE_RELEASE,
+};
+
+enum {
+	BC_BSTATE_NULL,
+	BC_BSTATE_SETUP,
+	BC_BSTATE_ACTIVATE,
+	BC_BSTATE_ACTIV,
+	BC_BSTATE_DEACTIVATE,
+	BC_BSTATE_CLEANUP,
+};
+
+#define BC_SETUP		0x0e0100
+#define BC_CLEANUP		0x0e0200
+
+#define ISDN_PID_L2_B_USER      0x420000ff
+#define ISDN_PID_L3_B_USER	0x430000ff
+
+
+extern	int		init_bchannel(bchannel_t *bc, int channel);
+extern	int		term_bchannel(bchannel_t *bc);
+
+
+#endif

Added: misdn-user/trunk/include/g711.h
===================================================================
--- misdn-user/trunk/include/g711.h	                        (rev 0)
+++ misdn-user/trunk/include/g711.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,68 @@
+/*
+ * This source code is quick table lookup implementation of
+ * convert 16 bit linear PCM and A-law u-law (ITU G.711) codings
+ * Tables are generated using ITU G.711 example code from
+ * Sun Microsystems, Inc.
+ *
+ * (C)2001 Karsten Keil kkeil at suse.de
+ *
+ *
+ *
+ */
+
+#ifndef G711_H
+#define G711_H
+
+extern	unsigned char	_l2u[4096];
+extern	unsigned char	_l2A[2048];
+extern	unsigned char	_u2A[256];
+extern	unsigned char	_A2u[256];
+extern	signed short	_u2l[256];
+extern	signed short	_A2l[256];
+
+static	__inline__ unsigned char	linear2ulaw(signed short l)
+{
+	unsigned char	mask;
+
+	mask = (l<0) ? 0x7f : 0xff;
+	if (l<0)
+		l = -l;
+	if (l<4)
+		return(0xff & mask);
+	l -= 4;
+	l >>= 3;
+	return(_l2u[l] & mask);
+}
+
+static	__inline__ unsigned char	linear2alaw(signed short l)
+{
+	unsigned char	mask;
+
+	mask = (l<0) ? 0x7f : 0xff;
+	if (l<0)
+		l = -l;
+	l >>= 4;
+	return(_l2A[l] & mask);
+}
+
+static	__inline__ signed short		ulaw2linear(unsigned char u)
+{
+	return(_u2l[u]);
+}
+
+static	__inline__ signed short		alaw2linear(unsigned char a)
+{
+	return(_A2l[a]);
+}
+
+static	__inline__ unsigned char	ulaw2alaw(unsigned char u)
+{
+	return(_u2A[u]);
+}
+
+static	__inline__ unsigned char	alaw2ulaw(unsigned char a)
+{
+	return(_A2u[a]);
+}
+
+#endif

Added: misdn-user/trunk/include/helper.h
===================================================================
--- misdn-user/trunk/include/helper.h	                        (rev 0)
+++ misdn-user/trunk/include/helper.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,58 @@
+/* $Id: helper.h,v 1.0 2003/08/27 07:35:32 kkeil Exp $
+ *
+ *   Basic declarations, defines and prototypes
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+#ifndef _mISDN_HELPER_H
+#define	_mISDN_HELPER_H
+#ifdef MEMDBG
+#include "memdbg.h"
+#endif
+
+#define int_error() \
+        fprintf(stderr, "mISDN: INTERNAL ERROR in %s:%d\n", \
+                       __FILE__, __LINE__)
+                       
+#define int_errtxt(fmt, arg...) \
+        fprintf(stderr, "mISDN: INTERNAL ERROR in %s:%d " fmt "\n", \
+                       __FILE__, __LINE__, ## arg)
+                       
+#define APPEND_TO_LIST(item,base) \
+	if (item->prev || item->next) \
+		int_errtxt("APPEND not clean %p<-%p->%p", \
+			item->prev, item, item->next); \
+	item->next = NULL; \
+	item->prev = base; \
+	while (item->prev && item->prev->next) \
+		item->prev = item->prev->next; \
+	if (item->prev == item) { \
+		int_errtxt("APPEND DUP %p", item); \
+	} else \
+		if (base) { \
+			item->prev->next = item; \
+		} else \
+			base = item
+
+#define INSERT_INTO_LIST(newi,nexti,base) \
+	newi->next = nexti; \
+	newi->prev = nexti->prev; \
+	if (newi->prev) \
+		newi->prev->next = newi; \
+	nexti->prev = newi; \
+	if (base == nexti) \
+		base = newi
+
+#define REMOVE_FROM_LIST(item) \
+	if (item->prev) \
+		item->prev->next = item->next; \
+	if (item->next) \
+		item->next->prev = item->prev
+
+#define REMOVE_FROM_LISTBASE(item,base) \
+	REMOVE_FROM_LIST(item); \
+	if (item == base) \
+		base = item->next
+
+#endif

Added: misdn-user/trunk/include/ibuffer.h
===================================================================
--- misdn-user/trunk/include/ibuffer.h	                        (rev 0)
+++ misdn-user/trunk/include/ibuffer.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,119 @@
+#ifndef IBUFFER_H
+#define IBUFFER_H
+#include <stdlib.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <string.h>
+
+/* ibuffer stuff */
+
+typedef struct _ibuffer		ibuffer_t;
+
+struct _ibuffer {
+	int		size;
+	unsigned char	*buffer;
+	int		ridx;
+	int		widx;
+	sem_t		*rsem;
+	sem_t		*wsem;	
+};
+
+static inline void
+clear_ibuffer(ibuffer_t *ib)
+{
+	if (!ib)
+		return;
+	ib->ridx = 0;
+	ib->widx = 0;
+}
+
+static inline ibuffer_t *
+init_ibuffer(int size)
+{
+	ibuffer_t	*ib;
+
+	ib = (ibuffer_t *)malloc(sizeof(ibuffer_t));
+	if (!ib)
+		return(NULL);
+	memset(ib, 0, sizeof(ibuffer_t));
+	ib->buffer = (unsigned char *)malloc(size);
+	if (!ib->buffer) {
+		free(ib);
+		return(NULL);
+	}
+	ib->size = size;
+	return(ib);
+}
+
+static inline void
+free_ibuffer(ibuffer_t *ib)
+{
+	if (!ib)
+		return;
+	if (ib->buffer)
+		free(ib->buffer);
+	free(ib);
+}
+
+static inline int
+ibuf_usedcount(ibuffer_t *ib)
+{
+	int l;
+
+	if (!ib)
+		return(0);
+	l = ib->widx - ib->ridx;
+	if (l<0)
+		l += ib->size;
+	return(l);
+}
+
+
+static inline int
+ibuf_freecount(ibuffer_t *ib)
+{
+	if (!ib)
+		return(0);
+	return(ib->size - ibuf_usedcount(ib));
+}
+
+static inline void
+ibuf_memcpy_w(ibuffer_t *ib, void *data, int len)
+{
+	unsigned char *p = (unsigned char *)data;
+	int	frag;
+
+	frag = ib->size - ib->widx;
+	if (frag < len) {
+		memcpy(&ib->buffer[ib->widx], p, frag);
+		p += frag;
+		frag = len - frag;
+		ib->widx = 0;
+	} else
+		frag = len;
+	memcpy(&ib->buffer[ib->widx], p, frag);
+	ib->widx += frag;
+	ib->widx %= ib->size;
+}
+
+static inline void
+ibuf_memcpy_r(void *data, ibuffer_t *ib, int len)
+{
+	unsigned char *p = (unsigned char *)data;
+	int	frag;
+
+	frag = ib->size - ib->ridx;
+	if (frag < len) {
+		memcpy(p, &ib->buffer[ib->ridx], frag);
+		p += frag;
+		frag = len - frag;
+		ib->ridx = 0;
+	} else
+		frag = len;
+	memcpy(p, &ib->buffer[ib->ridx], frag);
+	ib->ridx += frag;
+	ib->ridx %= ib->size;
+}
+
+#endif
+

Added: misdn-user/trunk/include/isdn_debug.h
===================================================================
--- misdn-user/trunk/include/isdn_debug.h	                        (rev 0)
+++ misdn-user/trunk/include/isdn_debug.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,36 @@
+#ifndef ISDN_DEBUG_H
+#define ISDN_DEBUG_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#define	DBGM_NET	0x00000001
+#define DBGM_MSG	0x00000002
+#define DBGM_FSM	0x00000004
+#define DBGM_TEI	0x00000010
+#define DBGM_L2		0x00000020
+#define DBGM_L3		0x00000040
+#define DBGM_L3DATA	0x00000080
+#define DBGM_BC		0x00000100
+#define DBGM_TONE	0x00000200
+#define	DBGM_BCDATA	0x00000400
+#define DBGM_MAN	0x00001000
+#define DBGM_APPL	0x00002000
+#define DBGM_ISDN	0x00004000
+#define DBGM_SOCK	0x00010000
+#define DBGM_CONN	0x00020000
+#define DBGM_CDATA	0x00040000
+#define DBGM_DDATA	0x00080000
+#define DBGM_SOUND	0x00100000
+#define DBGM_SDATA	0x00200000
+#define DBGM_TOPLEVEL	0x40000000
+#define DBGM_ALL	0xffffffff
+
+extern	int		dprint(unsigned int mask, int port, const char *fmt, ...);
+extern	int		eprint(const char *fmt, ...);
+extern	int		wprint(const char *fmt, ...);
+extern	int		debug_init(unsigned int, char *, char *, char *);
+extern	void		debug_close(void);
+extern	int		dhexprint(unsigned int, char *, unsigned char *, int);
+#endif

Added: misdn-user/trunk/include/isdn_msg.h
===================================================================
--- misdn-user/trunk/include/isdn_msg.h	                        (rev 0)
+++ misdn-user/trunk/include/isdn_msg.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,195 @@
+#ifndef ISDN_MSG_H
+#define ISDN_MSG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <pthread.h>
+#include <semaphore.h>
+
+#define MAX_MSG_SIZE		2080
+#define DEFAULT_HEADROOM	16
+
+typedef struct _msg {
+	struct _msg		*prev;
+	struct _msg		*next;
+	struct _msg_queue	*list;
+	int			len;
+	int			size;
+	unsigned char		*head;
+	unsigned char		*data;
+	unsigned char		*tail;
+	unsigned char		*end;
+	unsigned char		__data[MAX_MSG_SIZE];
+} msg_t;
+
+typedef	struct _msg_queue {
+	struct _msg	*prev;
+	struct _msg	*next;
+	pthread_mutex_t lock;
+	int		len;
+	int		maxlen;	
+} msg_queue_t;
+
+extern	void		msg_init(void);
+extern	msg_t		*alloc_msg(int);
+extern	void		free_msg(msg_t *);
+extern	msg_queue_t	*free_queue;
+extern	msg_t		*msg_copy(msg_t *msg);
+
+#define	msg_clone(m)	msg_copy(m)
+ 
+static inline void
+msg_queue_init(msg_queue_t *q)
+{
+	pthread_mutex_init(&q->lock, NULL);
+	q->len = 0;
+	q->prev = (msg_t *)q;
+	q->next = (msg_t *)q;
+}
+
+static inline int msg_queue_len(msg_queue_t *list_)
+{
+	return(list_->len);
+}
+
+static inline void msg_queue_head(msg_queue_t *list, msg_t *newm)
+{
+	msg_t *prev, *next;
+
+	pthread_mutex_lock(&list->lock);
+	newm->list = list;
+	list->len++;
+	prev = (msg_t *)list;
+	next = prev->next;
+	newm->next = next;
+	newm->prev = prev;
+	next->prev = newm;
+	prev->next = newm;
+	pthread_mutex_unlock(&list->lock);
+}
+
+
+static inline void msg_queue_tail(msg_queue_t *list, msg_t *newm)
+{
+	msg_t *prev, *next;
+
+	pthread_mutex_lock(&list->lock);
+	newm->list = list;
+	list->len++;
+	next = (msg_t *)list;
+	prev = next->prev;
+	newm->next = next;
+	newm->prev = prev;
+	next->prev = newm;
+	prev->next = newm;
+	pthread_mutex_unlock(&list->lock);
+}
+
+
+static inline msg_t *msg_dequeue(msg_queue_t *list)
+{
+	msg_t *next, *prev, *result;
+
+	pthread_mutex_lock(&list->lock);
+	prev = (msg_t *) list;
+	next = prev->next;
+	result = NULL;
+	if (next != prev) {
+		result = next;
+		next = next->next;
+		list->len--;
+		next->prev = prev;
+		prev->next = next;
+		result->next = NULL;
+		result->prev = NULL;
+		result->list = NULL;
+	}
+	pthread_mutex_unlock(&list->lock);
+	return result;
+}
+
+static __inline__ void msg_queue_purge(msg_queue_t *list)
+{
+	msg_t *msg;
+
+	while ((msg = msg_dequeue(list))!=NULL)
+		free_msg(msg);
+}
+
+static __inline__ unsigned char *msg_put(msg_t *msg, unsigned int len)
+{
+	unsigned char *tmp=msg->tail;
+	msg->tail+=len;
+	msg->len+=len;
+	if(msg->tail>msg->end)
+	{
+		fprintf(stderr, "msg_over_panic msg(%p) data(%p) head(%p)\n",
+			msg, msg->data, msg->head);
+		return(NULL);
+	}
+	return tmp;
+}
+
+static __inline__ unsigned char *msg_push(msg_t *msg, unsigned int len)
+{
+	msg->data-=len;
+	msg->len+=len;
+	if(msg->data < msg->head)
+	{
+		fprintf(stderr, "msg_under_panic msg(%p) data(%p) head(%p)\n",
+			msg, msg->data, msg->head);
+		return(NULL);
+	}
+	return msg->data;
+}
+
+
+static __inline__ char *__msg_pull(msg_t *msg, unsigned int len)
+{
+	msg->len-=len;
+	return 	(char *)(msg->data+=len);
+}
+
+static __inline__ unsigned char * msg_pull(msg_t *msg, unsigned int len)
+{
+	if (len > (unsigned int)msg->len)
+		return NULL;
+	return (unsigned char *)__msg_pull(msg,len);
+}
+
+static __inline__ int msg_headroom(msg_t *msg)
+{
+	return msg->data-msg->head;
+}
+
+static __inline__ int msg_tailroom(msg_t *msg)
+{
+	return msg->end-msg->tail;
+}
+
+static __inline__ void msg_reserve(msg_t *msg, unsigned int len)
+{
+	msg->data+=len;
+	msg->tail+=len;
+}
+
+static __inline__ void __msg_trim(msg_t *msg, unsigned int len)
+{
+	msg->len = len;
+	msg->tail = msg->data+len;
+}
+
+static __inline__ void msg_trim(msg_t *msg, unsigned int len)
+{
+	if ((unsigned int)msg->len > len) {
+		__msg_trim(msg, len);
+	}
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: misdn-user/trunk/include/isdn_net.h
===================================================================
--- misdn-user/trunk/include/isdn_net.h	                        (rev 0)
+++ misdn-user/trunk/include/isdn_net.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,304 @@
+#ifndef ISDN_NET_H
+#define ISDN_NET_H
+
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include "mISDNlib.h"
+#include "isdn_msg.h"
+#include "isdn_debug.h"
+#include "ibuffer.h"
+
+#define MSN_LEN		32
+#define	SUBADR_LEN	24
+#define UUS_LEN		256
+#define FAC_LEN		132
+#ifndef mISDN_FRAME_MIN
+#define mISDN_FRAME_MIN	8
+#endif
+
+typedef struct _layer2		layer2_t;
+typedef struct _layer3		layer3_t;
+typedef struct _layer4		layer4_t;
+typedef struct _bchannel	bchannel_t;
+typedef struct _mISDNif		mISDNif_t;
+typedef struct _mISDNinstance	mISDNinstance_t;
+typedef struct _net_stack	net_stack_t;
+typedef struct _manager		manager_t;
+typedef struct _nr_list		nr_list_t;
+typedef int (*ifunc_t)(net_stack_t *, msg_t *);
+typedef int (*bfunc_t)(void *, void *);
+typedef int (*afunc_t)(manager_t *, int, void *);
+
+
+#define	MAX_BDATA_SIZE	2048
+
+struct _bchannel {
+	sem_t			work;
+	msg_queue_t		workq;
+	pthread_t		tid;
+	manager_t		*manager;
+	void			*app;
+	int			channel;
+	pthread_mutex_t		lock;
+	int			cstate;
+	int			bstate;
+	int			l3id;
+	int			b_addr;
+	int			Flags;
+	int			ttime;
+	nr_list_t		*usednr;
+	int			l1_prot;
+	unsigned char		bc[8];
+	unsigned char		uu[UUS_LEN];
+	unsigned char		fac[FAC_LEN];
+	unsigned char		nr[MSN_LEN];
+	unsigned char		msn[MSN_LEN];
+	unsigned char		clisub[SUBADR_LEN];
+	unsigned char		cldsub[SUBADR_LEN];
+	int			cause_loc;
+	int			cause_val;
+	unsigned char		display[84];
+	msg_t			*smsg;
+	ibuffer_t		*rbuf;
+	ibuffer_t		*sbuf;
+	int			rrid;
+	int			rsid;
+};
+
+struct _manager	{
+	manager_t		*prev;
+	manager_t		*next;
+	bchannel_t		bc[2];
+	nr_list_t		*nrlist;
+	net_stack_t		*nst;
+	bfunc_t			man2stack;
+	afunc_t			application;
+	afunc_t			app_bc;
+	pthread_t		tid;
+	sem_t			work;
+	msg_queue_t		workq;
+};
+
+#define PR_APP_CHECK_NR		1
+#define PR_APP_ICALL		2
+#define PR_APP_OCHANNEL		3
+#define PR_APP_OCALL		4
+#define PR_APP_ALERT		5
+#define PR_APP_CONNECT		6
+#define PR_APP_HANGUP		7
+#define PR_APP_CLEAR		8
+#define PR_APP_USERUSER		9
+#define PR_APP_FACILITY		10
+#define PR_APP_OPEN_RECFILES	11
+#define PR_APP_CLOSE_RECFILES	12
+
+#define FLG_NST_READER_ABORT	1
+#define FLG_NST_TERMINATION	2
+
+#define FEATURE_NET_HOLD	0x00000001
+#define FEATURE_NET_PTP		0x00000002
+#define FEATURE_NET_CRLEN2	0x00000004
+#define FEATURE_NET_EXTCID	0x00000008
+
+struct _net_stack {
+	int			device;
+	int			cardnr;
+	int			d_stid;
+	int			l0_id;
+	int			l1_id;
+	int			l2_id;
+	msg_t			*phd_down_msg;
+	layer2_t		*layer2;
+	layer3_t		*layer3;
+	ifunc_t			l1_l2;
+	ifunc_t			l2_l3;
+	ifunc_t			l3_l2;
+	ifunc_t			manager_l3;
+	bfunc_t			l3_manager;
+	manager_t		*manager;
+	msg_queue_t		down_queue;
+	msg_queue_t		rqueue;
+	msg_queue_t		wqueue;
+	sem_t			work;
+	pthread_mutex_t		lock;
+	pthread_t		reader;
+	int			b_stid[2];
+	int			b_addr[2];
+	int			bcid[2];
+	u_long			flag;
+	struct _itimer		*tlist;
+	void			*l2fsm;
+	void			*teifsm;
+	u_long			feature;
+};
+
+struct _nr_list {
+	nr_list_t		*prev;
+	nr_list_t		*next;
+	unsigned char		len;
+	unsigned char		nr[MSN_LEN];
+	unsigned char		name[64];
+	int			typ;
+	int			flags;
+};
+
+#define NR_TYPE_INTERN		1
+#define NR_TYPE_AUDIO		2
+#define NR_TYPE_VOIP		3
+
+typedef struct _itimer {
+	struct _itimer		*prev;
+	struct _itimer		*next;
+	net_stack_t		*nst;
+	int			id;
+	int			expires;
+	u_long			Flags;
+	unsigned long		data;
+	int			(*function)(unsigned long);
+} itimer_t;
+
+#define FLG_TIMER_RUNING	1
+
+#define FLG_BC_USE		0x00000001
+#define FLG_BC_SENT_CID		0x00000002
+#define FLG_BC_CALL_ORGINATE	0x00000004
+#define FLG_BC_PROGRESS		0x00000008
+#define	FLG_BC_APPLICATION	0x00000010
+#define FLG_BC_TONE_DIAL	0x00000100
+#define FLG_BC_TONE_BUSY	0x00000200
+#define FLG_BC_TONE_ALERT	0x00000400
+#define FLG_BC_TONE_SILENCE	0x00000800
+#define FLG_BC_TONE_NONE	0x00000000
+#define FLG_BC_TONE		0x00000F00
+#define FLG_BC_RECORD		0x00010000
+#define FLG_BC_RECORDING	0x00020000
+#define FLG_BC_RAWDEVICE	0x01000000
+#define FLG_BC_KEEP_SEND	0x02000000
+#define FLG_BC_TERMINATE	0x08000000
+
+#define MSG_L1_PRIM		0x010000
+#define MSG_L2_PRIM		0x020000
+#define MSG_L3_PRIM		0x030000
+
+extern	int		do_net_stack_setup(net_stack_t *);
+extern	int		do_net_stack_cleanup(net_stack_t  *nst);
+extern	void		*do_netthread(void *);
+extern	int		term_netstack(net_stack_t *nst);
+
+extern	int		init_manager(manager_t **mlist, afunc_t application);
+extern	int		cleanup_manager(manager_t *mgr);
+
+extern	int		write_dmsg(net_stack_t *, msg_t *);
+extern	int		phd_conf(net_stack_t *, iframe_t *, msg_t *);
+
+extern	int		init_timer(itimer_t *, net_stack_t  *);
+extern	int		add_timer(itimer_t *);
+extern	int		del_timer(itimer_t *);
+extern	int		remove_timer(itimer_t *it);
+extern	int		timer_pending(itimer_t *);
+
+extern	u_char		*findie(u_char *, int, u_char, int);
+extern	u_char		*find_and_copy_ie(u_char *, int, u_char, int, msg_t *);
+extern	void		display_NR_IE(u_char *, char *, char *);
+
+extern	int		match_nr(manager_t *mgr, unsigned char *nx, nr_list_t **nrx);
+
+typedef struct _mISDNuser_head {
+	u_int	prim;
+	int	dinfo;
+} mISDNuser_head_t;
+
+#define mISDNUSER_HEAD_SIZE	sizeof(mISDNuser_head_t)
+
+/* interface msg help routines */
+
+static inline void mISDN_newhead(u_int prim, int dinfo, msg_t *msg)
+{
+	mISDNuser_head_t *hh = (mISDNuser_head_t *)msg->data;
+
+	hh->prim = prim;
+	hh->dinfo = dinfo;
+}
+
+static inline int if_newhead(void *arg, ifunc_t func, u_int prim, int dinfo,
+	msg_t *msg)
+{
+	if (!msg)
+		return(-ENXIO);
+	mISDN_newhead(prim, dinfo, msg);
+	return(func((net_stack_t *)arg, msg));
+}
+
+static inline void mISDN_addhead(u_int prim, int dinfo, msg_t *msg)
+{
+	mISDNuser_head_t *hh = (mISDNuser_head_t *)msg_push(msg, mISDNUSER_HEAD_SIZE);
+
+	hh->prim = prim;
+	hh->dinfo = dinfo;
+}
+
+
+static inline int if_addhead(void *arg, ifunc_t func, u_int prim, int dinfo,
+	msg_t *msg)
+{
+	if (!msg)
+		return(-ENXIO);
+	mISDN_addhead(prim, dinfo, msg);
+	return(func((net_stack_t *)arg, msg));
+}
+
+
+static inline msg_t *create_link_msg(u_int prim, int dinfo,
+	int len, void *arg, int reserve)
+{
+	msg_t	*msg;
+
+	if (!(msg = alloc_msg(len + mISDNUSER_HEAD_SIZE + reserve))) {
+		wprint("%s: no msg size %d+%d+%d\n", __FUNCTION__,
+			len, mISDNUSER_HEAD_SIZE, reserve);
+		return(NULL);
+	} else
+		msg_reserve(msg, reserve + mISDNUSER_HEAD_SIZE);
+	if (len)
+		memcpy(msg_put(msg, len), arg, len);
+	mISDN_addhead(prim, dinfo, msg);
+	return(msg);
+}
+
+static inline int if_link(void *farg, ifunc_t func, u_int prim, int dinfo, int len,
+	void *arg, int reserve)
+{
+	msg_t	*msg;
+	int	err;
+
+	if (!(msg = create_link_msg(prim, dinfo, len, arg, reserve)))
+		return(-ENOMEM);
+	err = func((net_stack_t *)farg, msg);
+	if (err)
+		free_msg(msg);
+	return(err);
+}
+
+static inline msg_t *prep_l3data_msg(u_int prim, int dinfo, int ssize, int dsize, msg_t *old)
+{
+	if (!old) {
+		old = alloc_msg(ssize + dsize + mISDNUSER_HEAD_SIZE + DEFAULT_HEADROOM);
+		if (!old) {
+			wprint("%s: no msg size %d+%d+%d\n", __FUNCTION__,
+				ssize, dsize, mISDNUSER_HEAD_SIZE + DEFAULT_HEADROOM);
+			return(NULL);
+		}
+	} else {
+		old->data = old->head + DEFAULT_HEADROOM;
+		old->tail = old->data;
+		old->len = 0;
+	}
+	memset(msg_put(old, ssize + mISDNUSER_HEAD_SIZE), 0,
+		ssize + mISDNUSER_HEAD_SIZE);
+	mISDN_newhead(prim, dinfo, old);
+	return(old);
+}
+
+#endif

Added: misdn-user/trunk/include/isound.h
===================================================================
--- misdn-user/trunk/include/isound.h	                        (rev 0)
+++ misdn-user/trunk/include/isound.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,24 @@
+#ifndef ISOUND_H
+#define ISOUND_H
+
+#include "ibuffer.h"
+
+typedef	struct _isound	isound_t;
+
+#define MAX_AUDIO_READ	2048
+
+struct _isound {
+	ibuffer_t	*sbuf;
+	ibuffer_t	*rbuf;
+	int		Flag;
+	int		data;
+	unsigned char	rtmp[MAX_AUDIO_READ];
+	unsigned char	wtmp[MAX_AUDIO_READ];
+	int		wlen;
+	int             widx;
+	sem_t		work;
+	pthread_t	rd_t;
+	pthread_t	wr_t;
+};
+
+#endif

Added: misdn-user/trunk/include/l3dss1.h
===================================================================
--- misdn-user/trunk/include/l3dss1.h	                        (rev 0)
+++ misdn-user/trunk/include/l3dss1.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,187 @@
+/* $Id: l3dss1.h,v 1.3 2004/07/04 14:08:15 jolly Exp $
+ *
+ *  DSS1 (Euro) D-channel protocol defines
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+#ifndef l3dss1_process
+
+#define T301	180000
+#define T302	15000
+#define T303	4000
+#define T304	30000
+#define T305	30000
+#define T308	4000
+/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */
+/* This makes some tests easier and quicker */
+#define T309	40000
+#define T310	30000
+#define T312	6000
+#define T313	4000
+#define T318	4000
+#define T319	4000
+#define N303	1
+#define T_CTRL	180000
+
+/* private TIMER events */
+#define CC_TIMER	0x000001
+#define CC_T301		0x030101
+#define CC_T302		0x030201
+#define CC_T303		0x030301
+#define CC_T304		0x030401
+#define CC_T305		0x030501
+#define CC_T308		0x030801
+#define CC_T309         0x030901
+#define CC_T310		0x031001
+#define CC_T312		0x031201
+#define CC_T313		0x031301
+#define CC_T318		0x031801
+#define CC_T319		0x031901
+#define CC_TCTRL	0x031f01
+/*
+ * Message-Types
+ */
+
+#define MT_ALERTING		0x01
+#define MT_CALL_PROCEEDING	0x02
+#define MT_CONNECT		0x07
+#define MT_CONNECT_ACKNOWLEDGE	0x0f
+#define MT_PROGRESS		0x03
+#define MT_SETUP		0x05
+#define MT_SETUP_ACKNOWLEDGE	0x0d
+#define MT_RESUME		0x26
+#define MT_RESUME_ACKNOWLEDGE	0x2e
+#define MT_RESUME_REJECT	0x22
+#define MT_SUSPEND		0x25
+#define MT_SUSPEND_ACKNOWLEDGE	0x2d
+#define MT_SUSPEND_REJECT	0x21
+#define MT_USER_INFORMATION	0x20
+#define MT_DISCONNECT		0x45
+#define MT_RELEASE		0x4d
+#define MT_RELEASE_COMPLETE	0x5a
+#define MT_RESTART		0x46
+#define MT_RESTART_ACKNOWLEDGE	0x4e
+#define MT_SEGMENT		0x60
+#define MT_CONGESTION_CONTROL	0x79
+#define MT_INFORMATION		0x7b
+#define MT_FACILITY		0x62
+#define MT_NOTIFY		0x6e
+#define MT_STATUS		0x7d
+#define MT_STATUS_ENQUIRY	0x75
+#define MT_HOLD			0x24
+#define MT_HOLD_ACKNOWLEDGE	0x28
+#define MT_HOLD_REJECT		0x30
+#define MT_RETRIEVE		0x31
+#define MT_RETRIEVE_ACKNOWLEDGE	0x33
+#define MT_RETRIEVE_REJECT	0x37
+
+#define IE_SEGMENT	0x00
+#define IE_BEARER	0x04
+#define IE_CAUSE	0x08
+#define IE_CALL_ID	0x10
+#define IE_CALL_STATE	0x14
+#define IE_CHANNEL_ID	0x18
+#define IE_FACILITY	0x1c
+#define IE_PROGRESS	0x1e
+#define IE_NET_FAC	0x20
+#define IE_NOTIFY	0x27
+#define IE_DISPLAY	0x28
+#define IE_DATE		0x29
+#define IE_KEYPAD	0x2c
+#define IE_SIGNAL	0x34
+#define IE_INFORATE	0x40
+#define IE_E2E_TDELAY	0x42
+#define IE_TDELAY_SEL	0x43
+#define IE_PACK_BINPARA	0x44
+#define IE_PACK_WINSIZE	0x45
+#define IE_PACK_SIZE	0x46
+#define IE_CUG		0x47
+#define	IE_REV_CHARGE	0x4a
+#define IE_CONNECT_PN	0x4c
+#define IE_CONNECT_SUB	0x4d
+#define IE_CALLING_PN	0x6c
+#define IE_CALLING_SUB	0x6d
+#define IE_CALLED_PN	0x70
+#define IE_CALLED_SUB	0x71
+#define IE_REDIR_NR	0x74
+#define IE_REDIR_DN	0x76
+#define IE_TRANS_SEL	0x78
+#define IE_RESTART_IND	0x79
+#define IE_LLC		0x7c
+#define IE_HLC		0x7d
+#define IE_USER_USER	0x7e
+#define IE_ESCAPE	0x7f
+#define IE_SHIFT	0x90
+#define IE_MORE_DATA	0xa0
+#define IE_COMPLETE	0xa1
+#define IE_CONGESTION	0xb0
+#define IE_REPEAT	0xd0
+
+#define IE_MANDATORY	0x0100
+/* mandatory not in every case */
+#define IE_MANDATORY_1	0x0200
+
+#define ERR_IE_COMPREHENSION	 1
+#define ERR_IE_UNRECOGNIZED	-1
+#define ERR_IE_LENGTH		-2
+#define ERR_IE_SEQUENCE		-3
+
+#define CAUSE_LOC_USER		0
+#define CAUSE_LOC_PNET_LOCUSER	1
+
+#define CAUSE_UNASSIGNED_NUMBER	1
+#define CAUSE_NO_TRANSIT_ROUTE	2
+#define CAUSE_NO_ROUTE		3
+#define CAUSE_CHANNEL_UNACCEPT	6
+#define CAUSE_NORMAL_CLEARING	16
+#define CAUSE_USER_BUSY		17
+#define CAUSE_NOUSER_RESPONDING	18
+#define CAUSE_CALL_REJECTED	21
+#define CAUSE_NONSELECTED_USER	26
+#define CAUSE_INVALID_NUMBER	28
+#define CAUSE_STATUS_RESPONSE	30
+#define CAUSE_NORMALUNSPECIFIED	31
+#define CAUSE_NO_CHANNEL	34
+#define CAUSE_TEMPORARY_FAILURE	41
+#define CAUSE_INVALID_CALLREF	81
+#define CAUSE_INCOMPATIBLE_DEST	88
+#define CAUSE_MANDATORY_IE_MISS	96
+#define CAUSE_MT_NOTIMPLEMENTED	97
+#define CAUSE_IE_NOTIMPLEMENTED	99
+#define CAUSE_INVALID_CONTENTS	100
+#define CAUSE_NOTCOMPAT_STATE	101
+#define CAUSE_TIMER_EXPIRED	102
+#define CAUSE_PROTOCOL_ERROR	111
+
+#define NO_CAUSE		254
+
+#define PROGRESS_TONE		8
+
+#define HOLDAUX_IDLE		0
+#define HOLDAUX_HOLD_REQ	1
+#define HOLDAUX_HOLD		2
+#define HOLDAUX_RETR_REQ	3
+#define HOLDAUX_HOLD_IND	4
+#define HOLDAUX_RETR_IND	5
+
+#else /* only l3dss1_process */
+
+/* l3dss1 specific data in l3 process */
+typedef struct
+  { unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */
+    ulong ll_id; /* remebered ll id */
+    u_char remote_operation; /* handled remote operation, 0 = not active */ 
+    int proc; /* rememered procedure */  
+    ulong remote_result; /* result of remote operation for statcallb */
+    char uus1_data[35]; /* data send during alerting or disconnect */
+  } dss1_proc_priv;
+
+/* l3dss1 specific data in protocol stack */
+typedef struct
+  { unsigned char last_invoke_id; /* last used value for invoking */
+    unsigned char invoke_used[32]; /* 256 bits for 256 values */
+  } dss1_stk_priv;        
+
+#endif /* only l3dss1_process */

Added: misdn-user/trunk/include/mISDNlib.h
===================================================================
--- misdn-user/trunk/include/mISDNlib.h	                        (rev 0)
+++ misdn-user/trunk/include/mISDNlib.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,457 @@
+#ifndef _mISDN_LIB_H
+#define _mISDN_LIB_H
+
+/* API library to use with /dev/mISDN */
+
+#define	MISDNUSER_MAJOR_VERSION	1
+#define	MISDNUSER_MINOR_VERSION	0
+#define	MISDNUSER_PATCHLEVEL	3
+#define	MISDNUSER_VERSION_CODE	((MISDNUSER_MAJOR_VERSION<<24) | (MISDNUSER_MINOR_VERSION<<16) | MISDNUSER_PATCHLEVEL)
+#define MISDNUSER_VERSION(x,y,z) ((x<<24) | (y<<16) | z)
+
+/* we need somme extentions */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+typedef unsigned short u16;
+
+#include <sys/types.h>
+#include <stdio.h>
+#include "linux/mISDNif.h"
+
+#define mISDN_INBUFFER_SIZE	0x20000
+
+typedef struct _iframe {
+	u_int	addr __attribute__((packed));
+	u_int	prim __attribute__((packed));
+	int	dinfo __attribute__((packed));
+	int	len __attribute__((packed));
+	union {
+		u_char  b[4];
+		void    *p;
+		int     i;
+		u_int     ui;
+	} data;
+} iframe_t;
+
+
+#define TIMEOUT_1SEC	1000000
+#define TIMEOUT_5SEC	5000000
+#define TIMEOUT_10SEC	10000000
+#define TIMEOUT_INFINIT -1
+
+// extern	void xxxxxxxxxx(void);
+
+/* Prototypes from device.c */
+
+/* mISDN_open(void)
+ *
+ * opens a mISDN device and allocate buffers for it
+ *
+ * parameter:
+ *    none
+ *
+ * return:
+ *    the file descriptor or -1 on error and the error cause in errno
+ */
+extern int mISDN_open(void);
+
+/* mISDN_close(int fid)
+ *
+ * close the mISDN device and frees related memory.
+ *
+ * parameter:
+ *    fid - file descriptor returned by mISDN_open
+ *
+ * return:
+ *    0 on success or -1 on error and the error cause in errno
+ *
+ */
+extern int mISDN_close(int fid);
+
+/* mISDN_read(int fid, void *buf, size_t count, int utimeout)
+ *
+ * read one message from device or buffer
+ *
+ * parameter:
+ * fid      - FILE descriptor returned by mISDN_open
+ * buf      - pointer to readbuffer
+ * count    - maximum length of read data
+ * utimeout - maximum time in microseconds to wait for data, if -1
+ *            wait until some data is ready
+ *
+ * return:
+ *    length of read data or -1 on error and the error cause in errno
+ *
+ */
+extern int mISDN_read(int fid, void *buf, size_t count, int utimeout);
+
+/* mISDN_read_frame(int fid, void *buf, size_t count, u_int addr,
+ *                  u_int msgtype, int utimeout)
+ *
+ * read one message for address (addr) and message type (msgtype)
+ * from device or buffer
+ *
+ * parameter:
+ * fid      - FILE descriptor returned by mISDN_open
+ * buf      - pointer to readbuffer
+ * count    - maximum length of read data
+ * addr     - address of frame
+ * msgtype  - message type of frame
+ * utimeout - maximum time in microseconds to wait for data, if -1
+ *            wait until some data is ready
+ *
+ * return:
+ *    length of read data or -1 on error and the error cause in errno
+ *
+ */
+extern int mISDN_read_frame(int fid, void *buf, size_t count, u_int addr,
+	u_int msgtype, int utimeout);
+
+/* mISDN_write(int fid, void *buf, size_t count, int utimeout)
+ *
+ * write a message to device
+ *
+ * parameter:
+ * fid      - FILE descriptor returned by mISDN_open
+ * buf      - pointer to data to write
+ * count    - length of data
+ * utimeout - maximum time in microseconds to wait for device ready to
+ *            accept new data, if -1 wait until device is ready
+ *
+ * return:
+ *    length of written data or -1 on error and the error cause in errno
+ *
+ */
+extern int mISDN_write(int fid, void *buf, size_t count, int utimeout);
+
+/* mISDN_write_frame(int fid, void *fbuf, u_int addr, u_int msgtype,
+ *                   int dinfo, int dlen, void *dbuf, int utimeout)
+ *
+ * write a frame to device
+ *
+ * parameter:
+ * fid      - FILE descriptor returned by mISDN_open
+ * fbuf     - buffer for frame, caller has to provide a big enougth buffer
+ * count    - length of data
+ * addr     - address for frame
+ * msgtype  - message type of frame
+ * dinfo    - data info parameter
+ * dlen     - len of dbuf data, if negativ it is an error code (dbuf len=0)
+ * dbuf     - pointer to frame payload data
+ * utimeout - maximum time in microseconds to wait for device ready to
+ *            accept new data, if -1 wait until device is ready
+ *
+ * return:
+ *    0 if successfull or -1 on error and the error cause in errno
+ *
+ */
+extern int mISDN_write_frame(int fid, void *fbuf, u_int addr, u_int msgtype,
+		int dinfo, int dlen, void *dbuf, int utimeout);
+
+/* int mISDN_select(int n, fd_set *readfds, fd_set *writefds,
+ *                  fd_set *exceptfds, struct timeval *timeout)
+ *
+ * select call which handles mISDN readbuffer
+ *
+ * parameters and use see man select
+ *
+ */
+
+extern int mISDN_select(int n, fd_set *readfds, fd_set *writefds,
+			fd_set *exceptfds, struct timeval *timeout);
+
+
+/* Prototypes from stack.c */
+
+/* mISDN_get_stack_count(int fid)
+ *
+ * get number of ISDN stacks
+ *
+ * parameter:
+ * fid      - FILE descriptor returned by mISDN_open
+ *
+ * return:
+ *    count of ISDN stacks, negativ values for error
+ *
+ */
+extern int mISDN_get_stack_count(int fid);
+
+/* mISDN_get_stack_info(int fid, int stack, void *info, size_t max_len)
+ *
+ * get the info about ISDN stack
+ *
+ * parameter:
+ * fid      - FILE descriptor returned by mISDN_open
+ * stack    - ID of the stack
+ * info     - buffer to store info
+ * max_len  - size of above buffer
+ *
+ * return:
+ *    length of stored info, negativ values are errors
+ *
+ */
+extern int mISDN_get_stack_info(int fid, int stack, void *info, size_t max_len);
+
+/* mISDN_new_stack(int fid, stack_info_t *s_info)
+ *
+ * create a new stack
+ *
+ * parameter:
+ * fid      - FILE descriptor returned by mISDN_open
+ * s_info   - info for the new stack
+ *
+ * return:
+ *    stack id or negativ error code
+ *
+ */
+extern int mISDN_new_stack(int fid, stack_info_t *s_info);
+
+/* mISDN_set_stack(int fid, int stack, mISDN_pid_t *pid)
+ *
+ * setup a stack for the given protocol
+ *
+ * parameter:
+ * fid      - FILE descriptor returned by mISDN_open
+ * stack    - stack id
+ * pid      - description of the stack protocol
+ *
+ * return:
+ *    0 on sucess other values are errors
+ *
+ */
+extern int mISDN_set_stack(int fid, int stack, mISDN_pid_t *pid);
+
+/* mISDN_clear_stack(int fid, int stack)
+ *
+ *  clear the protocol stack
+ *
+ * parameter:
+ * fid      - FILE descriptor returned by mISDN_open
+ * stack    - stack id
+ *
+ * return:
+ *    0 on sucess other values are errors
+ *
+ */
+extern int mISDN_clear_stack(int fid, int stack);
+
+/* mISDNprint_stack_info(FILE *file, stack_info_t *s_info)
+ *
+ * print out the stack_info in readable output
+ *
+ * parameter:
+ * file     - stream to print to
+ * s_info   - stack_info
+ *
+ * return:
+ *    nothing
+ *
+ */
+extern void mISDNprint_stack_info(FILE *file, stack_info_t *s_info);
+
+/* Prototypes from layer.c */
+
+/* mISDN_get_layerid(int fid, int stack, int layer)
+ *
+ * get the id of the layer given by stack and layer number
+ *
+ * parameter:
+ * fid      - FILE descriptor returned by mISDN_open
+ * stack    - ID of the stack
+ * layer    - layer number
+ *
+ * return:
+ *    layer id or negativ error code
+ *
+ */
+extern int mISDN_get_layerid(int fid, int stack, int layer);
+
+/* mISDN_new_layer(int fid, layer_info_t *l_info)
+ *
+ * create a new layer
+ *
+ * parameter:
+ * fid      - FILE descriptor returned by mISDN_open
+ * l_info   - info for the layer
+ *
+ * return:
+ *    0 on success or error code
+ *    l_info->id the id of the new layer
+ *    l_info->clone the id of a cloned layer
+ *
+ */
+extern int mISDN_new_layer(int fid, layer_info_t *l_info);
+
+/* mISDN_preregister_layer(int fid, u_int sid, u_int lid)
+ *
+ * preregister a layer on a stack
+ *
+ * parameter:
+ * fid      - FILE descriptor returned by mISDN_open
+ * sid      - stack id
+ * lid      - layer (instance) id
+ *
+ * return:
+ *    0 on success or error code
+ *
+ */
+extern int mISDN_register_layer(int, u_int, u_int);
+extern int mISDN_unregister_layer(int, u_int, u_int);
+extern int mISDN_get_setstack_ind(int fid, u_int lid);
+
+/* mISDN_connect(int fid, interface_info_t *i_info)
+ *
+ * create a new connection
+ *
+ * parameter:
+ * fid      - FILE descriptor returned by mISDN_open
+ * i_info   - info for the connection
+ *
+ * return:
+ *    0 on success or error code
+ *
+ */
+//extern int mISDN_connect(int fid, interface_info_t *i_info);
+
+/* mISDN_get_layer_info(int fid, int lid, void *info, size_t max_len)
+ *
+ * get the info about ISDN layer
+ *
+ * parameter:
+ * fid      - FILE descriptor returned by mISDN_open
+ * lid      - ID of the layer
+ * info     - buffer to store info
+ * max_len  - size of above buffer
+ *
+ * return:
+ *    length of stored info, negativ values are errors
+ *
+ */
+extern int mISDN_get_layer_info(int fid, int lid, void *info, size_t max_len);
+
+/* mISDNprint_layer_info(FILE *file, layer_info_t *l_info)
+ *
+ * print out the layer_info in readable output
+ *
+ * parameter:
+ * file     - stream to print to
+ * l_info   - layer_info
+ *
+ * return:
+ *    nothing
+ *
+ */
+extern void mISDNprint_layer_info(FILE *file, layer_info_t *l_info);
+
+/* mISDN_get_interface_info(int fid, interface_info_t *i_info)
+ *
+ * get the info about ISDN layer interface
+ *
+ * parameter:
+ * fid      - FILE descriptor returned by mISDN_open
+ * i_info   - contains the info about layer (i_info->owner) and
+ *            which interface (i_info->stat) and gives requested info back
+ *
+ * return:
+ *    0 on sucess other values are errors
+ *
+ */
+//extern int mISDN_get_interface_info(int fid, interface_info_t *i_info);
+
+/* Prototypes and defines for status.c */
+
+/* l1 status_info */
+typedef struct _status_info_l1 {
+	int	len;
+	int	typ;
+	int	protocol;
+	int	status;
+	int	state;
+	int	Flags;
+	int	T3;
+	int	delay;
+	int	debug;
+} status_info_l1_t;
+
+/* State values for l1 state machine (status_info_l1_t state field) */
+extern char *strL1SState[];
+
+
+/* l2 status_info */
+typedef struct _laddr {
+	u_char  A;
+	u_char  B;
+} laddr_t;
+                
+                
+typedef struct _status_info_l2 {
+	int	len;
+	int	typ;
+	int	protocol;
+	int	state;
+	int	sapi;
+	int	tei;
+	laddr_t addr;
+	int	maxlen;
+	u_int	flag;
+	u_int	vs;
+	u_int	va;
+	u_int	vr;
+	int	rc;
+	u_int	window;
+	u_int	sow;
+	int	T200;
+	int	N200;
+	int	T203;
+	int	len_i_queue;
+	int	len_ui_queue;
+	int	len_d_queue;
+	int	debug;
+	int	tei_state;
+	int	tei_ri;
+	int	T202;
+	int	N202;
+	int	tei_debug;
+} status_info_l2_t;
+
+/* State values for l2 state machine (status_info_l2_t state field) */
+extern char *strL2State[];
+
+/* mISDN_get_status_info(int fid, int id, void *info, size_t max_len)
+ *
+ * get status infos about layer instances in the ISDN stack
+ *
+ * parameter:
+ * fid      - FILE descriptor returned by mISDN_open
+ * id       - ID of the instance
+ * info     - buffer to store info
+ * max_len  - size of above buffer
+ *
+ * return:
+ *    length of stored info, negativ values are errors
+ *
+ */
+extern int mISDN_get_status_info(int fid, int id, void *info, size_t max_len);
+
+/* mISDNprint_status(FILE *file, status_info_t *si)
+ *
+ * print out the status in readable output
+ *
+ * parameter:
+ * file     - stream to print to
+ * s_info   - status_info
+ *
+ * return:
+ *    0 on success or -1 if no known status_info
+ *
+ */
+extern int mISDNprint_status(FILE *file, status_info_t *si);
+
+/* private functions */
+
+extern int set_wrrd_atomic(int fid);
+extern int clear_wrrd_atomic(int fid);
+
+#endif

Added: misdn-user/trunk/include/tone.h
===================================================================
--- misdn-user/trunk/include/tone.h	                        (rev 0)
+++ misdn-user/trunk/include/tone.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,29 @@
+#ifndef TONE_H
+#define TONE_H
+
+/* 
+ * These are 10 periods of the 425 Hz tone used by most inband signals
+ * Its actually not exacly 425 Hz, but 416,66667, which fit very well
+ * the 15% tolerance
+ */
+
+#define	TONE_425_SIZE		192
+extern const unsigned char tone_425[TONE_425_SIZE];
+
+/* 
+ * These are 10 ms of silence
+ */
+
+#define TONE_SILENCE_SIZE	80
+extern const unsigned char tone_SILENCE[TONE_SILENCE_SIZE];
+
+/* Values for tone pattern */
+#define TONE_ALERT_SILENCE_TIME	4000000
+#define TONE_ALERT_TIME		1000000
+#define TONE_BUSY_SILENCE_TIME	500000
+#define TONE_BUSY_TIME		500000
+
+extern int		tone_handler(bchannel_t *bc);
+extern int		set_tone(bchannel_t *bc, int tone);
+
+#endif

Added: misdn-user/trunk/lib/Makefile
===================================================================
--- misdn-user/trunk/lib/Makefile	                        (rev 0)
+++ misdn-user/trunk/lib/Makefile	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,48 @@
+CC = gcc
+AR = ar
+RANLIB = ranlib
+
+all: libmISDN.a libmISDN_pic.a libmISDN.so
+
+install:
+	install -m 644 libmISDN.so $(INSTALL_PREFIX)/usr/lib
+	install -m 644 libmISDN_pic.a $(INSTALL_PREFIX)/usr/lib
+	install -m 644 libmISDN.a $(INSTALL_PREFIX)/usr/lib
+
+LIBMISDN_OBJS = device.o layer.o stack.o status.o
+LIBMISDN_PICOBJS = $(LIBMISDN_OBJS:%.o=%.lo)
+
+ifeq ($(shell uname -m),x86_64)
+CFLAGS         += -fPIC
+endif
+
+libmISDN_pic.a: $(LIBMISDN_PICOBJS)
+	$(AR) cru $@ $^
+	$(RANLIB) $@
+
+libmISDN.a: $(LIBMISDN_OBJS)
+	$(AR) cru $@ $^
+	$(RANLIB) $@
+
+libmISDN.so: $(LIBMISDN_OBJS)
+	$(CC) $(CFLAGS) -shared -Xlinker -x -o $@ $^
+
+.c.o:
+	$(CC) $(CFLAGS) -o $@ -c $<
+
+.c.lo:
+	$(CC) $(CFLAGS) -fPIC -o $@ -c $<
+
+device.o device.lo: device.c ../include/mISDNlib.h
+layer.o layer.lo: layer.c ../include/mISDNlib.h
+stack.o stack.lo: stack.c ../include/mISDNlib.h
+status.o status.lo: status.c ../include/mISDNlib.h 
+
+clean:
+	rm -f libmISDN.a libMISDN_pic.a libmISDN.so
+	rm -f *.o *.lo *~ DEADJOE
+
+distclean: clean
+	rm -f *.a
+ 
+.SUFFIXES: .lo

Added: misdn-user/trunk/lib/device.c
===================================================================
--- misdn-user/trunk/lib/device.c	                        (rev 0)
+++ misdn-user/trunk/lib/device.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,688 @@
+#include "mISDNlib.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+
+
+
+/* API library to use with /dev/mISDN */
+
+typedef struct _mISDNdev {
+	struct _mISDNdev	*prev;
+	struct _mISDNdev	*next;
+	pthread_mutex_t		rmutex;
+	pthread_mutex_t		wmutex;
+	int			Flags;
+	int			fid;
+	int			isize;
+	unsigned char		*inbuf;
+	unsigned char           *irp;
+	unsigned char		*iend;
+} mISDNdev_t;
+
+#define FLG_mISDN_WRRD_ATOMIC	1
+
+mISDNdev_t *devlist = NULL;
+
+static	pthread_mutex_t	devlist_lock = PTHREAD_MUTEX_INITIALIZER;
+
+#define mISDN_DEVICE		"/dev/mISDN"
+
+#if 0
+void
+xxxxxxxxxx(void) {
+if (devlist)
+	fprintf(stderr, "xxxxxxxxxx dev %p prev %p next %p\n", devlist, devlist->prev, devlist->next);
+else
+	fprintf(stderr, "xxxxxxxxxx devlist %p\n", devlist);
+}
+#endif
+
+int
+mISDN_open(void)
+{
+	int		fid;
+	mISDNdev_t	*dev;
+
+	
+	if (0>(fid = open(mISDN_DEVICE, O_RDWR | O_NONBLOCK)))
+		return(fid);
+	pthread_mutex_lock(&devlist_lock);
+	dev = devlist;
+	while(dev) {
+		if (dev->fid==fid)
+			break;
+		dev = dev->next;
+	}
+	pthread_mutex_unlock(&devlist_lock);
+	if (dev) {
+		fprintf(stderr, "%s: device %d (%p) has allready fid(%d)\n",
+			__FUNCTION__, dev->fid, dev, fid);
+		close(fid);
+		errno = EBUSY;
+		return(-1); 
+	}
+	dev = malloc(sizeof(mISDNdev_t));
+	if (!dev) {
+		close(fid);
+		errno = ENOMEM;
+		return(-1);
+	}
+	memset(dev, 0, sizeof(mISDNdev_t));
+	dev->fid = fid;
+	dev->isize = mISDN_INBUFFER_SIZE;
+	dev->inbuf = malloc(dev->isize);
+	if (!dev->inbuf) {
+		free(dev);
+		close(fid);
+		errno = ENOMEM;
+		return(-1);
+	}
+	dev->irp = dev->inbuf;
+	dev->iend = dev->inbuf;
+	pthread_mutex_init(&dev->rmutex, NULL);
+	pthread_mutex_init(&dev->wmutex, NULL);
+	
+	pthread_mutex_lock(&devlist_lock);
+	dev->prev = devlist;
+	while(dev->prev && dev->prev->next)
+		dev->prev = dev->prev->next;
+	if (devlist)
+		dev->prev->next = dev;
+	else
+		devlist = dev;
+	pthread_mutex_unlock(&devlist_lock);
+	return(fid);
+}
+
+int
+mISDN_close(int fid)
+{
+	mISDNdev_t	*dev = devlist;
+	int		ret;
+
+	pthread_mutex_lock(&devlist_lock);
+	while(dev) {
+		if (dev->fid==fid)
+			break;
+		dev = dev->next;
+	}
+
+	if (!dev) {
+		pthread_mutex_unlock(&devlist_lock);
+		errno = ENODEV;
+		return(-1);
+	}
+	if (dev->prev)
+		dev->prev->next = dev->next;
+	if (dev->next)
+		dev->next->prev = dev->prev;
+	if (devlist==dev)
+		devlist=dev->next;
+	pthread_mutex_lock(&dev->rmutex);
+#ifdef CLOSE_REPORT
+	fprintf(stderr, "%s: fid(%d) isize(%d) inbuf(%p) irp(%p) iend(%p)\n",
+		__FUNCTION__, fid, dev->isize, dev->inbuf, dev->irp, dev->iend);	
+#endif
+	if (dev->inbuf)
+		free(dev->inbuf);
+	dev->inbuf = NULL;
+	pthread_mutex_unlock(&dev->rmutex);
+	ret = pthread_mutex_destroy(&dev->rmutex);
+	if (ret)
+		fprintf(stderr, "%s: rmutex destroy returns %d\n",
+			__FUNCTION__, ret);
+	pthread_mutex_lock(&dev->wmutex);
+	pthread_mutex_unlock(&dev->wmutex);
+	ret = pthread_mutex_destroy(&dev->wmutex);
+	if (ret)
+		fprintf(stderr, "%s: wmutex destroy returns %d\n",
+			__FUNCTION__, ret);
+	pthread_mutex_unlock(&devlist_lock);
+	free(dev);
+	return(close(fid));
+}
+
+static int
+mISDN_remove_iframe(mISDNdev_t *dev, iframe_t *frm)
+{
+	u_char	*ep;
+	int	len;
+
+	if (frm->len > 0)
+		len = mISDN_HEADER_LEN + frm->len;
+	else
+		len = mISDN_HEADER_LEN;
+	ep = (u_char *)frm;
+	ep += len;
+	if (ep >= dev->iend)
+		dev->iend = (u_char *)frm;
+	else {
+		memcpy(frm, ep, dev->iend - ep);
+		dev->iend -= len; 
+	}
+	
+	return(dev->iend - dev->irp);
+}
+
+int
+mISDN_read(int fid, void *buf, size_t count, int utimeout) {
+	mISDNdev_t	*dev;
+	int		ret = 0, len, sel;
+	fd_set		in;
+	iframe_t	*ifr;
+	struct timeval	tout;
+#ifdef MUTEX_TIMELOCK
+	struct timespec	ts;
+#endif
+	pthread_mutex_lock(&devlist_lock);
+	dev = devlist;
+	while(dev) {
+		if (dev->fid==fid)
+			break;
+		dev = dev->next;
+	}
+	pthread_mutex_unlock(&devlist_lock);
+	if (!dev) {
+		errno = ENODEV;
+		return(-1);
+	}
+	if (utimeout != -1) {
+		tout.tv_sec = utimeout/1000000;
+		tout.tv_usec = utimeout%1000000;
+#ifdef MUTEX_TIMELOCK
+		if (utimeout == 0) {
+			ret = pthread_mutex_trylock(&dev->rmutex);
+			if (ret) {
+				fprintf(stderr, "%s: mutex_trylock (%d)\n",
+					__FUNCTION__, ret);
+				errno = ret;
+				return(-1);
+			}
+		} else {
+#ifdef CLOCK_REALTIME
+			clock_gettime(CLOCK_REALTIME, &ts);
+#else
+			{
+				struct timeval  tv;
+				struct timezone tz;
+
+				gettimeofday(&tv,&tz);
+				TIMEVAL_TO_TIMESPEC(&tv,&ts);
+			}
+#endif
+			ts.tv_sec += tout.tv_sec;
+			ts.tv_nsec += 1000*tout.tv_usec;
+			if (ts.tv_nsec > 1000000000L) {
+				ts.tv_sec++;
+				ts.tv_nsec -= 1000000000L;
+			}
+			ret = pthread_mutex_timedlock(&dev->rmutex, &ts);
+			if (ret) {
+				fprintf(stderr, "%s: mutex_timedlock (%d)\n",
+					__FUNCTION__, ret);
+				errno = ret;
+				return(-1);
+			}
+		}
+#else
+		pthread_mutex_lock(&dev->rmutex);
+#endif
+	} else
+		pthread_mutex_lock(&dev->rmutex);
+
+	if (dev->Flags & FLG_mISDN_WRRD_ATOMIC) {
+//		fprintf(stderr, "%s: WRRD_ATOMIC try again\n", __FUNCTION__);
+		errno = EAGAIN;
+		ret = -1;
+		goto out;
+	}
+	len = dev->iend - dev->irp;
+	if (!len) {
+		dev->irp = dev->iend = dev->inbuf;
+		pthread_mutex_unlock(&dev->rmutex);
+		FD_ZERO(&in);
+		FD_SET(fid, &in);
+		if (utimeout != -1) {
+			sel = select(fid + 1, &in, NULL, NULL, &tout);
+		} else
+			sel = select(fid + 1, &in, NULL, NULL, NULL);
+		if (sel<0) {
+//			fprintf(stderr, "%s: select err(%d)\n", __FUNCTION__, errno);
+			return(sel);
+		} else if (sel==0) {
+//			fprintf(stderr, "%s: select timed out\n", __FUNCTION__);
+			return(0);
+		}
+		if (FD_ISSET(fid, &in)) {
+#ifdef MUTEX_TIMELOCK
+			if (!utimeout) {
+				ret = pthread_mutex_trylock(&dev->rmutex);
+				if (ret) {
+					fprintf(stderr, "%s: mutex_trylock (%d)\n",
+						__FUNCTION__, ret);
+					errno = ret;
+					return(-1);
+				}
+			} else
+#endif
+				pthread_mutex_lock(&dev->rmutex);
+			len = dev->isize  - (dev->iend - dev->irp);
+			if (len<=0) {
+				errno = ENOSPC;
+				ret = -1;
+				goto out;
+			}
+			if (dev->Flags & FLG_mISDN_WRRD_ATOMIC) {
+//				fprintf(stderr, "%s: WRRD_ATOMIC try again\n", __FUNCTION__);
+				errno = EAGAIN;
+				ret = -1;
+				goto out;
+			}
+			len = read(fid, dev->iend, len);
+//			fprintf(stderr, "%s: read %d\n", __FUNCTION__, len);
+			if (len <= 0) {
+				ret = len;
+				goto out;
+			}
+			dev->iend += len;
+			len = dev->iend - dev->irp;
+		} else {
+			return(0);
+		}
+	}
+	if (len < mISDN_HEADER_LEN) {
+		dev->iend = dev->irp;
+		fprintf(stderr, "%s: frame too short:%d\n",
+			__FUNCTION__, len);
+		errno = EINVAL;
+		ret = -1;
+		goto out;
+	}
+	ifr = (iframe_t *)dev->irp;
+	if (ifr->len > 0) {
+		if ((ifr->len + mISDN_HEADER_LEN) > len) {
+			dev->iend = dev->irp;
+			errno = EINVAL;
+			ret = -1;
+			goto out;
+		}
+		len = ifr->len + mISDN_HEADER_LEN;
+	} else
+		len = mISDN_HEADER_LEN;
+	if (len>count) {
+		errno = ENOSPC;
+		ret = -1;
+		goto out;
+	}
+	memcpy(buf, dev->irp, len);
+	dev->irp += len;
+	ret = len;
+out:
+	pthread_mutex_unlock(&dev->rmutex);
+	return(ret);
+}
+
+static iframe_t *
+mISDN_find_iframe(mISDNdev_t *dev, u_int addr, u_int prim) {
+	iframe_t	*frm;
+	u_char		*rp;
+	
+	rp = dev->irp;
+	while(rp<dev->iend) {
+		if ((dev->iend - rp) < mISDN_HEADER_LEN) {
+			return(NULL);
+		}
+		frm = (iframe_t *)rp;
+		if ((frm->addr == addr) && (frm->prim == prim))
+			return(frm);
+		if (frm->len > 0)
+			rp += mISDN_HEADER_LEN + frm->len;
+		else
+			rp += mISDN_HEADER_LEN;
+	}
+	return(NULL);
+}
+
+
+int
+mISDN_read_frame(int fid, void *buf, size_t count, u_int addr, u_int msgtype,
+	int utimeout)
+{
+	mISDNdev_t	*dev;
+	int		len, sel, first, ret = 0;
+	fd_set		in;
+	iframe_t	*ifr;
+	struct timeval	tout;
+#ifdef MUTEX_TIMELOCK
+	struct timespec	ts;
+#endif
+
+	pthread_mutex_lock(&devlist_lock);
+	dev = devlist;
+	while(dev) {
+		if (dev->fid==fid)
+			break;
+		dev = dev->next;
+	}
+	pthread_mutex_unlock(&devlist_lock);
+	if (!dev) {
+		errno = ENODEV;
+		return(-1);
+	}
+	if (utimeout != -1) {
+		tout.tv_sec = utimeout/1000000;
+		tout.tv_usec = utimeout%1000000;
+#ifdef MUTEX_TIMELOCK
+		if (utimeout == 0) {
+			ret = pthread_mutex_trylock(&dev->rmutex);
+			if (ret) {
+				fprintf(stderr, "%s: mutex_trylock (%d)\n",
+					__FUNCTION__, ret);
+				errno = ret;
+				return(-1);
+			}
+		} else {
+#ifdef CLOCK_REALTIME
+			clock_gettime(CLOCK_REALTIME, &ts);
+#else
+			{
+				struct timeval  tv;
+				struct timezone tz;
+
+				gettimeofday(&tv,&tz);
+				TIMEVAL_TO_TIMESPEC(&tv,&ts);
+			}
+#endif
+			ts.tv_sec += tout.tv_sec;
+			ts.tv_nsec += 1000*tout.tv_usec;
+			if (ts.tv_nsec > 1000000000L) {
+				ts.tv_sec++;
+				ts.tv_nsec -= 1000000000L;
+			}
+			ret = pthread_mutex_timedlock(&dev->rmutex, &ts);
+			if (ret) {
+				fprintf(stderr, "%s: mutex_timedlock (%d)\n",
+					__FUNCTION__, ret);
+				errno = ret;
+				return(-1);
+			}
+		}
+#else
+		pthread_mutex_lock(&dev->rmutex);
+#endif
+	} else
+		pthread_mutex_lock(&dev->rmutex);
+
+	first = 1;
+	while((utimeout == -1) || tout.tv_sec || tout.tv_usec || first) {
+		if (!first || !(dev->iend - dev->irp)) {
+			FD_ZERO(&in);
+			FD_SET(fid, &in);
+			if (utimeout != -1)
+				sel = select(fid + 1, &in, NULL, NULL, &tout);
+			else
+				sel = select(fid + 1, &in, NULL, NULL, NULL);
+			if (sel<0) {
+//				fprintf(stderr, "%s: select err(%d)\n", __FUNCTION__, errno);
+				ret = sel;
+				goto out;
+			} else if (sel==0) {
+//				fprintf(stderr, "%s: select timed out\n", __FUNCTION__);
+				ret = 0;
+				goto out;
+			}
+			if (FD_ISSET(fid, &in)) {
+				len = dev->isize - (dev->iend - dev->irp);
+				if (len<=0) {
+					errno = ENOSPC;
+					ret = -1;
+					goto out;
+				}
+				len = read(fid, dev->iend, len);
+//				fprintf(stderr, "%s: read %d\n", __FUNCTION__, len);
+				if (len <= 0) {
+					ret = len;
+					goto out;
+				}
+				dev->iend += len;
+			} else
+				continue;
+		}
+		if (dev->iend - dev->irp) {
+			ifr = mISDN_find_iframe(dev, addr, msgtype);
+			if (ifr) {
+				if (ifr->len > 0) {
+#if 0
+					if ((ifr->len + mISDN_HEADER_LEN) > len) {
+						dev->irp = dev->iend;
+						errno = EINVAL;
+						ret = -1;
+						goto out;
+					}
+#endif
+					len = ifr->len + mISDN_HEADER_LEN;
+				} else
+					len = mISDN_HEADER_LEN;
+				if (len > count) {
+					errno = ENOSPC;
+					ret = -1;
+					goto out;
+				}
+				memcpy(buf, ifr, len);
+				mISDN_remove_iframe(dev, ifr);
+				ret = len;
+				goto out;
+			}
+		}
+		first = 0;
+	}
+out:
+	pthread_mutex_unlock(&dev->rmutex);
+	return(ret);
+}
+
+int
+mISDN_write(int fid, void *buf, size_t count, int utimeout) {
+	mISDNdev_t	*dev;
+	int		len, sel;
+	fd_set		out;
+	struct timeval	tout;
+#ifdef MUTEX_TIMELOCK
+	struct timespec	ts;
+	int		ret;
+#endif
+
+	pthread_mutex_lock(&devlist_lock);
+	dev = devlist;
+	while(dev) {
+		if (dev->fid==fid)
+			break;
+		dev = dev->next;
+	}
+	pthread_mutex_unlock(&devlist_lock);
+	if (!dev) {
+		errno = ENODEV;
+		return(-1);
+	}
+	FD_ZERO(&out);
+	FD_SET(fid, &out);
+	if (utimeout != -1) {
+		tout.tv_sec = utimeout/1000000;
+		tout.tv_usec = utimeout%1000000;
+		sel = select(fid + 1, NULL, &out, NULL, &tout);
+	} else
+		sel = select(fid + 1, NULL, &out, NULL, NULL);
+	if (sel<=0)
+		return(sel);
+	if (!FD_ISSET(fid, &out))
+		return(0);
+	if (utimeout != -1) {
+#ifdef MUTEX_TIMELOCK
+		if (utimeout == 0) {
+			ret = pthread_mutex_trylock(&dev->wmutex);
+			if (ret) {
+				fprintf(stderr, "%s: mutex_trylock (%d)\n",
+					__FUNCTION__, ret);
+				errno = ret;
+				return(-1);
+			}
+		} else {
+#ifdef CLOCK_REALTIME
+			clock_gettime(CLOCK_REALTIME, &ts);
+#else
+			{
+				struct timeval  tv;
+				struct timezone tz;
+
+				gettimeofday(&tv,&tz);
+				TIMEVAL_TO_TIMESPEC(&tv,&ts);
+			}
+#endif
+			ts.tv_sec += tout.tv_sec;
+			ts.tv_nsec += 1000*tout.tv_usec;
+			if (ts.tv_nsec > 1000000000L) {
+				ts.tv_sec++;
+				ts.tv_nsec -= 1000000000L;
+			}
+			ret = pthread_mutex_timedlock(&dev->wmutex, &ts);
+			if (ret) {
+				fprintf(stderr, "%s: mutex_timedlock (%d)\n",
+					__FUNCTION__, ret);
+				errno = ret;
+				return(-1);
+			}
+		}
+#else
+		pthread_mutex_lock(&dev->wmutex);
+#endif
+	} else
+		pthread_mutex_lock(&dev->wmutex);
+	len = write(fid, buf, count);
+	pthread_mutex_unlock(&dev->wmutex);
+	return(len);
+}
+
+int
+mISDN_write_frame(int fid, void *fbuf, u_int addr, u_int msgtype,
+		int dinfo, int dlen, void *dbuf, int utimeout)
+{
+	iframe_t        *ifr = fbuf;
+	int		len = mISDN_HEADER_LEN;
+	int		ret;
+
+	if (!fbuf) {
+		errno = EINVAL;
+		return(-1);
+	}
+	if ((dlen > 0) && !dbuf) {
+		errno = EINVAL;
+		return(-1);
+	}
+	ifr->addr = addr;
+	ifr->prim = msgtype;
+	ifr->dinfo= dinfo;
+	ifr->len  = dlen;
+	if (dlen>0) {
+		len += dlen;
+		memcpy(&ifr->data.i, dbuf, dlen);
+	}
+	ret = mISDN_write(fid, ifr, len, utimeout);
+	if (ret == len)
+		ret = 0;
+	else if (ret>=0) {
+		errno = ENOSPC;
+		ret = -1;
+	}
+	return(ret);
+}
+
+int
+mISDN_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+	struct timeval *timeout)
+{
+	mISDNdev_t	*dev = devlist;
+
+	if (readfds) {
+		pthread_mutex_lock(&devlist_lock);
+		while(dev) {
+			if (FD_ISSET(dev->fid, readfds)) {
+				if (dev->iend - dev->irp) {
+					pthread_mutex_unlock(&devlist_lock);
+					FD_ZERO(readfds);
+					FD_SET(dev->fid, readfds);
+					if (writefds)
+						FD_ZERO(writefds);
+					if (exceptfds)
+						FD_ZERO(exceptfds);
+					return(1);
+				}
+			}
+			dev = dev->next;
+		}
+		pthread_mutex_unlock(&devlist_lock);
+	}
+	
+	return(select(n, readfds, writefds, exceptfds, timeout));
+}
+
+int
+set_wrrd_atomic(int fid)
+{
+	mISDNdev_t	*dev;
+	int		ret;
+
+	pthread_mutex_lock(&devlist_lock);
+	dev = devlist;
+	while(dev) {
+		if (dev->fid==fid)
+			break;
+		dev = dev->next;
+	}
+	pthread_mutex_unlock(&devlist_lock);
+	if (!dev) {
+		return(-1);
+	}
+	pthread_mutex_lock(&dev->rmutex);
+	if (dev->Flags & FLG_mISDN_WRRD_ATOMIC)
+		ret = 1;
+	else {
+		ret = 0;
+		dev->Flags |= FLG_mISDN_WRRD_ATOMIC;
+	}
+	pthread_mutex_unlock(&dev->rmutex);
+	return(ret);
+}
+
+int
+clear_wrrd_atomic(int fid)
+{
+	mISDNdev_t	*dev;
+	int		ret;
+
+	pthread_mutex_lock(&devlist_lock);
+	dev = devlist;
+	while(dev) {
+		if (dev->fid==fid)
+			break;
+		dev = dev->next;
+	}
+	pthread_mutex_unlock(&devlist_lock);
+	if (!dev) {
+		return(-1);
+	}
+	if (dev->Flags & FLG_mISDN_WRRD_ATOMIC) {
+		dev->Flags &= ~FLG_mISDN_WRRD_ATOMIC;
+		ret = 0;
+	} else {
+		ret = 1;
+	}
+	return(ret);
+}

Added: misdn-user/trunk/lib/layer.c
===================================================================
--- misdn-user/trunk/lib/layer.c	                        (rev 0)
+++ misdn-user/trunk/lib/layer.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,233 @@
+#include <errno.h>
+#include <string.h>
+#include "mISDNlib.h"
+
+int
+mISDN_get_layerid(int fid, int stack, int layer)
+{
+	iframe_t	ifr;
+	int		ret;
+
+	set_wrrd_atomic(fid);
+	ret = mISDN_write_frame(fid, &ifr, stack, MGR_GETLAYERID | REQUEST,
+		layer, 0, NULL, TIMEOUT_1SEC);
+	if (ret) {
+		clear_wrrd_atomic(fid);
+		return(ret);
+	}
+	ret = mISDN_read_frame(fid, &ifr, sizeof(iframe_t),
+		stack, MGR_GETLAYERID | CONFIRM, TIMEOUT_1SEC);
+	clear_wrrd_atomic(fid);
+	if (ret != mISDN_HEADER_LEN) {
+		if (ret>0)
+			ret = -EINVAL;
+			 
+	} else {
+		if (ifr.len)
+			ret = ifr.len;
+		else	
+			ret = ifr.dinfo;
+	}
+	return(ret);
+}
+
+int 
+mISDN_new_layer(int fid, layer_info_t *l_info)
+{
+	unsigned char	buf[sizeof(layer_info_t) + mISDN_HEADER_LEN];
+	iframe_t	*ifr = (iframe_t *)buf;
+	int		ret;
+	u_int		*ip;
+	
+	set_wrrd_atomic(fid);
+	ret = mISDN_write_frame(fid, buf, 0, MGR_NEWLAYER | REQUEST,
+		0, sizeof(layer_info_t), l_info, TIMEOUT_1SEC);
+//	fprintf(stderr, "%s: wret %d\n", __FUNCTION__, ret);
+	if (ret) {
+		clear_wrrd_atomic(fid);
+		return(ret);
+	}
+	ret = mISDN_read_frame(fid, ifr, sizeof(layer_info_t) + mISDN_HEADER_LEN,
+		0, MGR_NEWLAYER | CONFIRM, TIMEOUT_1SEC);
+	clear_wrrd_atomic(fid);
+//	fprintf(stderr, "%s: rret %d\n", __FUNCTION__, ret);
+	if (ret<0)
+		return(ret);
+	if (ret < (mISDN_HEADER_LEN + 2*sizeof(int))) {
+		if (ret == mISDN_HEADER_LEN)
+			ret = ifr->len;
+		else if (ret>0)
+			ret = -EINVAL;
+	} else {
+		ret = 0;
+		ip = &ifr->data.ui;
+		l_info->id = *ip++;
+		l_info->clone = *ip;
+	}
+//	fprintf(stderr, "%s: ret %x\n", __FUNCTION__, ret);
+	return(ret);
+}
+
+int
+mISDN_register_layer(int fid, u_int sid, u_int lid) 
+{
+	iframe_t	ifr;
+	int		ret;
+
+	set_wrrd_atomic(fid);
+	ret = mISDN_write_frame(fid, &ifr, sid, MGR_REGLAYER | REQUEST, lid,
+		0, NULL, TIMEOUT_1SEC);
+//	fprintf(stderr, "%s: wret %d\n", __FUNCTION__, ret); 
+	if (ret) {
+		clear_wrrd_atomic(fid);
+		return(ret);
+	}
+	ret = mISDN_read_frame(fid, &ifr, sizeof(iframe_t),
+		sid, MGR_REGLAYER | CONFIRM, TIMEOUT_1SEC);
+//	fprintf(stderr, "%s: rret %d\n", __FUNCTION__, ret);
+	if (ret != mISDN_HEADER_LEN) {
+		if (ret >= 0)
+			ret = -1;
+	} else {
+		ret = ifr.len;
+	}
+	return(ret);
+}
+
+int
+mISDN_unregister_layer(int fid, u_int sid, u_int lid) 
+{
+	iframe_t	ifr;
+	int		ret;
+
+	set_wrrd_atomic(fid);
+	ret = mISDN_write_frame(fid, &ifr, sid, MGR_UNREGLAYER | REQUEST, lid,
+		0, NULL, TIMEOUT_1SEC);
+//	fprintf(stderr, "%s: wret %d\n", __FUNCTION__, ret); 
+	if (ret) {
+		clear_wrrd_atomic(fid);
+		return(ret);
+	}
+	ret = mISDN_read_frame(fid, &ifr, sizeof(iframe_t),
+		sid, MGR_UNREGLAYER | CONFIRM, TIMEOUT_1SEC);
+//	fprintf(stderr, "%s: rret %d\n", __FUNCTION__, ret);
+	if (ret != mISDN_HEADER_LEN) {
+		if (ret >= 0)
+			ret = -1;
+	} else {
+		ret = ifr.len;
+	}
+	return(ret);
+}
+
+int
+mISDN_get_setstack_ind(int fid, u_int lid)
+{
+	iframe_t	ifr;
+	int		ret;
+
+	ret = mISDN_read_frame(fid, &ifr, sizeof(iframe_t),
+		lid, MGR_SETSTACK | INDICATION, TIMEOUT_5SEC);
+//	fprintf(stderr, "%s: rret %d\n", __FUNCTION__, ret);
+	if (ret != mISDN_HEADER_LEN) {
+		if (ret >= 0)
+			ret = -1;
+	} else {
+		ret = ifr.len;
+	}
+	return(ret);
+}
+
+#ifdef OBSOLATE
+int
+mISDN_connect(int fid, interface_info_t *i_info)
+{
+	unsigned char	buf[sizeof(interface_info_t) + mISDN_HEADER_LEN];
+	iframe_t	ifr;
+	int		ret;
+	
+	set_wrrd_atomic(fid);
+	ret = mISDN_write_frame(fid, buf, 0, MGR_CONNECT | REQUEST,
+		0, sizeof(interface_info_t), i_info, TIMEOUT_1SEC);
+	if (ret) {
+		clear_wrrd_atomic(fid);
+		return(ret);
+	}
+	ret = mISDN_read_frame(fid, &ifr, sizeof(iframe_t),
+		0, MGR_CONNECT | CONFIRM, TIMEOUT_1SEC);
+	clear_wrrd_atomic(fid);
+	if (ret != mISDN_HEADER_LEN) {
+		if (ret > 0)
+			ret = -1; 
+	} else {
+		if (ifr.len)
+			ret = ifr.len;
+		else
+			ret = ifr.data.i;
+	}
+	return(ret);
+}
+#endif
+
+int
+mISDN_get_layer_info(int fid, int lid, void *info, size_t max_len)
+{
+	iframe_t	ifr;
+	int		ret;
+
+	set_wrrd_atomic(fid);
+	ret = mISDN_write_frame(fid, &ifr, lid, MGR_GETLAYER | REQUEST,
+		0, 0, NULL, TIMEOUT_1SEC);
+	if (ret) {
+		clear_wrrd_atomic(fid);
+		return(ret);
+	}
+	ret = mISDN_read_frame(fid, info, max_len,
+		lid, MGR_GETLAYER | CONFIRM, TIMEOUT_1SEC);
+	clear_wrrd_atomic(fid);
+	return(ret);
+}
+
+void
+mISDNprint_layer_info(FILE *file, layer_info_t *l_info)
+{
+	int i;
+
+	fprintf(file, "instance id %08x\n", l_info->id);
+	fprintf(file, "       name %s\n", l_info->name);
+	fprintf(file, "        obj %08x\n", l_info->object_id);
+	fprintf(file, "        ext %08x\n", l_info->extentions);
+	fprintf(file, "      stack %08x\n", l_info->st);
+	fprintf(file, "      clone %08x\n", l_info->clone);
+	fprintf(file, "     parent %08x\n", l_info->parent);
+	for(i=0;i<=MAX_LAYER_NR;i++)
+		fprintf(file, "   prot%d %08x\n", i, l_info->pid.protocol[i]);
+}
+
+#ifdef OBSOLATE
+int
+mISDN_get_interface_info(int fid, interface_info_t *i_info)
+{
+	unsigned char   buf[sizeof(interface_info_t) + mISDN_HEADER_LEN];
+	iframe_t	*ifr = (iframe_t *)buf;
+	int		ret;
+
+	set_wrrd_atomic(fid);
+	ret = mISDN_write_frame(fid, ifr, i_info->owner, MGR_GETIF | REQUEST,
+		i_info->stat, 0, NULL, TIMEOUT_1SEC);
+	if (ret) {
+		clear_wrrd_atomic(fid);
+		return(ret);
+	}
+	ret = mISDN_read_frame(fid, ifr, sizeof(interface_info_t) + mISDN_HEADER_LEN,
+		i_info->owner, MGR_GETIF | CONFIRM, TIMEOUT_1SEC);
+	clear_wrrd_atomic(fid);
+	if (ret==mISDN_HEADER_LEN) {
+		ret = ifr->data.i;
+	} else if (ret == (sizeof(interface_info_t) + mISDN_HEADER_LEN)) {
+		ret = 0;
+		memcpy(i_info, &ifr->data.p, sizeof(interface_info_t));
+	}
+	return(ret);
+}
+#endif

Added: misdn-user/trunk/lib/stack.c
===================================================================
--- misdn-user/trunk/lib/stack.c	                        (rev 0)
+++ misdn-user/trunk/lib/stack.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,145 @@
+#include <errno.h>
+#include <string.h>
+#include "mISDNlib.h"
+// #include <stdio.h>
+
+int
+mISDN_get_stack_count(int fid)
+{
+	iframe_t	ifr;
+	int		ret;
+
+	set_wrrd_atomic(fid);
+	ret = mISDN_write_frame(fid, &ifr, 0, MGR_GETSTACK | REQUEST,
+		0, 0, NULL, TIMEOUT_1SEC);
+	if (ret) {
+		clear_wrrd_atomic(fid);
+		return(ret);
+	}
+	ret = mISDN_read_frame(fid, &ifr, sizeof(iframe_t), 0,
+		MGR_GETSTACK | CONFIRM, TIMEOUT_1SEC);
+	clear_wrrd_atomic(fid);
+	if (ret != mISDN_HEADER_LEN) {
+		if (ret > 0)
+			ret = -EINVAL; 
+	} else {
+		if (ifr.len)
+			ret = ifr.len;
+		else
+			ret = ifr.dinfo;
+	}
+	return(ret);
+}
+
+int
+mISDN_new_stack(int fid, stack_info_t *s_info)
+{
+	u_char		buf[sizeof(stack_info_t) + mISDN_HEADER_LEN];
+	iframe_t	ifr;
+	int		ret;
+
+	set_wrrd_atomic(fid);
+	ret = mISDN_write_frame(fid, buf, 0, MGR_NEWSTACK | REQUEST,
+		0, sizeof(stack_info_t), s_info, TIMEOUT_1SEC);
+	if (ret) {
+		clear_wrrd_atomic(fid);
+		return(ret);
+	}
+	ret = mISDN_read_frame(fid, &ifr, sizeof(iframe_t), 0, 
+		MGR_NEWSTACK | CONFIRM, TIMEOUT_1SEC);
+	clear_wrrd_atomic(fid);
+	if (ret == mISDN_HEADER_LEN) {
+		if (ifr.len)
+			ret = ifr.len;
+		else
+			ret = ifr.dinfo;
+	}
+	return(ret);
+}
+
+int
+mISDN_set_stack(int fid, int stack, mISDN_pid_t *pid)
+{
+	u_char		buf[sizeof(mISDN_pid_t) + mISDN_HEADER_LEN];
+	iframe_t	ifr;
+	int		ret;
+
+	set_wrrd_atomic(fid);
+	ret = mISDN_write_frame(fid, buf, stack, MGR_SETSTACK | REQUEST,
+		0, sizeof(mISDN_pid_t), pid, TIMEOUT_1SEC);
+	if (ret) {
+		clear_wrrd_atomic(fid);
+		return(ret);
+	}
+	ret = mISDN_read_frame(fid, &ifr, sizeof(iframe_t),
+		stack, MGR_SETSTACK | CONFIRM, TIMEOUT_1SEC);
+	clear_wrrd_atomic(fid);
+	if (ret == mISDN_HEADER_LEN)
+		ret = ifr.len;
+	else if (ret>0)
+		ret = -EINVAL;
+	return(ret);
+}
+
+int
+mISDN_clear_stack(int fid, int stack)
+{
+	iframe_t	ifr;
+	int		ret;
+
+	set_wrrd_atomic(fid);
+	ret = mISDN_write_frame(fid, &ifr, stack, MGR_CLEARSTACK | REQUEST,
+		0, 0, NULL, TIMEOUT_1SEC);
+	if (ret) {
+		clear_wrrd_atomic(fid);
+		return(ret);
+	}
+	ret = mISDN_read_frame(fid, &ifr, sizeof(iframe_t),
+		stack, MGR_CLEARSTACK | CONFIRM, TIMEOUT_1SEC);
+	clear_wrrd_atomic(fid);
+	if (ret == mISDN_HEADER_LEN)
+		ret = ifr.len;
+	else if (ret>0)
+		ret = -EINVAL;
+	return(ret);
+}
+
+int
+mISDN_get_stack_info(int fid, int stack, void *info, size_t max_len)
+{
+	iframe_t	ifr;
+	int		ret;
+
+	set_wrrd_atomic(fid);
+
+	ret = mISDN_write_frame(fid, &ifr, stack, MGR_GETSTACK | REQUEST,
+		0, 0, NULL, TIMEOUT_1SEC);
+	if (ret) {
+		clear_wrrd_atomic(fid);
+		return(ret);
+	}
+	ret = mISDN_read_frame(fid, info, max_len,
+		stack, MGR_GETSTACK | CONFIRM, TIMEOUT_1SEC);
+	clear_wrrd_atomic(fid);
+	if (ret == mISDN_HEADER_LEN)
+		ret = ((iframe_t *)info)->len;
+	return(ret);
+}
+
+void
+mISDNprint_stack_info(FILE *file, stack_info_t *s_info)
+{
+	int i;
+
+	fprintf(file, "stack id %08x\n", s_info->id);
+	fprintf(file, "     ext %08x\n", s_info->extentions);
+	for(i=0;i<=MAX_LAYER_NR;i++)
+		fprintf(file, "   prot%d %08x\n", i, s_info->pid.protocol[i]);
+	for(i=0;i<s_info->instcnt;i++)
+		fprintf(file, "   inst%d %08x\n", i, s_info->inst[i]);
+	fprintf(file, "     mgr %08x\n", s_info->mgr);
+	fprintf(file, "  master %08x\n", s_info->master);
+	fprintf(file, "   clone %08x\n", s_info->clone);
+	for(i=0;i<s_info->childcnt;i++)
+		fprintf(file, "  child%d %08x\n", i, s_info->child[i]);
+}

Added: misdn-user/trunk/lib/status.c
===================================================================
--- misdn-user/trunk/lib/status.c	                        (rev 0)
+++ misdn-user/trunk/lib/status.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,79 @@
+#include <errno.h>
+#include <string.h>
+#include "mISDNlib.h"
+
+/* State values for l1 state machine (status_info_l1_t state field) */
+char *strL1SState[] =
+{
+	"ST_L1_F2",
+	"ST_L1_F3",
+	"ST_L1_F4",
+	"ST_L1_F5",
+	"ST_L1_F6",
+	"ST_L1_F7",
+	"ST_L1_F8",
+};
+
+
+/* State values for l2 state machine (status_info_l2_t state field) */
+char *strL2State[] =
+{
+	"ST_L2_1",
+	"ST_L2_2",
+	"ST_L2_3",
+	"ST_L2_4",
+	"ST_L2_5",
+	"ST_L2_6",
+	"ST_L2_7",
+	"ST_L2_8",
+};
+
+int
+mISDN_get_status_info(int fid, int id, void *info, size_t max_len)
+{
+	iframe_t	ifr;
+	int		ret;
+
+	set_wrrd_atomic(fid);
+	ret = mISDN_write_frame(fid, &ifr, id, MGR_STATUS | REQUEST,
+		0, 0, NULL, TIMEOUT_1SEC);
+	if (ret) {
+		clear_wrrd_atomic(fid);
+		return(ret);
+	}
+	ret = mISDN_read_frame(fid, info, max_len,
+		id, MGR_STATUS | CONFIRM, TIMEOUT_1SEC);
+	clear_wrrd_atomic(fid);
+	return(ret);
+}
+
+/* not complete now */
+
+int 
+mISDNprint_status(FILE *file, status_info_t *si)
+{
+	int ret=0;
+	status_info_l1_t *si1;
+	status_info_l2_t *si2;
+
+	switch(si->typ) {
+		case STATUS_INFO_L1:
+			si1 = (status_info_l1_t *)si;
+			fprintf(file," prot:%x status:%d state:%s Flags:%x\n",
+				si1->protocol, si1->status,
+				strL1SState[si1->state], si1->Flags);
+			break;
+		case STATUS_INFO_L2:
+			si2 = (status_info_l2_t *)si;
+			fprintf(file," prot:%x tei:%d state:%s flag:%x\n",
+				si2->protocol, si2->tei,
+				strL2State[si2->state], si2->flag);
+			break;
+		default:
+			fprintf(file, "unknown status type %d\n", si->typ);
+			break;
+	}
+	return(ret);
+}
+
+

Added: misdn-user/trunk/suppserv/Makefile
===================================================================
--- misdn-user/trunk/suppserv/Makefile	                        (rev 0)
+++ misdn-user/trunk/suppserv/Makefile	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,45 @@
+CC = gcc
+AR = ar
+RANLIB = ranlib
+
+#CFLAGS += -DASN1_DEBUG
+
+SUPPSERV_OBJ = asn1.o asn1_enc.o asn1_generic.o asn1_aoc.o asn1_basic_service.o asn1_comp.o asn1_diversion.o asn1_address.o fac.o
+SUPPSERV_PICOBJ = $(SUPPSERV_OBJ:%.o=%.lo)
+
+all: libsuppserv.a libsuppserv_pic.a libsuppserv.so
+
+main: $(SUPPSERVOBJ)
+
+install:
+	install -m 644 libsuppserv.a $(INSTALL_PREFIX)/usr/lib
+	install -m 644 libsuppserv_pic.a $(INSTALL_PREFIX)/usr/lib
+	install -m 644 libsuppserv.so $(INSTALL_PREFIX)/usr/lib
+	cp *.h $(INSTALL_PREFIX)/usr/include/mISDNuser/
+
+libsuppserv_pic.a: $(SUPPSERV_PICOBJ)
+	$(AR) cru $@ $<
+	$(RANLIB) $@
+
+libsuppserv.a: $(SUPPSERV_OBJ)
+	$(AR) cru $@ $<
+	$(RANLIB) $@
+
+libsuppserv.so: $(SUPPSERV_OBJ)
+	$(CC) -shared -Xlinker -x -o $@ $^
+
+
+.c.o:
+	$(CC) $(CFLAGS) -o $@ -c $<
+
+.c.lo:
+	$(CC) $(CFLAGS) -fPIC -o $@ -c $<
+
+clean:
+	rm -f *.o *.lo *~ DEADJOE *.so
+	rm -f libsuppserv.a libsuppserv_pic.a
+
+distclean: clean
+	rm -f *.a
+
+.SUFFIXES: .lo

Added: misdn-user/trunk/suppserv/asn1.c
===================================================================
--- misdn-user/trunk/suppserv/asn1.c	                        (rev 0)
+++ misdn-user/trunk/suppserv/asn1.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,80 @@
+/* $Id: asn1.c,v 1.2 2006/08/16 13:14:54 nadi Exp $
+ *
+ */
+
+#include "asn1.h"
+
+int ParseTag(u_char *p, u_char *end, int *tag)
+{
+	*tag = *p;
+	return 1;
+}
+
+int ParseLen(u_char *p, u_char *end, int *len)
+{
+	int l, i;
+
+	if (*p == 0x80) { // indefinite
+		*len = -1;
+		return 1;
+	}
+	if (!(*p & 0x80)) { // one byte
+		*len = *p;
+		return 1;
+	}
+	*len = 0;
+	l = *p & ~0x80;
+	p++;
+	for (i = 0; i < l; i++) {
+		*len = (*len << 8) + *p; 
+		p++;
+	}
+	return l+1;
+}
+
+#ifdef ASN1_DEBUG
+int
+ParseASN1(u_char *p, u_char *end, int level)
+{
+	int tag, len;
+	int ret;
+	int j;
+	u_char *tag_end, *beg;
+
+	beg = p;
+
+	CallASN1(ret, p, end, ParseTag(p, end, &tag));
+	CallASN1(ret, p, end, ParseLen(p, end, &len));
+#ifdef ASN1_DEBUG
+	for (j = 0; j < level*5; j++) print_asn1msg(PRT_DEBUG_DECODE, " ");
+	print_asn1msg(PRT_DEBUG_DECODE, "TAG 0x%02x LEN %3d\n", tag, len);
+#endif
+	
+	if (tag & ASN1_TAG_CONSTRUCTED) {
+		if (len == -1) { // indefinite
+			while (*p) {
+				CallASN1(ret, p, end, ParseASN1(p, end, level + 1));
+			}
+			p++;
+			if (*p) 
+				return -1;
+			p++;
+		} else {
+			tag_end = p + len;
+			while (p < tag_end) {
+				CallASN1(ret, p, end, ParseASN1(p, end, level +1));
+			}
+		}
+	} else {
+		for (j = 0; j < level*5; j++) print_asn1msg(PRT_DEBUG_DECODE, " ");
+		while (len--) {
+			print_asn1msg(PRT_DEBUG_DECODE, "%02x ", *p);
+			p++;
+		}
+		print_asn1msg(PRT_DEBUG_DECODE, "\n");
+	}
+	for (j = 0; j < level*5; j++) print_asn1msg(PRT_DEBUG_DECODE, " ");
+	print_asn1msg(PRT_DEBUG_DECODE, "END (%d)\n", p - beg - 2);
+	return p - beg;
+}
+#endif

Added: misdn-user/trunk/suppserv/asn1.h
===================================================================
--- misdn-user/trunk/suppserv/asn1.h	                        (rev 0)
+++ misdn-user/trunk/suppserv/asn1.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,346 @@
+#ifndef __ASN1_H__
+#define __ASN1_H__
+
+#include "suppserv.h"
+#include <asm/types.h>
+#include <sys/types.h>
+#include <stdio.h>
+
+typedef enum {
+	invoke       = 1,
+	returnResult = 2,
+	returnError  = 3,
+	reject       = 4,
+} asn1Component;
+
+typedef enum {
+	GeneralP     = 0,
+	InvokeP      = 1,
+	ReturnResultP= 2,
+	ReturnErrorP = 3,
+} asn1Problem;
+
+struct PublicPartyNumber {
+	int publicTypeOfNumber;
+	char numberDigits[30];
+};
+
+struct PartyNumber {
+	int type;
+	union {
+		char unknown[30];
+		struct PublicPartyNumber publicPartyNumber;
+	} p;
+};
+
+struct Address {
+	struct PartyNumber partyNumber;
+	char partySubaddress[30];
+};
+
+struct ServedUserNr {
+	int all;
+	struct PartyNumber partyNumber;
+};
+
+struct ActDivNotification {
+	int procedure;
+	int basicService;
+	struct ServedUserNr servedUserNr;
+	struct Address address;
+};
+
+struct DeactDivNotification {
+	int procedure;
+	int basicService;
+	struct ServedUserNr servedUserNr;
+};
+
+struct ReqCallDeflection {
+	struct Address address;
+	int pres;
+};
+
+struct ServedUserNumberList {
+	struct PartyNumber partyNumber[10];
+};
+
+struct IntResult {
+	struct ServedUserNr servedUserNr;
+	int procedure;
+	int basicService;
+	struct Address address;
+};
+
+struct IntResultList {
+	struct IntResult intResult[10];
+};
+
+struct asn1Invoke {
+	__u16 invokeId;
+	__u16 operationValue;
+	union {
+		struct ActDivNotification actNot;
+		struct DeactDivNotification deactNot;
+		struct ReqCallDeflection reqCD;
+		struct FacAOCDChargingUnit AOCDchu;
+		struct FacAOCDCurrency AOCDcur;
+	} o;
+};
+
+struct asn1ReturnResult {
+	__u16 invokeId;
+	union {
+		struct ServedUserNumberList list;
+		struct IntResultList resultList;
+	} o;
+};
+
+struct asn1ReturnError {
+	__u16 invokeId;
+	__u16 errorValue;
+};
+
+struct asn1Reject {
+	int invokeId;
+	asn1Problem problem;
+	__u16 problemValue;
+};
+
+struct asn1_parm {
+	asn1Component comp;
+	union {
+		struct asn1Invoke       inv;
+		struct asn1ReturnResult retResult;
+		struct asn1ReturnError  retError;
+		struct asn1Reject	reject;
+	} u;
+};
+
+
+#ifdef ASN1_DEBUG
+#define print_asn1msg(dummy, fmt, args...) printf(fmt, ## args)
+int ParseASN1(u_char *p, u_char *end, int level);
+#else
+#define print_asn1msg(dummy, fmt, args...) 
+#define ParseASN1(p,end,level)
+#endif
+
+#define int_error() \
+	printf("mISDN: INTERNAL ERROR in %s:%d\n", \
+		   __FILE__, __LINE__)
+
+int ParseTag(u_char *p, u_char *end, int *tag);
+int ParseLen(u_char *p, u_char *end, int *len);
+
+#define ASN1_TAG_BOOLEAN           (0x01) // is that true?
+#define ASN1_TAG_INTEGER           (0x02)
+#define ASN1_TAG_BIT_STRING        (0x03)
+#define ASN1_TAG_OCTET_STRING      (0x04)
+#define ASN1_TAG_NULL              (0x05)
+#define ASN1_TAG_OBJECT_IDENTIFIER (0x06)
+#define ASN1_TAG_ENUM              (0x0a)
+#define ASN1_TAG_SEQUENCE          (0x30)
+#define ASN1_TAG_SET               (0x31)
+#define ASN1_TAG_NUMERIC_STRING    (0x12)
+#define ASN1_TAG_PRINTABLE_STRING  (0x13)
+#define ASN1_TAG_IA5_STRING        (0x16)
+#define ASN1_TAG_UTC_TIME          (0x17)
+
+#define ASN1_TAG_CONSTRUCTED       (0x20)
+#define ASN1_TAG_CONTEXT_SPECIFIC  (0x80)
+
+#define ASN1_TAG_EXPLICIT          (0x100)
+#define ASN1_TAG_OPT               (0x200)
+#define ASN1_NOT_TAGGED            (0x400)
+
+#define CallASN1(ret, p, end, todo) do { \
+        ret = todo; \
+	if (ret < 0) { \
+                int_error(); \
+                return -1; \
+        } \
+        p += ret; \
+} while (0)
+
+#define INIT \
+	int tag, len; \
+	int ret; \
+	u_char *beg; \
+        \
+        print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> %s\n", __FUNCTION__); \
+	beg = p; \
+	CallASN1(ret, p, end, ParseTag(p, end, &tag)); \
+	CallASN1(ret, p, end, ParseLen(p, end, &len)); \
+        if (len >= 0) { \
+                if (p + len > end) \
+                        return -1; \
+                end = p + len; \
+        }
+
+#define XSEQUENCE_1(todo, act_tag, the_tag, arg1) do { \
+	if (p < end) { \
+  	        if (((the_tag) &~ ASN1_TAG_OPT) == ASN1_NOT_TAGGED) { \
+		        if (((u_char)act_tag == *p) || ((act_tag) == ASN1_NOT_TAGGED)) { \
+			        CallASN1(ret, p, end, todo(pc, p, end, arg1)); \
+                        } else { \
+                                if (!((the_tag) & ASN1_TAG_OPT)) { \
+                                        print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 1 %s:%d\n", __FUNCTION__, __LINE__); \
+                	    	        return -1; \
+                                } \
+                        } \
+	        } else { \
+                        if ((the_tag) & ASN1_TAG_EXPLICIT) { \
+		                if ((u_char)(((the_tag) & 0xff) | (ASN1_TAG_CONTEXT_SPECIFIC | ASN1_TAG_CONSTRUCTED)) == *p) { \
+                                        int xtag, xlen; \
+	                                CallASN1(ret, p, end, ParseTag(p, end, &xtag)); \
+			                CallASN1(ret, p, end, ParseLen(p, end, &xlen)); \
+  	                                CallASN1(ret, p, end, todo(pc, p, end, arg1)); \
+                                } else { \
+                                        if (!(the_tag) & ASN1_TAG_OPT) { \
+                                                print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 2 %s:%d\n", __FUNCTION__, __LINE__); \
+                        	    	        return -1; \
+                                        } \
+                                } \
+                        } else { \
+		                if ((u_char)(((the_tag) & 0xff) | (ASN1_TAG_CONTEXT_SPECIFIC | (act_tag & ASN1_TAG_CONSTRUCTED))) == *p) { \
+  	                                CallASN1(ret, p, end, todo(pc, p, end, arg1)); \
+                                } else { \
+                                        if (!(the_tag) & ASN1_TAG_OPT) { \
+                                                print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 3 %s:%d\n", __FUNCTION__, __LINE__); \
+                        	    	        return -1; \
+                                        } \
+                                } \
+		        } \
+		} \
+        } else { \
+                if (!(the_tag) & ASN1_TAG_OPT) { \
+                        print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 4 %s:%d\n", __FUNCTION__, __LINE__); \
+			return -1; \
+                } \
+        } \
+} while (0)
+
+#define XSEQUENCE_OPT_1(todo, act_tag, the_tag, arg1) \
+        XSEQUENCE_1(todo, act_tag, (the_tag | ASN1_TAG_OPT), arg1)
+
+#define XSEQUENCE(todo, act_tag, the_tag) XSEQUENCE_1(todo, act_tag, the_tag, -1)
+#define XSEQUENCE_OPT(todo, act_tag, the_tag) XSEQUENCE_OPT_1(todo, act_tag, the_tag, -1)
+
+#define XCHOICE_1(todo, act_tag, the_tag, arg1) \
+	if (act_tag == ASN1_NOT_TAGGED) { \
+		return todo(pc, beg, end, arg1); \
+        } \
+        if (the_tag == ASN1_NOT_TAGGED) { \
+		  if (act_tag == tag) { \
+                            return todo(pc, beg, end, arg1); \
+                  } \
+         } else { \
+		  if ((the_tag | (0x80 | (act_tag & 0x20))) == tag) { \
+                            return todo(pc, beg, end, arg1); \
+                  } \
+	 }
+
+#define XCHOICE(todo, act_tag, the_tag) XCHOICE_1(todo, act_tag, the_tag, -1)
+
+#define XCHOICE_DEFAULT do {\
+          print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 5 %s:%d\n", __FUNCTION__, __LINE__); \
+          return -1; \
+	  } while (0)
+
+#define CHECK_P do { \
+        if (p >= end) \
+                 return -1; \
+        } while (0) 
+
+/*
+** ASN.1 Encoding
+*/
+
+int encodeNull(__u8 *dest);
+int encodeBoolean(__u8 *dest, __u32 i);
+int encodeInt(__u8 *dest, __u32 i);
+int encodeEnum(__u8 *dest, __u32 i);
+int encodeNumberDigits(__u8 *dest, __s8 *nd, __u8 len);
+int encodePublicPartyNumber(__u8 *dest, __s8 *facilityPartyNumber);
+int encodePartyNumber(__u8 *dest, __s8 *facilityPartyNumber);
+int encodeServedUserNumber(__u8 *dest, __s8 *servedUserNumber);
+int encodeAddress(__u8 *dest, __s8 *facilityPartyNumber, __s8 *calledPartySubaddress);
+
+/*
+** ASN.1 Parsing
+*/
+
+int ParseBoolean(struct asn1_parm *pc, u_char *p, u_char *end, int *i);
+int ParseNull(struct asn1_parm *pc, u_char *p, u_char *end, int dummy);
+int ParseInteger(struct asn1_parm *pc, u_char *p, u_char *end, int *i);
+int ParseEnum(struct asn1_parm *pc, u_char *p, u_char *end, int *i);
+int ParseIA5String(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseNumericString(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseOctetString(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+
+int ParseARGReqCallDeflection(struct asn1_parm *pc, u_char *p, u_char *end, struct ReqCallDeflection *reqCD);
+int ParseARGActivationStatusNotificationDiv(struct asn1_parm *pc, u_char *p, u_char *end, struct ActDivNotification *actNot);
+int ParseARGDeactivationStatusNotificationDiv(struct asn1_parm *pc, u_char *p, u_char *end, struct DeactDivNotification *deactNot);
+int ParseARGInterrogationDiversion(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
+int ParseRESInterrogationDiversion(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
+int ParseARGInterrogateServedUserNumbers(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
+int ParseRESInterrogateServedUserNumbers(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
+int ParseARGDiversionInformation(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
+int ParseIntResult(struct asn1_parm *parm, u_char *p, u_char *end, struct IntResult *intResult);
+int ParseIntResultList(struct asn1_parm *parm, u_char *p, u_char *end, struct IntResultList *intResultList);
+int ParseServedUserNr(struct asn1_parm *parm, u_char *p, u_char *end, struct ServedUserNr *servedUserNr);
+int ParseProcedure(struct asn1_parm *pc, u_char *p, u_char *end, int *procedure);
+int ParseServedUserNumberList(struct asn1_parm *parm, u_char *p, u_char *end, struct ServedUserNumberList *list);
+int ParseDiversionReason(struct asn1_parm *parm, u_char *p, u_char *end, char *str);
+
+int ParsePresentedAddressScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParsePresentedNumberScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParsePresentedNumberUnscreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseAddressScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseNumberScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseAddress(struct asn1_parm *pc, u_char *p, u_char *end, struct Address *address);
+int ParsePartyNumber(struct asn1_parm *pc, u_char *p, u_char *end, struct PartyNumber *partyNumber);
+int ParsePublicPartyNumber(struct asn1_parm *pc, u_char *p, u_char *end, struct PublicPartyNumber *publicPartyNumber);
+int ParsePrivatePartyNumber(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParsePublicTypeOfNumber(struct asn1_parm *pc, u_char *p, u_char *end, int *publicTypeOfNumber);
+int ParsePrivateTypeOfNumber(struct asn1_parm *pc, u_char *p, u_char *end, int *privateTypeOfNumber);
+int ParsePartySubaddress(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseUserSpecifiedSubaddress(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseNSAPSubaddress(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseSubaddressInformation(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseScreeningIndicator(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseNumberDigits(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+
+int ParseInvokeId(struct asn1_parm *parm, u_char *p, u_char *end, int *invokeId);
+int ParseOperationValue(struct asn1_parm *parm, u_char *p, u_char *end, int *operationValue);
+int ParseInvokeComponent(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
+int ParseReturnResultComponent(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
+int ParseComponent(struct asn1_parm *parm, u_char *p, u_char *end);
+int XParseComponent(struct asn1_parm *parm, u_char *p, u_char *end);
+
+int ParseAOCECurrency(struct asn1_parm *pc, u_char *p, u_char *end, int dummy);
+int ParseAOCDChargingUnit(struct asn1_parm *pc,u_char *p, u_char *end, struct FacAOCDChargingUnit *chu);
+int ParseAOCDCurrency(struct asn1_parm *pc, u_char *p, u_char *end, struct FacAOCDCurrency *cur);
+int ParseAOCDCurrencyInfo(struct asn1_parm *pc,u_char *p, u_char *end, struct FacAOCDCurrency *cur);
+int ParseAOCDChargingUnitInfo(struct asn1_parm *pc,u_char *p, u_char *end, struct FacAOCDChargingUnit *chu);
+int ParseRecordedCurrency(struct asn1_parm *pc,u_char *p, u_char *end, struct FacAOCDCurrency *cur);
+int ParseRecordedUnitsList(struct asn1_parm *pc,u_char *p, u_char *end, int *recordedUnits);
+int ParseTypeOfChargingInfo(struct asn1_parm *pc,u_char *p, u_char *end, int *typeOfChargingInfo);
+int ParseRecordedUnits(struct asn1_parm *pc,u_char *p, u_char *end, int *recordedUnits);
+int ParseAOCDBillingId(struct asn1_parm *pc, u_char *p, u_char *end, int *billingId);
+int ParseAOCECurrencyInfo(struct asn1_parm *pc, u_char *p, u_char *end, int dummy);
+int ParseAOCEChargingUnitInfo(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
+int ParseAOCEBillingId(struct asn1_parm *pc,u_char *p, u_char *end, int *billingId);
+int ParseCurrency(struct asn1_parm *pc,u_char *p, u_char *end, char *currency);
+int ParseAmount(struct asn1_parm *pc,u_char *p, u_char *end, struct FacAOCDCurrency *cur);
+int ParseCurrencyAmount(struct asn1_parm *pc,u_char *p, u_char *end, int *currencyAmount);
+int ParseMultiplier(struct asn1_parm *pc,u_char *p, u_char *end, int *multiplier);
+int ParseTypeOfUnit(struct asn1_parm *pc,u_char *p, u_char *end, int *typeOfUnit);
+int ParseNumberOfUnits(struct asn1_parm *pc,u_char *p, u_char *end, int *numberOfUnits);
+int ParseChargingAssociation(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
+int ParseChargeIdentifier(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
+
+int ParseBasicService(struct asn1_parm *pc, u_char *p, u_char *end, int *basicService);
+
+#endif

Added: misdn-user/trunk/suppserv/asn1_address.c
===================================================================
--- misdn-user/trunk/suppserv/asn1_address.c	                        (rev 0)
+++ misdn-user/trunk/suppserv/asn1_address.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,233 @@
+/* $Id: asn1_address.c,v 1.2 2006/08/16 14:15:52 nadi Exp $
+ *
+ */
+
+#include "asn1.h"
+#include <stdio.h>
+#include <string.h>
+
+void buildnumber(char *num, int oc3, int oc3a, char *result, int version,
+		 int *provider, int *sondernummer, int *intern, int *local,
+		 int dir, int who);
+
+
+// ======================================================================
+// Address Types EN 300 196-1 D.3
+
+int ParsePresentationRestricted(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	int ret;
+
+	ret = ParseNull(pc, p, end, -1);
+	if (ret < 0)
+		return ret;
+	strcpy(str, "(presentation restricted)");
+	return ret;
+}
+
+int ParseNotAvailInterworking(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	int ret;
+
+	ret = ParseNull(pc, p, end, -1);
+	if (ret < 0)
+		return ret;
+	strcpy(str, "(not available)");
+	return ret;
+}
+
+int ParsePresentedAddressScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	INIT;
+
+	XCHOICE_1(ParseAddressScreened, ASN1_TAG_SEQUENCE, 0, str);
+	XCHOICE_1(ParsePresentationRestricted, ASN1_TAG_NULL, 1, str);
+	XCHOICE_1(ParseNotAvailInterworking, ASN1_TAG_NULL, 2, str);
+	XCHOICE_1(ParseAddressScreened, ASN1_TAG_NULL, 3, str);
+	XCHOICE_DEFAULT;
+}
+
+int ParsePresentedNumberScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	INIT;
+
+	XCHOICE_1(ParseNumberScreened, ASN1_TAG_SEQUENCE, 0, str);
+	XCHOICE_1(ParsePresentationRestricted, ASN1_TAG_NULL, 1, str);
+	XCHOICE_1(ParseNotAvailInterworking, ASN1_TAG_NULL, 2, str);
+	XCHOICE_1(ParseNumberScreened, ASN1_TAG_NULL, 3, str);
+	XCHOICE_DEFAULT;
+}
+
+int ParsePresentedNumberUnscreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	struct PartyNumber partyNumber;
+	INIT;
+
+	XCHOICE_1(ParsePartyNumber, ASN1_TAG_SEQUENCE, 0, &partyNumber); // FIXME EXP
+	XCHOICE_1(ParsePresentationRestricted, ASN1_TAG_NULL, 1, str);
+	XCHOICE_1(ParseNotAvailInterworking, ASN1_TAG_NULL, 2, str);
+	XCHOICE_1(ParsePartyNumber, ASN1_TAG_SEQUENCE, 3, &partyNumber); // FIXME EXP
+	XCHOICE_DEFAULT;
+}
+
+int ParseNumberScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	struct PartyNumber partyNumber;
+	char screeningIndicator[30];
+	INIT;
+
+	XSEQUENCE_1(ParsePartyNumber, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &partyNumber);
+	XSEQUENCE_1(ParseScreeningIndicator, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, screeningIndicator);
+
+//	str += sprintf(str, "%s", partyNumber);
+
+	return p - beg;
+}
+
+int ParseAddressScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	struct PartyNumber partyNumber;
+	char partySubaddress[30] = { 0, };
+	char screeningIndicator[30];
+	INIT;
+
+	XSEQUENCE_1(ParsePartyNumber, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &partyNumber);
+	XSEQUENCE_1(ParseScreeningIndicator, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, screeningIndicator);
+	XSEQUENCE_OPT_1(ParsePartySubaddress, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, partySubaddress);
+
+//	str += sprintf(str, "%s", partyNumber);
+	if (strlen(partySubaddress))
+		str += sprintf(str, ".%s", partySubaddress);
+
+	return p - beg;
+}
+
+int ParseAddress(struct asn1_parm *pc, u_char *p, u_char *end, struct Address *address)
+{
+	INIT;
+
+	address->partySubaddress[0] = 0;
+	XSEQUENCE_1(ParsePartyNumber, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &address->partyNumber);
+	
+	XSEQUENCE_OPT_1(ParsePartySubaddress, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, address->partySubaddress);
+
+	return p - beg;
+}
+
+int ParsePartyNumber(struct asn1_parm *pc, u_char *p, u_char *end, struct PartyNumber *partyNumber)
+{
+	INIT;
+
+	partyNumber->type = 0;
+	XCHOICE_1(ParseNumberDigits, ASN1_TAG_NUMERIC_STRING, 0, partyNumber->p.unknown); // unknownPartyNumber
+	partyNumber->type = 1;
+	XCHOICE_1(ParsePublicPartyNumber, ASN1_TAG_SEQUENCE, 1, &partyNumber->p.publicPartyNumber); 
+#if 0
+	XCHOICE_1(ParseNumberDigits, ASN1_TAG_NUMERIC_STRING, 3, str); // dataPartyNumber
+	XCHOICE_1(ParseNumberDigits, ASN1_TAG_NUMERIC_STRING, 4, str); // telexPartyNumber
+	XCHOICE_1(ParsePrivatePartyNumber, ASN1_TAG_SEQUENCE, 5, str);
+	XCHOICE_1(ParseNumberDigits, ASN1_TAG_NUMERIC_STRING, 8, str); // nationalStandardPartyNumber
+#endif
+	XCHOICE_DEFAULT;
+}
+
+int ParsePublicPartyNumber(struct asn1_parm *pc, u_char *p, u_char *end, struct PublicPartyNumber *publicPartyNumber)
+{
+	INIT;
+
+	XSEQUENCE_1(ParsePublicTypeOfNumber, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &publicPartyNumber->publicTypeOfNumber);
+	XSEQUENCE_1(ParseNumberDigits, ASN1_TAG_NUMERIC_STRING, ASN1_NOT_TAGGED, publicPartyNumber->numberDigits);
+
+	return p - beg;
+}
+
+#if 0
+int ParsePrivatePartyNumber(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	int privateTypeOfNumber;
+	char numberDigits[20];
+	INIT;
+
+	XSEQUENCE_1(ParsePrivateTypeOfNumber, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &privateTypeOfNumber); 
+	XSEQUENCE_1(ParseNumberDigits, ASN1_TAG_NUMERIC_STRING, ASN1_NOT_TAGGED, numberDigits); 
+
+	switch (privateTypeOfNumber) {
+	case 0: str += sprintf(str, "(unknown)"); break;
+	case 1: str += sprintf(str, "(regional2)"); break;
+	case 2: str += sprintf(str, "(regional1)"); break;
+	case 3: str += sprintf(str, "(ptn)"); break;
+	case 4: str += sprintf(str, "(local)"); break;
+	case 6: str += sprintf(str, "(abbrev)"); break;
+	}
+	str += sprintf(str, numberDigits);
+
+	return p - beg;
+}
+#endif
+
+int ParsePublicTypeOfNumber(struct asn1_parm *pc, u_char *p, u_char *end, int *publicTypeOfNumber)
+{
+	return ParseEnum(pc, p, end, publicTypeOfNumber);
+}
+
+#if 0
+int ParsePrivateTypeOfNumber(struct asn1_parm *pc, u_char *p, u_char *end, int *privateTypeOfNumber)
+{
+	return ParseEnum(pc, p, end, privateTypeOfNumber);
+}
+#endif
+
+int ParsePartySubaddress(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	INIT;
+
+	XCHOICE_1(ParseUserSpecifiedSubaddress, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, str);
+	XCHOICE_1(ParseNSAPSubaddress, ASN1_TAG_OCTET_STRING, ASN1_NOT_TAGGED, str);
+	XCHOICE_DEFAULT;
+}
+
+int ParseUserSpecifiedSubaddress(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	int oddCountIndicator;
+	INIT;
+
+	XSEQUENCE_1(ParseSubaddressInformation, ASN1_TAG_OCTET_STRING, ASN1_NOT_TAGGED, str);
+	XSEQUENCE_OPT_1(ParseBoolean, ASN1_TAG_BOOLEAN, ASN1_NOT_TAGGED, &oddCountIndicator);
+	
+	return p - beg;
+}
+
+int ParseNSAPSubaddress(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	return ParseOctetString(pc, p, end, str);
+}
+
+int ParseSubaddressInformation(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	return ParseOctetString(pc, p, end, str);
+}
+
+int ParseScreeningIndicator(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	int ret;
+	int screeningIndicator;
+
+	ret = ParseEnum(pc, p, end, &screeningIndicator);
+	if (ret < 0)
+		return ret;
+	
+	switch (screeningIndicator) {
+	case 0: sprintf(str, "user provided, not screened"); break;
+	case 1: sprintf(str, "user provided, passed"); break;
+	case 2: sprintf(str, "user provided, failed"); break;
+	case 3: sprintf(str, "network provided"); break;
+	default: sprintf(str, "(%d)", screeningIndicator); break;
+	}
+
+	return ret;
+}
+
+int ParseNumberDigits(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	return ParseNumericString(pc, p, end, str);
+}

Added: misdn-user/trunk/suppserv/asn1_aoc.c
===================================================================
--- misdn-user/trunk/suppserv/asn1_aoc.c	                        (rev 0)
+++ misdn-user/trunk/suppserv/asn1_aoc.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,358 @@
+/* $Id: asn1_aoc.c,v 1.3 2006/08/16 14:15:52 nadi Exp $
+ *
+ */
+
+#include "asn1.h"
+#include <string.h>
+
+// ======================================================================
+// AOC EN 300 182-1 V1.3.3
+
+int
+ParseAOCDCurrency(struct asn1_parm *pc, u_char *p, u_char *end, struct FacAOCDCurrency *cur)
+{
+	INIT;
+
+	cur->chargeNotAvailable = 1;
+	cur->freeOfCharge = 0;
+	memset(cur->currency, 0 , sizeof(cur->currency));
+	cur->currencyAmount = 0;
+	cur->multiplier = 0;
+	cur->typeOfChargingInfo = -1;
+	cur->billingId = -1;
+	XCHOICE(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED); // chargeNotAvail
+	cur->chargeNotAvailable = 0;
+	XCHOICE_1(ParseAOCDCurrencyInfo, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, cur);
+	XCHOICE_DEFAULT;
+}
+
+int
+ParseAOCDChargingUnit(struct asn1_parm *pc, u_char *p, u_char *end, struct FacAOCDChargingUnit *chu)
+{
+	INIT;
+
+	chu->chargeNotAvailable = 1;
+	chu->freeOfCharge = 0;
+	chu->recordedUnits = 0;
+	chu->typeOfChargingInfo = -1;
+	chu->billingId = -1;
+	XCHOICE(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED); // chargeNotAvail
+	chu->chargeNotAvailable = 0;
+	XCHOICE_1(ParseAOCDChargingUnitInfo, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, chu);
+	XCHOICE_DEFAULT;
+}
+
+#if 0
+// AOCECurrency
+
+int
+ParseAOCECurrency(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	INIT;
+
+	XCHOICE(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED); // chargeNotAvail
+	XCHOICE(ParseAOCECurrencyInfo, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
+	XCHOICE_DEFAULT;
+}
+#endif
+
+// AOCEChargingUnit
+
+int
+ParseAOCEChargingUnit(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	INIT;
+
+	XCHOICE(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED); // chargeNotAvail
+	XCHOICE(ParseAOCEChargingUnitInfo, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
+	XCHOICE_DEFAULT;
+}
+
+// AOCDCurrencyInfo
+
+int
+ParseAOCDSpecificCurrency(struct asn1_parm *pc, u_char *p, u_char *end, struct FacAOCDCurrency *cur)
+{
+	INIT;
+
+	XSEQUENCE_1(ParseRecordedCurrency, ASN1_TAG_SEQUENCE, 1, cur);
+	XSEQUENCE_1(ParseTypeOfChargingInfo, ASN1_TAG_ENUM, 2, &cur->typeOfChargingInfo);
+	XSEQUENCE_OPT_1(ParseAOCDBillingId, ASN1_TAG_ENUM, 3, &cur->billingId);
+
+	return p - beg;
+}
+
+int
+ParseAOCDCurrencyInfo(struct asn1_parm *pc, u_char *p, u_char *end, struct FacAOCDCurrency *cur)
+{
+	INIT;
+
+	XCHOICE_1(ParseAOCDSpecificCurrency, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, cur);
+
+	cur->freeOfCharge = 1;
+	XCHOICE(ParseNull, ASN1_TAG_NULL, 1); // freeOfCharge
+	cur->freeOfCharge = 0;
+	XCHOICE_DEFAULT;
+}
+
+// AOCDChargingUnitInfo
+
+int
+ParseAOCDSpecificChargingUnits(struct asn1_parm *pc, u_char *p, u_char *end, struct FacAOCDChargingUnit *chu)
+{
+	INIT;
+
+	XSEQUENCE_1(ParseRecordedUnitsList, ASN1_TAG_SEQUENCE, 1, &chu->recordedUnits);
+	XSEQUENCE_1(ParseTypeOfChargingInfo, ASN1_TAG_ENUM, 2, &chu->typeOfChargingInfo);
+	XSEQUENCE_OPT_1(ParseAOCDBillingId, ASN1_TAG_ENUM, 3, &chu->billingId);
+
+//	p_L3L4(pc, CC_CHARGE | INDICATION, &recordedUnits);
+
+	return p - beg;
+}
+
+int
+ParseAOCDChargingUnitInfo(struct asn1_parm *pc, u_char *p, u_char *end, struct FacAOCDChargingUnit *chu)
+{
+	INIT;
+
+	XCHOICE_1(ParseAOCDSpecificChargingUnits, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, chu);
+
+	chu->freeOfCharge = 1;
+	XCHOICE(ParseNull, ASN1_TAG_NULL, 1); // freeOfCharge
+	chu->freeOfCharge = 0;
+
+	XCHOICE_DEFAULT;
+}
+
+// RecordedCurrency
+
+int
+ParseRecordedCurrency(struct asn1_parm *pc, u_char *p, u_char *end, struct FacAOCDCurrency *cur)
+{
+	INIT;
+
+	XSEQUENCE_1(ParseCurrency, ASN1_TAG_IA5_STRING, 1, (char *)cur->currency);
+	XSEQUENCE_1(ParseAmount, ASN1_TAG_SEQUENCE, 2, cur);
+
+	return p - beg;
+}
+
+// RecordedUnitsList
+
+int
+ParseRecordedUnitsList(struct asn1_parm *pc, u_char *p, u_char *end, int *recordedUnits)
+{
+	int i;
+	int units;
+	INIT;
+
+	*recordedUnits = 0;
+	XSEQUENCE_1(ParseRecordedUnits, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, recordedUnits);
+	for (i = 0; i < 31; i++) {
+		units = 0;
+		XSEQUENCE_OPT_1(ParseRecordedUnits, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, &units);
+		*recordedUnits += units;
+	}
+
+	return p - beg;
+}
+
+// TypeOfChargingInfo
+
+int
+ParseTypeOfChargingInfo(struct asn1_parm *pc, u_char *p, u_char *end, int *typeOfChargingInfo)
+{
+	return ParseEnum(pc, p, end, typeOfChargingInfo);
+}
+
+// RecordedUnits
+
+int
+ParseRecordedUnitsChoice(struct asn1_parm *pc, u_char *p, u_char *end, int *recordedUnits)
+{
+	INIT;
+
+	XCHOICE_1(ParseNumberOfUnits, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, recordedUnits);
+	XCHOICE(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED); // not available
+	XCHOICE_DEFAULT;
+}
+
+int
+ParseRecordedUnits(struct asn1_parm *pc, u_char *p, u_char *end, int *recordedUnits)
+{
+	int typeOfUnit;
+	INIT;
+
+	XSEQUENCE_1(ParseRecordedUnitsChoice, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, recordedUnits);
+	XSEQUENCE_OPT_1(ParseTypeOfUnit, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &typeOfUnit);
+
+	return p - beg;
+}
+
+// AOCDBillingId
+
+int
+ParseAOCDBillingId(struct asn1_parm *pc, u_char *p, u_char *end, int *billingId)
+{
+	return ParseEnum(pc, p, end, billingId);
+}
+
+#if 0
+// AOCECurrencyInfo
+
+int
+ParseAOCESpecificCurrency(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int billingId;
+	INIT;
+
+	XSEQUENCE(ParseRecordedCurrency, ASN1_TAG_SEQUENCE, 1);
+	XSEQUENCE_OPT_1(ParseAOCEBillingId, ASN1_TAG_ENUM, 2, &billingId);
+
+	return p - beg;
+}
+
+int
+ParseAOCECurrencyInfoChoice(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	INIT;
+
+	XCHOICE(ParseAOCESpecificCurrency, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
+	XCHOICE(ParseNull, ASN1_TAG_NULL, 1); // freeOfCharge
+	XCHOICE_DEFAULT;
+}
+
+int
+ParseAOCECurrencyInfo(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	INIT;
+
+	XSEQUENCE(ParseAOCECurrencyInfoChoice, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED);
+	XSEQUENCE_OPT(ParseChargingAssociation, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED);
+	XCHOICE_DEFAULT;
+}
+#endif
+
+// AOCEChargingUnitInfo
+
+int
+ParseAOCESpecificChargingUnits(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int recordedUnits;
+	int billingId;
+	INIT;
+
+	XSEQUENCE_1(ParseRecordedUnitsList, ASN1_TAG_SEQUENCE, 1, &recordedUnits);
+	XSEQUENCE_OPT_1(ParseAOCEBillingId, ASN1_TAG_ENUM, 2, &billingId);
+
+//	p_L3L4(pc, CC_CHARGE | INDICATION, &recordedUnits);
+
+	return p - beg;
+}
+
+int
+ParseAOCEChargingUnitInfoChoice(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	INIT;
+
+	XCHOICE(ParseAOCESpecificChargingUnits, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
+	XCHOICE(ParseNull, ASN1_TAG_NULL, 1); // freeOfCharge
+	XCHOICE_DEFAULT;
+}
+
+int
+ParseAOCEChargingUnitInfo(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	INIT;
+
+	XSEQUENCE(ParseAOCEChargingUnitInfoChoice, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED);
+	XSEQUENCE_OPT(ParseChargingAssociation, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED);
+
+	return p - beg;
+}
+
+// AOCEBillingId
+
+int
+ParseAOCEBillingId(struct asn1_parm *pc, u_char *p, u_char *end, int *billingId)
+{
+	return ParseEnum(pc, p, end, billingId);
+}
+
+// Currency
+
+int
+ParseCurrency(struct asn1_parm *pc, u_char *p, u_char *end, char *currency)
+{
+	return ParseIA5String(pc, p, end, currency);
+}
+
+// Amount
+
+int
+ParseAmount(struct asn1_parm *pc, u_char *p, u_char *end, struct FacAOCDCurrency *cur)
+{
+	INIT;
+
+	XSEQUENCE_1(ParseCurrencyAmount, ASN1_TAG_INTEGER, 1, &cur->currencyAmount);
+	XSEQUENCE_1(ParseMultiplier, ASN1_TAG_INTEGER, 2, &cur->multiplier);
+
+	return p - beg;
+}
+
+// CurrencyAmount
+
+int
+ParseCurrencyAmount(struct asn1_parm *pc, u_char *p, u_char *end, int *currencyAmount)
+{
+	return ParseInteger(pc, p, end, currencyAmount);
+}
+
+// Multiplier
+
+int
+ParseMultiplier(struct asn1_parm *pc, u_char *p, u_char *end, int *multiplier)
+{
+	return ParseEnum(pc, p, end, multiplier);
+}
+
+// TypeOfUnit
+
+int
+ParseTypeOfUnit(struct asn1_parm *pc, u_char *p, u_char *end, int *typeOfUnit)
+{
+	return ParseInteger(pc, p, end, typeOfUnit);
+}
+
+// NumberOfUnits
+
+int
+ParseNumberOfUnits(struct asn1_parm *pc, u_char *p, u_char *end, int *numberOfUnits)
+{
+	return ParseInteger(pc, p, end, numberOfUnits);
+}
+
+// Charging Association
+
+int
+ParseChargingAssociation(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+//	char partyNumber[30];
+	INIT;
+
+//	XCHOICE_1(ParsePartyNumber, ASN1_TAG_SEQUENCE, 0, partyNumber);
+	XCHOICE(ParseChargeIdentifier, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED);
+	XCHOICE_DEFAULT;
+}
+
+// ChargeIdentifier
+
+int
+ParseChargeIdentifier(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int chargeIdentifier;
+
+	return ParseInteger(pc, p, end, &chargeIdentifier);
+}
+

Added: misdn-user/trunk/suppserv/asn1_basic_service.c
===================================================================
--- misdn-user/trunk/suppserv/asn1_basic_service.c	                        (rev 0)
+++ misdn-user/trunk/suppserv/asn1_basic_service.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,14 @@
+/* $Id: asn1_basic_service.c,v 1.2 2006/08/16 14:15:52 nadi Exp $
+ *
+ */
+
+#include "asn1.h"
+
+// ======================================================================
+// Basic Service Elements EN 300 196-1 D.6
+
+int ParseBasicService(struct asn1_parm *pc, u_char *p, u_char *end, int *basicService)
+{
+	return ParseEnum(pc, p, end, basicService);
+}
+

Added: misdn-user/trunk/suppserv/asn1_comp.c
===================================================================
--- misdn-user/trunk/suppserv/asn1_comp.c	                        (rev 0)
+++ misdn-user/trunk/suppserv/asn1_comp.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,224 @@
+/* $Id: asn1_comp.c,v 1.3 2006/08/16 14:15:52 nadi Exp $
+ *
+ */
+
+#include "asn1.h"
+#include <stdio.h>
+
+// ======================================================================
+// Component EN 300 196-1 D.1
+
+int
+ParseInvokeId(struct asn1_parm *pc, u_char *p, u_char *end, int *invokeId)
+{
+	return ParseInteger(pc, p, end, invokeId);
+}
+
+int
+ParseErrorValue(struct asn1_parm *pc, u_char *p, u_char *end, int *errorValue)
+{
+	return ParseInteger(pc, p, end, errorValue);
+}
+
+int
+ParseOperationValue(struct asn1_parm *pc, u_char *p, u_char *end, int *operationValue)
+{
+	return ParseInteger(pc, p, end, operationValue);
+}
+
+int
+ParseInvokeComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int invokeId, operationValue;
+	INIT;
+
+	pc->comp = invoke;
+	XSEQUENCE_1(ParseInvokeId, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &invokeId);
+//	XSEQUENCE_OPT(ParseLinkedId, ASN1_TAG_INTEGER, 0);
+	XSEQUENCE_1(ParseOperationValue, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &operationValue);
+	pc->u.inv.invokeId = invokeId;
+	pc->u.inv.operationValue = operationValue;
+	switch (operationValue) {
+#if 0
+	case 7:	 XSEQUENCE(ParseARGActivationDiversion, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+	case 8:	 XSEQUENCE(ParseARGDeactivationDiversion, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+#endif
+ 	case 9:	 XSEQUENCE_1(ParseARGActivationStatusNotificationDiv, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, &pc->u.inv.o.actNot); break;
+ 	case 10: XSEQUENCE_1(ParseARGDeactivationStatusNotificationDiv, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, &pc->u.inv.o.deactNot); break;
+#if 0
+ 	case 11: XSEQUENCE(ParseARGInterrogationDiversion, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+ 	case 12: XSEQUENCE(ParseARGDiversionInformation, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+#endif
+	case 13: XSEQUENCE_1(ParseARGReqCallDeflection, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, &pc->u.inv.o.reqCD); break;
+#if 0
+ 	case 17: XSEQUENCE(ParseARGInterrogateServedUserNumbers, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+//	case 30: XSEQUENCE(ParseChargingRequest, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+//	case 31: XSEQUENCE(ParseAOCSCurrency, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+//	case 32: XSEQUENCE(ParseAOCSSpecialArr, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+#endif
+	case 33: XSEQUENCE_1(ParseAOCDCurrency, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &pc->u.inv.o.AOCDcur); break;
+	case 34: XSEQUENCE_1(ParseAOCDChargingUnit, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &pc->u.inv.o.AOCDchu); break;
+#if 0
+	case 35: XSEQUENCE(ParseAOCECurrency, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+	case 36: XSEQUENCE(ParseAOCEChargingUnit, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+#endif
+	default:
+		return -1;
+	}
+
+	return p - beg;
+}
+
+int
+ParseReturnResultComponentSequence(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int operationValue;
+	INIT;
+
+	XSEQUENCE_1(ParseOperationValue, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &operationValue);
+	switch (operationValue) {
+ 	case 11: XSEQUENCE(ParseRESInterrogationDiversion, ASN1_TAG_SET, ASN1_NOT_TAGGED); break;
+ 	case 17: XSEQUENCE(ParseRESInterrogateServedUserNumbers, ASN1_TAG_SET, ASN1_NOT_TAGGED); break;
+	default: return -1;
+	}
+		
+	return p - beg;
+}
+
+int
+ParseReturnResultComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int invokeId;
+	INIT;
+
+	pc->comp = returnResult;
+	XSEQUENCE_1(ParseInvokeId, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &invokeId);
+	XSEQUENCE_OPT(ParseReturnResultComponentSequence, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
+	pc->u.retResult.invokeId = invokeId;
+
+	return p - beg;
+}
+
+int
+ParseReturnErrorComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+        int invokeId;
+        int errorValue;
+        char error[80];
+        INIT;
+
+	pc->comp = returnError;
+
+	XSEQUENCE_1(ParseInvokeId, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &invokeId);
+	XSEQUENCE_1(ParseErrorValue, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &errorValue);
+
+	pc->u.retError.invokeId = invokeId;
+	pc->u.retError.errorValue = errorValue;
+
+	switch (errorValue) {
+		case 0: sprintf(error, "not subscribed"); break;
+		case 3: sprintf(error, "not available"); break;
+		case 4: sprintf(error, "not implemented"); break;
+		case 6: sprintf(error, "invalid served user nr"); break;
+		case 7: sprintf(error, "invalid call state"); break;
+		case 8: sprintf(error, "basic service not provided"); break;
+		case 9: sprintf(error, "not incoming call"); break;
+		case 10: sprintf(error, "supplementary service interaction not allowed"); break;
+		case 11: sprintf(error, "resource unavailable"); break;
+		case 12: sprintf(error, "invalid diverted-to nr"); break;
+		case 14: sprintf(error, "special service nr"); break;
+		case 15: sprintf(error, "diversion to served user nr"); break;
+		case 23: sprintf(error, "incoming call accepted"); break;
+		case 24: sprintf(error, "number of diversions exceeded"); break;
+		case 46: sprintf(error, "not activated"); break;
+		case 48: sprintf(error, "request already accepted"); break;
+		default: sprintf(error, "(%d)", errorValue); break;
+	}
+	print_asn1msg(PRT_DEBUG_DECODE, "ReturnError: %s\n", error);
+
+	return p - beg;
+}
+
+int
+ParseProblemValue(struct asn1_parm *pc, u_char *p, u_char *end, asn1Problem prob)
+{
+	INIT;
+	
+	pc->u.reject.problem = prob;
+	
+	print_asn1msg(PRT_DEBUG_DECODE, "ParseProblemValue: %d %d\n", prob, *p);
+	pc->u.reject.problemValue = *p++;
+	return p - beg;
+}
+
+int
+ParseRejectProblem(struct asn1_parm *pc, u_char *p, u_char *end)
+{
+        INIT;
+
+	XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 0, GeneralP);
+	XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 1, InvokeP);
+	XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 2, ReturnResultP);
+	XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 3, ReturnErrorP);
+	XCHOICE_DEFAULT;
+}
+
+int
+ParseRejectComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+        int invokeId = -1;
+        int rval;
+        INIT;
+
+	pc->comp = reject;
+
+	XSEQUENCE_OPT_1(ParseInvokeId, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &invokeId);
+	XSEQUENCE_OPT(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED);
+	
+	print_asn1msg(PRT_DEBUG_DECODE, "ParseRejectComponent: invokeId %d\n", invokeId);
+
+	pc->u.reject.invokeId = invokeId;
+	
+	rval = ParseRejectProblem(pc, p, end);
+
+	print_asn1msg(PRT_DEBUG_DECODE, "ParseRejectComponent: rval %d\n", rval);
+
+	if (rval > 0)
+		p += rval;
+	else
+		return(-1);
+
+	return p - beg;
+}
+
+int
+ParseUnknownComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	INIT;
+	
+	pc->comp = tag;
+	return end - beg;
+}
+
+int
+ParseComponent(struct asn1_parm *pc, u_char *p, u_char *end)
+{
+        INIT;
+
+	XCHOICE(ParseInvokeComponent, ASN1_TAG_SEQUENCE, 1);
+	XCHOICE(ParseReturnResultComponent, ASN1_TAG_SEQUENCE, 2);
+	XCHOICE(ParseReturnErrorComponent, ASN1_TAG_SEQUENCE, 3);
+	XCHOICE(ParseRejectComponent, ASN1_TAG_SEQUENCE, 4);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 5);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 6);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 7);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 8);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 9);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 10);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 11);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 12);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 13);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 14);
+	XCHOICE_DEFAULT;
+}
+

Added: misdn-user/trunk/suppserv/asn1_diversion.c
===================================================================
--- misdn-user/trunk/suppserv/asn1_diversion.c	                        (rev 0)
+++ misdn-user/trunk/suppserv/asn1_diversion.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,324 @@
+/* $Id: asn1_diversion.c,v 1.3 2006/08/16 14:15:52 nadi Exp $
+ *
+ */
+
+#include "asn1.h"
+#include <stdio.h>
+
+// ======================================================================
+// Diversion Supplementary Services ETS 300 207-1 Table 3
+
+int
+ParseARGReqCallDeflection(struct asn1_parm *pc, u_char *p, u_char *end, struct ReqCallDeflection *reqCD)
+{
+	INIT;
+
+	XSEQUENCE_1(ParseAddress, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, &reqCD->address);
+	XSEQUENCE_1(ParseBoolean, ASN1_TAG_BOOLEAN, ASN1_NOT_TAGGED, &reqCD->pres);
+
+	return p - beg;
+}
+
+#if 0
+int
+ParseARGActivationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int procedure, basicService;
+	struct ServedUserNr servedUserNr;
+	struct Address address;
+	INIT;
+
+	XSEQUENCE_1(ParseProcedure, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &procedure);
+	XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &basicService);
+	XSEQUENCE_1(ParseAddress, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, &address);
+	XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &servedUserNr);
+
+	return p - beg;
+}
+
+int
+ParseARGDeactivationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int procedure, basicService;
+	struct ServedUserNr servedUserNr;
+	INIT;
+
+	XSEQUENCE_1(ParseProcedure, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &procedure);
+	XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &basicService);
+	XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &servedUserNr);
+
+	print_asn1msg(PRT_SHOWNUMBERS, "Deactivation Diversion %d (%d), \n",
+		  procedure, basicService);
+	return p - beg;
+}
+#endif
+
+int
+ParseARGActivationStatusNotificationDiv(struct asn1_parm *pc, u_char *p, u_char *end, struct ActDivNotification *actNot)
+{
+	INIT;
+
+	XSEQUENCE_1(ParseProcedure, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &actNot->procedure);
+	XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &actNot->basicService);
+	XSEQUENCE_1(ParseAddress, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, &actNot->address);
+	XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &actNot->servedUserNr);
+
+	return p - beg;
+}
+
+int
+ParseARGDeactivationStatusNotificationDiv(struct asn1_parm *pc, u_char *p, u_char *end, struct DeactDivNotification *deactNot)
+{
+	INIT;
+
+	XSEQUENCE_1(ParseProcedure, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &deactNot->procedure);
+	XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &deactNot->basicService);
+	XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &deactNot->servedUserNr);
+
+	return p - beg;
+}
+
+#if 0
+int 
+ParseARGInterrogationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int procedure, basicService;
+	struct ServedUserNr servedUserNr;
+	INIT;
+
+	XSEQUENCE_1(ParseProcedure, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &procedure);
+	XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &basicService);
+	XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &servedUserNr);
+
+	print_asn1msg(PRT_SHOWNUMBERS, "Interrogation Diversion %d (%d), \n",
+		procedure, basicService);
+	return p - beg;
+}
+#endif
+
+int 
+ParseRESInterrogationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	print_asn1msg(PRT_SHOWNUMBERS, "Interrogation Diversion Result\n");
+	return ParseIntResultList(pc, p,  end, &pc->u.retResult.o.resultList);
+}
+
+#if 0
+int 
+ParseARGInterrogateServedUserNumbers(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	print_asn1msg(PRT_SHOWNUMBERS, "Interrogate Served User Numbers\n");
+	return 0;
+}
+#endif
+
+int 
+ParseRESInterrogateServedUserNumbers(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int ret;
+
+	ret = ParseServedUserNumberList(pc, p, end, &pc->u.retResult.o.list);
+	if (ret < 0)
+		return ret;
+
+	print_asn1msg(PRT_SHOWNUMBERS, "Interrogate Served User Numbers:\n");
+	
+	return ret;
+}
+
+int 
+ParseARGDiversionInformation(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	char diversionReason[20];
+	int basicService;
+	char servedUserSubaddress[30];
+	char callingAddress[80];
+	char originalCalledNr[80];
+	char lastDivertingNr[80];
+	char lastDivertingReason[20];
+	INIT;
+	
+	servedUserSubaddress[0] = 0;
+	callingAddress[0] = 0;
+	originalCalledNr[0] = 0;
+	lastDivertingNr[0] = 0;
+	lastDivertingReason[0] = 0;
+
+	XSEQUENCE_1(ParseDiversionReason, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, diversionReason);
+	XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &basicService);
+	XSEQUENCE_OPT_1(ParsePartySubaddress, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, servedUserSubaddress);
+	XSEQUENCE_OPT_1(ParsePresentedAddressScreened, ASN1_NOT_TAGGED, 0 | ASN1_TAG_EXPLICIT, callingAddress);
+	XSEQUENCE_OPT_1(ParsePresentedNumberUnscreened, ASN1_NOT_TAGGED, 1 | ASN1_TAG_EXPLICIT, originalCalledNr);
+	XSEQUENCE_OPT_1(ParsePresentedNumberUnscreened, ASN1_NOT_TAGGED, 2 | ASN1_TAG_EXPLICIT, lastDivertingNr);
+	XSEQUENCE_OPT_1(ParseDiversionReason, ASN1_TAG_ENUM, 3 | ASN1_TAG_EXPLICIT, lastDivertingReason);
+//	XSEQUENCE_OPT_1(ParseQ931InformationElement, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, userInfo);
+	print_asn1msg(PRT_SHOWNUMBERS, "Diversion Information %s(%d) %s\n"
+		  "  callingAddress %s originalCalled Nr %s\n"
+		  "  lastDivertingNr %s lastDiverting Reason %s\n",
+		  diversionReason, basicService, servedUserSubaddress, callingAddress,
+		  originalCalledNr, lastDivertingNr, lastDivertingReason);
+	return p - beg;
+}
+
+int 
+ParseIntResultList(struct asn1_parm *pc, u_char *p, u_char *end, struct IntResultList *intResultList)
+{
+	int i;
+	INIT;
+
+	for (i = 0; i < 10; i++) {
+		intResultList->intResult[i].basicService = -1;
+		XSEQUENCE_OPT_1(ParseIntResult, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, 
+				&intResultList->intResult[i] );
+	}
+
+	return p - beg;
+}
+
+int 
+ParseIntResult(struct asn1_parm *pc, u_char *p, u_char *end, struct IntResult *intResult)
+{
+	INIT;
+
+	XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &intResult->servedUserNr);
+	XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &intResult->basicService);
+	XSEQUENCE_1(ParseProcedure, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &intResult->procedure);
+	XSEQUENCE_1(ParseAddress, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, &intResult->address);
+
+	return p - beg;
+}
+
+int
+ParseServedUserNrAll(struct asn1_parm *pc, u_char *p, u_char *end, struct ServedUserNr *servedUserNr)
+{
+	int ret;
+
+	ret = ParseNull(pc, p, end, 0);
+	if (ret < 0)
+		return ret;
+	servedUserNr->all = 1;
+
+	return ret;
+}
+
+int
+ParseServedUserNr(struct asn1_parm *pc, u_char *p, u_char *end, struct ServedUserNr *servedUserNr)
+{
+	INIT;
+
+	servedUserNr->all = 0;
+	XCHOICE_1(ParseServedUserNrAll, ASN1_TAG_NULL, ASN1_NOT_TAGGED, servedUserNr);
+	XCHOICE_1(ParsePartyNumber, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &servedUserNr->partyNumber);
+	XCHOICE_DEFAULT;
+}
+
+int
+ParseProcedure(struct asn1_parm *pc, u_char *p, u_char *end, int *procedure)
+{
+	return ParseEnum(pc, p, end, procedure);
+}
+
+int ParseServedUserNumberList(struct asn1_parm *pc, u_char *p, u_char *end, struct ServedUserNumberList *list)
+{
+	int i;
+	INIT;
+
+	for (i = 0; i < 10; i++) {
+		list->partyNumber[i].type = -1;
+		XSEQUENCE_OPT_1(ParsePartyNumber, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &list->partyNumber[i]);
+	}
+
+	return p - beg;
+}
+
+int
+ParseDiversionReason(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	int ret;
+	int diversionReason;
+
+	ret = ParseEnum(pc, p, end, &diversionReason);
+	if (ret < 0)
+		return ret;
+	
+	switch (diversionReason) {
+	case 0: sprintf(str, "unknown"); break;
+	case 1: sprintf(str, "CFU"); break;
+	case 2: sprintf(str, "CFB"); break;
+	case 3: sprintf(str, "CFNR"); break;
+	case 4: sprintf(str, "CD (Alerting)"); break;
+	case 5: sprintf(str, "CD (Immediate)"); break;
+	default: sprintf(str, "(%d)", diversionReason); break;
+	}
+
+	return ret;
+}
+
+int encodeActivationDiversion(__u8 *dest, struct FacCFActivate *CFActivate)
+{
+	__u8 *p;
+
+	dest[0] = 0x30;  // sequence
+	dest[1] = 0;     // length
+	p = &dest[2];
+
+	p += encodeEnum(p, CFActivate->Procedure);
+	p += encodeEnum(p, CFActivate->BasicService);
+	p += encodeAddress(p, CFActivate->ForwardedToNumber, CFActivate->ForwardedToSubaddress);
+	p += encodeServedUserNumber(p, CFActivate->ServedUserNumber);
+
+	dest[1] = p - &dest[2];
+	return p - dest;
+}
+
+int encodeDeactivationDiversion(__u8 *dest, struct FacCFDeactivate *CFDeactivate)
+{
+	__u8 *p;
+
+	dest[0] = 0x30;  // sequence
+	dest[1] = 0;     // length
+	p = &dest[2];
+
+	p += encodeEnum(p, CFDeactivate->Procedure);
+	p += encodeEnum(p, CFDeactivate->BasicService);
+	p += encodeServedUserNumber(p, CFDeactivate->ServedUserNumber);
+
+	dest[1] = p - &dest[2];
+	return p - dest;
+}
+
+int encodeInterrogationDiversion(__u8 *dest, struct FacCFInterrogateParameters *params)
+{
+	__u8 *p;
+
+	dest[0] = 0x30;  // sequence
+	dest[1] = 0;     // length
+	p = &dest[2];
+
+	p += encodeEnum(p, params->Procedure);
+#if 0
+	if (basicService == 0)
+		p += encodeNull(p);
+	else
+#endif
+	p += encodeEnum(p, params->BasicService);
+	p += encodeServedUserNumber(p, params->ServedUserNumber);
+
+	dest[1] = p - &dest[2];
+	return p - dest;
+}
+
+int encodeInvokeDeflection(__u8 *dest, struct FacCDeflection *CD)
+{
+	__u8 *p;
+
+	dest[0] = 0x30;  // sequence
+	dest[1] = 0;     // length
+	p = &dest[2];
+
+	p += encodeAddress(p, CD->DeflectedToNumber, CD->DeflectedToSubaddress);
+	p += encodeBoolean(p, CD->PresentationAllowed);
+
+	dest[1] = p - &dest[2];
+	return p - dest;
+}

Added: misdn-user/trunk/suppserv/asn1_diversion.h
===================================================================
--- misdn-user/trunk/suppserv/asn1_diversion.h	                        (rev 0)
+++ misdn-user/trunk/suppserv/asn1_diversion.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,9 @@
+#ifndef __ASN1_DIVERSION_H__
+#define __ASN1_DIVERSION_H__
+
+int encodeActivationDiversion(__u8 *dest, struct FacCFActivate *CFActivate);
+int encodeDeactivationDiversion(__u8 *dest, struct FacCFDeactivate *CFDeactivate);
+int encodeInterrogationDiversion(__u8 *dest, struct FacCFInterrogateParameters *params);
+int encodeInvokeDeflection(__u8 *dest, struct FacCDeflection *CD);
+
+#endif

Added: misdn-user/trunk/suppserv/asn1_enc.c
===================================================================
--- misdn-user/trunk/suppserv/asn1_enc.c	                        (rev 0)
+++ misdn-user/trunk/suppserv/asn1_enc.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,134 @@
+/* $Id: asn1_enc.c,v 1.2 2006/08/16 14:15:52 nadi Exp $
+ *
+ */
+
+#include "asn1.h"
+#include <string.h>
+
+int encodeNull(__u8 *dest)
+{
+	dest[0] = 0x05;  // null
+	dest[1] = 0;     // length
+	return 2;
+}
+
+int encodeBoolean(__u8 *dest, __u32 i)
+{
+	dest[0] = 0x01;  // BOOLEAN
+	dest[1] = 1;     // length 1
+	dest[2] = i ? 1:0;  // Value
+	return 3;
+}
+
+int encodeInt(__u8 *dest, __u32 i)
+{
+	__u8 *p;
+
+	dest[0] = 0x02;  // integer
+	dest[1] = 0;     // length
+	p = &dest[2];
+	do {
+		*p++ = i;
+		i >>= 8;
+	} while (i);
+
+	dest[1] = p - &dest[2];
+	return p - dest;
+}
+
+int encodeEnum(__u8 *dest, __u32 i)
+{
+	__u8 *p;
+
+	dest[0] = 0x0a;  // integer
+	dest[1] = 0;     // length
+	p = &dest[2];
+	do {
+		*p++ = i;
+		i >>= 8;
+	} while (i);
+
+	dest[1] = p - &dest[2];
+	return p - dest;
+}
+
+int encodeNumberDigits(__u8 *dest, __s8 *nd, __u8 len)
+{
+	__u8 *p;
+	int i;
+
+	dest[0] = 0x12;    // numeric string
+	dest[1] = 0x0;     // length
+	p = &dest[2];
+	for (i = 0; i < len; i++)
+		*p++ = *nd++;
+
+	dest[1] = p - &dest[2];
+	return p - dest;
+}
+
+int encodePublicPartyNumber(__u8 *dest, __s8 *facilityPartyNumber)
+{
+	__u8 *p;
+
+	dest[0] = 0x20;  // sequence
+	dest[1] = 0;     // length
+	p = &dest[2];
+	p += encodeEnum(p, (facilityPartyNumber[2] & 0x70) >> 4);
+	p += encodeNumberDigits(p, &facilityPartyNumber[4], facilityPartyNumber[0] - 3);
+
+	dest[1] = p - &dest[2];
+	return p - dest;
+}
+
+int encodePartyNumber(__u8 *dest, __s8 *facilityPartyNumber)
+{
+	__u8 *p = dest;
+
+	p += encodeNumberDigits(p, facilityPartyNumber, strlen((char *)facilityPartyNumber));
+	dest[0] = 0x80;
+#if 0
+	switch (facilityPartyNumber[1]) {
+	case 0: // unknown
+		p += encodeNumberDigits(p, &facilityPartyNumber[4], facilityPartyNumber[0] - 3);
+		dest[0] &= 0x20;
+		dest[0] |= 0x81;
+		break;
+	case 1: // publicPartyNumber
+		p += encodePublicPartyNumber(p, facilityPartyNumber);
+		dest[0] &= 0x20;
+		dest[0] |= 0x81;
+		break;
+	default:
+		int_error();
+		return -1;
+	}
+#endif
+	return p - dest;
+}
+
+int encodeServedUserNumber(__u8 *dest, __s8 *servedUserNumber)
+{
+	if (servedUserNumber[0])
+		return encodePartyNumber(dest, servedUserNumber);
+        else
+		return encodeNull(dest);
+}
+
+int encodeAddress(__u8 *dest, __s8 *facilityPartyNumber, __s8 *calledPartySubaddress)
+{
+	__u8 *p = dest;
+
+	dest[0] = 0x30;  // invoke id tag, integer
+	dest[1] = 0;     // length
+	p = &dest[2];
+
+	p += encodePartyNumber(p, facilityPartyNumber);
+#if 0 // FIXME
+	if (calledPartySubaddress[0])
+		p += encodePartySubaddress(p, calledPartySubaddress);
+#endif
+	dest[1] = p - &dest[2];
+	return p - dest;
+}
+

Added: misdn-user/trunk/suppserv/asn1_generic.c
===================================================================
--- misdn-user/trunk/suppserv/asn1_generic.c	                        (rev 0)
+++ misdn-user/trunk/suppserv/asn1_generic.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,112 @@
+/* $Id: asn1_generic.c,v 1.3 2006/08/16 14:15:52 nadi Exp $
+ *
+ */
+
+#include "asn1.h"
+
+// ======================================================================
+// general ASN.1
+
+int
+ParseBoolean(struct asn1_parm *pc, u_char *p, u_char *end, int *i)
+{
+	INIT;
+
+	*i = 0;
+	while (len--) {
+		CHECK_P;
+		*i = (*i >> 8) + *p;
+		p++;
+	}
+	print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> BOOL = %d %#x\n", *i, *i);
+	return p - beg;
+}
+
+int
+ParseNull(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	INIT;
+
+	return p - beg;
+}
+
+int
+ParseInteger(struct asn1_parm *pc, u_char *p, u_char *end, int *i)
+{
+	INIT;
+
+	*i = 0;
+	while (len--) {
+		CHECK_P;
+		*i = (*i << 8) + *p;
+		p++;
+	}
+	print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> INT = %d %#x\n", *i, *i);
+	return p - beg;
+}
+
+int
+ParseEnum(struct asn1_parm *pc, u_char *p, u_char *end, int *i)
+{
+	INIT;
+
+	*i = 0;
+	while (len--) {
+		CHECK_P;
+		*i = (*i << 8) + *p;
+		p++;
+	}
+	print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> ENUM = %d %#x\n", *i, *i);
+	return p - beg;
+}
+
+int
+ParseIA5String(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	INIT;
+
+	print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> IA5 = ");
+	while (len--) {
+		CHECK_P;
+		print_asn1msg(PRT_DEBUG_DECODE, "%c", *p);
+		*str++ = *p;
+		p++;
+	}
+	print_asn1msg(PRT_DEBUG_DECODE, "\n");
+	*str = 0;
+	return p - beg;
+}
+
+int
+ParseNumericString(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	INIT;
+
+	print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> NumStr = ");
+	while (len--) {
+		CHECK_P;
+		print_asn1msg(PRT_DEBUG_DECODE, "%c", *p);
+		*str++ = *p;
+		p++;
+	}
+	print_asn1msg(PRT_DEBUG_DECODE, "\n");
+	*str = 0;
+	return p - beg;
+}
+
+int
+ParseOctetString(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	INIT;
+
+	print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> Octets = ");
+	while (len--) {
+		CHECK_P;
+		print_asn1msg(PRT_DEBUG_DECODE, " %02x", *p);
+		*str++ = *p;
+		p++;
+	}
+	print_asn1msg(PRT_DEBUG_DECODE, "\n");
+	*str = 0;
+	return p - beg;
+}

Added: misdn-user/trunk/suppserv/fac.c
===================================================================
--- misdn-user/trunk/suppserv/fac.c	                        (rev 0)
+++ misdn-user/trunk/suppserv/fac.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,156 @@
+/*
+ * fac.c
+ *
+ * Copyright (C) 2006, Nadi Sarrar
+ * Nadi Sarrar <nadi at beronet.com>
+ *
+ * Portions of this file are based on the mISDN sources
+ * by Karsten Keil.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include "asn1.h"
+#include "asn1_diversion.h"
+#include "l3dss1.h"
+#include <string.h>
+
+enum {
+	SUPPLEMENTARY_SERVICE 	= 0x91,
+} SERVICE_DISCRIMINATOR;
+
+/*
+ * Facility IE Encoding
+ */
+
+static __u8* encodeInvokeComponentHead (__u8 *p, __u8 ie_id)
+{
+	*p++ = ie_id; // IE identifier
+	*p++ = 0;     // length -- not known yet
+	*p++ = 0x91;  // remote operations protocol
+	*p++ = 0xa1;  // invoke component
+	*p++ = 0;     // length -- not known yet
+	return p;
+}
+
+static int encodeInvokeComponentLength (__u8 *msg, __u8 *p)
+{
+	msg[4] = p - &msg[5];
+	msg[1] = p - &msg[2];
+	return msg[1] + 2;
+}
+
+static int encodeFacCDeflection (__u8 *dest, struct FacCDeflection *CD)
+{
+	__u8 *p;
+	p = encodeInvokeComponentHead(dest, IE_FACILITY);
+	p += encodeInt(p, 0x02);
+	p += encodeInt(p, 13); // Calldefection
+	p += encodeInvokeDeflection(p, CD);
+	return encodeInvokeComponentLength(dest, p);
+}
+
+int encodeFac (__u8 *dest, struct FacParm *fac)
+{
+	int len = -1;
+
+	switch (fac->Function) {
+	case Fac_None:
+	case Fac_GetSupportedServices:
+	case Fac_Listen:
+	case Fac_Suspend:
+	case Fac_Resume:
+	case Fac_CFActivate:
+	case Fac_CFDeactivate:
+	case Fac_CFInterrogateParameters:
+	case Fac_CFInterrogateNumbers:
+	case Fac_AOCDCurrency:
+	case Fac_AOCDChargingUnit:
+		break;
+	case Fac_CD:
+		len = encodeFacCDeflection(dest, &(fac->u.CDeflection));
+	}
+	return len;
+}
+
+/*
+ * Facility IE Decoding
+ */
+
+int decodeFac (__u8 *src, struct FacParm *fac)
+{
+	struct asn1_parm pc;
+	int 	fac_len,
+			offset;
+	__u8 	*end,
+		 	*p = src;
+
+	if (!p)
+		goto _dec_err;
+
+	offset = ParseLen(p, p + 3, &fac_len);
+	if (offset < 0)
+		goto _dec_err;
+	p += offset;
+	end = p + fac_len;
+
+	ParseASN1(p + 1, end, 0);
+
+	if (*p++ != SUPPLEMENTARY_SERVICE)
+		goto _dec_err;
+
+	if (ParseComponent(&pc, p, end) == -1)
+		goto _dec_err;
+
+	switch (pc.comp) {
+	case invoke:
+		switch (pc.u.inv.operationValue) {
+		case Fac_CD:
+			fac->Function = Fac_CD;
+			if (pc.u.inv.o.reqCD.address.partyNumber.type == 0)
+				strncpy((char *)fac->u.CDeflection.DeflectedToNumber,
+						pc.u.inv.o.reqCD.address.partyNumber.p.unknown,
+						sizeof(fac->u.CDeflection.DeflectedToNumber));
+			else
+				strncpy((char *)fac->u.CDeflection.DeflectedToNumber,
+						pc.u.inv.o.reqCD.address.partyNumber.p.publicPartyNumber.numberDigits,
+						sizeof(fac->u.CDeflection.DeflectedToNumber));
+			fac->u.CDeflection.PresentationAllowed = pc.u.inv.o.reqCD.pres;
+			*(fac->u.CDeflection.DeflectedToSubaddress) = 0;
+			return 0;
+		case Fac_AOCDCurrency:
+			fac->Function = Fac_AOCDCurrency;
+			memcpy(&(fac->u.AOCDcur), &(pc.u.inv.o.AOCDcur), sizeof(struct FacAOCDCurrency));
+			return 0;
+		case Fac_AOCDChargingUnit:
+			fac->Function = Fac_AOCDChargingUnit;
+			memcpy(&(fac->u.AOCDchu), &(pc.u.inv.o.AOCDchu), sizeof(struct FacAOCDChargingUnit));
+			return 0;
+		default:
+			goto _dec_err;
+		}
+		break;
+	case returnResult:
+	case returnError:
+	case reject:
+		goto _dec_err;
+	}
+
+_dec_err:
+	fac->Function = Fac_None;
+	return -1;
+} 
+

Added: misdn-user/trunk/suppserv/suppserv.h
===================================================================
--- misdn-user/trunk/suppserv/suppserv.h	                        (rev 0)
+++ misdn-user/trunk/suppserv/suppserv.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,152 @@
+/*
+ * suppserv.h
+ *
+ * Copyright (C) 2006, Nadi Sarrar
+ * Nadi Sarrar <nadi at beronet.com>
+ *
+ * Portions of this file are based on the mISDN sources
+ * by Karsten Keil.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __SUPPSERV_H__
+#define __SUPPSERV_H__
+
+#include <asm/types.h>
+
+/*
+ * Structs for Facility Messages
+ */
+
+enum FacFunction {
+	Fac_None 					= 0xffff,
+	Fac_GetSupportedServices 	= 0x0000,
+	Fac_Listen 					= 0x0001,
+	Fac_Suspend 				= 0x0004,
+	Fac_Resume 					= 0x0005,
+	Fac_CFActivate 				= 0x0009,
+	Fac_CFDeactivate 			= 0x000a,
+	Fac_CFInterrogateParameters = 0x000b,
+	Fac_CFInterrogateNumbers 	= 0x000c,
+	Fac_CD 						= 0x000d,
+	Fac_AOCDCurrency 			= 0x0021,
+	Fac_AOCDChargingUnit 		= 0x0022,
+};
+
+struct FacListen {
+	__u32 NotificationMask;
+};
+
+struct FacSuspend {
+	__s8  CallIdentity[16];
+};
+
+struct FacResume {
+	__s8  CallIdentity[16];
+};
+
+struct FacCFActivate {
+	__u32 Handle;
+	__u16 Procedure;
+	__u16 BasicService;
+	__s8  ServedUserNumber[16];
+	__s8  ForwardedToNumber[16];
+	__s8  ForwardedToSubaddress[16];
+};
+
+struct FacCFDeactivate {
+	__u32 Handle;
+	__u16 Procedure;
+	__u16 BasicService;
+	__s8  ServedUserNumber[16];
+};
+
+struct FacCDeflection {
+	__u16 PresentationAllowed;
+	__s8  DeflectedToNumber[16];
+	__s8  DeflectedToSubaddress[16];
+};
+
+#define FacCFInterrogateParameters FacCFDeactivate
+
+struct FacCFInterrogateNumbers {
+	__u32 Handle;
+};
+
+struct FacAOCDChargingUnit {
+	__u16 chargeNotAvailable;
+	__u16 freeOfCharge;
+	__s32 recordedUnits;
+	__s32 typeOfChargingInfo;
+	__s32 billingId;
+};
+
+struct FacAOCDCurrency {
+	__u16 chargeNotAvailable;
+	__u16 freeOfCharge;
+	__u8  currency[11];
+	__s32 currencyAmount;
+	__s32 multiplier;
+	__s32 typeOfChargingInfo;
+	__s32 billingId;
+};
+
+struct FacParm {
+	enum FacFunction Function;
+	union {
+		struct FacListen Listen;
+		struct FacSuspend Suspend;
+		struct FacResume Resume;
+		struct FacCFActivate CFActivate;
+		struct FacCFDeactivate CFDeactivate;
+		struct FacCFInterrogateParameters CFInterrogateParameters;
+		struct FacCFInterrogateNumbers CFInterrogateNumbers;
+		struct FacCDeflection CDeflection;
+		struct FacAOCDChargingUnit AOCDchu;
+		struct FacAOCDCurrency AOCDcur;
+	} u;
+};
+
+/*
+ * encodeFac (__u8 *dest, struct FacParm *fac)
+ *
+ * encode the facility (fac) into the buffer (dest)
+ *
+ * parameter:
+ * dest  - destination buffer
+ * fac   - facility to encode
+ *
+ * returns:
+ *    length of the encoded facility, or -1 on error
+ */
+int encodeFac (__u8 *dest, struct FacParm *fac);
+
+/*
+ * decodeFac (__u8 *src, struct FacParm *fac)
+ *
+ * decode the facility (src) and write the result to (fac)
+ *
+ * parameter:
+ * src   - encoded facility
+ * fac   - where to store the result
+ *
+ * returns:
+ *    0 on success, -1 on error
+ */
+int decodeFac (__u8 *src, struct FacParm *fac);
+
+#endif

Added: misdn-user/trunk/tenovis/Makefile
===================================================================
--- misdn-user/trunk/tenovis/Makefile	                        (rev 0)
+++ misdn-user/trunk/tenovis/Makefile	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,40 @@
+LIBINCL	:= $(INCLUDEDIR)/mISDNlib.h
+
+TENOVISLIB := lib/libtenovis.a
+
+TENOVISINC := lib/tenovis.h
+
+SUBDIRS := lib
+
+PROGS	:= testlib tstlib
+
+all: sublib $(PROGS)
+
+install:
+	for i in $(PROGS) ; do \
+		install -m 755 $$i $(INSTALL_PREFIX)/usr/bin ;\
+	done
+
+testlib: testlib.o $(TENOVISLIB) $(mISDNLIB)
+
+tstlib: tstlib.o $(TENOVISLIB) $(mISDNLIB)
+
+
+testlib.o : testlib.c ../include/l3dss1.h $(LIBINCL) $(TENOVISINC)
+
+tstlib.o : tstlib.c $(LIBINCL) $(TENOVISINC)
+
+sublib:
+	$(MAKE) -C lib lib
+
+subdirs:
+	set -e; for i in $(SUBDIRS) ; do $(MAKE) -C $$i $(TARGET); done
+
+clean:
+	make TARGET=$@ subdirs
+	rm -f *.o *~ DEADJOE
+	rm -f testlib tstlib
+
+distclean: clean
+	make TARGET=$@ subdirs
+	rm -f *.a $(PROGS)

Added: misdn-user/trunk/tenovis/lib/Makefile
===================================================================
--- misdn-user/trunk/tenovis/lib/Makefile	                        (rev 0)
+++ misdn-user/trunk/tenovis/lib/Makefile	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,21 @@
+
+lib: libtenovis.a
+
+libtenovis.a: tenovis_device.o tenovis_intern.o
+	rm -f $@
+	ar -r $@ $^
+	ar -s $@
+
+tenovis_device.o : tenovis_device.c tenovis.h tenovis_int.h \
+			../../include/mISDNlib.h
+
+tenovis_intern.o : tenovis_intern.c tenovis.h tenovis_int.h \
+			../../include/mISDNlib.h
+
+clean:
+	rm -f *.o *~ DEADJOE
+	rm -f libtenovis.a
+
+distclean: clean
+	rm -f *.a
+

Added: misdn-user/trunk/tenovis/lib/tenovis.h
===================================================================
--- misdn-user/trunk/tenovis/lib/tenovis.h	                        (rev 0)
+++ misdn-user/trunk/tenovis/lib/tenovis.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,68 @@
+/* Interface for Tenovis */
+
+/*
+ * int DL3open(void);
+ *
+ * DL3open() opens a device through which the D channel can be accessed.
+ *
+ * Returns a file descriptor on success or -1 in case of an error.
+ *   The file descriptor is used in all other DL3* calls and for select().
+ *
+ */
+
+extern	int	DL3open(void);
+
+/*
+ *
+ * int DL3close(int DL3fd)
+ *
+ *  DL3close(int DL3fd) closes the DL3fd previously opened DL3open().
+ *
+ *  The file descriptor DL3fd must not be used after DL3close() was called !
+ *
+ *  Parameter:
+ *     DL3fd : file descriptor assigned by DL3open
+ *
+ *  Returnvalue:
+ *     0 on success or -1 if the file descriptor was already closed or
+ *     is not valid.
+ *
+ */
+       
+extern	int	DL3close(int DL3fd);
+
+/*
+ * int DL3write(int DL3fd, const void *buf, size_t count);
+ *
+ * Sends a message to the layer 3 of the D channel stack.
+ *
+ *  Parameter:
+ *     DL3fd : file descriptor assigned by DL3open
+ *       buf : pointer to the message buffer
+ *     count : the length of the message in bytes 
+ *
+ *  Returnvalue:
+ *     0 on success or -1 on error in which case errno is set.
+ *
+ *
+ */
+
+extern	int	DL3write(int DL3fd, const void *buf, size_t count);
+
+/*
+ * size_t DL3read(int DL3fd, void *buf, size_t count);
+ *
+ * Reads a message from the Layer 3 of the D channel stack.
+ *
+ *  Parameter:
+ *     DL3fd : file descriptor assigned by DL3open
+ *       buf : pointer to the message buffer
+ *     count : the maximum message size which can read
+ *
+ *  Returnvalue:
+ *     the length of the message in bytes or -1 in case of an error
+ *     -2 if it was an internal (not L3) message
+ */
+
+extern	size_t	DL3read(int DL3fd, void *buf, size_t count);
+

Added: misdn-user/trunk/tenovis/lib/tenovis_device.c
===================================================================
--- misdn-user/trunk/tenovis/lib/tenovis_device.c	                        (rev 0)
+++ misdn-user/trunk/tenovis/lib/tenovis_device.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,171 @@
+/* 
+ * Interface for Tenovis
+ * device functions
+ *
+ */
+
+#include "tenovis_int.h"
+#include "tenovis.h"
+
+/*
+ * int DL3open(void);
+ *
+ * DL3open() opens a device through which the D channel can be accessed.
+ *
+ * Returns a file descriptor on success or -1 in case of an error.
+ *   The file descriptor is used in all other DL3* calls and for select().
+ *
+ */
+
+int
+DL3open(void)
+{
+	int			fid, ret;
+	tenovisdev_t		*dev;
+	
+	if (0>(fid = mISDN_open()))
+		return(fid);
+	dev = get_tdevice(fid);
+	if (dev) {
+		fprintf(stderr, "%s device %d (%p) has allready fid(%d)\n",
+			__FUNCTION__, dev->fid, dev, fid);
+		close(fid);
+		errno = EBUSY;
+		return(-1); 
+	}
+	dev = alloc_tdevice(fid);
+	if (!dev) {
+		return(-1);
+	}
+	ret = setup_tdevice(dev);
+	if (ret)
+		ret  = -1;
+	else
+		ret = fid;
+	return(ret);
+}
+
+/*
+ *
+ * int DL3close(int DL3fd)
+ *
+ *  DL3close(int DL3fd) closes the DL3fd previously opened DL3open().
+ *
+ *  The file descriptor DL3fd must not be used after DL3close() was called !
+ *
+ *  Parameter:
+ *     DL3fd : file descriptor assigned by DL3open
+ *
+ *  Returnvalue:
+ *     0 on success or -1 if the file descriptor was already closed or
+ *     is not valid.
+ *
+ */
+       
+int
+DL3close(int DL3fd)
+{
+	tenovisdev_t	*dev;
+	int		ret;
+
+	dev = get_tdevice(DL3fd);
+	if (!dev) {
+		errno = ENODEV;
+		return(-1);
+	}
+	shutdown_tdevice(dev);
+	ret = free_tdevice(dev);
+	return(ret);
+}
+
+
+/*
+ * int DL3write(int DL3fd, const void *buf, size_t count);
+ *
+ * Sends a message to the layer 3 of the D channel stack.
+ *
+ *  Parameter:
+ *     DL3fd : file descriptor assigned by DL3open
+ *       buf : pointer to the message buffer
+ *     count : the length of the message in bytes 
+ *
+ *  Returnvalue:
+ *     0 on success or -1 on error in which case errno is set.
+ *
+ *
+ */
+
+extern	int	DL3write(int DL3fd, const void *buf, size_t count)
+{
+	tenovisdev_t	*dev;
+	int		ret;
+
+	dev = get_tdevice(DL3fd);
+	if (!dev) {
+		errno = ENODEV;
+		return(-1);
+	}
+	if (!count)
+		return(0);
+	ret = mISDN_write_frame(dev->fid, dev->buf.p, dev->tlid | FLG_MSG_TARGET | FLG_MSG_UP,
+		DL_DATA | INDICATION, 0, count, (void *)buf, TIMEOUT_1SEC);
+	return(ret);
+}
+
+/*
+ * size_t DL3read(int DL3fd, void *buf, size_t count);
+ *
+ * Reads a message from the Layer 3 of the D channel stack.
+ *
+ *  Parameter:
+ *     DL3fd : file descriptor assigned by DL3open
+ *       buf : pointer to the message buffer
+ *     count : the maximum message size which can read
+ *
+ *  Returnvalue:
+ *     the length of the message in bytes or -1 in case of an error
+ *     -2 if it was an internal (not L3) message
+ */
+
+extern	size_t	DL3read(int DL3fd, void *buf, size_t count)
+{
+	tenovisdev_t	*dev;
+	int		ret;
+
+	dev = get_tdevice(DL3fd);
+	if (!dev) {
+		errno = ENODEV;
+		return(-1);
+	}
+	if (!buf) {
+		errno = EINVAL;
+		return(-1);
+	}
+	if (!count)
+		return(0);
+	if (count > dev->size - mISDN_HEADER_LEN)
+		count = dev->size - mISDN_HEADER_LEN;
+	ret = mISDN_read(dev->fid, dev->buf.p, count + mISDN_HEADER_LEN,
+		TIMEOUT_10SEC);
+#ifdef PRINTDEBUG
+	fprintf(stdout, __FUNCTION__": mISDN_read ret(%d) adr(%x) pr(%x) di(%x) l(%d)\n",
+				ret, dev->buf.f->addr, dev->buf.f->prim,
+				dev->buf.f->dinfo, dev->buf.f->len);
+#endif
+	if (ret <= 0)
+		return(ret);
+	if (dev->buf.f->addr == (dev->tlid | FLG_MSG_TARGET | FLG_MSG_UP)) {
+		if (dev->buf.f->prim == (DL_DATA | REQUEST)) {
+			if (dev->buf.f->len > count) {
+				errno = ENOSPC;
+				return(-1);
+			}
+			ret = dev->buf.f->len;
+			memcpy(buf, &dev->buf.f->data.p, ret);
+			return(ret);
+		}
+	}
+	ret = intern_read(dev);
+	return(ret);
+}
+

Added: misdn-user/trunk/tenovis/lib/tenovis_int.h
===================================================================
--- misdn-user/trunk/tenovis/lib/tenovis_int.h	                        (rev 0)
+++ misdn-user/trunk/tenovis/lib/tenovis_int.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,47 @@
+
+#include "mISDNlib.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+
+//#define PRINTDEBUG
+#undef	PRINTDEBUG
+
+#define	TN_INBUFFER_SIZE	4000
+
+typedef struct _tenovisdev {
+	struct _tenovisdev	*prev;
+	struct _tenovisdev	*next;
+	int			fid;
+	unsigned int		dstid;
+	unsigned int		dl0id;
+	unsigned int		dl1id;
+	unsigned int		dl2id;
+	unsigned int		dl3id;
+	unsigned int		dl4id;
+	unsigned int		tlid;
+	unsigned int		hwid;
+	unsigned int		Flags;
+	pthread_mutex_t		mutex;
+	int			size;
+	union {
+		unsigned char	*p;
+		iframe_t	*f;
+	} buf;
+} tenovisdev_t;
+
+#define TN_FLG_L2_ACTIV		0x0001
+
+extern	tenovisdev_t		*get_tdevice(int fid);
+extern	tenovisdev_t		*alloc_tdevice(int fid);
+extern	int			free_tdevice(tenovisdev_t *dev);
+extern	int			setup_tdevice(tenovisdev_t *dev);
+extern	int			shutdown_tdevice(tenovisdev_t *dev);
+extern	int			intern_read(tenovisdev_t *dev);

Added: misdn-user/trunk/tenovis/lib/tenovis_intern.c
===================================================================
--- misdn-user/trunk/tenovis/lib/tenovis_intern.c	                        (rev 0)
+++ misdn-user/trunk/tenovis/lib/tenovis_intern.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,299 @@
+/* 
+ * Internal functions for Tenovis lib
+ *
+ */
+
+#include "tenovis_int.h"
+#include "tenovis.h"
+
+static	tenovisdev_t	*tdevlist = NULL;
+static	pthread_mutex_t	tdevlist_lock = PTHREAD_MUTEX_INITIALIZER;
+
+tenovisdev_t *
+alloc_tdevice(int fid)
+{
+	tenovisdev_t	*dev;
+
+	dev = malloc(sizeof(tenovisdev_t));
+	if (!dev) {
+		close(fid);
+		errno = ENODEV;
+		return(NULL);
+	}
+	memset(dev, 0, sizeof(tenovisdev_t));
+	dev->fid = fid;
+	dev->size = TN_INBUFFER_SIZE;
+	dev->buf.p = malloc(dev->size);
+	if (!dev->buf.p) {
+		close(fid);
+		free(dev);
+		errno = ENODEV;
+		return(NULL);
+	}
+	pthread_mutex_init(&dev->mutex, NULL);
+	pthread_mutex_lock(&tdevlist_lock);
+	dev->prev = tdevlist;
+	while(dev->prev && dev->prev->next)
+		dev->prev = dev->prev->next;
+	if (tdevlist)
+		dev->prev->next = dev;
+	else
+		tdevlist = dev;
+	pthread_mutex_unlock(&tdevlist_lock);
+	return(dev);
+}
+
+tenovisdev_t *
+get_tdevice(int fid)
+{
+	tenovisdev_t	*dev;
+
+	pthread_mutex_lock(&tdevlist_lock);
+	dev = tdevlist;
+	while(dev) {
+		if (dev->fid==fid)
+			break;
+		dev = dev->next;
+	}
+	pthread_mutex_unlock(&tdevlist_lock);
+	return(dev);
+}
+
+int
+free_tdevice(tenovisdev_t *dev)
+{
+	int	ret;
+
+	if (dev->prev)
+		dev->prev->next = dev->next;
+	if (dev->next)
+		dev->next->prev = dev->prev;
+	if (tdevlist==dev)
+		tdevlist=dev->next;
+	pthread_mutex_lock(&dev->mutex);
+	if (dev->buf.p)
+		free(dev->buf.p);
+	dev->buf.p = NULL;
+	pthread_mutex_unlock(&dev->mutex);
+	ret = pthread_mutex_destroy(&dev->mutex);
+	if (ret)
+		fprintf(stderr, "%s mutex destroy returns %d\n",
+			__FUNCTION__, ret);
+	ret = mISDN_close(dev->fid);
+	free(dev);
+	return(ret);
+}
+
+int
+setup_tdevice(tenovisdev_t *dev)
+{
+	int			ret;
+	stack_info_t		*stinf;
+	layer_info_t		linf;
+#ifdef OBSOLETE
+	interface_info_t	iinf;
+#endif
+
+	ret = mISDN_write_frame(dev->fid, dev->buf.p, 0,
+		MGR_SETDEVOPT | REQUEST, FLG_mISDNPORT_ONEFRAME,
+		0, NULL, TIMEOUT_1SEC);
+#ifdef PRINTDEBUG
+	fprintf(stdout, "MGR_SETDEVOPT ret(%d)\n", ret);
+#endif			
+	ret = mISDN_read(dev->fid, dev->buf.p, 1024, TIMEOUT_10SEC);
+#ifdef PRINTDEBUG
+	fprintf(stdout, "mISDN_read ret(%d) pr(%x) di(%x) l(%d)\n",
+		ret, dev->buf.f->prim, dev->buf.f->dinfo, dev->buf.f->len);
+#endif
+	ret = mISDN_get_stack_count(dev->fid);
+#ifdef PRINTDEBUG
+	fprintf(stdout, "stackcnt %d\n", ret);
+#endif
+	if (ret <= 0) {
+		free_tdevice(dev);
+		errno = ENODEV;
+		return(-1);
+	}
+	ret = mISDN_get_stack_info(dev->fid, 1, dev->buf.p, dev->size);
+	stinf = (stack_info_t *)&dev->buf.f->data.p;
+#ifdef PRINTDEBUG
+	mISDNprint_stack_info(stdout, stinf);
+	fprintf(stdout, "ext(%x) instcnt(%d) childcnt(%d)\n",
+		stinf->extentions, stinf->instcnt, stinf->childcnt);
+#endif
+	dev->dstid = stinf->id;
+	dev->dl0id = mISDN_get_layerid(dev->fid, dev->dstid, 0);
+	dev->dl1id = mISDN_get_layerid(dev->fid, dev->dstid, 1);
+	dev->dl2id = mISDN_get_layerid(dev->fid, dev->dstid, 2);
+	dev->dl3id = mISDN_get_layerid(dev->fid, dev->dstid, 3);
+	dev->dl4id = mISDN_get_layerid(dev->fid, dev->dstid, 4);
+#ifdef PRINTDEBUG
+	fprintf(stdout, " dl0id = %08x\n", dev->dl0id);
+	fprintf(stdout, " dl1id = %08x\n", dev->dl1id);
+	fprintf(stdout, " dl2id = %08x\n", dev->dl2id);
+	fprintf(stdout, " dl3id = %08x\n", dev->dl3id);
+	fprintf(stdout, " dl4id = %08x\n", dev->dl4id);
+#ifdef #OBSOLETE
+	memset(&iinf, 0, sizeof(interface_info_t));
+	iinf.owner = dev->dl2id;
+	iinf.stat = FLG_MSG_TARGET | FLG_MSG_UP;
+	ret = mISDN_get_interface_info(dev->fid, &iinf);
+	fprintf(stdout, "l2 up   own(%x) -> peer(%x)\n",
+		iinf.owner, iinf.peer);
+	memset(&iinf, 0, sizeof(interface_info_t));
+	iinf.owner = dev->dl2id;
+	iinf.stat = FLG_MSG_TARGET | FLG_MSG_DOWN;
+	ret = mISDN_get_interface_info(dev->fid, &iinf);
+	fprintf(stdout, "l2 down own(%x) -> peer(%x)\n",
+		iinf.owner, iinf.peer);
+	memset(&iinf, 0, sizeof(interface_info_t));
+	iinf.owner = dev->dl3id;
+	iinf.stat = FLG_MSG_TARGET | FLG_MSG_UP;
+	ret = mISDN_get_interface_info(dev->fid, &iinf);
+	fprintf(stdout, "l3 up   own(%x) -> peer(%x)\n",
+		iinf.owner, iinf.peer);
+	memset(&iinf, 0, sizeof(interface_info_t));
+	iinf.owner = dev->dl3id;
+	iinf.stat = FLG_MSG_TARGET | FLG_MSG_DOWN;
+	ret = mISDN_get_interface_info(dev->fid, &iinf);
+	fprintf(stdout, "l3 down own(%x) -> peer(%x)\n",
+		iinf.owner, iinf.peer);
+#endif
+#endif
+	memset(&linf, 0, sizeof(layer_info_t));
+	strcpy(&linf.name[0], "tenovis L2");
+	linf.object_id = -1;
+	linf.extentions = EXT_INST_MIDDLE;
+	linf.pid.protocol[stinf->instcnt] = ISDN_PID_ANY;
+	linf.pid.layermask = ISDN_LAYER(stinf->instcnt);
+	linf.st = dev->dstid;
+	dev->tlid = mISDN_new_layer(dev->fid, &linf);
+#ifdef PRINTDEBUG
+	fprintf(stdout, "mISDN_new_layer ret(%x)\n", dev->tlid);
+	ret = mISDN_get_stack_info(dev->fid, 1, dev->buf.p, dev->size);
+	stinf = (stack_info_t *)&dev->buf.f->data.p;
+	mISDNprint_stack_info(stdout, stinf);
+#endif
+#ifdef OBSOLETE
+	memset(&iinf, 0, sizeof(interface_info_t));
+	iinf.extentions = EXT_INST_MIDDLE;
+	iinf.owner = dev->tlid;
+	iinf.peer = dev->dl3id;
+	iinf.stat = FLG_MSG_TARGET | FLG_MSG_UP;
+	ret = mISDN_write_frame(dev->fid, dev->buf.p, dev->tlid,
+		MGR_SETIF | REQUEST, 0, sizeof(interface_info_t),
+		&iinf, TIMEOUT_1SEC);
+#ifdef PRINTDEBUG
+	fprintf(stdout, "mISDN_write_frame ret(%d)\n", ret);
+#endif
+	ret = mISDN_read(dev->fid, dev->buf.p, 1024, TIMEOUT_10SEC);
+#ifdef PRINTDEBUG
+	fprintf(stdout, "mISDN_read ret(%d) pr(%x) di(%x) l(%d)\n",
+		ret, dev->buf.f->prim, dev->buf.f->dinfo,
+		dev->buf.f->len);
+#endif
+	memset(&iinf, 0, sizeof(interface_info_t));
+	iinf.extentions = EXT_INST_MIDDLE;
+	iinf.owner = dev->tlid;
+	iinf.peer = dev->dl2id;
+	iinf.stat = FLG_MSG_TARGET | FLG_MSG_DOWN;
+	ret = mISDN_write_frame(dev->fid, dev->buf.p, dev->tlid,
+		MGR_SETIF | REQUEST, 0, sizeof(interface_info_t),
+		&iinf, TIMEOUT_1SEC);
+#ifdef PRINTDEBUG
+	fprintf(stdout, "mISDN_write_frame ret(%d)\n", ret);
+#endif
+	ret = mISDN_read(dev->fid, dev->buf.p, 1024, TIMEOUT_10SEC);
+#ifdef PRINTDEBUG
+	fprintf(stdout, "mISDN_read ret(%d) pr(%x) di(%x) l(%d)\n",
+		ret, dev->buf.f->prim, dev->buf.f->dinfo,
+		dev->buf.f->len);
+	memset(&iinf, 0, sizeof(interface_info_t));
+	iinf.owner = dev->dl2id;
+	iinf.stat = FLG_MSG_TARGET | FLG_MSG_UP;
+	ret = mISDN_get_interface_info(dev->fid, &iinf);
+	fprintf(stdout, "l2 up   own(%x) -> peer(%x)\n",
+		iinf.owner, iinf.peer);
+	memset(&iinf, 0, sizeof(interface_info_t));
+	iinf.owner = dev->dl2id;
+	iinf.stat = FLG_MSG_TARGET | FLG_MSG_DOWN;
+	ret = mISDN_get_interface_info(dev->fid, &iinf);
+	fprintf(stdout, "l2 down own(%x) -> peer(%x)\n",
+		iinf.owner, iinf.peer);
+	memset(&iinf, 0, sizeof(interface_info_t));
+	iinf.owner = dev->dl3id;
+	iinf.stat = FLG_MSG_TARGET | FLG_MSG_UP;
+	ret = mISDN_get_interface_info(dev->fid, &iinf);
+	fprintf(stdout, "l3 up   own(%x) -> peer(%x)\n",
+		iinf.owner, iinf.peer);
+	memset(&iinf, 0, sizeof(interface_info_t));
+	iinf.owner = dev->dl3id;
+	iinf.stat = FLG_MSG_TARGET | FLG_MSG_DOWN;
+	ret = mISDN_get_interface_info(dev->fid, &iinf);
+	fprintf(stdout, "l3 down own(%x) -> peer(%x)\n",
+		iinf.owner, iinf.peer);
+#endif
+#endif
+	return(0);
+}
+
+int
+shutdown_tdevice(tenovisdev_t *dev)
+{
+	int	ret;
+
+	pthread_mutex_lock(&dev->mutex);
+	if (dev->buf.p) {
+		if (dev->tlid) {
+			ret = mISDN_write_frame(dev->fid, dev->buf.p,
+				dev->tlid, MGR_DELLAYER | REQUEST,
+				0, 0, NULL, TIMEOUT_1SEC);
+#ifdef PRINTDEBUG
+			fprintf(stdout, "MGR_DELLAYER ret(%d)\n", ret);
+#endif			
+			ret = mISDN_read(dev->fid, dev->buf.p, 1024,
+				TIMEOUT_10SEC);
+#ifdef PRINTDEBUG
+			fprintf(stdout, "mISDN_read ret(%d) pr(%x) di(%x) l(%d)\n",
+				ret, dev->buf.f->prim, dev->buf.f->dinfo,
+				dev->buf.f->len);
+#endif
+		}
+	}
+	pthread_mutex_unlock(&dev->mutex);
+	return(0);
+}
+
+int
+intern_read(tenovisdev_t *dev)
+{
+	int	ret;
+
+#ifdef PRINTDEBUG
+	fprintf(stdout, __FUNCTION__" addr(%x) prim(%x)\n",
+		dev->buf.f->addr, dev->buf.f->prim);
+#endif
+	if (dev->buf.f->addr == (dev->tlid | FLG_MSG_TARGET | FLG_MSG_UP)) {
+		if (dev->buf.f->prim == (DL_ESTABLISH | REQUEST)) {
+			dev->Flags |= TN_FLG_L2_ACTIV;
+			ret = mISDN_write_frame(dev->fid, dev->buf.p,
+				dev->tlid | FLG_MSG_TARGET | FLG_MSG_UP, DL_ESTABLISH | CONFIRM,
+				0, 0, NULL, TIMEOUT_1SEC);
+#ifdef PRINTDEBUG
+			fprintf(stdout, __FUNCTION__": estab cnf ret(%d)\n",
+				ret);
+#endif
+		} else if (dev->buf.f->prim == (DL_RELEASE | REQUEST)) {
+			dev->Flags &= ~TN_FLG_L2_ACTIV;
+			ret = mISDN_write_frame(dev->fid, dev->buf.p,
+				dev->tlid | FLG_MSG_TARGET | FLG_MSG_UP, DL_RELEASE | CONFIRM,
+				0, 0, NULL, TIMEOUT_1SEC);
+#ifdef PRINTDEBUG
+			fprintf(stdout, __FUNCTION__": rel cnf ret(%d)\n",
+				ret);
+#endif
+		}
+	}
+	return(-2);
+}
+

Added: misdn-user/trunk/tenovis/testlib.c
===================================================================
--- misdn-user/trunk/tenovis/testlib.c	                        (rev 0)
+++ misdn-user/trunk/tenovis/testlib.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,283 @@
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include "mISDNlib.h"
+#include "lib/tenovis.h"
+#include "l3dss1.h"
+
+
+int			tid;
+int			hid;
+int			dl3id;
+int			l2activ = 0;
+
+#define BUFFER_SIZE	2048
+
+u_char			buffer[BUFFER_SIZE];
+u_char			msg[BUFFER_SIZE];
+iframe_t		*frame;
+
+
+int
+init_lowdchannel(void)
+{
+	stack_info_t		*stinf;
+	layer_info_t		linf;
+	int			ret;
+#ifdef OBSOLETE
+	interface_info_t	iinf;
+#endif
+	int			dstid, dl2id;
+
+	frame = (iframe_t *)buffer;
+	hid = mISDN_open();
+	if (hid < 0)
+		return(-1);
+	
+	ret = mISDN_write_frame(hid, buffer, 0,
+		MGR_SETDEVOPT | REQUEST, FLG_mISDNPORT_ONEFRAME,
+		0, NULL, TIMEOUT_1SEC);
+	fprintf(stdout, "MGR_SETDEVOPT ret(%d)\n", ret);
+	ret = mISDN_read(hid, buffer, BUFFER_SIZE, TIMEOUT_10SEC);
+	fprintf(stdout, "mISDN_read ret(%d) pr(%x) di(%x) l(%d)\n",
+		ret, frame->prim, frame->dinfo, frame->len);
+	ret = mISDN_get_stack_count(hid);
+	fprintf(stdout, "stackcnt %d\n", ret);
+	if (ret <= 0) {
+		mISDN_close(hid);
+		return(-1);
+	}
+	ret = mISDN_get_stack_info(hid, 1, buffer, BUFFER_SIZE);
+	stinf = (stack_info_t *)&frame->data.p;
+	mISDNprint_stack_info(stdout, stinf);
+	fprintf(stdout, "ext(%x) instcnt(%d) childcnt(%d)\n",
+		stinf->extentions, stinf->instcnt, stinf->childcnt);
+	dstid = stinf->id;
+	dl2id = mISDN_get_layerid(hid, dstid, 2);
+	fprintf(stdout, " dl2id = %08x\n", dl2id);
+#ifdef OBSOLETE
+	memset(&iinf, 0, sizeof(interface_info_t));
+	iinf.owner = dl2id;
+	iinf.stat = FLG_MSG_TARGET | FLG_MSG_UP;
+	ret = mISDN_get_interface_info(hid, &iinf);
+	fprintf(stdout, "l2 up   own(%x) -> peer(%x)\n",
+		iinf.owner, iinf.peer);
+	memset(&iinf, 0, sizeof(interface_info_t));
+	iinf.owner = dl2id;
+	iinf.stat = FLG_MSG_TARGET | FLG_MSG_DOWN;
+	ret = mISDN_get_interface_info(hid, &iinf);
+	fprintf(stdout, "l2 down own(%x) -> peer(%x)\n",
+		iinf.owner, iinf.peer);
+
+#endif
+	memset(&linf, 0, sizeof(layer_info_t));
+	strcpy(&linf.name[0], "tst L3");
+	linf.object_id = -1;
+	linf.extentions = EXT_INST_MIDDLE;
+	linf.pid.protocol[stinf->instcnt] = ISDN_PID_ANY;
+	linf.pid.layermask = ISDN_LAYER(stinf->instcnt);
+	linf.st = dstid;
+	dl3id = mISDN_new_layer(hid, &linf);
+	fprintf(stdout, "mISDN_new_layer ret(%x)\n", dl3id);
+
+	ret = mISDN_get_stack_info(hid, 1, buffer, BUFFER_SIZE);
+	stinf = (stack_info_t *)&frame->data.p;
+	mISDNprint_stack_info(stdout, stinf);
+
+#ifdef OBSOLETE
+	memset(&iinf, 0, sizeof(interface_info_t));
+	iinf.extentions = EXT_INST_MIDDLE;
+	iinf.owner = dl3id;
+	iinf.peer = dl2id;
+	iinf.stat = FLG_MSG_TARGET | FLG_MSG_DOWN;
+	ret = mISDN_write_frame(hid, buffer, dl3id,
+		MGR_SETIF | REQUEST, 0, sizeof(interface_info_t),
+		&iinf, TIMEOUT_1SEC);
+	fprintf(stdout, "mISDN_write_frame ret(%d)\n", ret);
+	ret = mISDN_read(hid, buffer, 1024, TIMEOUT_10SEC);
+	fprintf(stdout, "mISDN_read ret(%d) pr(%x) di(%x) l(%d)\n",
+		ret, frame->prim, frame->dinfo,
+		frame->len);
+	memset(&iinf, 0, sizeof(interface_info_t));
+	iinf.owner = dl2id;
+	iinf.stat = FLG_MSG_TARGET | FLG_MSG_UP;
+	ret = mISDN_get_interface_info(hid, &iinf);
+	fprintf(stdout, "l2 up   own(%x) -> peer(%x)\n",
+		iinf.owner, iinf.peer);
+	memset(&iinf, 0, sizeof(interface_info_t));
+	iinf.owner = dl2id;
+	iinf.stat = FLG_MSG_TARGET | FLG_MSG_DOWN;
+	ret = mISDN_get_interface_info(hid, &iinf);
+	fprintf(stdout, "l2 down own(%x) -> peer(%x)\n",
+		iinf.owner, iinf.peer);
+#endif
+	return(0);
+}
+
+
+int
+close_lowdchannel(void)
+{
+	int	ret;
+
+	ret = mISDN_write_frame(hid, buffer, dl3id, MGR_DELLAYER | REQUEST,
+		0, 0, NULL, TIMEOUT_1SEC);
+	fprintf(stdout, "MGR_DELLAYER ret(%d)\n", ret);
+	ret = mISDN_read(hid, buffer, 1024, TIMEOUT_10SEC);
+	fprintf(stdout, "mISDN_read ret(%d) pr(%x) di(%x) l(%d)\n",
+		ret, frame->prim, frame->dinfo, frame->len);
+	return(0);
+}
+
+int
+process_lowdchannel(int len)
+{
+	int	ret;
+
+	fprintf(stderr, "mISDN_read pr(%x) di(%x) l(%d)\n",
+		frame->prim, frame->dinfo, frame->len);
+	if (frame->prim == (DL_DATA | INDICATION)) {
+		ret = DL3write(tid, &frame->data.p, frame->len);
+		fprintf(stderr, "DL3write ret(%d)\n", ret);
+	} else if (frame->prim == (DL_UNITDATA | INDICATION)) {
+		ret = DL3write(tid, &frame->data.p, frame->len);
+		fprintf(stderr, "DL3write ret(%d)\n", ret);
+	} else if (frame->prim == (DL_ESTABLISH | CONFIRM)) {
+		fprintf(stderr, "estab cnf\n");
+		l2activ = 1;
+	} else if (frame->prim == (DL_ESTABLISH | INDICATION)) {
+		fprintf(stderr, "estab ind\n");
+		l2activ = 1;
+	} else if (frame->prim == (DL_RELEASE | CONFIRM)) {
+		fprintf(stderr, "release cnf\n");
+		l2activ = 0;
+	} else if (frame->prim == (DL_RELEASE | INDICATION)) {
+		fprintf(stderr, "release ind\n");
+		l2activ = 0;
+	}
+	return(0);
+}
+
+int
+send_lowdchannel(int len)
+{
+	int	ret;
+
+	if (!l2activ) {
+		ret = mISDN_write_frame(hid, buffer, dl3id | FLG_MSG_TARGET | FLG_MSG_DOWN,
+			DL_ESTABLISH | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+		fprintf(stderr, "estab req ret(%d)\n", ret);
+		ret = mISDN_read(hid, buffer, 1024, TIMEOUT_10SEC);
+		fprintf(stderr, "estab read ret(%d)\n", ret);
+		if (ret >= 16) {
+			if (frame->prim == (DL_ESTABLISH | CONFIRM)) {
+				fprintf(stderr, "estab cnf\n");
+				l2activ = 1;
+			}
+			if (frame->prim == (DL_ESTABLISH | INDICATION)) {
+				fprintf(stderr, "estab ind\n");
+				l2activ = 1;
+			}
+		}
+	}
+	ret = mISDN_write_frame(hid, buffer, dl3id | FLG_MSG_TARGET | FLG_MSG_DOWN,
+		DL_DATA | REQUEST, 0, len, msg, TIMEOUT_1SEC);
+	return(ret);
+}
+
+
+static void
+term_handler(int sig)
+{
+	int	err;
+
+	fprintf(stderr,"signal %d received\n", sig);
+	close_lowdchannel();
+	err = DL3close(tid);
+	fprintf(stderr,"DL3close returns %d\n", err);
+	exit(0);		
+}
+
+
+int main(argc,argv)
+int argc;
+char *argv[];
+{
+	int		ret, n;
+	int		err;
+	fd_set		in;
+
+	fprintf(stderr,"%s\n", argv[0]);
+	tid = DL3open();
+	fprintf(stderr,"DL3open returns %d\n", tid);
+	if (tid<0) {
+		fprintf(stderr,"DL3open error %s\n", strerror(errno));
+		exit(1);
+	}
+	if (init_lowdchannel()) {
+		DL3close(tid);
+		exit(1);
+	}
+	signal(SIGTERM, term_handler);
+	signal(SIGINT, term_handler);
+	signal(SIGPIPE, term_handler);
+	while(1) {
+		FD_ZERO(&in);
+		n = fileno(stdin);
+		FD_SET(n, &in);
+		if (n<tid)
+			n = tid;
+		FD_SET(tid, &in);
+		if (n<hid)
+			n = hid;
+		FD_SET(hid, &in);
+		n++;
+		ret = select(n, &in, NULL, NULL, NULL);
+		if (ret<0)
+			continue;
+		if (FD_ISSET(fileno(stdin), &in))
+			break;
+		if (FD_ISSET(tid, &in)) {
+			ret = DL3read(tid, msg, 2048);
+			if (ret == -2) {
+				fprintf(stderr,"DL3read internal processing\n");
+			} else if (ret == -1) {
+				fprintf(stderr,"DL3read errno %d: %s\n",
+					errno, strerror(errno)); 
+			} else if (ret == 0) {
+				fprintf(stderr,"DL3read empty frame ?\n");
+			} else {
+				fprintf(stderr,"DL3read %d bytes\n", ret);
+				send_lowdchannel(ret);
+			}
+		}
+		if (FD_ISSET(hid, &in)) {
+			ret = mISDN_read(hid, buffer, 1024, TIMEOUT_1SEC);
+			if (ret < 0) {
+				fprintf(stderr,"mISDN_read errno %d: %s\n",
+					errno, strerror(errno));
+			} else if (ret == 0) {
+				fprintf(stderr,"mISDN_read empty frame ?\n");
+			} else {
+				fprintf(stderr,"mISDN_read %d bytes\n", ret);
+				if (ret < 16) {
+					fprintf(stderr,"mISDN_read incomplete frame\n");
+					continue;
+				}
+				process_lowdchannel(ret);
+			}
+		}
+	}
+	err = close_lowdchannel();
+	fprintf(stderr,"close_lowdchannel returns %d\n", err);
+	err = DL3close(tid);
+	fprintf(stderr,"DL3close returns %d\n", err);
+	return(0);
+}

Added: misdn-user/trunk/tenovis/tstlib.c
===================================================================
--- misdn-user/trunk/tenovis/tstlib.c	                        (rev 0)
+++ misdn-user/trunk/tenovis/tstlib.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,156 @@
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include "mISDNlib.h"
+#include "lib/tenovis.h"
+#include "l3dss1.h"
+
+#define	make_dss1_head(f, cr, mt) \
+		*f++ = 8;\
+		*f++ = 1;\
+		*f++ = cr;\
+		*f++ = mt
+
+int	tid;
+u_char	callref;
+
+static void
+term_handler(int sig)
+{
+	int	err;
+
+	fprintf(stderr,"signal %d received\n", sig);
+	err = DL3close(tid);
+	fprintf(stderr,"DL3close returns %d\n", err);
+	exit(0);		
+}
+
+
+int
+handle_msg(u_char *imsg, int len)
+{
+	u_char	mt,cr;
+	u_char	omsg[2048], *p;
+	int 	ret;
+
+	cr = imsg[2];
+	callref = cr;
+	mt = imsg[3];
+	p = omsg;
+	switch(mt) {
+		case MT_SETUP:
+			make_dss1_head(p, (cr ^ 0x80), MT_CALL_PROCEEDING);
+			*p++ = IE_CHANNEL_ID;
+			*p++ = 3;
+			*p++ = 0xa1;
+			*p++ = 0x83;
+			*p++ = 0x05;
+			ret = DL3write(tid, omsg, p - omsg);
+			fprintf(stderr,"CALLP write ret %d\n", ret);
+			p = omsg;
+			make_dss1_head(p, (cr ^ 0x80), MT_ALERTING);
+			ret = DL3write(tid, omsg, p - omsg);
+			fprintf(stderr,"ALERT write ret %d\n", ret);
+			p = omsg;
+			make_dss1_head(p, (cr ^ 0x80), MT_CONNECT);
+			ret = DL3write(tid, omsg, p - omsg);
+			fprintf(stderr,"CONN write ret %d\n", ret);
+			break;
+		case MT_DISCONNECT:
+			make_dss1_head(p, (cr ^= 0x80), MT_RELEASE);
+			ret = DL3write(tid, omsg, p - omsg);
+			fprintf(stderr,"REL write ret %d\n", ret);
+			break;
+		case MT_RELEASE:
+			make_dss1_head(p, (cr ^= 0x80), MT_RELEASE_COMPLETE);
+			ret = DL3write(tid, omsg, p - omsg);
+			fprintf(stderr,"RELC write ret %d\n", ret);
+			break;
+		case MT_RELEASE_COMPLETE:
+			fprintf(stderr,"got RELC len(%d)\n", len);
+			break;
+		case MT_STATUS:
+			fprintf(stderr,"got STATUS cr(%x) len(%d)\n",
+				cr, len);
+			break;
+		default:
+			fprintf(stderr,"got mt(%x) cr(%x) len(%d)\n",
+				mt, cr, len);
+			break;
+	}
+	return(0);
+}
+
+int main(argc,argv)
+int argc;
+char *argv[];
+
+{
+	u_char		imsg[2048];
+	u_char		omsg[2048], *p;
+	int		ret, n, loop = 1;
+	int		err;
+	fd_set		in;
+
+	fprintf(stderr,"%s\n", argv[0]);
+	tid = DL3open();
+	fprintf(stderr,"DL3open returns %d\n", tid);
+	if (tid<0) {
+		fprintf(stderr,"DL3open error %s\n", strerror(errno));
+		exit(1);
+	}
+	signal(SIGTERM, term_handler);
+	signal(SIGINT, term_handler);
+	signal(SIGPIPE, term_handler);
+	while(loop) {
+		FD_ZERO(&in);
+		n = fileno(stdin);
+		FD_SET(n, &in);
+		if (n<tid)
+			n = tid;
+		FD_SET(tid, &in);
+		n++;
+		ret = select(n, &in, NULL, NULL, NULL);
+		if (ret<0)
+			continue;
+		if (FD_ISSET(fileno(stdin), &in)) {
+			fgets(imsg, 2048, stdin);
+			switch(imsg[0]) {
+				case 'q':
+				case 'Q':
+					loop = 0;
+					break;
+				case 'h':
+				case 'H':
+					p = omsg;
+					make_dss1_head(p, (callref ^ 0x80),
+						MT_DISCONNECT);
+					*p++ = IE_CAUSE;
+					*p++ = 2;
+					*p++ = 0x80;
+					*p++ = 0x90;
+					ret = DL3write(tid, omsg, p - omsg);
+					fprintf(stderr,"DISC write ret %d\n", ret);
+					break;
+				default:
+					fprintf(stderr,"commands are (h)angup and (q)uit\n");
+					break;
+			}
+		}
+		if (FD_ISSET(tid, &in)) {
+			ret = DL3read(tid, imsg, 2048);
+			if (ret>0)
+				handle_msg(imsg, ret);
+		}
+	}
+	err = DL3close(tid);
+	fprintf(stderr,"DL3close returns %d\n", err);
+	return(0);
+}

Added: misdn-user/trunk/voip/Makefile
===================================================================
--- misdn-user/trunk/voip/Makefile	                        (rev 0)
+++ misdn-user/trunk/voip/Makefile	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,89 @@
+# ifndef SF_DIR
+# SF_DIR = /home/kkeil/speak_freely-7.2
+# endif
+
+mISDNLIB = $(mISDN_DIR)/lib/libmISDN.a
+ISDNNETLIB = $(mISDN_DIR)/i4lnet/libisdnnet.a
+
+HLIBINCL = $(mISDN_DIR)/include/mISDNlib.h
+INETINCL = $(mISDN_DIR)/include/isdn_net.h
+
+EXTRA_CFLAGS :=
+EXTRA_INCLUDE :=
+EXTRA_LIB :=
+
+#GSM_DIR := ../../gsm-1.0-pl6
+
+ifdef GSM_DIR
+EXTRA_CFLAGS += -DGSM_COMPRESSION
+EXTRA_INCLUDE += -I$(GSM_DIR)/inc
+EXTRA_LIB += $(GSM_DIR)/lib/libgsm.a
+endif
+
+PROGRAMMS = voipisdn
+
+all: $(PROGRAMMS)
+
+install:
+	for i in $(PROGRAMMS) ; do \
+		install -m 755 $$i $(INSTALL_PREFIX)/usr/bin ;\
+	done
+
+INTERNET_PORT = 2074
+
+CARGS	= -DInternet_Port=$(INTERNET_PORT)
+
+CCFLAGS	= -O3 -DLINUX -DM_LITTLE_ENDIAN
+
+LFLAGS	= -lncurses -lm -lrt -lpthread
+
+DEBUG	= -g -DHEXDUMP
+
+CFLAGS	:= $(CFLAGS) $(DEBUG) $(EXTRA_INCLUDE) \
+	$(CARGS) $(DUPLEX) $(CCFLAGS) $(DOMAIN) $(EXTRA_CFLAGS)
+
+LEX	= flex -8
+
+VOIPISDNOBJ = voip_isdn.o rtpacket.o voip_timer.o \
+		read_cfg.o voip_appl.o voip_isdn_app.o
+
+voipisdn: $(VOIPISDNOBJ) $(ISDNNETLIB) $(mISDNLIB) $(EXTRA_LIB) \
+		$(HLIBINCL) $(INETINCL) \
+		globals.h iapplication.h
+	$(CC) $(VOIPISDNOBJ) $(ISDNNETLIB) $(mISDNLIB) $(EXTRA_LIB) \
+		$(LFLAGS) -o $@
+
+rtpacket.o: rtpacket.c rtpacket.h \
+		$(mISDN_DIR)/include/g711.h
+
+voip_timer.o: voip_timer.c vitimer.h
+
+voip_appl.o: voip_appl.c $(mISDN_DIR)/include/g711.h \
+		globals.h rtpacket.h iapplication.h \
+		$(HLIBINCL) $(INETINCL)
+
+voip_isdn_app.o: voip_isdn_app.c \
+		globals.h rtpacket.h iapplication.h \
+		$(HLIBINCL) $(INETINCL)
+
+voip_isdn.o: voip_isdn.c $(mISDN_DIR)/include/g711.h \
+		globals.h rtpacket.h iapplication.h \
+		$(HLIBINCL) $(INETINCL) 
+
+cfg_lex.c: cfg.lex
+	$(LEX) cfg.lex
+	mv lex.yy.c cfg_lex.c
+
+read_cfg.o: read_cfg.c cfg_lex.c cfg.lex iapplication.h
+
+tstparse.o: tstparse.c
+
+tstparse: tstparse.o read_cfg.o
+
+clean:
+	rm -f *.o cfg_lex.c DEADJOE
+	find ./ -name '*~' -exec rm {} \;
+	rm -f voipisdn
+
+distclean: clean
+	rm -f *.a $(PROGRAMMS) tstparse

Added: misdn-user/trunk/voip/Makefile.org
===================================================================
--- misdn-user/trunk/voip/Makefile.org	                        (rev 0)
+++ misdn-user/trunk/voip/Makefile.org	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,83 @@
+# ifndef SF_DIR
+# SF_DIR = /home/kkeil/speak_freely-7.2
+# endif
+
+HISAXLIB = $(HISAX_DIR)/lib/libhisax.a
+ISDNNETLIB = $(HISAX_DIR)/i4lnet/libisdnnet.a
+
+HLIBINCL = $(HISAX_DIR)/include/hisaxlib.h
+INETINCL = $(HISAX_DIR)/include/isdn_net.h
+
+EXTRA_CFLAGS :=
+EXTRA_INCLUDE :=
+EXTRA_LIB :=
+
+GSM_DIR := ../../gsm-1.0-pl6
+
+ifdef GSM_DIR
+EXTRA_CFLAGS += -DGSM_COMPRESSION
+EXTRA_INCLUDE += -I$(GSM_DIR)/inc
+EXTRA_LIB += $(GSM_DIR)/lib/libgsm.a
+endif
+
+PROGRAMMS = voipisdn
+
+all: $(PROGRAMMS)
+
+INTERNET_PORT = 2074
+
+CARGS	= -DInternet_Port=$(INTERNET_PORT)
+
+CCFLAGS	= -O3 -DLINUX -DM_LITTLE_ENDIAN
+
+LFLAGS	= -lncurses -lm -lrt -lpthread
+
+DEBUG	= -g -DHEXDUMP
+
+CFLAGS	:= $(CFLAGS) $(DEBUG) $(EXTRA_INCLUDE) \
+	$(CARGS) $(DUPLEX) $(CCFLAGS) $(DOMAIN) $(EXTRA_CFLAGS)
+
+LEX	= flex -8
+
+VOIPISDNOBJ = voip_isdn.o rtpacket.o voip_timer.o \
+		read_cfg.o voip_appl.o voip_isdn_app.o
+
+voipisdn: $(VOIPISDNOBJ) $(ISDNNETLIB) $(HISAXLIB) $(EXTRA_LIB) \
+		$(HLIBINCL) $(INETINCL) \
+		globals.h iapplication.h
+	$(CC) $(VOIPISDNOBJ) $(ISDNNETLIB) $(HISAXLIB) $(EXTRA_LIB) \
+		$(LFLAGS) -o $@
+
+rtpacket.o: rtpacket.c rtpacket.h \
+		$(HISAX_DIR)/include/g711.h
+
+voip_timer.o: voip_timer.c vitimer.h
+
+voip_appl.o: voip_appl.c $(HISAX_DIR)/include/g711.h \
+		globals.h rtpacket.h iapplication.h \
+		$(HLIBINCL) $(INETINCL)
+
+voip_isdn_app.o: voip_isdn_app.c \
+		globals.h rtpacket.h iapplication.h \
+		$(HLIBINCL) $(INETINCL)
+
+voip_isdn.o: voip_isdn.c $(HISAX_DIR)/include/g711.h \
+		globals.h rtpacket.h iapplication.h \
+		$(HLIBINCL) $(INETINCL) 
+
+cfg_lex.c: cfg.lex
+	$(LEX) cfg.lex
+	mv lex.yy.c cfg_lex.c
+
+read_cfg.o: read_cfg.c cfg_lex.c cfg.lex iapplication.h
+
+tstparse.o: tstparse.c
+
+tstparse: tstparse.o read_cfg.o
+
+clean:
+	rm -f *.o cfg_lex.c DEADJOE
+	find ./ -name '*~' -exec rm {} \;
+
+distclean: clean
+	rm -f *.a $(PROGRAMMS) tstparse

Added: misdn-user/trunk/voip/cfg.lex
===================================================================
--- misdn-user/trunk/voip/cfg.lex	                        (rev 0)
+++ misdn-user/trunk/voip/cfg.lex	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,115 @@
+WSP	[ \t]
+NWSP	[^ \t\n]
+VCHR    [A-Za-z_]
+VCHRZ   [A-Za-z_0-9]
+VCHRX	[A-Za-z\-\._0-9]
+VCHRP	[A-Za-z\-\.\/_0-9]
+MSN	[Mm][Ss][Nn]
+AUDIONR	[Aa][Uu][Dd][Ii][Oo][Nn][Rr]
+VOIPNR	[Vv][Oo][Ii][Pp][Nn][Rr]
+DEBUG   [Dd][Ee][Bb][Uu][Gg]
+PORT	[Pp][Oo][Rr][Tt]
+GSM	[Gg][Ss][Mm]
+RECORD	[Rr][Ee][Cc][Oo][Rr][Dd]
+FILE	[Ff][Ii][Ll][Ee]
+PATH	[Pp][Aa][Tt][Hh]
+CTRL	[Cc][Tt][Rr][Ll]
+ZIF	[0-9]
+HZIF	[0-9a-fA-F]
+HEX	0[Xx]{HZIF}+
+NR	{ZIF}+
+NAME	{VCHRX}+
+PATHSTR	{VCHRP}+
+
+%START Normal Comment Number Name NumValue PathValue
+
+%%
+	int		AktState=0;
+	ulong		val=0;
+	nr_list_t	*new_nr = NULL;
+
+<Normal>{
+^#.*		;
+{DEBUG}{WSP}+   {
+			BEGIN NumValue;
+			AktState = ST_DEB;
+		}
+{RECORD}{CTRL}{FILE}{WSP}+ {
+			BEGIN PathValue;
+			AktState = ST_RCF;
+}
+
+{RECORD}{FILE}{PATH}{WSP}+ {
+			BEGIN PathValue;
+			AktState = ST_RFP;
+}
+
+{PORT}{WSP}+   {
+			BEGIN NumValue;
+			AktState = ST_PORT;
+		}
+{MSN}{WSP}+	{
+			BEGIN Number;
+			AktState = ST_MSN;
+			new_nr = getnewnr(NR_TYPE_INTERN);
+		}
+{AUDIONR}{WSP}+	{
+			BEGIN Number;
+			AktState = ST_AUDIO;
+			new_nr = getnewnr(NR_TYPE_AUDIO);
+		}
+{VOIPNR}{WSP}+	{
+			BEGIN Number;
+			AktState = ST_VNR;
+			new_nr = getnewnr(NR_TYPE_VOIP);
+		}
+{GSM}{WSP}*	{
+			add_cfgflag(AktState, new_nr, FLAG_GSM);
+		}
+{WSP}+		;
+[^ \t\n]	{
+			yyless(0);
+			BEGIN Name; 
+		}
+\n		{
+			new_nr = NULL;
+		}
+}
+
+<Number>{
+{WSP}*		;
+{NR}		{
+			add_cfgnr(AktState, new_nr, yytext, yyleng);
+			BEGIN Normal;
+		}
+}
+<Name>{
+{WSP}*		;
+{NAME}		{
+			add_cfgname(AktState, new_nr, yytext, yyleng);
+			BEGIN Normal;
+		}
+}
+<NumValue>{
+{WSP}*		;
+{HEX}		{
+			val = strtol(yytext, NULL, 16);
+			add_cfgval(AktState, new_nr, val);
+			AktState = ST_NORM;
+			BEGIN Normal;
+		}
+{NR}		{
+			val = strtol(yytext, NULL, 0);
+			add_cfgval(AktState, new_nr, val);
+			AktState = ST_NORM;
+			BEGIN Normal;
+		}
+}
+<PathValue>{
+{WSP}*		;
+{PATHSTR}	{
+			add_path(AktState, yytext, yyleng);
+			AktState = ST_NORM;
+			BEGIN Normal;
+		}
+}

Added: misdn-user/trunk/voip/example/pingi2.voip.cfg
===================================================================
--- misdn-user/trunk/voip/example/pingi2.voip.cfg	                        (rev 0)
+++ misdn-user/trunk/voip/example/pingi2.voip.cfg	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,36 @@
+#
+# tstsetup voipisdn
+#
+#
+# File to control recording of channels
+# see rec_ctrl.sample
+#
+RecordCtrlFile /var/tmp/rec_ctrl
+
+#
+# Path to diretory where record files are saved
+# Record filenames are <timestamp>_<channel>.r (from phone)
+#                      <timestamp>_<channel>.s (to phone)
+#
+RecordFilePath /var/tmp/
+
+#
+# MSN  <number>
+# local number
+#
+MSN	12345
+MSN	888
+#
+# VOIPNR <number>  <hostname|addresse> [GSM]
+# foreign numbers on hostname or address
+# option: using of GSM
+#
+VOIPNR	4566		pictra_client GSM
+VOIPNR	4568		pictra_client
+VOIPNR  4567		10.23.200.1
+#
+# AUDIONR <number>
+# number for calling the local soundcard
+#
+AUDIONR 789
+

Added: misdn-user/trunk/voip/example/rec_ctrl.sample
===================================================================
--- misdn-user/trunk/voip/example/rec_ctrl.sample	                        (rev 0)
+++ misdn-user/trunk/voip/example/rec_ctrl.sample	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,7 @@
+# 
+# for each channel one line with a value:
+#	0 don't record channel
+#	1 record channel
+#
+1
+0

Added: misdn-user/trunk/voip/globals.h
===================================================================
--- misdn-user/trunk/voip/globals.h	                        (rev 0)
+++ misdn-user/trunk/voip/globals.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,19 @@
+#ifndef FLAG_GSM
+#define FLAG_GSM	0x0020
+#endif
+
+extern	int		parse_cfg(char *, manager_t *);
+
+#ifdef INIT_GLOBALS
+	int	global_debug = 0;
+	int	rtp_port = Internet_Port;
+	int	default_flags = 0;
+	char	RecordCtrlFile[1024] = {0,};
+	char	RecordFilePath[1024] = {0,};
+#else
+extern	int	global_debug;
+extern	int	rtp_port;
+extern	int	default_flags;
+extern	char	RecordCtrlFile[1024];
+extern  char	RecordFilePath[1024];
+#endif

Added: misdn-user/trunk/voip/iapplication.h
===================================================================
--- misdn-user/trunk/voip/iapplication.h	                        (rev 0)
+++ misdn-user/trunk/voip/iapplication.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,137 @@
+#ifndef IAPPLICATION_H
+#define IAPPLICATION_H
+
+#include "vitimer.h"
+#ifdef GSM_COMPRESSION
+#include <gsm.h>
+#endif
+
+#define AP_MODE_IDLE		0
+#define	AP_MODE_INTERN_CALL	1
+#define AP_MODE_AUDIO_CALL	2
+#define AP_MODE_VOIP_OCALL	3
+#define AP_MODE_VOIP_ICALL	4
+
+#define AP_FLG_AUDIO_ACTIV	1
+#define AP_FLG_VOIP_ALERTING	2
+#define AP_FLG_VOIP_ACTIV	4
+
+#define AP_FLG_VOIP_NEW_CONN	0x01000000
+#define AP_FLG_VOIP_PEER_VALID	0x02000000
+#define	AP_FLG_VOIP_SENT_BYE	0x04000000
+#define AP_FLG_VOIP_PEER_BYE	0x08000000
+#define AP_FLG_VOIP_PEER_SF	0x10000000
+
+#define AP_FLG_AUDIO_USED	0x00000100
+#define	AP_FLG_VOIP_ABORT	0x80000000
+
+#define AP_PR_VOIP_ISDN		1
+#define AP_PR_VOIP_NEW		2
+#define AP_PR_VOIP_SPEAKFREE	3
+#define AP_PR_VOIP_BYE		4
+
+#define MAX_HOST_SIZE		64
+#define MAX_NETBUFFER_SIZE	8040
+
+#define SLOW_TIMEOUT_s		10
+#define SLOW_TIMEOUT_us		0
+#define NORMAL_TIMEOUT_s	0
+#define NORMAL_TIMEOUT_us	(320*125)
+
+#define SNDFLG_ULAW		0x00000001
+#define SNDFLG_ALAW		0x00000002
+#define SNDFLG_LINEAR16		0x00000004
+#define SNDFLG_COMPR_GSM	0x00000100
+
+typedef struct _iapplication	iapplication_t;
+typedef struct _vapplication	vapplication_t;
+typedef struct _vconnection	vconnection_t;
+
+struct _iapplication {
+	iapplication_t	*prev;
+	iapplication_t	*next;
+	manager_t	*mgr;
+	vapplication_t	*vapp;
+	void		*data1;
+	void		*data2;
+	vconnection_t	*con;
+	void		*para;
+	vi_timer_t	timer;
+	pthread_t	tid;
+	int		Flags;
+	int		mode;
+};
+
+struct _vapplication {
+	manager_t		*mgr_lst;
+	char			hostname[MAX_HOST_SIZE];
+	unsigned int		flags;
+	struct timeval		tout;
+	int			debug;
+	int			port;
+	int			dsock;
+	int			csock;
+	struct sockaddr_in	daddr;
+	struct sockaddr_in	caddr;
+	struct sockaddr_in	from;
+	int			fromlen;
+	iapplication_t		*iapp_lst;
+	int			rlen;
+	union {
+		unsigned char		d[MAX_NETBUFFER_SIZE];
+	}			buf;
+};
+
+struct _vconnection {
+	int			sock;
+	struct sockaddr_in	cpeer;
+	struct sockaddr_in	dpeer;
+	char			rmtname[256];
+	char			con_hostname[32];
+	unsigned int		own_ssrc;
+	unsigned int		peer_ssrc;
+	unsigned int		timestamp;
+	unsigned short		seq;
+	unsigned short		lastseq;
+	unsigned char		oc;
+	unsigned char		pc;
+	msg_queue_t		aqueue;
+	msg_t			*amsg;
+	int			rlen;
+	unsigned char		*rbuf;
+	unsigned int		sndflags;
+	int			pkt_size;
+	int			slen;
+#ifdef GSM_COMPRESSION
+	gsm			r_gsm;
+	gsm			s_gsm;
+#endif
+	unsigned char		sbuf[1024];
+	unsigned char		dbuf[1152];
+	unsigned char		cbuf[1024];
+};
+
+extern	pthread_t	run_voip(vapplication_t *v);
+extern	void		*voip_sender(void *arg);
+
+extern	void		clear_connection(iapplication_t *);
+extern	void		free_application(iapplication_t *);
+extern	unsigned long	getnew_ssrc(vapplication_t *);
+extern	iapplication_t	*new_application(vapplication_t *);
+extern	vconnection_t	*new_connection(iapplication_t *, struct in_addr *);
+extern	int		SendCtrl(iapplication_t *);
+
+extern	int		voip_application_handler(iapplication_t *, int,
+				unsigned char *);
+extern	int		setup_voip(iapplication_t *, bchannel_t *);
+extern	int		close_voip(iapplication_t *, bchannel_t *);
+
+extern	int		setup_voip_ocall(iapplication_t *, bchannel_t *);
+extern	int		alert_voip(iapplication_t *, bchannel_t *);
+extern	int		facility_voip(iapplication_t *, bchannel_t *);
+extern	int		useruser_voip(iapplication_t *, bchannel_t *);
+extern	int		connect_voip(iapplication_t *, bchannel_t *);
+extern	int		disconnect_voip(iapplication_t *, bchannel_t *);
+extern	int		release_voip(iapplication_t *, bchannel_t *);
+
+#endif

Added: misdn-user/trunk/voip/options.h
===================================================================
--- misdn-user/trunk/voip/options.h	                        (rev 0)
+++ misdn-user/trunk/voip/options.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,13 @@
+
+	int	debugforce;
+	int	whichport;
+	int	jitter;
+	int	jitteridlet;
+	int	record;
+	int	hexdump;
+	int	blowfish_spec;
+	BF_KEY	blowfishkey;
+	char	ideakey[17];
+	char	deskey[9];
+	char	*curotp;
+	char	*pgppass;

Added: misdn-user/trunk/voip/prep.conf
===================================================================
--- misdn-user/trunk/voip/prep.conf	                        (rev 0)
+++ misdn-user/trunk/voip/prep.conf	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,9 @@
+#undef PUSH_TO_TALK
+#undef USE_CURSES
+#undef AUDIO_DEVICE_FILE
+#undef HALF_DUPLEX
+#undef HEWLETT_PACKARD
+#define UNIX5
+#undef UNIX420
+#undef Solaris
+#undef sgi

Added: misdn-user/trunk/voip/read_cfg.c
===================================================================
--- misdn-user/trunk/voip/read_cfg.c	                        (rev 0)
+++ misdn-user/trunk/voip/read_cfg.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,143 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "isdn_net.h"
+#include "helper.h"
+#define INIT_GLOBALS
+#include "globals.h"
+
+static	manager_t *akt_mgr;
+
+int		add_cfgnr(int  state, nr_list_t *nr, char *t, int l);
+int		add_cfgname(int  state, nr_list_t *nr, char *t, int l);
+int		add_cfgval(int  state, nr_list_t *nr, ulong val);
+nr_list_t	*getnewnr(int typ);
+int		add_cfgflag(int  state, nr_list_t *nr, int flag);
+int		add_path(int  state, char *t, int l);
+
+enum {
+	ST_NORM,
+	ST_MSN,
+	ST_VNR,
+	ST_AUDIO,
+	ST_DEB,
+	ST_PORT,
+	ST_RFP,
+	ST_RCF,
+};
+
+#include "cfg_lex.c"
+
+int yywrap(void)
+{
+	return(1);
+}
+
+int parse_cfg(char *FName, manager_t *mgr) {
+	int ret;
+
+	yyin = fopen(FName, "r");
+	if (!yyin) {
+		fprintf(stderr,"cannot open cfg file %s\n", FName);
+		return(1);
+	} else
+		fprintf(stderr,"parsing cfg file %s\n", FName);
+	akt_mgr = mgr;
+	BEGIN Normal;
+	ret = yylex();
+	fclose(yyin);
+	return(ret);
+}
+
+nr_list_t *
+getnewnr(int typ)
+{
+	nr_list_t	*nr;
+	
+	nr = malloc(sizeof(nr_list_t));
+	memset(nr, 0, sizeof(nr_list_t));
+	nr->typ = typ;
+	return(nr);
+}
+
+int
+add_cfgnr(int  state, nr_list_t *nr, char *t, int l)
+{
+//	printf("%s(%d,%p,%s)\n", __FUNCTION__, state, nr, t);
+	if (nr) {
+		switch(state) {
+			default:
+				strcpy(nr->nr, t);
+				nr->len = l;
+				APPEND_TO_LIST(nr, akt_mgr->nrlist);
+				break;
+		}
+	}
+	return(0);
+}
+
+int
+add_cfgname(int  state, nr_list_t *nr, char *t, int l)
+{
+//	printf("%s(%d,%p,%s)\n", __FUNCTION__, state, nr, t);
+	if (nr) {
+		switch(state) {
+			default:
+				strcpy(nr->name, t);
+				break;
+		}
+	}
+	return(0);
+}
+
+int
+add_cfgval(int  state, nr_list_t *nr, ulong val)
+{
+	if (nr) {
+	} else {
+		switch(state) {
+			case ST_DEB:
+				global_debug = val;
+				break;
+			case ST_PORT:
+				rtp_port  = val;
+				break;
+		}
+	}
+	return(0);
+}
+
+int
+add_cfgflag(int  state, nr_list_t *nr, int flag)
+{
+	if (nr) {
+		nr->flags ^= flag;
+	} else {
+		default_flags ^= flag;
+	}
+	return(0);
+}
+
+int
+add_path(int  state, char *t, int l)
+{
+//	printf("%s(%d,%s)\n", __FUNCTION__, state, t);
+	if (l<1)
+		return(0);
+	switch(state) {
+		default:
+			fprintf(stderr, "%s: Unknown state(%d) text(%s)\n", __FUNCTION__,
+				state, t);
+		case ST_RCF:
+			strcpy(RecordCtrlFile, t);
+			break;
+		case ST_RFP:
+			strcpy(RecordFilePath, t);
+			if (RecordFilePath[l-1] != '/') {
+				RecordFilePath[l] = '/';
+				RecordFilePath[l+1] = 0;
+			}
+			break;
+	}
+	return(0);
+}

Added: misdn-user/trunk/voip/rtp.h
===================================================================
--- misdn-user/trunk/voip/rtp.h	                        (rev 0)
+++ misdn-user/trunk/voip/rtp.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,133 @@
+/*
+* rtp.h  --  RTP header file
+* RTP draft: November 1994 version
+*
+* $Id: rtp.h,v 1.0 2003/08/27 07:35:32 kkeil Exp $
+*/
+
+#define RTP_SEQ_MOD (1<<16)
+#define RTP_TS_MOD  (0xffffffff)
+/*
+* Current type value.
+*/
+#define RTP_VERSION 2
+
+#define RTP_MAX_SDES 256   /* maximum text length for SDES */
+
+typedef enum {
+  RTCP_SR   = 200,
+  RTCP_RR   = 201,
+  RTCP_SDES = 202,
+  RTCP_BYE  = 203,
+  RTCP_APP  = 204
+} rtcp_type_t;
+
+typedef enum {
+  RTCP_SDES_END    =  0,
+  RTCP_SDES_CNAME  =  1,
+  RTCP_SDES_NAME   =  2,
+  RTCP_SDES_EMAIL  =  3,
+  RTCP_SDES_PHONE  =  4,
+  RTCP_SDES_LOC    =  5,
+  RTCP_SDES_TOOL   =  6,
+  RTCP_SDES_NOTE   =  7,
+  RTCP_SDES_PRIV   =  8, 
+  RTCP_SDES_IMG    =  9,
+  RTCP_SDES_DOOR   = 10,
+  RTCP_SDES_SOURCE = 11
+} rtcp_sdes_type_t;
+
+typedef enum {
+	AE_PCMU,
+	AE_1016,
+	AE_G721,
+	AE_GSM,
+	AE_G723,
+	AE_IDVI,
+	AE_LPC,
+	AE_PCMA,
+	AE_L16,
+	AE_G728,
+	AE_MAX
+} audio_encoding_t;
+
+typedef struct {
+	audio_encoding_t encoding;	/* type of encoding (differs) */
+	unsigned sample_rate;		/* sample frames per second */
+	unsigned channels;		/* number of interleaved channels */
+} audio_descr_t;
+                
+typedef struct {
+  unsigned int version:2;  /* protocol version */
+  unsigned int p:1;        /* padding flag */
+  unsigned int x:1;        /* header extension flag */
+  unsigned int cc:4;       /* CSRC count */
+  unsigned int m:1;        /* marker bit */
+  unsigned int pt:7;       /* payload type */
+  u_int16_t seq;             /* sequence number */
+  u_int32_t ts;              /* timestamp */
+  u_int32_t ssrc;            /* synchronization source */
+  u_int32_t csrc[1];         /* optional CSRC list */
+} rtp_hdr_t;
+
+typedef struct {
+  unsigned int version:2;  /* protocol version */
+  unsigned int p:1;        /* padding flag */
+  unsigned int count:5;    /* varies by payload type */
+  unsigned int pt:8;       /* payload type */
+  u_int16_t length;          /* packet length in words, without this word */
+} rtcp_common_t;
+
+/* reception report */
+typedef struct {
+  u_int32_t ssrc;            /* data source being reported */
+  unsigned int fraction:8; /* fraction lost since last SR/RR */
+  int lost:24;             /* cumulative number of packets lost (signed!) */
+  u_int32_t last_seq;        /* extended last sequence number received */
+  u_int32_t jitter;          /* interarrival jitter */
+  u_int32_t lsr;             /* last SR packet from this source */
+  u_int32_t dlsr;            /* delay since last SR packet */
+} rtcp_rr_t;
+
+typedef struct {
+  u_int8_t type;             /* type of SDES item (rtcp_sdes_type_t) */
+  u_int8_t length;           /* length of SDES item (in octets) */
+  char data[1];            /* text, not zero-terminated */
+} rtcp_sdes_item_t;
+
+/* one RTCP packet */
+typedef struct {
+  rtcp_common_t common;    /* common header */
+  union {
+    /* sender report (SR) */
+    struct {
+      u_int32_t ssrc;        /* source this RTCP packet refers to */
+      u_int32_t ntp_sec;     /* NTP timestamp */
+      u_int32_t ntp_frac;
+      u_int32_t rtp_ts;      /* RTP timestamp */
+      u_int32_t psent;       /* packets sent */
+      u_int32_t osent;       /* octets sent */ 
+      /* variable-length list */
+      rtcp_rr_t rr[1];
+    } sr;
+
+    /* reception report (RR) */
+    struct {
+      u_int32_t ssrc;        /* source this generating this report */
+      /* variable-length list */
+      rtcp_rr_t rr[1];
+    } rr;
+
+    /* BYE */
+    struct {
+      u_int32_t src[1];      /* list of sources */
+      /* can't express trailing text */
+    } bye;
+
+    /* source description (SDES) */
+    struct rtcp_sdes_t {
+      u_int32_t src;              /* first SSRC/CSRC */
+      rtcp_sdes_item_t item[1]; /* list of SDES items */
+    } sdes;
+  } r;
+} rtcp_t;

Added: misdn-user/trunk/voip/rtpacket.c
===================================================================
--- misdn-user/trunk/voip/rtpacket.c	                        (rev 0)
+++ misdn-user/trunk/voip/rtpacket.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,858 @@
+/*
+
+	      RTP input packet construction and parsing
+
+*/
+
+#include <pwd.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include "g711.h"
+#include "rtpacket.h"
+
+#ifndef FALSE
+#define	FALSE	0
+#endif
+
+#ifndef TRUE
+#define	TRUE	1
+#endif
+
+audio_descr_t adt[] = {
+/* enc	   sample ch */
+  {AE_PCMU,  8000, 1},	/*  0 PCMU */
+  {AE_MAX,   8000, 1},	/*  1 1016 */
+  {AE_G721,  8000, 1},	/*  2 G721 */
+  {AE_GSM,   8000, 1},	/*  3 GSM */
+  {AE_G723,  8000, 1},	/*  4 Unassigned */
+  {AE_IDVI,  8000, 1},	/*  5 DVI4 */
+  {AE_IDVI, 16000, 1},	/*  6 DVI4 */
+  {AE_LPC,   8000, 1},	/*  7 LPC */
+  {AE_PCMA,  8000, 1},	/*  8 PCMA */
+  {AE_MAX,	0, 1},	/*  9 G722 */
+  {AE_L16,  44100, 2},	/* 10 L16 */
+  {AE_L16,  44100, 1},	/* 11 L16 */
+  {AE_MAX,	0, 1},	/* 12 */
+};
+
+#define MAX_MISORDER 100
+#define MAX_DROPOUT  3000
+
+/*  ISRTP  --  Determine if a packet is RTP or not.  If so, convert
+	       in place into a sound buffer.  */
+
+int isrtp(pkt, len)
+  unsigned char *pkt;
+  int len;
+{
+#ifdef RationalWorld
+    rtp_hdr_t *rh = (rtp_hdr_t *) pkt;
+#endif
+
+    unsigned int r_version, r_p, r_x, r_cc, r_m, r_pt,
+		 r_seq, r_ts;
+
+    /* Tear apart the header in a byte- and bit field-order
+       independent fashion. */
+
+    r_version = (pkt[0] >> 6) & 3;
+    r_p = !!(pkt[0] & 0x20);
+    r_x = !!(pkt[0] & 0x10);
+    r_cc = pkt[0] & 0xF;
+    r_m = !!(pkt[1] & 0x80);
+    r_pt = pkt[1] & 0x1F;
+    r_seq = ntohs(*((short *) (pkt + 2)));
+    r_ts = ntohl(*((long *) (pkt + 4)));
+
+    if (
+#ifdef RationalWorld
+	rh->version == RTP_VERSION && /* Version ID correct */
+	rh->pt < ELEMENTS(adt) &&     /* Payload type credible */
+	adt[rh->pt].sample_rate != 0 && /* Defined payload type */
+				      /* Padding, if present, is plausible */
+	(!rh->p || (pkt[len - 1] < (len - (12 + 4 * rh->cc))))
+#else
+	r_version == RTP_VERSION &&   /* Version ID correct */
+	r_pt < ELEMENTS(adt) &&       /* Payload type credible */
+	adt[r_pt].sample_rate != 0 && /* Defined payload type */
+				      /* Padding, if present, is plausible */
+	(!r_p || (pkt[len - 1] < (len - (12 + 4 * r_cc))))
+#endif
+       ) {
+	unsigned char *payload;
+	int lex, paylen;
+
+			      /* Length of fixed header extension, if any */
+	lex = r_x ? (ntohs(*((short *) (pkt + 2 + 12 + 4 * r_cc))) + 1) * 4 : 0;
+	payload = pkt + (12 + 4 * r_cc) + lex; /* Start of payload */
+	paylen = len - ((12 + 4 * r_cc) +      /* Length of payload */
+		    lex + (r_p ? pkt[len - 1] : 0));
+	return TRUE;
+    }
+    return FALSE;
+}
+
+/*  ISVALIDRTCPPACKET  --  Consistency check a packet to see if
+			   is a compliant RTCP packet.	Note that
+			   since this must also accept Speak Freely
+			   SDES packets, the test on the protocol is
+			   not as tight as were it exclusively for
+			   RTP.  */
+
+int isValidRTCPpacket(p, len)
+  unsigned char *p;
+  int len;
+{
+    unsigned char *end;
+
+    if (((((p[0] >> 6) & 3) != RTP_VERSION) &&	   /* Version incorrect ? */
+	((((p[0] >> 6) & 3) != 1))) ||		   /* Allow Speak Freely too */
+	((p[0] & 0x20) != 0) || 		   /* Padding in first packet ? */
+	((p[1] != RTCP_SR) && (p[1] != RTCP_RR))) { /* First item not SR or RR ? */
+	return FALSE;
+    }
+    end = p + len;
+
+    do {
+	/* Advance to next subpacket */
+	p += (ntohs(*((short *) (p + 2))) + 1) * 4;
+    } while (p < end && (((p[0] >> 6) & 3) == RTP_VERSION));
+
+    return p == end;
+}
+
+/*  ISRTCPBYEPACKET  --  Test if this RTCP packet contains a BYE.  */
+
+int isRTCPByepacket(p, len)
+  unsigned char *p;
+  int len;
+{
+    unsigned char *end;
+    int sawbye = FALSE;
+						   /* Version incorrect ? */
+    if ((((p[0] >> 6) & 3) != RTP_VERSION && ((p[0] >> 6) & 3) != 1) ||
+	((p[0] & 0x20) != 0) || 		   /* Padding in first packet ? */
+	((p[1] != RTCP_SR) && (p[1] != RTCP_RR))) { /* First item not SR or RR ? */
+	return FALSE;
+    }
+    end = p + len;
+
+    do {
+	if (p[1] == RTCP_BYE) {
+	    sawbye = TRUE;
+	}
+	/* Advance to next subpacket */
+	p += (ntohs(*((short *) (p + 2))) + 1) * 4;
+    } while (p < end && (((p[0] >> 6) & 3) == RTP_VERSION));
+
+    return (p == end) && sawbye;
+}
+
+/*  ISRTCPAPPPACKET  --  Test if this RTCP packet contains a APP item
+			 with a given name.  If so, returns a pointer
+			 to the APP sub-packet in app_ptr.  */
+
+int isRTCPAPPpacket(p, len, name, app_ptr)
+  unsigned char *p;
+  int len;
+  char *name;
+  unsigned char **app_ptr;
+{
+    unsigned char *end;
+
+    *app_ptr = NULL;
+						   /* Version incorrect ? */
+    if ((((p[0] >> 6) & 3) != RTP_VERSION && ((p[0] >> 6) & 3) != 1) ||
+	((p[0] & 0x20) != 0) || 		   /* Padding in first packet ? */
+	((p[1] != RTCP_SR) && (p[1] != RTCP_RR))) { /* First item not SR or RR ? */
+	return FALSE;
+    }
+    end = p + len;
+
+    do {
+	if ((p[1] == RTCP_APP) && (memcmp(p + 8, name, 4) == 0)) {
+	    *app_ptr = p;
+	    return TRUE;
+	}
+	/* Advance to next subpacket */
+	p += (ntohs(*((short *) (p + 2))) + 1) * 4;
+    } while (p < end && (((p[0] >> 6) & 3) == RTP_VERSION));
+
+    return FALSE;
+}
+
+#if 0
+/*  RTP_MAKE_SDES  --  Generate a source description for this
+		       user, based either on information obtained
+		       from the password file or supplied by
+		       environment variables.  Strict construction
+		       of the RTP specification requires every
+		       SDES packet to be a composite which begins
+		       with a sender or receiver report.  If the
+                       "strict" argument is true, we'll comply with
+                       this.  Unfortunately, Look Who's Listening
+		       Server code was not aware of this little
+		       twist when originally implemented, so it will
+		       take some time to transition all the running
+		       servers to composite packet aware code.	*/
+
+int rtp_make_sdes(pkt, ssrc_i, port, strict)
+  char **pkt;
+  unsigned long ssrc_i;
+  int port, strict;
+{
+    unsigned char zp[1500];
+    unsigned char *p = zp;
+    rtcp_t *rp;
+    unsigned char *ap;
+    char *sp, *ep;
+    int l, hl;
+    struct passwd *pw;
+    char s[256], ev[1024];
+
+#define addSDES(item, text) *ap++ = item; *ap++ = l = strlen(text); \
+			    bcopy(text, ap, l); ap += l
+
+    hl = 0;
+    if (strict) {
+	*p++ = RTP_VERSION << 6;
+	*p++ = RTCP_RR;
+	*p++ = 0;
+	*p++ = 1;
+	*((long *) p) = htonl(ssrc_i);
+	p += 4;
+	hl = 8;
+    }
+
+    rp = (rtcp_t *) p;
+#ifdef RationalWorld
+    rp->common.version = RTP_VERSION;
+    rp->common.p = 0;
+    rp->common.count = 1;
+    rp->common.pt = RTCP_SDES;
+#else
+    *((short *) p) = htons((RTP_VERSION << 14) | RTCP_SDES | (1 << 8));
+#endif	
+    rp->r.sdes.src = htonl(ssrc_i);
+
+    ap = (unsigned char *) rp->r.sdes.item;
+
+    ep = getenv("SPEAKFREE_ID");
+    if (ep != NULL) {
+	if (strlen(ep) == 0) {
+	    ep = NULL;
+	} else {
+	    strcpy(ev, ep);
+	    ep = ev;
+	}
+    }
+
+    /* Build canonical name for this user.  This is generally
+       a name which can be used for "talk" and "finger", and
+       is not necessarily the user's E-mail address. */
+
+    if ((sp = getenv("SPEAKFREE_CNAME")) != NULL && strlen(sp) > 0) {
+        /* If strict, drop leading asterisk that's used to request an
+	   unlisted entry on an LWL server. */
+        if (strict && sp[0] == '*') {
+	    sp++;
+	}
+	addSDES(RTCP_SDES_CNAME, sp);
+    } else {
+	pw = getpwuid(getuid());
+	if (pw != NULL) {
+	    char dn[64];
+	    char hn[MAXHOSTNAMELEN];
+
+	    dn[0] = hn[0] = 0;
+	    getdomainname(dn, sizeof dn);
+	    gethostname(hn, sizeof hn);
+	    if (dn[0] != 0) {
+                sprintf(s, "%s@%s", pw->pw_name, dn);
+	    } else {
+		struct hostent *h;
+		struct in_addr naddr;
+
+		h = gethostbyname(hn);
+                if (strchr(h->h_name, '.') != NULL) {
+                    sprintf(s, "%s@%s", pw->pw_name, h->h_name);
+		} else {
+		    bcopy(h->h_addr, &naddr, sizeof naddr);
+                    sprintf(s, "%s@%s", pw->pw_name, inet_ntoa(naddr));
+		}
+	    }
+	    addSDES(RTCP_SDES_CNAME, s);
+	    if (ep == NULL && pw->pw_gecos != NULL) {
+                char *gc = strchr(pw->pw_gecos, ',');
+
+		if (gc != NULL) {
+		    *gc = 0;
+		}
+		addSDES(RTCP_SDES_NAME, pw->pw_gecos);
+	    }
+	} else {
+#ifdef Solaris
+	    {	char s[12];
+		sysinfo(SI_HW_SERIAL, s, 12);
+                sprintf(s, "Unknown@%s.hostid.net", s);
+	    }
+#else
+            sprintf(s, "Unknown@%lu.hostid.net", gethostid());
+#endif
+	    addSDES(RTCP_SDES_CNAME, s);
+	}
+    }
+
+    /* If a SPEAKFREE_ID environment variable is present,
+       parse the items it contains.  Format:
+
+       SPEAKFREE_ID=<full name>:<E-mail address>:<phone number>:<location>
+
+    */
+
+    if (ep != NULL) {
+	int i;
+	static int items[] = { RTCP_SDES_NAME, RTCP_SDES_EMAIL,
+			       RTCP_SDES_PHONE, RTCP_SDES_LOC };
+	char *np;
+
+	for (i = 0; i < ELEMENTS(items); i++) {
+	    while (*ep && isspace(*ep)) {
+		ep++;
+	    }
+	    if (*ep == 0) {
+		break;
+	    }
+            if ((np = strchr(ep, ':')) != NULL) {
+		*np++ = 0;
+	    } else {
+		np = NULL;
+	    }
+	    if (strlen(ep) > 0) {
+                /* If strict, drop leading asterisk that's used to request an
+		   unlisted entry on an LWL server. */
+                if (strict && items[i] == RTCP_SDES_EMAIL && ep[0] == '*') {
+		    ep++;
+		}
+		addSDES(items[i], ep);
+	    }
+	    if (np == NULL) {
+		break;
+	    }
+	    ep = np;
+	}
+    }
+
+    addSDES(RTCP_SDES_TOOL, "Speak Freely for Unix");
+
+    if (!strict) {
+
+	/* If a port number is specified, add a PRIV item indicating
+           the port we're communicating on. */
+
+	if (port >= 0) {
+	    char s[20];
+
+            sprintf(s, "\001P%d", port);
+	    addSDES(RTCP_SDES_PRIV, s);
+	}
+    }
+    
+    *ap++ = RTCP_SDES_END;
+    *ap++ = 0;
+
+    l = ap - p;
+
+    rp->common.length = htons(((l + 3) / 4) - 1);
+    l = hl + ((ntohs(rp->common.length) + 1) * 4);
+
+    /* Okay, if the total length of this packet is not an odd
+       multiple of 4 bytes, we're going to put a pad at the
+       end of it.  Why?  Because we may encrypt the packet
+       later and that requires it be a multiple of 8 bytes,
+       and we don't want the encryption code to have to
+       know all about our weird composite packet structure.
+       Oh yes, there's no reason to do this if strict isn't
+       set, since we never encrypt packets sent to a Look
+       Who's Listening server.
+
+       Why an odd multiple of 4 bytes, I head you ask?
+       Because when we encrypt an RTCP packet, we're required
+       to prefix it with four random bytes to deter a known
+       plaintext attack, and since the total buffer we
+       encrypt, including the random bytes, has to be a
+       multiple of 8 bytes, the message needs to be an odd
+       multiple of 4. */
+
+    if (strict) {
+	int pl = (l & 4) ? l : l + 4;
+
+	if (pl > l) {
+	    int pad = pl - l;
+
+	    bzero(zp + l, pad);       /* Clear pad area to zero */
+	    zp[pl - 1] = pad;	      /* Put pad byte count at end of packet */
+            p[0] |= 0x20;             /* Set the "P" bit in the header of the
+					 SDES (last in message) packet */
+                                      /* If we've added an additional word to
+					 the packet, adjust the length in the
+					 SDES message, which must include the
+					 pad */
+	    rp->common.length = htons(ntohs(rp->common.length) + ((pad) / 4));
+	    l = pl;		      /* Include pad in length of packet */
+	}
+    }
+
+    *pkt = (char *) malloc(l);
+    if (*pkt != NULL) {
+	bcopy(zp, *pkt, l);
+	return l;
+    }
+    return 0;
+}
+
+/*  RTP_MAKE_SDES_S--  Generate a source description for this
+		       servers to composite packet aware code.	*/
+
+int rtp_make_sdes_s(pkt, strict, r)
+  char **pkt;
+  struct rtcp_sdes_request *r;
+  int strict;
+{
+    unsigned char zp[1500];
+    unsigned char *p = zp;
+    unsigned long *ssrc;
+    rtcp_t *rp;
+    unsigned char *ap;
+    int l, hl, i;
+
+#define addSDES(item, text) *ap++ = item; *ap++ = l = strlen(text); \
+			    bcopy(text, ap, l); ap += l
+
+    ssrc = (unsigned long *)r->ssrc;
+    hl = 0;
+    if (strict) {
+	*p++ = RTP_VERSION << 6;
+	*p++ = RTCP_RR;
+	*p++ = 0;
+	*p++ = 1;
+	*((long *) p) = htonl(*ssrc);
+	p += 4;
+	hl = 8;
+    }
+
+    rp = (rtcp_t *) p;
+#ifdef RationalWorld
+    rp->common.version = RTP_VERSION;
+    rp->common.p = 0;
+    rp->common.count = 1;
+    rp->common.pt = RTCP_SDES;
+#else
+    *((short *) p) = htons((RTP_VERSION << 14) | RTCP_SDES | (1 << 8));
+#endif	
+    rp->r.sdes.src = htonl(*ssrc);
+
+    ap = (unsigned char *) rp->r.sdes.item;
+
+    for (i = 0; i < r->nitems; i++) {
+    	addSDES(r->item[i].r_item, r->item[i].r_text);
+    }
+    
+    *ap++ = RTCP_SDES_END;
+    *ap++ = 0;
+
+    l = ap - p;
+
+    rp->common.length = htons(((l + 3) / 4) - 1);
+    l = hl + ((ntohs(rp->common.length) + 1) * 4);
+
+    /* Okay, if the total length of this packet is not an odd
+       multiple of 4 bytes, we're going to put a pad at the
+       end of it.  Why?  Because we may encrypt the packet
+       later and that requires it be a multiple of 8 bytes,
+       and we don't want the encryption code to have to
+       know all about our weird composite packet structure.
+       Oh yes, there's no reason to do this if strict isn't
+       set, since we never encrypt packets sent to a Look
+       Who's Listening server.
+
+       Why an odd multiple of 4 bytes, I head you ask?
+       Because when we encrypt an RTCP packet, we're required
+       to prefix it with four random bytes to deter a known
+       plaintext attack, and since the total buffer we
+       encrypt, including the random bytes, has to be a
+       multiple of 8 bytes, the message needs to be an odd
+       multiple of 4. */
+
+    if (strict) {
+	int pl = (l & 4) ? l : l + 4;
+
+	if (pl > l) {
+	    int pad = pl - l;
+
+	    bzero(zp + l, pad);       /* Clear pad area to zero */
+	    zp[pl - 1] = pad;	      /* Put pad byte count at end of packet */
+            p[0] |= 0x20;             /* Set the "P" bit in the header of the
+					 SDES (last in message) packet */
+                                      /* If we've added an additional word to
+					 the packet, adjust the length in the
+					 SDES message, which must include the
+					 pad */
+	    rp->common.length = htons(ntohs(rp->common.length) + ((pad) / 4));
+	    l = pl;		      /* Include pad in length of packet */
+	}
+    }
+
+    if (*pkt == NULL)
+	    *pkt = (char *) malloc(l);
+    if (*pkt != NULL) {
+	bcopy(zp, *pkt, l);
+	return l;
+    }
+    return 0;
+}
+
+#endif
+
+/*  RTP_MAKE_BYE  --  Create a "BYE" RTCP packet for this connection.  */
+
+int rtp_make_bye(p, ssrc_i, raison, strict)
+  unsigned char *p;
+  unsigned long ssrc_i;
+  char *raison;
+  int strict;
+{
+    rtcp_t *rp;
+    unsigned char *ap, *zp;
+    int l, hl;
+
+    /* If requested, prefix the packet with a null receiver
+       report.	This is required by the RTP spec, but is not
+       required in packets sent only to the Look Who's Listening
+       server. */
+
+    zp = p;
+    hl = 0;
+    if (strict) {
+	*p++ = RTP_VERSION << 6;
+	*p++ = RTCP_RR;
+	*p++ = 0;
+	*p++ = 1;
+	*((long *) p) = htonl(ssrc_i);
+	p += 4;
+	hl = 8;
+    }
+
+    rp = (rtcp_t *) p;
+#ifdef RationalWorld
+    rp->common.version = RTP_VERSION;
+    rp->common.p = 0;
+    rp->common.count = 1;
+    rp->common.pt = RTCP_BYE;
+#else
+    *((short *) p) = htons((RTP_VERSION << 14) | RTCP_BYE | (1 << 8));
+#endif	
+    rp->r.bye.src[0] = htonl(ssrc_i);
+
+    ap = (unsigned char *) rp->r.sdes.item;
+
+    l = 0;
+    if (raison != NULL) {
+	l = strlen(raison);
+	if (l > 0) {
+	    *ap++ = l;
+	    bcopy(raison, ap, l);
+	    ap += l;
+	}
+    }
+
+    while ((ap - p) & 3) {
+	*ap++ = 0;
+    }
+    l = ap - p;
+
+    rp->common.length = htons((l / 4) - 1);
+
+    l = hl + ((ntohs(rp->common.length) + 1) * 4);
+
+    /* If strict, pad the composite packet to an odd multiple of 4
+       bytes so that if we decide to encrypt it we don't have to worry
+       about padding at that point. */
+
+    if (strict) {
+	int pl = (l & 4) ? l : l + 4;
+
+	if (pl > l) {
+	    int pad = pl - l;
+
+	    bzero(zp + l, pad);       /* Clear pad area to zero */
+	    zp[pl - 1] = pad;	      /* Put pad byte count at end of packet */
+            p[0] |= 0x20;             /* Set the "P" bit in the header of the
+					 SDES (last in message) packet */
+                                      /* If we've added an additional word to
+					 the packet, adjust the length in the
+					 SDES message, which must include the
+					 pad */
+	    rp->common.length = htons(ntohs(rp->common.length) + ((pad) / 4));
+	    l = pl;		      /* Include pad in length of packet */
+	}
+    }
+
+    return l;
+}
+
+/*  RTP_MAKE_APP  --  Create a "APP" (application-defined) RTCP packet
+		      for this connection with the given type (name)
+		      and content. */
+
+int rtp_make_app(p, ssrc_i, strict, type, content, len)
+  unsigned char	*p, *content;
+  unsigned long	ssrc_i;
+  int		strict, len;
+  char		*type;
+{
+    rtcp_t *rp;
+    unsigned char *ap, *zp;
+    int l, hl;
+
+    /* If requested, prefix the packet with a null receiver
+       report.	This is required by the RTP spec, but is not
+       required in packets sent only to other copies of Speak
+       Freely. */
+
+    zp = p;
+    hl = 0;
+    if (strict) {
+	*p++ = RTP_VERSION << 6;
+	*p++ = RTCP_RR;
+	*p++ = 0;
+	*p++ = 1;
+	*((long *) p) = htonl(ssrc_i);
+	p += 4;
+	hl = 8;
+    }
+
+    rp = (rtcp_t *) p;
+    *((short *) p) = htons((RTP_VERSION << 14) | RTCP_APP | (1 << 8));
+    rp->r.bye.src[0] = htonl(ssrc_i);
+
+    ap = p + 8;
+    bcopy(type, ap, 4);
+    ap += 4;
+
+    bcopy(content, ap, len);
+    ap += len;
+
+    while ((ap - p) & 3) {
+	*ap++ = 0;
+    }
+    l = ap - p;
+
+    rp->common.length = htons((l / 4) - 1);
+
+    l = hl + ((ntohs(rp->common.length) + 1) * 4);
+
+    /* If strict, pad the composite packet to an odd multiple of 4
+       bytes so that if we decide to encrypt it we don't have to worry
+       about padding at that point. */
+
+    if (strict) {
+	int pl = (l & 4) ? l : l + 4;
+
+	if (pl > l) {
+	    int pad = pl - l;
+
+	    bzero(zp + l, pad);       /* Clear pad area to zero */
+	    zp[pl - 1] = pad;	      /* Put pad byte count at end of packet */
+            p[0] |= 0x20;             /* Set the "P" bit in the header of the
+					 SDES (last in message) packet */
+                                      /* If we've added an additional word to
+					 the packet, adjust the length in the
+					 SDES message, which must include the
+					 pad */
+	    rp->common.length = htons(ntohs(rp->common.length) + ((pad) / 4));
+	    l = pl;		      /* Include pad in length of packet */
+	}
+    }
+
+    return l;
+}
+
+#if 0
+/*  RTPOUT  --	Convert a sound buffer into an RTP packet, given the
+		SSRC, timestamp, and sequence number appropriate for the
+		next packet sent to this connection.  */
+
+int rtpout(sb, ssrc_i, timestamp_i, seq_i, spurt)
+  soundbuf *sb;
+  unsigned long ssrc_i, timestamp_i;
+  unsigned short seq_i;
+  int spurt;
+{
+    soundbuf rp;
+    rtp_hdr_t *rh = (rtp_hdr_t *) &rp;
+    int pl = 0;
+
+#ifdef RationalWorld
+    rh->version = RTP_VERSION;
+    rh->p = 0;
+    rh->x = 0;
+    rh->cc = 0;
+    rh->m = !!spurt;
+#else
+    *((short *) rh) = htons((RTP_VERSION << 14) | (spurt ? 0x80 : 0));
+#endif
+    rh->seq = htons(seq_i);
+    rh->ts = htonl(timestamp_i);
+    rh->ssrc = htonl(ssrc_i);
+
+    /* GSM */
+
+    if (sb->compression & fCompGSM) {
+#ifdef RationalWorld
+	rh->pt = 3;
+#else
+	((char *) rh)[1] = 3;
+#endif
+	bcopy(sb->buffer.buffer_val + 2, ((char *) &rp) + 12,
+		  (int) sb->buffer.buffer_len - 2);
+	pl = (sb->buffer.buffer_len - 2) + 12;
+
+    /* ADPCM */
+
+    } else if (sb->compression & fCompADPCM) {
+#ifdef RationalWorld
+	rh->pt = 5;
+#else
+	((char *) rh)[1] = 5;
+#endif
+	bcopy(sb->buffer.buffer_val, ((char *) &rp) + 12 + 4,
+		  (int) sb->buffer.buffer_len - 3);
+	bcopy(sb->buffer.buffer_val + ((int) sb->buffer.buffer_len - 3),
+		  ((char *) &rp) + 12, 3);
+	((char *) &rp)[15] = 0;
+	pl = (sb->buffer.buffer_len + 1) + 12;
+
+    /* LPC */
+
+    } else if (sb->compression & fCompLPC) {
+	int i, n = (sb->buffer.buffer_len - 2) / 14;
+	char *ip = (char *) (sb->buffer.buffer_val + 2),
+	     *op = (char *) &rp + 12;
+#ifdef RationalWorld
+	rh->pt = 7;
+#else
+	((char *) rh)[1] = 7;
+#endif
+	for (i = 0; i < n; i++) {
+	    bcopy(ip, op, 3);
+	    bcopy(ip + 4, op + 3, 10);
+	    op[13] = 0;
+	    ip += 14;
+	    op += 14;
+	}
+	pl = 12 + 14 * n;
+
+    } else if (sb->compression & fEnculaw) {
+#ifdef RationalWorld
+    	rh->pt = 0;
+#else
+	((char *) rh)[1] = 0;
+#endif
+    	bcopy(sb->buffer.buffer_val, ((char *) &rp) + 12,
+    		(int) sb->buffer.buffer_len);
+    	pl = (int) sb->buffer.buffer_len + 12;
+    } else {	/* default Uncompressed PCMA samples fEncAlaw */
+#ifdef RationalWorld
+	rh->pt = 8;
+#else
+	((char *) rh)[1] = 8;
+#endif
+	bcopy(sb->buffer.buffer_val, ((char *) &rp) + 12,
+		(int) sb->buffer.buffer_len);
+	pl = (int) sb->buffer.buffer_len + 12;
+    }
+    if (pl > 0) {
+	bcopy((char *) &rp, (char *) sb, pl);
+    }
+    return pl;
+}
+
+#endif
+
+/*  PARSESDES  --  Look for an SDES message in a possibly composite
+		   RTCP packet and extract pointers to selected items
+                   into the caller's structure.  */
+
+int parseSDES(packet, r)
+  unsigned char *packet;
+  struct rtcp_sdes_request *r;
+{
+    int i, success = FALSE;
+    unsigned char *p = packet;
+
+    /* Initialise all the results in the request packet to NULL. */
+
+    for (i = 0; i < r->nitems; i++) {
+	r->item[i].r_text = NULL;
+    }
+
+    /* Walk through the individual items in a possibly composite
+       packet until we locate an SDES. This allows us to accept
+       packets that comply with the RTP standard that all RTCP packets
+       begin with an SR or RR. */
+
+    while ((p[0] >> 6 & 3) == RTP_VERSION || (p[0] >> 6 & 3) == 1) {
+	if ((p[1] == RTCP_SDES) && ((p[0] & 0x1F) > 0)) {
+	    unsigned char *cp = p + 8,
+			  *lp = cp + (ntohs(*((short *) (p + 2))) + 1) * 4;
+
+	    bcopy(p + 4, r->ssrc, 4);
+	    while (cp < lp) {
+		unsigned char itype = *cp;
+
+		if (itype == RTCP_SDES_END) {
+		    break;
+		}
+
+		/* Search for a match in the request and fill the
+		   first unused matching item.	We do it this way to
+		   permit retrieval of multiple PRIV items in the same
+		   packet. */
+
+		for (i = 0; i < r->nitems; i++) {
+		    if (r->item[i].r_item == itype &&
+			r->item[i].r_text == NULL) {
+			r->item[i].r_text = (char *) cp;
+			success = TRUE;
+			break;
+		    }
+		}
+		cp += cp[1] + 2;
+	    }
+	    break;
+	}
+	/* If not of interest to us, skip to next subpacket. */
+	p += (ntohs(*((short *) (p + 2))) + 1) * 4;
+    }
+    return success;
+}
+
+/*  COPYSDESITEM  --  Copy an SDES item to a zero-terminated user
+		      string.  */
+
+void copySDESitem(s, d)
+  char *s, *d;
+{
+    int len = s[1] & 0xFF;
+
+    bcopy(s + 2, d, len);
+    d[len] = 0;
+}
+

Added: misdn-user/trunk/voip/rtpacket.h
===================================================================
--- misdn-user/trunk/voip/rtpacket.h	                        (rev 0)
+++ misdn-user/trunk/voip/rtpacket.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,32 @@
+#ifndef H_RTPACKET_H
+#define H_RTPACKET_H
+
+#include "rtp.h"
+
+#define ELEMENTS(array)	(sizeof(array)/sizeof((array)[0]))
+#define	fEnculaw	0x100000
+#define	fEncAlaw	0x200000
+
+struct rtcp_sdes_request_item {
+    unsigned char r_item;
+    char *r_text;
+};
+
+struct rtcp_sdes_request {
+    int nitems; 		      /* Number of items requested */
+    unsigned char ssrc[4];	      /* Source identifier */
+    struct rtcp_sdes_request_item item[10]; /* Request items */
+};
+
+extern	int	isrtp(unsigned char *, int);
+extern	int	isValidRTCPpacket(unsigned char *, int);
+extern	int	isRTCPByepacket(unsigned char *, int);
+extern	int	isRTCPAPPpacket(unsigned char *, int, char *, unsigned char **);
+extern	int	rtp_make_sdes(char **, unsigned long, int, int);
+extern	int	rtp_make_sdes_s(char **, int, struct rtcp_sdes_request *);
+extern	int	rtp_make_bye(unsigned char *, unsigned long, char *, int);
+extern	int	rtp_make_app(unsigned char *, unsigned long, int, char *,
+			unsigned char *, int);
+extern	int	parseSDES(unsigned char *, struct rtcp_sdes_request *);
+extern	void	copySDESitem(char *, char *);
+#endif

Added: misdn-user/trunk/voip/testlog
===================================================================
--- misdn-user/trunk/voip/testlog	                        (rev 0)
+++ misdn-user/trunk/voip/testlog	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,3 @@
+debug_init: debug_mask = 0
+debug_init: debug_mask = 0
+debug_close: debug channel now closed

Added: misdn-user/trunk/voip/tstcfg
===================================================================
--- misdn-user/trunk/voip/tstcfg	                        (rev 0)
+++ misdn-user/trunk/voip/tstcfg	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,13 @@
+#
+# tstsetup voip
+#
+DEBUG	066
+PORT	2074
+GSM
+
+MSN	12345
+MSN	888
+VOIPNR	4566		pictra_client GSM
+VOIPNR  4567		10.23.200.1
+AUDIONR 789
+

Added: misdn-user/trunk/voip/tstparse.c
===================================================================
--- misdn-user/trunk/voip/tstparse.c	                        (rev 0)
+++ misdn-user/trunk/voip/tstparse.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "isdn_net.h"
+#include "globals.h"
+
+extern	int		parse_cfg(char *, manager_t *);
+
+int main(argc,argv)
+int argc;
+char *argv[];
+{
+	manager_t	mgr;
+	nr_list_t	*nr;
+
+	memset(&mgr, 0, sizeof(manager_t));
+	printf("Start: Debug %x Port %d Flags %x\n",
+		global_debug, rtp_port, default_flags);
+	parse_cfg("tstcfg", &mgr);
+	printf("AfterParse: Debug %x Port %d Flags %x\n",
+		global_debug, rtp_port, default_flags);
+	nr = mgr.nrlist;
+	while(nr) {
+		printf("nr(%s) len(%d) flg(%x) typ(%d) name(%s)\n",
+			nr->nr, nr->len, nr->flags, nr->typ, nr->name);
+		nr = nr->next;
+	}
+	return(0);
+}
\ No newline at end of file

Added: misdn-user/trunk/voip/vitimer.h
===================================================================
--- misdn-user/trunk/voip/vitimer.h	                        (rev 0)
+++ misdn-user/trunk/voip/vitimer.h	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,32 @@
+#ifndef VITIMER_H
+#define VITIMER_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+
+typedef	struct _vi_timer		vi_timer_t;
+typedef int (*timef_t)(void *, unsigned long, struct timeval *);
+
+struct _vi_timer {
+	vi_timer_t	*prev;
+	vi_timer_t	*next;
+	struct timeval	tv;
+	void		*data;
+	unsigned long	val;
+	timef_t		func;	
+};
+
+extern	int		run_vitimer(void);
+extern	void		remove_vitimer(vi_timer_t *);
+extern	int		init_vitimer(vi_timer_t *, void *, unsigned long, timef_t);
+extern	int		add_vitimer_abs(vi_timer_t *, struct timeval *);
+extern	int		add_vitimer_rel(vi_timer_t *, struct timeval *);
+extern	void		clean_vitimer(void);
+extern	struct timeval	*get_next_vitimer_time(void);
+extern	int		get_next_vitimer_dist(struct timeval *);
+
+
+#endif

Added: misdn-user/trunk/voip/voip_appl.c
===================================================================
--- misdn-user/trunk/voip/voip_appl.c	                        (rev 0)
+++ misdn-user/trunk/voip/voip_appl.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,1541 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include "helper.h"
+#include "g711.h"
+#include "isdn_net.h"
+#include "isound.h"
+#include "rtpacket.h"
+#include "iapplication.h"
+
+
+#define RANDOM_DEVICE	"/dev/urandom"
+
+#define RTP_PAD_FLAG	0x20
+
+static int
+init_voipsocks(vapplication_t *v)
+{
+	v->dsock = socket(AF_INET, SOCK_DGRAM, 0);
+	if (v->dsock < 0) {
+            perror("opening data socket");
+	    return 1;
+	}
+	v->csock = socket(AF_INET, SOCK_DGRAM, 0);
+	if (v->csock < 0) {
+            perror("opening control socket");
+	    return 1;
+	}
+
+	if (v->csock < v->dsock) {
+		int tmpsock = v->dsock;
+		v->dsock = v->csock;
+		v->csock = tmpsock;
+	}
+	
+	/* Create caddr/daddr with wildcards. */
+
+	v->daddr.sin_family = v->caddr.sin_family = AF_INET;
+	v->daddr.sin_addr.s_addr = v->caddr.sin_addr.s_addr = INADDR_ANY;
+	v->daddr.sin_port = htons(v->port);
+	if (bind(v->dsock, (struct sockaddr *) &v->daddr,
+		sizeof(struct sockaddr_in)) < 0) {
+		perror("binding data socket");
+		return 1;
+	}
+	v->caddr.sin_port = htons(v->port + 1);
+	if (bind(v->csock, (struct sockaddr *) &v->caddr,
+		sizeof(struct sockaddr_in)) < 0) {
+		perror("binding control socket");
+		return 1;
+	}
+	dprint(DBGM_SOCK, -1, "socket ports #%d/#%d\n",
+		ntohs(v->daddr.sin_port), ntohs(v->caddr.sin_port));
+	return(0);
+}
+
+int
+SendBye(iapplication_t *ia, char *bye)
+{
+	vconnection_t	*c;
+	int		len;
+
+	c = ia->con;
+	if (!c)
+		return(-EINVAL);
+	if (ia->Flags & (AP_FLG_VOIP_SENT_BYE | AP_FLG_VOIP_PEER_BYE))
+		return(0);
+	len = rtp_make_bye(c->cbuf, c->own_ssrc, bye, 1);
+	dprint(DBGM_SOCK, -1, "C socket send %d bytes to %s\n",
+		len, inet_ntoa(c->cpeer.sin_addr));
+	ia->Flags |= AP_FLG_VOIP_SENT_BYE;
+	if (len) {
+		dhexprint(DBGM_CDATA, "send ctrl packet:", c->cbuf, len);
+		len = sendto(c->sock, c->cbuf, len, 0,
+			(struct sockaddr *)&c->cpeer, sizeof(c->cpeer));
+		if (len < 0) {
+			eprint("cannot send ctrl msg errno(%d)\n", errno);
+			return(-errno);
+		}
+	} else {
+		eprint("cannot compose Bye message\n");
+		return(-EINVAL);
+	}
+	return(0);
+}
+
+void
+clear_connection(iapplication_t *ia)
+{
+	vconnection_t	*c = ia->con;
+
+	if (c) {
+		dprint(DBGM_SOCK, -1, "clear connection to %s ssrc(%lx/%lx)\n",
+			c->rmtname, c->own_ssrc, c->peer_ssrc);
+		if (ia->Flags & AP_FLG_VOIP_PEER_VALID) {
+			msg_queue_purge(&c->aqueue);
+			if (c->amsg)
+				free_msg(c->amsg);
+			SendBye(ia, "closing");
+		}
+		if (c->sock)
+			close(c->sock);
+#ifdef GSM_COMPRESSION
+		if (c->r_gsm)
+			gsm_destroy(c->r_gsm);
+		if (c->s_gsm)
+			gsm_destroy(c->s_gsm);
+#endif
+		free(c);
+		ia->con = NULL;
+	}
+}
+
+void
+free_application(iapplication_t *ia)
+{
+	vconnection_t	*c = ia->con;
+
+	if (!ia)
+		return;
+	if (c)
+		clear_connection(ia);
+	REMOVE_FROM_LISTBASE(ia, ia->vapp->iapp_lst);
+	free(ia);
+}
+
+static void
+close_voipsocks(vapplication_t *v)
+{
+	dprint(DBGM_SOCK, -1, "socket closed\n");
+	while(v->iapp_lst) {
+		free_application(v->iapp_lst);
+	}
+	close(v->csock);
+	close(v->dsock);
+	v->csock = 0;
+	v->dsock = 0;
+}
+
+static iapplication_t *
+get_connection(vapplication_t *v,  unsigned long ssrc, int exact)
+{
+	iapplication_t	*ip;
+
+	ip = v->iapp_lst;
+	while (ip) {
+		if (ip->con) {
+			dprint(DBGM_SOCK, -1, "ip(%p) %x %s/%s %x/%x\n",
+				ip, ip->Flags,
+				inet_ntoa(v->from.sin_addr),
+				inet_ntoa(ip->con->cpeer.sin_addr),
+				ssrc, ip->con->peer_ssrc);
+			if (memcmp(&v->from.sin_addr, &(ip->con->cpeer.sin_addr),
+				sizeof(struct in_addr)) == 0) {
+				if (ip->Flags & AP_FLG_VOIP_PEER_VALID) {
+					if (ip->Flags & AP_FLG_VOIP_PEER_SF) {
+						return(ip);
+					} else if (ip->con->peer_ssrc == ssrc) {
+						return(ip);
+					}
+				} else if (!exact) {
+					if (!get_connection(v, ssrc, 1)) {
+						ip->con->peer_ssrc = ssrc;
+						ip->Flags |= AP_FLG_VOIP_PEER_VALID;
+						return(ip);
+					}
+				}
+			}
+		}
+		ip = ip->next;
+	}
+	return(NULL);
+}
+
+unsigned long
+my_random_ul(void) {
+	int		rd;
+	unsigned long	r;
+
+	rd = open(RANDOM_DEVICE, O_RDONLY);
+	if (rd<0)
+		return(random());
+	read(rd, &r, sizeof(r));
+	close(rd);
+	return(r);
+}
+ 
+unsigned long
+getnew_ssrc(vapplication_t *v) 
+/* this excludes 0 as value, but I think its OK */
+{
+	unsigned long	ssrc = 0;
+	iapplication_t	*ip;
+	
+	while(!ssrc) {
+		ssrc = my_random_ul();		
+		ip = v->iapp_lst;
+		while (ip) {
+			if (ip->con) {
+				if (ip->con->peer_ssrc == ssrc) {
+					ssrc = 0;
+					break;
+				}
+				if (ip->con->own_ssrc == ssrc) {
+					ssrc = 0;
+					break;
+				}
+			}
+			ip = ip->next;
+		}
+	}
+	return(ssrc);
+}
+
+vconnection_t *
+new_connection(iapplication_t *ia, struct in_addr *addr)
+{
+	vconnection_t	*c;
+	
+	c = malloc(sizeof(vconnection_t));
+	if (!c)
+		return(NULL);
+	memset(c, 0, sizeof(vconnection_t));
+	msg_queue_init(&c->aqueue);
+	c->sock = socket(AF_INET, SOCK_DGRAM, 0);
+	c->cpeer.sin_family = c->dpeer.sin_family = AF_INET;
+	memcpy(&c->cpeer.sin_addr, addr, sizeof(struct in_addr));
+	memcpy(&c->dpeer.sin_addr, addr, sizeof(struct in_addr));
+	c->dpeer.sin_port = htons(ia->vapp->port);
+	c->cpeer.sin_port = htons(ia->vapp->port + 1);
+#if 0
+	/* Compute the number of sound samples needed to fill a
+	   packet of TINY_PACKETS bytes. */
+
+	if (rtp) {
+		sound_packet = (gsmcompress | lpccompress | adpcmcompress) ? (160 * 4)
+					   : 320;
+	} else if (vat) {
+		sound_packet = (gsmcompress | lpccompress | adpcmcompress) ? (160 * 4)
+					   : 320;
+	} else {
+		sound_packet = ((TINY_PACKETS - ((sizeof(soundbuf) - BUFL))) *
+						(compressing ? 2 : 1));
+		if (gsmcompress) {
+			sound_packet = compressing ? 3200 : 1600;
+		} else if (adpcmcompress) {
+			sound_packet *= 2;
+			sound_packet -= 4;				  /* Leave room for state at the end */
+		} else if (lpccompress) {
+			sound_packet = 10 * LPC_FRAME_SIZE;
+		} else if (lpc10compress) {
+			sound_packet = compressing ? 3600 : 1800;
+		}
+	}
+
+#ifdef SHOW_PACKET_SIZE
+	printf("Samples per packet = %d\n", sound_packet);
+#endif
+	lread = sound_packet;
+#endif
+	/* default size */
+	c->pkt_size = 320;
+	return(c);
+}
+
+iapplication_t *
+new_application(vapplication_t *v)
+{
+	iapplication_t  *ip;
+
+	ip = malloc(sizeof(iapplication_t));
+	if (!ip)
+		return(NULL);
+	memset(ip, 0, sizeof(iapplication_t));
+	ip->vapp = v;
+	APPEND_TO_LIST(ip, v->iapp_lst);
+	return(ip);
+}
+
+static iapplication_t *
+new_peer_connection(vapplication_t *v, unsigned long ssrc, int version)
+{
+	iapplication_t	*ip;
+	vconnection_t	*c;
+	struct hostent	*h;
+
+	ip = new_application(v);
+	if (!ip)
+		return(NULL);
+	c = new_connection(ip, &v->from.sin_addr);
+	if (!c) {
+		free_application(ip);
+		return(NULL);
+	}
+	h = gethostbyaddr((char *) &v->from.sin_addr, sizeof(struct in_addr),
+		AF_INET);
+	if (h == NULL) {
+		strcpy(c->rmtname, inet_ntoa(v->from.sin_addr));
+	} else {
+		strcpy(c->rmtname, h->h_name);
+	}
+	strncpy(c->con_hostname, c->rmtname, 31);
+	c->peer_ssrc = ssrc;
+	c->own_ssrc = getnew_ssrc(v);
+	ip->Flags |= AP_FLG_VOIP_PEER_VALID;
+	if (version == 1) /* speakfreely without RTP */
+		ip->Flags |= AP_FLG_VOIP_PEER_SF;
+	ip->con = c;
+	return(ip);
+}
+
+static int
+play_data(iapplication_t *ip)
+{
+	isound_t	*is = ip->data2;
+	int		maxlen;
+	unsigned char	*buf = ip->con->rbuf;
+
+	if (!is || !is->rbuf) {
+		wprint("ip->data2 %p\n", is);
+		return(-1);
+	}
+	maxlen = ibuf_freecount(is->rbuf);
+	dprint(DBGM_SOUND, -1, "%s: %d data max(%d)\n", __FUNCTION__,
+		ip->con->rlen, maxlen);
+	if (maxlen > ip->con->rlen)
+		maxlen = ip->con->rlen;
+	else if (maxlen < ip->con->rlen) {
+		dprint(DBGM_SOUND, -1, "pb shortage, skip %d bytes (%d/%d/%d/%d/%d)\n",
+			ip->con->rlen - maxlen, ip->con->rlen, maxlen,
+			is->rbuf->ridx, is->rbuf->widx, is->rbuf->size);
+		wprint("playbuffer shortage, skip %d bytes\n",
+			ip->con->rlen - maxlen);
+		buf += (ip->con->rlen - maxlen);
+	}
+	if (maxlen)
+		ibuf_memcpy_w(is->rbuf, buf, maxlen);
+	if (is->rbuf->rsem)
+		sem_post(is->rbuf->rsem);
+	return(maxlen);
+}
+
+static int
+receive_data(vapplication_t *v) {
+	iapplication_t	*iap;
+	unsigned long	ssrc, ts;
+	unsigned short	seq;
+	unsigned char	cc, payl;
+	unsigned char	ver;
+	rtp_hdr_t	*rh;
+
+	if (v->rlen < 12)
+		return(-2);
+	rh = (rtp_hdr_t *)&v->buf.d;
+	ver = (v->buf.d[0] >> 6) & 3;
+	if (ver != RTP_VERSION) {
+		dprint(DBGM_SOCK, -1, "rtp version %d\n",
+			ver);
+		return(-3);
+	}
+	ssrc = ntohl(rh->ssrc);
+	iap = get_connection(v, ssrc, 1);
+	if (!iap) { /* data from not known source ignored before a CTRL packet */
+		dprint(DBGM_SOCK, -1, "rtp data ignored from %s ssrc(%lx)\n",
+			inet_ntoa(v->from.sin_addr), ssrc);
+		return(-4);
+	}
+	cc = v->buf.d[0] & 0xf;
+	payl = v->buf.d[1] & 0x7f;
+	seq = ntohs(rh->seq);
+	ts = ntohl(rh->ts);
+	iap->con->rlen = v->rlen - 4*cc - 12;
+	if (v->buf.d[0] & RTP_PAD_FLAG) {
+		iap->con->rlen -= v->buf.d[v->rlen-1]; 
+	}
+	dprint(DBGM_SOCK, -1, "rtp data len(%d) pl(%x) seq(%d) ts(%lx)\n",
+		iap->con->rlen, payl, seq, ts);
+	if (iap->con->rlen <= 0) {
+		dprint(DBGM_SOCK, -1, "rtp data len error %d\n", iap->con->rlen);
+		return(-5);
+	}
+	iap->con->rbuf = v->buf.d + 4*cc + 12;
+	if (payl == 8) { /* alaw */
+		/* default */
+	} else if (payl == 0) { /* ulaw */
+		int	i;
+
+		for (i=0;i<iap->con->rlen;i++)
+			iap->con->rbuf[i] = ulaw2alaw(iap->con->rbuf[i]);
+#ifdef GSM_COMPRESSION
+	} else if (payl == 3) { /* GSM */
+		int	i;
+		gsm_signal	gs[640], *gp;
+		u_char		buf[640], *p;
+
+		if (!(iap->con->sndflags & SNDFLG_COMPR_GSM)) {
+			iap->con->sndflags |= SNDFLG_COMPR_GSM;
+			iap->con->pkt_size = 640;
+		}
+		if (!iap->con->r_gsm)
+			iap->con->r_gsm = gsm_create();
+		if (iap->con->rlen != 4*33) {
+			eprint("%s wrong GSM Data size %d/%d\n", __FUNCTION__,
+				iap->con->rlen, 4*33);
+			return(-6);
+		}
+		gp = gs;
+		p = iap->con->rbuf;
+		for (i=0;i<4; i++) {
+			gsm_decode(iap->con->r_gsm, p, gp);
+			p += 33;
+			gp += 160;
+		}
+		gp = gs;
+		p = iap->con->rbuf = buf;
+		iap->con->rlen = 640;
+		for (i=0;i<640;i++)
+			*p++ = linear2alaw(*gp++);
+#endif
+	} else {
+		dprint(DBGM_SOCK, -1, "rtp data payload %x not supported\n", payl);
+		return(-7);
+	}
+	return(play_data(iap));
+}
+
+static int
+receive_ctrl(vapplication_t *v) {
+	iapplication_t	*iap;
+	unsigned char	*app;
+	unsigned long	ssrc;
+	int		ver;
+
+	if (v->rlen < 8)
+		return(1);
+	ver = (v->buf.d[0] >> 6) & 3;
+	if ((ver != RTP_VERSION) && (ver != 1)) {
+		dprint(DBGM_SOCK, -1, "rtp version %d\n",
+			ver);
+		return(2);
+	}
+	ssrc = ntohl(*((unsigned long *)&v->buf.d[4]));
+	iap = get_connection(v, ssrc, 0);
+	if (!iap) { /* New connection */
+		if (isRTCPByepacket(v->buf.d, v->rlen)) {
+			dprint(DBGM_CONN, -1, "bye in new connection from %s ignored\n",
+				inet_ntoa(v->from.sin_addr));
+			return(3);
+		}
+		dprint(DBGM_CONN, -1, "new connection from %s ssrc(%x)\n",
+			inet_ntoa(v->from.sin_addr), ssrc);
+		iap = new_peer_connection(v, ssrc, ver);
+		if (!iap) {
+			return(4);
+		}
+		voip_application_handler(iap, AP_PR_VOIP_NEW, NULL);
+	} else {
+		if (isRTCPByepacket(v->buf.d, v->rlen)) {
+			iap->Flags |= AP_FLG_VOIP_PEER_BYE;
+			dprint(DBGM_CONN, -1, "connection from %s bye\n",
+				inet_ntoa(v->from.sin_addr));
+		}
+	}
+	if (isRTCPAPPpacket(v->buf.d, v->rlen, "ISDN", &app)) {
+		return(voip_application_handler(iap, AP_PR_VOIP_ISDN, app));
+	}
+	if (iap->Flags & AP_FLG_VOIP_PEER_BYE) {
+		clear_connection(iap); 
+		voip_application_handler(iap, AP_PR_VOIP_BYE, NULL);
+	}
+	return(0);
+#if 0
+	/* See if this connection is active.  If not, initialise a new
+	   connection. */
+
+	busyreject = FALSE;
+	newconn = FALSE;
+	c = conn;
+	while (c != NULL) {
+		if (memcmp(&from.sin_addr, &(c->con_addr),
+			   sizeof(struct in_addr)) == 0) {
+		break;
+		}
+		c = c->con_next;
+	}
+	/* Initialise fields in connection.  Only fields which need to
+	   be reinitialised when a previously idle host resumes activity
+	   need be set here. */
+
+	if (newconn) {
+		c->face_file = NULL;
+		c->face_filename[0] = 0;
+		c->face_viewer = 0;
+		c->face_stat = FSinit;
+		c->face_address = 0L;
+		c->face_retry = 0;
+		c->con_compmodes = -1;
+		c->con_protocol = PROTOCOL_UNKNOWN;
+		c->con_rseq = -1;
+		c->con_reply_current = FALSE;
+		c->con_busy = 0;
+			bcopy("\221\007\311\201", c->con_session, 4);
+		lpc_init(&c->lpcc);
+		busyreject = isBusy();
+	}
+
+	if (c != NULL) {
+		/* Reset connection timeout. */
+		c->con_timeout = 0;
+
+		if (newconn) {
+		if (showhosts) {
+			fprintf(stdout, "%s: %s %s %s\n", prog, etime(), c->con_hostname,
+				busyreject ? "sending busy signal" : "connect");
+		}
+		}
+		if (busyreject) {
+		continue;
+		}
+
+		/* Request face data from the other end, starting with
+		   block zero.  If the connection was created itself
+			   by a face data request, don't request the face from
+		   the other end; wait, instead, for some sound to
+		   arrive.	We use face_stat to decide when to make the
+		   request rather than newconn, since a connection may
+		   have been created by a face request from the other
+			   end, which didn't trigger a reciprocal request by
+		   us. */
+
+		if (!control && (c->con_protocol == PROTOCOL_SPEAKFREE) &&
+			(c->face_stat == FSinit) &&
+			isSoundPacket(ntohl(sb.compression)) &&
+			(ntohl(sb.compression) & fFaceOffer)) {
+		c->face_address = 0;
+		c->face_timeout = 0;
+		c->face_retry = 0;
+		c->face_stat = FSreply;   /* Activate request from timeout */
+		faceTransferActive++;	  /* Mark face transfer underway */
+		if (faceTransferActive == 1) {
+			windtimer();	  /* Set timer to fast cadence */
+		}
+		}
+
+	} else {
+		continue;
+	}
+
+	wasrtp = FALSE;
+
+#ifdef CRYPTO
+
+		/* If a DES key is present and we're talking RTP or VAT
+	   protocol we must decrypt the packet at this point.
+	   We decrypt the packet if:
+
+		1.  A DES key was given on the command line, and
+			either:
+
+			a)	The packet arrived on the control port
+			(and hence must be from an RTP/VAT client), or
+
+			b)	The protocol has already been detected as
+			RTP or VAT by reception of a valid control
+			port message.  */
+
+	if ((control || (c->con_protocol == PROTOCOL_RTP) ||
+			(c->con_protocol == PROTOCOL_VAT)) &&
+		 rtpdeskey[0]) {
+
+		/* One more little twist.  If this packet arrived on the
+		   control channel, see if it passes all the tests for a
+			   valid RTCP packet.  If so, we'll assume it isn't
+		   encrypted.  RTP utilities have the option of either
+		   encrypting their control packets or sending them in
+		   the clear, so a hack like this is the only way we have
+		   to guess whether something we receive is encrypted. */
+
+		if (!isValidRTCPpacket((unsigned char *) &sb, rll)) {
+		des_key_schedule sched;
+		des_cblock ivec;
+		int drll = rll;
+		char *whichkey;
+		static int toggle = 0;
+
+		bzero(ivec, 8);
+		drll = (rll + 7) & (~7);
+		if (Debug) {
+					fprintf(stdout, "Decrypting %d VAT/RTP bytes with DES key.\r\n",
+				drll);
+		}
+		if (drll > rll) {
+			/* Should only happen for VAT protocol.  Zero the rest of
+			   the DES encryption block to guarantee consistency. */
+			bzero(((char *) &sb) + rll, drll - rll);
+		}
+
+		/* If the protocol is unknown, toggle back and forth
+		   between the RTP and VAT DES keys until we crack the
+		   packet and set the protocol. */
+
+		if (c->con_protocol == PROTOCOL_UNKNOWN || 
+			c->con_protocol == PROTOCOL_VATRTP_CRYPT ||
+			c->con_protocol == PROTOCOL_SPEAKFREE) {
+			whichkey = toggle == 0 ? vatdeskey :
+				   (toggle == 1 ? rtpdeskey : NULL);
+			toggle = (toggle + 1) % 3;
+		} else {
+			whichkey = c->con_protocol == PROTOCOL_VAT ?
+				vatdeskey : rtpdeskey;
+		}
+		if (whichkey != NULL) {
+			des_set_key((des_cblock *) (whichkey + 1), sched);
+			des_ncbc_encrypt((des_cblock *) &sb,
+			(des_cblock *) &sb, rll, sched,
+			(des_cblock *) ivec, DES_DECRYPT);
+
+			/* Just one more thing.  In RTP (unlike VAT), when
+			   an RTCP control packet is encrypted, 4 bytes of
+			   random data are prefixed to the packet to prevent
+			   known-plaintext attacks.  We have to strip this
+			   prefix after decrypting. */
+
+			if (control && ((*(((char *) &sb) + 4) & 0xC0) == 0x80)) {
+			rll -= 4;
+			bcopy(((char *) &sb) + 4, (char *) &sb, rll);
+			}
+		}
+#ifdef HEXDUMP
+		if (hexdump) {
+			xd(stdout, (unsigned char *)&sb, rll, TRUE);
+		}
+#endif
+		}
+	}
+#endif
+
+	/* If this packet arrived on the session control port, dispatch
+	   it to the appropriate handler for its protocol. */
+
+	if (control) {
+		short protocol = PROTOCOL_VATRTP_CRYPT;
+		unsigned char *p = (unsigned char *) &sb;
+		unsigned char *apkt;
+		int proto = (p[0] >> 6) & 3;
+
+		if (proto == 0) {		  /* VAT */
+		/* To avoid spoofing by bad encryption keys, require
+				   a proper ID message be seen before we'll flip into
+		   VAT protocol. */
+		if (((p[1] == 1) || (p[1] == 3)) ||
+			((c->con_protocol == PROTOCOL_VAT) && (p[1] == 2))) {
+			protocol = PROTOCOL_VAT;
+			bcopy(p + 2, c->con_session, 2);  /* Save conference ID */
+
+			if (p[1] == 1 && showhosts) {
+			char uname[256];
+
+			bcopy(p + 4, uname, rll - 4);
+			uname[rll - 4] = 0;
+			if (strcmp(uname, c->con_uname) != 0) {
+				strcpy(c->con_uname, uname);
+				fprintf(stdout, "%s: %s sending from %s.\n", prog,
+					c->con_uname, c->con_hostname);
+			}
+			}
+
+			/* Handling of VAT IDLIST could be a lot more elegant
+			   than this. */
+
+			if (p[1] == 3 && showhosts) {
+			char *uname;
+
+			uname = (char *) malloc(rll);
+			if (uname != NULL) {
+				unsigned char *bp = p, *ep = p + rll;
+				int i = bp[4];
+
+				bp += 8;
+				uname[0] = 0;
+				*ep = 0;
+				while (--i >= 0 && bp < ep) {
+				bp += 4;
+								strcat(uname, "\t");
+				strcat(uname, (char *) bp);
+				while (isspace(uname[strlen(uname) - 1])) {
+					uname[strlen(uname) - 1] = 0;
+				}
+								strcat(uname, "\n");
+				bp += (strlen((char *) bp) + 3) & ~3;
+				}
+				if (strncmp(uname, c->con_uname, (sizeof c->con_uname - 1)) != 0) {
+				strncpy(c->con_uname, uname, sizeof c->con_uname);
+				if (strlen(uname) > ((sizeof c->con_uname) - 1)) {
+					c->con_uname[((sizeof c->con_uname) - 1)] = 0;
+				}
+				fprintf(stdout, "%s: now in conference at %s:\n%s", prog,
+					c->con_hostname, uname);
+				}
+				free(uname);
+			}
+			}
+
+			/* If it's a DONE packet, reset protocol to unknown. */
+
+			if (p[1] == 2) {
+				c->con_protocol = protocol = PROTOCOL_UNKNOWN;
+				c->con_timeout = hosttimeout - 1;
+				c->con_uname[0] = c->con_email[0] = 0;
+				if (showhosts) {
+					fprintf(stdout, "%s: %s VAT connection closed.\n",
+						prog, c->con_hostname);
+				}
+			}
+		}
+
+		} else if (proto == RTP_VERSION || proto == 1) { /* RTP */
+		if (isValidRTCPpacket((unsigned char *) &sb, rll)) {
+			protocol = (proto == 1) ? PROTOCOL_SPEAKFREE : PROTOCOL_RTP;
+			bcopy(p + 4, c->con_session, 4);  /* Save SSRC */
+
+					/* If it's a BYE packet, reset protocol to unknown. */
+
+			if (isRTCPAPPpacket((unsigned char *) &sb, rll,
+					RTCP_APP_TEXT_CHAT, &apkt) && apkt != NULL) {
+			char *ident = c->con_hostname;
+
+			/* To identify the sender, get successively more
+			   personal depending on the information we have at
+			   hand, working down from hostname (which may just
+						   be an IP address if we couldn't resolve the host,
+			   through E-mail address, to user name. */
+
+			if (c->con_email[0] != 0) {
+				ident = c->con_email;
+			}
+			if (c->con_uname[0] != 0) {
+				ident = ident = c->con_uname;
+			}
+
+						printf("%s: %s\n", ident, (char *) (apkt + 12));
+
+					/* Otherwise, it's presumably an SDES, from which we
+			   should update the user identity information for the
+			   connection. */
+
+			} else {
+			struct rtcp_sdes_request rp;
+
+			rp.nitems = 5;
+			rp.item[0].r_item = RTCP_SDES_CNAME;
+			rp.item[1].r_item = RTCP_SDES_NAME;
+			rp.item[2].r_item = RTCP_SDES_EMAIL;
+			rp.item[3].r_item = RTCP_SDES_TOOL;
+			rp.item[4].r_item = RTCP_SDES_NOTE;
+			if (parseSDES((unsigned char *) &sb, &rp)) {
+				char uname[256], email[256];
+
+				uname[0] = email[0] = 0;
+				if (rp.item[1].r_text != NULL) {
+				copySDESitem(rp.item[1].r_text, uname);
+				if (rp.item[2].r_text != NULL) {
+					copySDESitem(rp.item[2].r_text, email);
+				} else if (rp.item[2].r_text != NULL) {
+					copySDESitem(rp.item[0].r_text, email);
+				}
+				} else if (rp.item[2].r_text != NULL) {
+				copySDESitem(rp.item[2].r_text, uname);
+				} else if (rp.item[0].r_text != NULL) {
+				copySDESitem(rp.item[0].r_text, uname);
+				}
+				if (rp.item[4].r_text != NULL) {
+				copySDESitem(rp.item[4].r_text, hm_note);
+				h_appl_mgr(1, hm_note, c->con_hostname);
+				}
+				if (strcmp(uname, c->con_uname) != 0 ||
+				strcmp(email, c->con_email) != 0) {
+				strcpy(c->con_uname, uname);
+				strcpy(c->con_email, email);
+				if (showhosts && uname[0]) {
+									fprintf(stdout, "%s: %s", prog, uname);
+					if (email[0]) {
+									  fprintf(stdout, " (%s)", email);
+					}
+									fprintf(stdout, " sending from %s.\n",
+						c->con_hostname);
+				}
+				}
+			}
+			}
+		} else {
+			if (Debug) {
+						fprintf(stdout, "Invalid RTCP packet received.\n");
+			}
+		}
+		} else {
+		if (Debug) {
+					fprintf(stdout, "Bogus protocol 3 control message.\n");
+		}
+		}
+
+		/* If protocol changed, update in connection and, if appropriate,
+		   update the reply command. */
+
+		if (protocol != c->con_protocol) {
+		static char *pname[] = {
+					"Speak Freely",
+					"VAT",
+					"RTP",
+					"VAT/RTP encrypted",
+					"Unknown"
+		};
+
+		c->con_protocol = protocol;
+		if (showhosts) {
+					fprintf(stdout, "%s: %s sending in %s protocol.\n",
+				prog, c->con_hostname, pname[protocol]);
+		}
+		c->con_reply_current = FALSE;
+		}
+		continue;
+	}
+
+	/* If this message is tagged with our Speak Freely protocol
+	   bit, force protocol back to Speak Freely.  This allows us
+	   to switch back to Speak Freely after receiving packets in
+	   VAT.  We can still get confused if we receive a packet from
+		   an older version of Speak Freely that doesn't tag. */
+
+	if (c->con_protocol == PROTOCOL_VAT ||
+		c->con_protocol == PROTOCOL_VATRTP_CRYPT) {
+		unsigned char *p = (unsigned char *) &sb;
+
+		if (((p[0] >> 6) & 3) == 1) {
+		c->con_protocol = PROTOCOL_SPEAKFREE;
+		}
+	}
+
+	/* If this is a VAT packet, translate it into a sound buffer. */
+
+	if (((c->con_protocol == PROTOCOL_VAT)) &&
+		(bcmp(((unsigned char *) &sb) + 2, c->con_session, 2) == 0) &&
+		isvat((unsigned char *) &sb, rll)) {
+		if (sb.buffer.buffer_len == 0) {
+		if (Debug) {
+					fprintf(stdout, "Ignoring unparseable VAT packet.\n");
+		}
+		continue;
+		}
+		wasrtp = TRUE;
+
+	/* If this is an RTP packet, transmogrify it into a sound
+	   buffer we can understand. */
+
+	} else if ((c->con_protocol == PROTOCOL_RTP) &&
+		 (bcmp(((unsigned char *) &sb) + 8, c->con_session, 4) == 0) &&
+		 isrtp((unsigned char *) &sb, rll)) {
+		if (sb.buffer.buffer_len == 0) {
+		if (Debug) {
+					fprintf(stdout, "Ignoring unparseable RTP packet.\n");
+		}
+		continue;
+		}
+		wasrtp = TRUE;
+	}
+
+	if (!wasrtp) {
+		int xbl;
+
+		/* Convert relevant fields from network to host
+		   byte order, if necessary. */
+
+		sb.compression = ntohl(sb.compression);
+		sb.buffer.buffer_len = ntohl(sb.buffer.buffer_len);
+
+		if (sb.compression & fCompRobust) {
+		int aseq = (sb.buffer.buffer_len >> 24) & 0xFF;
+
+		if (aseq == c->con_rseq) {
+			continue;
+		}
+		c->con_rseq = aseq;
+		sb.buffer.buffer_len &= 0xFFFFFFL;
+		}
+
+		/* Now if this is a valid Speak Freely packet (as
+		   opposed to a VAT packet masquerading as one, or
+		   an encrypted VAT or RTP packet we don't have the
+		   proper key to decode), the length received from the
+		   socket will exactly equal the buffer length plus
+		   the size of the header. This is a reasonably
+		   good validity check, well worth it considering the
+		   horrors treating undecipherable garbage as a sound
+		   buffer could inflict on us. */
+
+		xbl = sb.buffer.buffer_len + (sizeof(struct soundbuf) - BUFL);
+
+		/* If this packet is encrypted with an algorithm which requires
+		   padding the packet to an 8-byte boundary, adjust the actual
+		   content length to account for the padding. */
+
+		if ((sb.compression & (fEncDES | fEncIDEA | fEncBF | fEncPGP)) != 0) {
+			xbl = ((sb.buffer.buffer_len + 7) & (~7)) +
+				(sizeof(struct soundbuf) - BUFL);
+		}
+
+		/* If packet is compressed with LPC-10, compensate for "packet
+		   stuffing". */
+
+		if ((sb.compression & fCompLPC10) && (sb.buffer.buffer_len >= 16)) {
+			xbl -= 16;
+		}
+		if (xbl != rll) {
+			if (Debug) {
+				fprintf(stdout,
+					"Sound buffer length %d doesn't match %d byte packet. Hdr=%08lX\n",
+					xbl, rll, sb.compression);
+			}
+			if (showhosts && c->con_protocol != PROTOCOL_UNKNOWN) {
+				fprintf(stdout, "%s: %s sending in unknown protocol or encryption.\n",
+					prog, c->con_hostname);
+			}
+			c->con_protocol = PROTOCOL_UNKNOWN;
+			continue;
+		}
+
+		/* It does appear to be a genuine Speak Freely sound
+		   buffer. On that basis, set the protocol to Speak Freely
+		   even if the buffer isn't explicitly tagged. */
+
+		if (c->con_protocol != PROTOCOL_SPEAKFREE) {
+			c->con_protocol = PROTOCOL_SPEAKFREE;
+			if (showhosts) {
+				fprintf(stdout, "%s: %s sending in Speak Freely protocol.\n", prog, c->con_hostname);
+			}
+			c->con_reply_current = FALSE;
+		}
+	}
+
+	/* If this is a face request and we have a face file open,
+	   respond to it.  Note that servicing of face file data requests
+	   is stateless. */
+
+	if (sb.compression & fFaceData) {
+		if (sb.compression & faceRequest) {
+		long l;
+
+		/* Request for face data. */
+
+		if (facefile != NULL) {
+			fseek(facefile, sb.buffer.buffer_len, 0);
+			*((long *) sb.buffer.buffer_val) = htonl(sb.buffer.buffer_len);
+			l = fread(sb.buffer.buffer_val + sizeof(long),
+			1, 512 - (sizeof(long) + (sizeof(soundbuf) - BUFL)), facefile);
+			sb.compression = fProtocol | fFaceData | faceReply;
+			if (Debug) {
+						fprintf(stdout, "%s: sending %ld bytes of face data at %d to %s\n",
+				prog, l, ntohl(*((long *) sb.buffer.buffer_val)),
+				c->con_hostname);
+			}
+			l += sizeof(long);
+		} else {
+			/* No face file.  Shut down requestor. */
+			sb.compression = fProtocol | fFaceData | faceLess;
+			l = 0;
+		}
+		bcopy((char *) &(from.sin_addr), (char *) &(name.sin_addr),
+			sizeof(struct in_addr));
+
+		sb.compression = htonl(sb.compression);
+		sb.buffer.buffer_len = htonl(l);
+		if (sendto(sock, (char *) &sb,
+			(int) ((sizeof(struct soundbuf) - BUFL) + l),
+			0, (struct sockaddr *) &(name), sizeof name) < 0) {
+					perror("sending face image data");
+		}
+		} else if (sb.compression & faceReply) {
+
+		/* Face data packet received from remote server. */
+
+		if ((c->face_file == NULL) && (sb.buffer.buffer_len > 0)) {
+					sprintf(c->face_filename, "%sSF-%s.bmp", FACEDIR, c->con_hostname);
+					c->face_file = fopen(c->face_filename, "w");
+		}
+		if (c->face_file != NULL) {
+			if (sb.buffer.buffer_len > sizeof(long)) {
+			long lp =  ntohl(*((long *) sb.buffer.buffer_val));
+
+			if (lp == c->face_address) {
+				fseek(c->face_file, lp, 0);
+				fwrite(sb.buffer.buffer_val + sizeof(long),
+					sb.buffer.buffer_len - sizeof(long), 1,
+					c->face_file);
+				if (Debug) {
+								fprintf(stdout, "%s: writing %ld bytes at %ld in face file %s\n",
+					prog, sb.buffer.buffer_len - sizeof(long),
+					lp, c->face_filename);
+				}
+				c->face_address += sb.buffer.buffer_len - sizeof(long);
+				/* Timeout will make next request after the
+				   configured interval. */
+				c->face_stat = FSreply;
+				c->face_retry = 0;
+			} else {
+				if (Debug) {
+								fprintf(stdout, "%s: discarded %ld bytes for %ld in face file %s, expected data for %ld\n",
+					prog, sb.buffer.buffer_len - sizeof(long),
+					lp, c->face_filename, c->face_address);
+				}
+			}
+			} else {
+			pid_t cpid;
+
+			if (Debug) {
+							fprintf(stdout, "%s: closing face file %s\n",
+				prog, c->face_filename);
+			}
+			fclose(c->face_file);
+			c->face_file = NULL;
+			c->face_stat = FScomplete;
+			faceTransferActive--;
+
+			/* Start viewer to display face.  We terminate
+			   audio output (if active) before doing this since
+						   we don't know the nature of the audio output
+						   resource.  If it's an open file handle which
+			   would be inherited by the child process, that
+			   would hang the audio device as long as the
+			   viewer is active.  */
+
+			if (audiok) {
+				audiok = FALSE;
+				if (Debug) {
+								fprintf(stdout, "%s: releasing audio before viewer fork().\n", prog);
+				}
+			}
+			cpid = fork();
+			if (cpid == 0) {
+				char geom[30], *gp1 = NULL, *gp2 = NULL;
+
+#ifdef NEEDED
+				/* These should be reset by the execlp(). */
+				signal(SIGHUP, SIG_DFL);
+				signal(SIGINT, SIG_DFL);
+				signal(SIGTERM, SIG_DFL);
+				signal(SIGALRM, SIG_DFL);
+				signal(SIGCHLD, SIG_DFL);
+#endif
+
+				/* Now we need to close any shared resources
+				   that might have been inherited from the parent
+				   process to avoid their being locked up for the
+							   duration of the viewer's execution. */
+
+				close(sock);
+				if (record != NULL) {
+				fclose(record);
+				}
+				if (facefile != NULL) {
+				fclose(facefile);
+				}
+#ifdef FACE_SET_GEOMETRY
+				/* Attempt to reasonably place successive face windows
+							   on the screen to avoid the user's having to place
+				   them individually (for window managers with
+				   interactivePlacement enabled). */
+
+#define faceInterval 120	/* Interval, in pixels, between successive faces */
+							sprintf(geom, "-0+%d", facesDisplayed * faceInterval);
+							gp1 = "-geometry";
+				gp2 = geom;
+#endif
+							execlp("xv",  "xv", c->face_filename, gp1, gp2, (char *) 0);
+							perror("launching face image viewer");
+				facesDisplayed--;
+				exit(0);
+				/* Leave face image around, for the moment, so the user can
+				   try to view it manually. */
+			} else if (cpid == (pid_t) -1) {
+							perror("creating face image viewer process");
+			} else {
+				c->face_viewer = cpid;
+				facesDisplayed++;
+			}
+			}
+		}
+		} else if (sb.compression & faceLess) {
+		if (c->face_file != NULL) {
+			fclose(c->face_file);
+			unlink(c->face_filename);
+		}
+		c->face_stat = FSabandoned;
+		faceTransferActive--;
+		if (Debug) {
+					fprintf(stdout, "%s: no face image available for %s\n",
+			prog, c->con_hostname);
+		}
+		}
+		continue;			  /* Done with packet */
+	}
+
+	/* If the packet requests loop-back, immediately dispatch it
+	   back to the host who sent it to us.	To prevent an infinite
+	   loop-back cycle, we clear the loop-back bit in the header
+	   before sending the message.	We leave the host of origin
+	   unchanged, allowing the sender to identify the packet as
+	   one he originated. */
+
+	if (sb.compression & fLoopBack) {
+		bcopy((char *) &(from.sin_addr), (char *) &(name.sin_addr),
+		sizeof(struct in_addr));
+		sb.compression &= ~fLoopBack;	/* Prevent infinite loopback */
+
+		sb.compression = htonl(sb.compression);
+		sb.buffer.buffer_len = htonl(sb.buffer.buffer_len);
+		if (sendto(sock, (char *) &sb, rll,
+		0, (struct sockaddr *) &(name), sizeof name) < 0) {
+				perror("sending datagram message");
+		}
+		sb.compression = ntohl(sb.compression);
+		sb.buffer.buffer_len = ntohl(sb.buffer.buffer_len);
+	}
+
+
+	/* If this packet has been "stuffed" for maximum efficiency,
+	   un-stuff it at this point. */
+
+	if ((sb.compression & fCompLPC10) && (sb.buffer.buffer_len >= 16)) {
+		bcopy(sb.sendinghost, (char *) &sb + rll,
+		  sizeof sb.sendinghost);
+		rll += sizeof sb.sendinghost;
+	}
+
+
+#ifdef CRYPTO
+	if ((sb.compression & fKeyPGP)) {
+		char cmd[256], f[40], kmd[16];
+		FILE *kfile;
+		FILE *pipe;
+		struct MD5Context md5c;
+
+		MD5Init(&md5c);
+		MD5Update(&md5c, sb.buffer.buffer_val, sb.buffer.buffer_len);
+		MD5Final(kmd, &md5c);
+
+		if (memcmp(c->keymd5, kmd, 16) != 0) {
+		bcopy(kmd, c->keymd5, 16);
+				sprintf(f, "/tmp/.SF_SKEY%d", getpid());
+
+				kfile = fopen(f, "w");
+		if (kfile == NULL) {
+					fprintf(stdout, "Cannot open encrypted session key file %s\n", f);
+		} else {
+			fwrite(sb.buffer.buffer_val, sb.buffer.buffer_len, 1, kfile);
+			fclose(kfile);
+#ifdef ZZZ
+			if (pgppass == NULL) {
+			static char s[256]; 
+
+						fprintf(stdout, "Enter PGP pass phrase: ");
+			if (fgets(s, sizeof s, stdin) != NULL) {
+				s[strlen(s) - 1] = 0;
+				pgppass = s;
+			}
+			}
+#endif
+					sprintf(cmd, "pgp -f +nomanual +verbose=0 +armor=off %s%s%s <%s",
+						pgppass ? "-z\"" : "", pgppass ? pgppass : "",
+						pgppass ? "\" " : "", f);
+#ifdef PGP_DEBUG
+					fprintf(stdout, "Decoding session key with: %s\n", cmd);
+#else
+			if (Debug) {
+					   fprintf(stdout, "%s: decoding PGP session key.\n", prog);
+			}
+#endif
+					pipe = popen(cmd, "r");
+			if (pipe == NULL) {
+						fprintf(stdout, "Unable to open pipe to: %s\n", cmd);
+			} else {
+			int lr;
+
+			/* Okay, explanation time again.  On some systems
+			   (Silicon Graphics, for example), the timer tick
+			   alarm signal can cause the pending read from the
+						   PGP key pipe to return an "Interrupted system
+						   call" status (EINTR) with (as far as I've ever
+						   seen and I sincerely hope it's always) zero bytes
+			   read.  This happens frequently when the timer is
+			   running and the user takes longer to enter the
+			   secret key pass phrase than the timer tick.	So,
+			   if this happens we keep on re-issuing the pipe
+			   read until the phrase allows PGP to finish the
+			   job. */
+
+			while ((lr = fread(c->pgpkey, 1, 17, pipe)) != 17 &&
+				   (errno == EINTR)) ;
+			if (lr == 17) {
+				c->pgpkey[0] = TRUE;
+#ifdef PGP_DEBUG
+				{	
+				int i;
+
+								fprintf(stdout, "Session key for %s:", c->con_hostname);
+				for (i = 0; i < 16; i++) {
+									fprintf(stdout, " %02X", c->pgpkey[i + 1] & 0xFF);
+				}
+								fprintf(stdout, "\n");
+				}
+#else
+				if (Debug) {
+							   fprintf(stdout, "%s: PGP session key decoded.\n", prog);
+				}
+#endif
+			} else {
+				c->pgpkey[0] = FALSE;
+							fprintf(stdout, "%s: Error decoding PGP session key.\n", prog);
+#ifdef PGP_DEBUG
+							fprintf(stdout, "Read status from pipe: %d\n", lr);
+							perror("reading decoded PGP key from pipe");
+#endif
+			}
+			pclose(pipe);
+			}
+			unlink(f);
+		}
+		}
+	} else
+#endif
+	{
+		playbuffer(&sb, c);
+	}
+#endif
+}
+
+int
+SendCtrl(iapplication_t *ia)
+{
+	vconnection_t	*c;
+	unsigned char	*p;
+	int		len;
+
+	c = ia->con;
+	if (!c)
+		return(-EINVAL);
+	if (ia->Flags & (AP_FLG_VOIP_SENT_BYE | AP_FLG_VOIP_PEER_BYE))
+		return(-EBUSY);
+	if (!c->amsg) {
+		c->amsg = msg_dequeue(&c->aqueue);
+		if (c->amsg)
+			c->oc++;
+	}
+	if (!c->amsg) { /* make RR */
+		c->amsg = alloc_msg(4);
+		if (!c->amsg)
+			return(-ENOMEM);
+		p = msg_put(c->amsg, 4);
+		*p++ = c->pc;
+		*p++ = c->oc;
+		*p++ = 0;
+		*p++ = 0x81; /* RR */
+		len = rtp_make_app(c->cbuf, c->own_ssrc, 1, "ISDN",
+			c->amsg->data, c->amsg->len);
+		free_msg(c->amsg);
+		c->amsg = NULL;
+	} else {
+		p = c->amsg->data;
+		*p++ = c->pc;
+		*p = c->oc;
+		len = rtp_make_app(c->cbuf, c->own_ssrc, 1, "ISDN",
+			c->amsg->data, c->amsg->len);
+	}
+	dprint(DBGM_SOCK, -1, "C socket send %d bytes to %s\n",
+		len, inet_ntoa(c->cpeer.sin_addr));
+	if (len) {
+		dhexprint(DBGM_CDATA, "send ctrl packet:", c->cbuf, len);
+		len = sendto(c->sock, c->cbuf, len, 0,
+			(struct sockaddr *)&c->cpeer, sizeof(c->cpeer));
+		if (len < 0) {
+			eprint("cannot send ctrl msg errno(%d)\n", errno);
+			return(-errno);
+		}
+	} else {
+		eprint("cannot compose APP message\n");
+		return(-EINVAL);
+	}
+	return(0);
+}
+
+static void *
+voipscan(void *arg) {
+	int		ret;
+	vapplication_t	*v = arg;
+	fd_set		fdset;
+	struct timeval	timeout;
+
+	init_voipsocks(v);
+	while (!(v->flags & AP_FLG_VOIP_ABORT)) {
+		run_vitimer();
+		FD_ZERO(&fdset);
+		FD_SET(v->dsock, &fdset);
+		FD_SET(v->csock, &fdset);
+		if (get_next_vitimer_dist(&timeout)) {
+			timeout = v->tout;
+		}
+		ret = select(v->csock + 1, &fdset, NULL, NULL, &timeout);
+		if (ret < 0) { /* error */
+			dprint(DBGM_SOCK, -1, "socket select errno %d: %s\n",
+				errno, strerror(errno));
+			continue;
+		}
+		if (ret == 0) { /* timeout */
+			dprint(DBGM_SOCK, -1, "socket select timeout\n");
+			continue;
+		}
+		if (FD_ISSET(v->dsock, &fdset)) { /* data packet */
+			v->fromlen = sizeof(struct sockaddr_in);
+			v->rlen = recvfrom(v->dsock, v->buf.d, MAX_NETBUFFER_SIZE,
+				0, (struct sockaddr *) &v->from, &v->fromlen);
+			if (v->rlen <= 0) {
+				dprint(DBGM_SOCK, -1, "D socket rlen(%d)\n",
+					v->rlen); 
+				continue;
+			}
+			dhexprint(DBGM_DDATA, "data packet:", v->buf.d, v->rlen);
+			ret = receive_data(v);
+			if (ret<0)
+				dprint(DBGM_SOCK, -1, "receive_data ret(%d)\n", ret);
+		}
+		if (FD_ISSET(v->csock, &fdset)) { /* ctrl packet */
+			v->fromlen = sizeof(struct sockaddr_in);
+			v->rlen = recvfrom(v->csock, v->buf.d, MAX_NETBUFFER_SIZE,
+				0, (struct sockaddr *) &v->from, &v->fromlen);
+			if (v->rlen <= 0) {
+				dprint(DBGM_SOCK, -1, "C socket rlen(%d)\n",
+					v->rlen); 
+				continue;
+			}
+			dhexprint(DBGM_CDATA, "ctrl packet:", v->buf.d, v->rlen);
+			ret = receive_ctrl(v);
+			if (ret)
+				dprint(DBGM_SOCK, -1, "receive_ctrl ret(%d)\n", ret);
+		}
+	}
+	close_voipsocks(v);
+	return(NULL);
+}
+
+pthread_t
+run_voip(vapplication_t *v) {
+	int		ret;
+	pthread_t	tid;
+
+	ret = pthread_create(&tid, NULL, voipscan, (void *)v);
+	return(tid);
+}
+
+static int
+rtpout_ap(iapplication_t *iap)
+{
+	int		len, r;
+	rtp_hdr_t	*rh;
+
+	rh = (rtp_hdr_t *)iap->con->dbuf;
+	iap->con->dbuf[0] = RTP_VERSION << 6;
+	rh->seq = htons(iap->con->seq);
+	rh->ts = htonl(iap->con->timestamp);
+	rh->ssrc = htonl(iap->con->own_ssrc);
+
+#ifdef GSM_COMPRESSION
+	if (iap->con->sndflags & SNDFLG_COMPR_GSM) { /* GSM */
+		int	i;
+		gsm_signal	gs[640], *gp;
+		u_char		*p;
+
+		if (!iap->con->s_gsm)
+			iap->con->s_gsm = gsm_create();
+		if (iap->con->slen != 4*160) {
+			eprint("%s wrong GSM Data size %d/%d\n", __FUNCTION__,
+				iap->con->rlen, 4*160);
+			return(0);
+		}
+		gp = gs;
+		p = iap->con->sbuf;
+		for (i=0;i<640;i++)
+			*gp++ = alaw2linear(*p++);
+		p = &iap->con->dbuf[12];
+		gp = gs;
+		for (i=0;i<4; i++) {
+			gsm_encode(iap->con->s_gsm, gp, p);
+			p += 33;
+			gp += 160;
+		}
+		len = 4*33 + 12;
+		iap->con->dbuf[1] = 3;
+	} else
+#endif
+	{
+		iap->con->dbuf[1] = 8;
+		memcpy(&iap->con->dbuf[12], iap->con->sbuf, iap->con->slen);
+		len = 12 + iap->con->slen;
+	}
+	r = len % 4;
+	if (r) {
+		int i;
+		r = 4 - r;
+		for (i=0; i<r; i++)
+			iap->con->dbuf[len++] = 0;
+		iap->con->dbuf[len-1] = r;
+		iap->con->dbuf[0] |= RTP_PAD_FLAG; 
+	}
+	return(len);
+}
+
+static int
+send_sdata(iapplication_t *ap)
+{
+	int	len, ret;	
+
+	len = rtpout_ap(ap);
+	ap->con->seq++;
+	ap->con->timestamp += ap->con->slen;
+	if (len)
+		ret = sendto(ap->con->sock, ap->con->dbuf, len, 0,
+			(struct sockaddr *) &ap->con->dpeer,
+			sizeof(struct sockaddr_in));
+	else
+		ret = 0;
+	return(ret);
+}
+
+void *
+voip_sender(void *arg)
+{
+	iapplication_t	*ap = arg;
+	isound_t 	*is;
+	int		avail, ret = 0;
+
+
+	while (!(ap->Flags & AP_FLG_VOIP_ABORT)) {
+		is = ap->data2;
+		if (!is || !is->sbuf) {
+			dprint(DBGM_SOUND, -1, "application data2 NULL\n");
+			break;
+		}
+		if (!ap->con) {
+			dprint(DBGM_SOUND, -1, "application ap->con NULL\n");
+			break;
+		}
+		avail = ibuf_usedcount(is->sbuf);
+		if (avail >= ap->con->pkt_size) {
+			ap->con->slen = ap->con->pkt_size;
+			ibuf_memcpy_r(ap->con->sbuf, is->sbuf, ap->con->slen);
+			if (is->sbuf->wsem)
+				sem_post(is->sbuf->wsem);
+#if 0
+			register unsigned char *start = bs;
+			register int j;
+			int squelched = (squelch > 0), osl = soundel;
+
+			/* If entire buffer is less than squelch, ditch it.  If
+			   we haven't received sqdelay samples since the last
+			   squelch event, continue to transmit. */
+
+			if (sqdelay > 0 && sqwait > 0) {
+				if (debugging) {
+					printf("Squelch countdown: %d samples left.\n",
+						sqwait);
+				}
+				sqwait -= soundel;
+				squelched = FALSE;
+			} else if (squelch > 0) {
+				for (j = 0; j < soundel; j++) {
+#ifdef USQUELCH
+					if (((*start++ & 0x7F) ^ 0x7F) > squelch)
+#else
+					int samp = alaw2linear(*start++);
+
+					if (samp < 0) {
+						samp = -samp;
+					}
+					if (samp > squelch)
+#endif
+					{
+						squelched = FALSE;
+						sqwait = sqdelay;
+						break;
+					}
+				}
+			}
+
+			if (squelched) {
+				if (debugging) {
+					printf("Entire buffer squelched.\n");
+				}
+				spurt = TRUE;
+			} else {
+				netbuf.compression = fProtocol | (ring ? (fSetDest | fDestSpkr) : 0);
+				netbuf.compression |= debugging ? fDebug : 0;
+				netbuf.compression |= loopback ? fLoopBack : 0;
+				ring = FALSE;
+				if (compressing) {
+					int is = soundel, os = soundel / 2;
+
+					rate_flow(buf, buf, &is, &os);
+					soundel = os;
+					netbuf.compression |= fComp2X;
+				}
+				netbuf.buffer.buffer_len = soundel;
+				if (!sendpkt(&netbuf)) {
+					exiting();
+					return(2);
+				}
+				if (debugging && !vat && !rtp) {
+					fprintf(stdout, "Sent %d audio samples in %d bytes.\r\n",
+						osl, soundel);
+				}
+			}
+#endif
+			ret = send_sdata(ap);
+			dprint(DBGM_SOUND, -1, "send_sdata ret %d\n", ret);
+			if (ret<=0) {
+				dprint(DBGM_SOUND, -1, "send_sdata ret %d\n", ret);
+				ap->Flags |= AP_FLG_VOIP_ABORT;
+			}
+		} else {
+			sem_wait(&is->work);
+		}
+	}
+	return((void *)ret);
+}
+

Added: misdn-user/trunk/voip/voip_isdn.c
===================================================================
--- misdn-user/trunk/voip/voip_isdn.c	                        (rev 0)
+++ misdn-user/trunk/voip/voip_isdn.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,832 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <string.h>
+#include <fcntl.h>
+#include "g711.h"
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include "isdn_net.h"
+#include "l3dss1.h"
+#include "helper.h"
+#include "bchannel.h"
+#include "tone.h"
+#include "isound.h"
+#include "globals.h"
+
+#include "iapplication.h"
+
+vapplication_t	voip;
+
+static int
+getnext_record(FILE *f)
+{
+	int	opt = 0;
+	char	line[128];
+
+	while(!feof(f)) {
+		if (fgets(line, 128, f)) {
+//			fprintf(stderr, "%s: line:%s", __FUNCTION__, line);
+			if (line[0]=='\n')
+				continue;
+			if (line[0]==0)
+				continue;
+			if (line[0]=='#')
+				continue;
+			sscanf(line,"%d", &opt);
+			return(opt);
+		}
+	}
+	return(0);
+}
+
+int
+read_rec_ctrlfile(void)
+{
+	FILE		*f;
+	int		opt;
+	manager_t	*mgr = voip.mgr_lst;
+
+	if (RecordCtrlFile[0] == 0) {
+		dprint(DBGM_TOPLEVEL, -1, "%s: no RecordCtrlFile\n", __FUNCTION__);
+		return(-ENOENT);
+	}
+	f = fopen(RecordCtrlFile, "r");
+	if (!f) {
+		dprint(DBGM_TOPLEVEL, -1, "%s: cannot open %s: %s\n", __FUNCTION__,
+			RecordCtrlFile, strerror(errno));
+		return(-errno);
+	}
+	while(mgr) {
+		opt = getnext_record(f);
+		dprint(DBGM_TOPLEVEL, -1, "%s: mgr %p ch1: %d\n", __FUNCTION__,
+			mgr, opt);
+		if (opt) {
+			mgr->bc[0].Flags |= FLG_BC_RECORD;
+		} else {
+			mgr->bc[0].Flags &= ~FLG_BC_RECORD;
+		}
+		opt = getnext_record(f);
+		dprint(DBGM_TOPLEVEL, -1, "%s: mgr %p ch2: %d\n", __FUNCTION__,
+			mgr, opt);
+		if (opt) {
+			mgr->bc[1].Flags |= FLG_BC_RECORD;
+		} else {
+			mgr->bc[1].Flags &= ~FLG_BC_RECORD;
+		}
+		mgr = mgr->next;
+	}
+	fclose(f);
+	return(0);
+}
+
+static void
+sig_usr1_handler(int sig)
+{
+	dprint(DBGM_TOPLEVEL, -1, "%s: got sig(%d)\n", __FUNCTION__, sig);
+	read_rec_ctrlfile();
+	signal(SIGUSR1, sig_usr1_handler);
+}
+
+#if 0
+static void
+sig_segfault(int sig, siginfo_t *si, void *arg) {
+	int	i,*ip = arg;
+
+	dprint(DBGM_TOPLEVEL, -1, "segfault %d, %p, %p\n",
+		sig, si, arg);
+	if (si) {
+		dprint(DBGM_TOPLEVEL, -1, "si: sig(%d) err(%d) code(%d) pid(%d)\n",
+			si->si_signo, si->si_errno, si->si_code, si->si_pid);
+		dprint(DBGM_TOPLEVEL, -1, "si: status(%x) value(%x)\n",
+			si->si_status, si->si_value.sival_int);
+		dprint(DBGM_TOPLEVEL, -1, "si: int(%x) ptr(%p) addr(%p)\n",
+			si->si_int, si->si_ptr, si->si_addr);
+	}
+	if (ip) {
+		ip -= 10;
+		for(i=0;i<20;i++)
+			dprint(DBGM_TOPLEVEL, -1, "ip %3d: %x\n", i-10, ip[i]);
+	}
+	ip = (int *)si;
+	if (ip) {
+		ip -= 10;
+		for(i=0;i<20;i++)
+			dprint(DBGM_TOPLEVEL, -1, "si %3d: %x\n", i-10, ip[i]);
+	}
+
+}
+#endif
+
+static void
+term_handler(int sig)
+{
+	pthread_t	tid;
+	manager_t	*mgr = voip.mgr_lst;
+
+	tid = pthread_self();
+	dprint(DBGM_TOPLEVEL, -1,"signal %d received from thread %ld\n", sig, tid);
+	voip.flags |= AP_FLG_VOIP_ABORT;
+	while(mgr) {
+		term_netstack(mgr->nst);
+		term_bchannel(&mgr->bc[0]);
+		term_bchannel(&mgr->bc[1]);
+		mgr = mgr->next;
+	}
+}
+
+#if 0
+
+static void
+child_handler(int sig)
+{
+	manager_t	*mgr = voip.mgr_lst;
+	pid_t		pid;
+	int		stat;
+
+	dprint(DBGM_TOPLEVEL, -1,"signal %d received\n", sig);
+	while (mgr) {
+		if (mgr->bc[0].pid) {
+			pid = waitpid(mgr->bc[0].pid, &stat, WNOHANG);
+			dprint(DBGM_TOPLEVEL, -1,  "%s: waitpid(%d) stat(%x) ret(%d)\n", __FUNCTION__,
+				mgr->bc[0].pid, stat, pid);
+			if (mgr->bc[0].pid == pid) {
+				mgr->bc[0].pid = 0;
+//				if (mgr->bc[0].state == BC_STATE_ACTIV)
+				break;
+			}
+		}
+		if (mgr->bc[1].pid) {
+			pid = waitpid(mgr->bc[1].pid, &stat, WNOHANG);
+			dprint(DBGM_TOPLEVEL, -1,  "%s: waitpid(%d) stat(%x) ret(%d)\n", __FUNCTION__,
+				mgr->bc[1].pid, stat, pid);
+			if (mgr->bc[1].pid == pid) {
+				mgr->bc[1].pid = 0;
+//				if (mgr->bc[1].state == BC_STATE_ACTIV)
+				break;
+			}
+		}
+		mgr = mgr->next;
+	}
+	signal(SIGCHLD, child_handler);
+}
+
+#endif
+
+static void *
+read_audio(void *arg)
+{
+	isound_t	*ia = arg;
+	pthread_t	tid;
+	fd_set		rfd, efd;
+	int		ret,i;
+
+	tid = pthread_self();
+	dprint(DBGM_TOPLEVEL, -1,  "%s: tid %ld\n", __FUNCTION__, tid);
+	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+	while(1) {
+		FD_ZERO(&rfd);
+		FD_ZERO(&efd);
+		FD_SET(ia->data, &rfd);
+		FD_SET(ia->data, &efd);
+		ret = select(ia->data +1, &rfd, NULL, &efd, NULL);
+		if (ret < 0) {
+			dprint(DBGM_TOPLEVEL, -1,  "%s: select error %d %s\n", __FUNCTION__,
+				errno, strerror(errno));
+			if (errno == EAGAIN)
+				continue;
+			if (errno == EINTR)
+				continue;
+		}
+		if (FD_ISSET(ia->data, &rfd)) {
+			ret = read(ia->data, ia->rtmp, MAX_AUDIO_READ);
+			if (ret < 0) {
+				dprint(DBGM_TOPLEVEL, -1,  "%s: read error %d %s\n", __FUNCTION__,
+					errno, strerror(errno));
+				if (errno == EAGAIN)
+					continue;
+				continue;
+			}
+			if (!ret) {
+				dprint(DBGM_TOPLEVEL, -1,  "%s: zero read\n", __FUNCTION__);
+				continue;
+			}
+			if (ret > ibuf_freecount(ia->rbuf)) {
+				dprint(DBGM_TOPLEVEL, -1,  "%s: rbuf overflow %d/%d\n", __FUNCTION__,
+					ret, ibuf_freecount(ia->rbuf));
+				ret = ibuf_freecount(ia->rbuf);
+			}
+			for (i=0; i<ret; i++)
+				ia->rtmp[i] = ulaw2alaw(ia->rtmp[i]);
+			ibuf_memcpy_w(ia->rbuf, ia->rtmp, ret);
+			if (ia->rbuf->rsem)
+				sem_post(ia->rbuf->rsem);
+		}
+		if (FD_ISSET(ia->data, &efd)) {
+			dprint(DBGM_TOPLEVEL, -1,  "%s: exception\n", __FUNCTION__);
+			break;
+		}
+	}
+	return NULL;
+}
+
+static void *
+work_audio(void *arg)
+{
+	isound_t	*ia = arg;
+	pthread_t	tid;
+	int		ret, i;
+
+	tid = pthread_self();
+	dprint(DBGM_TOPLEVEL, -1,  "%s: tid %ld\n", __FUNCTION__, tid);
+	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+	while(1) {
+		sem_wait(&ia->work);
+		if (ia->wlen) {
+			ret = write(ia->data, &ia->wtmp[ia->widx], ia->wlen);
+			if (ret == -1)
+				continue;
+			if (ret < ia->wlen) {
+				ia->wlen -= ret;
+				ia->widx += ret;
+				continue;
+			}
+			ia->wlen = 0;
+			ia->widx = 0;
+		}
+		if ((ia->wlen = ibuf_usedcount(ia->sbuf))) {
+			ibuf_memcpy_r(ia->wtmp, ia->sbuf, ia->wlen);
+			for (i=0; i<ia->wlen; i++)
+				ia->wtmp[i] = alaw2ulaw(ia->wtmp[i]);
+			ret = write(ia->data, &ia->wtmp[0], ia->wlen);
+			if (ret == -1)
+				continue;
+			if (ret < ia->wlen) {
+				ia->wlen -= ret;
+				ia->widx = ret;
+				continue;
+			}
+			ia->wlen = 0;
+		}
+	}
+	return(NULL);
+}
+
+int
+setup_voip(iapplication_t *ap, bchannel_t *bc)
+{
+	isound_t	*ia;
+	int		ret;
+
+	dprint(DBGM_APPL, -1, "%s(%p, %p)\n", __FUNCTION__, ap, bc);
+	if (!bc)
+		return(-EINVAL);
+	if (!ap)
+		return(-EINVAL);
+	if (!bc->sbuf)
+		return(-EINVAL);
+	if (bc->rbuf)
+		return(-EINVAL);
+	bc->rbuf = init_ibuffer(2048);
+	if (!bc->rbuf)
+		return(-ENOMEM);
+	bc->rbuf->wsem = &bc->work;
+	ia = malloc(sizeof(isound_t));
+	if (!ia)
+		return(-ENOMEM);
+	memset(ia, 0, sizeof(isound_t));
+	ap->data2 = ia;
+	sem_init(&ia->work, 0, 0);
+	ia->sbuf = bc->rbuf;
+	ia->rbuf = bc->sbuf;
+	bc->sbuf->wsem = &ia->work;
+	bc->rbuf->rsem = &ia->work;
+	ret = pthread_create(&ap->tid, NULL, voip_sender, (void *)ap);
+	dprint(DBGM_APPL, -1,  "%s: create voip_sender %ld ret %d\n", __FUNCTION__,
+		ap->tid, ret);
+	return(ret);
+}
+
+int
+close_voip(iapplication_t *ap, bchannel_t *bc)
+{
+	isound_t	*ia;
+	int		ret, *retval;
+
+	dprint(DBGM_APPL, -1, "%s(%p, %p)\n", __FUNCTION__, ap, bc);
+	if (!bc)
+		return(-EINVAL);
+	if (!ap)
+		return(-EINVAL);
+	ia = ap->data2;
+	ap->data2 = NULL;
+	ap->Flags &= ~AP_FLG_VOIP_ACTIV;
+	if (!ia)
+		return(-EINVAL);
+	ret = pthread_cancel(ap->tid);
+	dprint(DBGM_APPL, -1, "%s: cancel sender ret(%d)\n", __FUNCTION__,
+		ret);
+	ret = pthread_join(ap->tid, (void *)&retval);
+	dprint(DBGM_APPL, -1, "%s: join sender ret(%d) rval(%p)\n", __FUNCTION__,
+		ret, retval);
+	ia->sbuf = NULL;
+	ia->rbuf = NULL;
+	if (bc->sbuf)
+		bc->sbuf->wsem = NULL;
+	if (bc->rbuf)
+		free_ibuffer(bc->rbuf);
+	bc->rbuf = NULL;
+	ret = sem_destroy(&ia->work);
+	dprint(DBGM_APPL, -1, "%s: sem_destroy work %d\n", __FUNCTION__,
+		ret);
+	free(ia);
+	return(0);
+}
+
+
+static int
+setup_audio(iapplication_t *ap, bchannel_t *bc)
+{
+	isound_t	*ia;
+	int		ret;
+
+	if (!bc)
+		return(-EINVAL);
+	if (!ap)
+		return(-EINVAL);
+	if (!bc->sbuf)
+		return(-EINVAL);
+	if (bc->rbuf)
+		return(-EINVAL);
+	bc->rbuf = init_ibuffer(2048);
+	if (!bc->rbuf)
+		return(-ENOMEM);
+	bc->rbuf->wsem = &bc->work;
+	ia = malloc(sizeof(isound_t));
+	if (!ia)
+		return(-ENOMEM);
+	memset(ia, 0, sizeof(isound_t));
+	sem_init(&ia->work, 0, 0);
+	ia->data = open("/dev/audio", O_RDWR | O_NONBLOCK);
+	if (ia->data < 0) {
+		free(ia);
+		dprint(DBGM_TOPLEVEL, -1,  "%s: open rdwr %d %s\n", __FUNCTION__,
+			errno, strerror(errno));
+		return(-errno);
+	}
+	ap->data2 = ia;
+	ia->sbuf = bc->rbuf;
+	ia->rbuf = bc->sbuf;
+	bc->sbuf->wsem = &ia->work;
+	bc->rbuf->rsem = &ia->work;
+	ret = pthread_create(&ia->rd_t, NULL, read_audio, (void *)ia);
+	dprint(DBGM_TOPLEVEL, -1,  "%s: create rd_t %ld ret %d\n", __FUNCTION__,
+		ia->rd_t, ret);
+	ret = pthread_create(&ia->wr_t, NULL, work_audio, (void *)ia);
+	dprint(DBGM_TOPLEVEL, -1,  "%s: create wr_t %ld ret %d\n", __FUNCTION__,
+		ia->wr_t, ret);
+	return(0);
+}
+
+static int
+close_audio(iapplication_t *ap, bchannel_t *bc)
+{
+	isound_t	*ia;
+	int		ret, *retval;
+
+	if (!bc)
+		return(-EINVAL);
+	if (!ap)
+		return(-EINVAL);
+	ia = ap->data2;
+	ap->data2 = NULL;
+	if (!ia)
+		return(-EINVAL);
+	close(ia->data);
+	ret = pthread_cancel(ia->rd_t);
+	dprint(DBGM_TOPLEVEL, -1, "%s: cancel rd_t ret(%d)\n", __FUNCTION__,
+		ret);
+	ret = pthread_cancel(ia->wr_t);
+	dprint(DBGM_TOPLEVEL, -1, "%s: cancel wr_t ret(%d)\n", __FUNCTION__,
+		ret);
+	ret = pthread_join(ia->rd_t, (void *)&retval);
+	dprint(DBGM_TOPLEVEL, -1, "%s: join rd_t ret(%d) rval(%p)\n", __FUNCTION__,
+		ret, retval);
+	ret = pthread_join(ia->wr_t, (void *)&retval);
+	dprint(DBGM_TOPLEVEL, -1, "%s: join wr_t ret(%d) rval(%p)\n", __FUNCTION__,
+		ret, retval);
+	ia->sbuf = NULL;
+	ia->rbuf = NULL;
+	if (bc->sbuf)
+		bc->sbuf->wsem = NULL;
+	if (bc->rbuf)
+		free_ibuffer(bc->rbuf);
+	bc->rbuf = NULL;
+	ret = sem_destroy(&ia->work);
+	dprint(DBGM_TOPLEVEL, -1, "%s: sem_destroy work %d\n", __FUNCTION__,
+		ret);
+	free(ia);
+	return(0);
+}
+
+static int
+route_call(iapplication_t *ap, bchannel_t *bc)
+{
+	bchannel_t	*newbc = NULL;
+	int		ret;
+
+	if (bc) {
+		display_NR_IE(bc->msn,  __FUNCTION__, ": msn");
+		display_NR_IE(bc->nr,   __FUNCTION__, ":  nr");
+	}
+	ap->data1 = bc;
+	if (!bc)
+		return(-EINVAL);
+	read_rec_ctrlfile();
+	if (bc->usednr->typ == NR_TYPE_INTERN) {
+		ap->mode = AP_MODE_INTERN_CALL;
+		ret = ap->mgr->app_bc(ap->mgr, PR_APP_OCHANNEL, &newbc);
+		if (0 >= ret)
+			dprint(DBGM_TOPLEVEL, -1,  "%s: no free channel ret(%d)\n", __FUNCTION__,
+				ret);
+		if (!newbc) {
+			bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
+			bc->cause_val = CAUSE_USER_BUSY;
+			ap->mgr->app_bc(ap->mgr, PR_APP_HANGUP, bc);
+			return(0);
+		}
+		newbc->app = ap;
+		ap->data2 = newbc;
+		newbc->Flags |= FLG_BC_APPLICATION;
+		newbc->msn[0] = bc->usednr->len +1;
+		newbc->msn[1] = 0x81;
+		memcpy(&newbc->msn[2], bc->usednr->nr, bc->usednr->len);
+		if (bc->msn[0])
+			memcpy(newbc->nr, bc->msn, bc->msn[0] + 1);
+		newbc->l1_prot = ISDN_PID_L1_B_64TRANS;
+		ap->mgr->app_bc(ap->mgr, PR_APP_OCALL, newbc);
+	} else if (bc->usednr->typ == NR_TYPE_AUDIO) {
+		if (ap->vapp->flags & AP_FLG_AUDIO_USED) {
+			bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
+			bc->cause_val = CAUSE_USER_BUSY;
+			ap->mgr->app_bc(ap->mgr, PR_APP_HANGUP, bc);
+			return(0);
+		} else
+			ap->vapp->flags |= AP_FLG_AUDIO_USED;
+		ap->mode = AP_MODE_AUDIO_CALL;
+		bc->Flags |= FLG_BC_PROGRESS;
+		ap->mgr->app_bc(ap->mgr, PR_APP_ALERT, bc);
+		ret = setup_audio(ap, bc);
+		if (ret) {
+			ap->vapp->flags &= ~AP_FLG_AUDIO_USED;
+			bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
+			bc->cause_val = CAUSE_INCOMPATIBLE_DEST;
+			ap->mgr->app_bc(ap->mgr, PR_APP_HANGUP, bc);
+			return(0);
+		}
+		ap->Flags |= AP_FLG_AUDIO_ACTIV;
+		strcpy(bc->display,"connect to AUDIO");
+		ap->mgr->app_bc(ap->mgr, PR_APP_CONNECT, bc);
+	} else if (bc->usednr->typ == NR_TYPE_VOIP) {
+		ap->mode = AP_MODE_VOIP_OCALL;
+		ret = setup_voip_ocall(ap, bc);
+	}
+	return(0);
+}
+
+static int
+connect_call(iapplication_t *ap, bchannel_t *bc)
+{
+	bchannel_t	*peer = NULL;
+	int		ret;
+
+	read_rec_ctrlfile();
+	if (ap->mode == AP_MODE_INTERN_CALL) {
+		if (ap->data1 == bc) {
+			peer = ap->data2;
+		} else if (ap->data2 == bc) {
+			peer = ap->data1;
+		}
+		if (peer) {
+			ap->mgr->app_bc(ap->mgr, PR_APP_CONNECT, peer);
+			bc->rbuf = peer->sbuf;
+			peer->rbuf = bc->sbuf;
+			if (bc->sbuf)
+				bc->sbuf->rsem = &peer->work;
+			if (peer->sbuf)
+				peer->sbuf->rsem = &bc->work;
+		} else {
+			return(-EINVAL);
+		}
+	} else if (ap->mode == AP_MODE_VOIP_OCALL) {
+		bc = ap->data1;
+		ap->Flags &= ~AP_FLG_VOIP_ALERTING;
+		sprintf(bc->display,"connect to %s", bc->usednr->name);
+		ap->mgr->app_bc(ap->mgr, PR_APP_CONNECT, bc);
+	} else if (ap->mode == AP_MODE_VOIP_ICALL) {
+		ret = connect_voip(ap, bc);
+		if (!ret) {
+			ap->Flags |= AP_FLG_VOIP_ACTIV;
+			ap->mgr->app_bc(ap->mgr, PR_APP_CONNECT, bc);
+		}
+		return(ret);
+	}
+	return(0);
+}
+
+static int
+hangup_call(iapplication_t *ap, bchannel_t *bc)
+{
+	if ((ap->mode == AP_MODE_VOIP_OCALL) ||
+		(ap->mode == AP_MODE_VOIP_ICALL)) {
+		if (ap->Flags & AP_FLG_VOIP_ACTIV) {
+			close_voip(ap, bc);
+		}
+		return(disconnect_voip(ap, bc));
+	}
+	return(0);
+}
+
+static int
+clear_call(iapplication_t *ap, bchannel_t *bc)
+{
+	bchannel_t	*peer = NULL;
+
+	if (ap->mode == AP_MODE_INTERN_CALL) {
+		if (ap->data1 == bc) {
+			peer = ap->data2;
+			ap->data1 = NULL;
+		} else if (ap->data2 == bc) {
+			peer = ap->data1;
+			ap->data2= NULL;
+		}
+		bc->rbuf = NULL;
+		if (bc->sbuf)
+			bc->sbuf->rsem = &bc->work;
+		if (peer) {
+			peer->Flags |= FLG_BC_PROGRESS;
+			peer->cause_loc = bc->cause_loc;
+			peer->cause_val = bc->cause_val;
+			peer->rbuf = NULL;
+			if (peer->sbuf)
+				peer->sbuf->rsem = &peer->work;
+			ap->mgr->app_bc(ap->mgr, PR_APP_HANGUP, peer);
+		} else {
+			free_application(ap);
+		}
+		if (bc)
+			bc->app = NULL;
+	} else if (ap->mode == AP_MODE_AUDIO_CALL) {
+		if (ap->Flags & AP_FLG_AUDIO_ACTIV) {
+			close_audio(ap, bc);
+			ap->Flags &= ~AP_FLG_AUDIO_ACTIV;
+			ap->vapp->flags &= ~AP_FLG_AUDIO_USED;
+		}
+		if (bc)
+			bc->app = NULL;
+		free_application(ap);
+	} else if (ap->mode == AP_MODE_VOIP_OCALL) {
+		if (ap->Flags & AP_FLG_VOIP_ACTIV) {
+			close_voip(ap, bc);
+		}
+		release_voip(ap, bc);
+		ap->mode = AP_MODE_IDLE;
+		free_application(ap);
+	} else if (ap->mode == AP_MODE_VOIP_ICALL) {
+		if (ap->Flags & AP_FLG_VOIP_ACTIV) {
+			close_voip(ap, bc);
+		}
+		release_voip(ap, bc);
+		ap->mode = AP_MODE_IDLE;
+		free_application(ap);
+	}
+	return(0);
+}
+
+static int
+alert_call(iapplication_t *ap, bchannel_t *bc)
+{
+	bchannel_t	*peer = NULL;
+
+	if (ap->mode == AP_MODE_VOIP_ICALL) {
+		return(alert_voip(ap, bc));
+	} else if (ap->mode == AP_MODE_INTERN_CALL) {
+		if (bc != ap->data2)
+			return(0);
+		peer = ap->data1;
+		if (!peer)
+			return(0);
+		peer->Flags |= FLG_BC_PROGRESS;
+		ap->mgr->app_bc(ap->mgr, PR_APP_ALERT, peer);
+	}
+	return(0);
+}
+
+static int
+facility_info(iapplication_t *ap, bchannel_t *bc)
+{
+	if ((ap->mode == AP_MODE_VOIP_ICALL) ||
+		(ap->mode == AP_MODE_VOIP_OCALL)) {
+		return(facility_voip(ap, bc));
+	}
+	return(0);
+}
+
+static int
+useruser_info(iapplication_t *ap, bchannel_t *bc)
+{
+	if ((ap->mode == AP_MODE_VOIP_ICALL) ||
+		(ap->mode == AP_MODE_VOIP_OCALL)) {
+		return(useruser_voip(ap, bc));
+	}
+	return(0);
+}
+
+static int
+open_recfiles(iapplication_t *ap, bchannel_t *bc)
+{
+	char		filename[2048];
+	struct timeval	tv;
+	int		ret;
+
+	if (!bc)
+		return(-EINVAL);
+	if (!RecordFilePath[0]) {
+		dprint(DBGM_TOPLEVEL, -1, "%s: RecordFilePath not set\n", __FUNCTION__);
+		return(-EINVAL);
+	}
+	gettimeofday(&tv, NULL);
+	sprintf(filename, "%s%08lx_%02d.r",
+		RecordFilePath, tv.tv_sec, bc->channel);
+	dprint(DBGM_TOPLEVEL, -1, "%s: rf.r:%s\n", __FUNCTION__,
+		filename);
+	if (bc->rrid > 0)
+		close(bc->rrid);
+	bc->rrid = open(filename, O_WRONLY|O_CREAT|O_TRUNC,S_IRWXU);
+	if (bc->rrid < 0) {
+		ret = -errno;
+		dprint(DBGM_TOPLEVEL, -1, "%s: rf.r error %s\n", __FUNCTION__,
+			strerror(errno));
+
+		return(ret);
+	}
+	filename[strlen(filename)-1] = 's';
+	dprint(DBGM_TOPLEVEL, -1, "%s: rf.s:%s\n", __FUNCTION__,
+		filename);
+	if (bc->rsid > 0)
+		close(bc->rsid);
+	bc->rsid = open(filename, O_WRONLY|O_CREAT|O_TRUNC,S_IRWXU);
+	if (bc->rsid < 0) {
+		ret = -errno;
+		dprint(DBGM_TOPLEVEL, -1, "%s: rf.s error %s\n", __FUNCTION__,
+			strerror(errno));
+		close(bc->rrid);
+		bc->rrid = -1;
+		return(ret);
+	}
+	bc->Flags |= FLG_BC_RECORDING;
+	return(0);
+}
+
+static int
+close_recfiles(iapplication_t *ap, bchannel_t *bc)
+{
+	if (!bc)
+		return(-EINVAL);
+	if (bc->rrid > 0)
+		close(bc->rrid);
+	bc->rrid = -1;
+	if (bc->rsid > 0)
+		close(bc->rsid);
+	bc->rsid = -1;
+	bc->Flags &= ~FLG_BC_RECORDING;
+	return(0);
+}
+
+static int
+application_handler(manager_t *mgr, int prim, void *arg)
+{
+	bchannel_t	*bc = arg;
+	iapplication_t	*appl = NULL;
+
+	if (!bc)
+		return(-EINVAL);
+	if (prim == PR_APP_ICALL) {
+		appl = new_application(&voip);
+		if (!appl)
+			return(-EBUSY);
+		appl->mgr = mgr;
+		bc->app = appl;
+		return(route_call(appl, bc));
+			return(-EBUSY);
+	}
+	appl = bc->app;
+	if (!appl)
+		return(-EINVAL);
+	if (prim == PR_APP_CONNECT) {
+		return(connect_call(appl, bc));
+	} else if (prim == PR_APP_ALERT) {
+		return(alert_call(appl, bc));
+	} else if (prim == PR_APP_FACILITY) {
+		return(facility_info(appl, bc));
+	} else if (prim == PR_APP_USERUSER) {
+		return(useruser_info(appl, bc));
+	} else if (prim == PR_APP_HANGUP) {
+		return(hangup_call(appl, bc));
+	} else if (prim == PR_APP_CLEAR) {
+		return(clear_call(appl, bc));
+	} else if (prim == PR_APP_OPEN_RECFILES) {
+		return(open_recfiles(appl, bc));
+	} else if (prim == PR_APP_CLOSE_RECFILES) {
+		return(close_recfiles(appl, bc));
+	}
+	return(-EINVAL);
+}
+
+int main(argc,argv)
+int argc;
+char *argv[];
+
+{
+	int		ret, *retp;
+	char		host_cfg[MAX_HOST_SIZE+16];
+	pthread_t	voip_id;
+	nr_list_t	*nr;
+	
+	debug_init(global_debug, "testlog", NULL, NULL);
+	memset(&voip, 0, sizeof(vapplication_t));
+	voip.tout.tv_sec = NORMAL_TIMEOUT_s;
+	voip.tout.tv_usec = NORMAL_TIMEOUT_us;
+	msg_init();
+	ret = init_manager(&voip.mgr_lst, application_handler);
+	if (ret) {
+		fprintf(stderr, "error in init_manager %d\n", ret);
+		exit(1);
+	}
+	parse_cfg("voip.cfg", voip.mgr_lst);
+	if (gethostname(voip.hostname, MAX_HOST_SIZE)) {
+		fprintf(stderr, "error getting hostname: %s\n",
+			strerror(errno));
+		exit(1);
+	}
+	sprintf(host_cfg, "%s.voip.cfg", voip.hostname);
+	parse_cfg(host_cfg, voip.mgr_lst);
+	debug_init(global_debug, NULL, NULL, NULL);
+	voip.port = rtp_port; 
+	voip.flags = default_flags;
+	voip.debug = global_debug;
+	fprintf(stderr, "%s: debug(%x) port(%d)\n", __FUNCTION__,
+		global_debug, rtp_port);
+	nr = voip.mgr_lst->nrlist;
+	while(nr) {
+		dprint(DBGM_TOPLEVEL, -1, "nr(%s) len(%d) flg(%x) typ(%d) name(%s)\n",
+			nr->nr, nr->len, nr->flags, nr->typ, nr->name);
+		nr = nr->next;
+	}
+	signal(SIGTERM, term_handler);
+	signal(SIGINT, term_handler);
+	signal(SIGPIPE, term_handler);
+	signal(SIGUSR1, sig_usr1_handler);
+	signal(SIGALRM, SIG_IGN);
+	read_rec_ctrlfile();
+#if 0
+	signal(SIGCHLD, child_handler);
+#endif
+#if 0
+	{
+		static struct sigaction sa;
+		
+		sa.sa_handler = NULL;
+		sa.sa_restorer = NULL;
+		sa.sa_sigaction = sig_segfault;
+		sa.sa_flags = SA_ONESHOT | SA_SIGINFO;
+		sigemptyset(&sa.sa_mask);
+		ret = sigaction(SIGSEGV, &sa, NULL);
+		fprintf(stderr, "sigaction ret(%d)\n",
+			ret);
+	}
+#endif
+	voip_id = run_voip(&voip);
+	retp = do_netthread(voip.mgr_lst->nst);
+	fprintf(stderr, "do_main_loop returns(%p)\n", retp);
+	while (voip.mgr_lst) {
+		manager_t	*next = voip.mgr_lst->next;
+		cleanup_manager(voip.mgr_lst);
+		voip.mgr_lst = next;
+	}
+	voip.flags |= AP_FLG_VOIP_ABORT;
+	ret = pthread_join(voip_id, (void *)&retp);
+	fprintf(stderr, "%s: join voipscan ret(%d) rval(%p)\n", __FUNCTION__,
+		ret, retp);
+	debug_close();
+	return(0);
+}

Added: misdn-user/trunk/voip/voip_isdn_app.c
===================================================================
--- misdn-user/trunk/voip/voip_isdn_app.c	                        (rev 0)
+++ misdn-user/trunk/voip/voip_isdn_app.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,509 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include "isdn_net.h"
+#include "l3dss1.h"
+#include "globals.h"
+#include "iapplication.h"
+
+
+static void MsgAddIE(msg_t *msg, u_char ie, u_char *iep, int reset) {
+	int	l;
+	u_char	*p;
+
+	if (ie & 0x80)
+		l = 1;
+	else {
+		if (iep && *iep)
+			l = 2 + *iep;
+		else
+			return;
+	}
+	p = msg_put(msg, l);
+	*p++ = ie;
+	l--;
+	if (l) {
+		memcpy(p, iep, l);
+		if (reset)
+			*iep = 0;
+	}
+}
+
+static msg_t *
+make_msg_head(int size, u_char mt) {
+	u_char	*p;
+	msg_t	*msg;
+
+	msg = alloc_msg(size);
+	if (msg) {
+		p = msg_put(msg, 3);
+		p++;
+		p++;
+		*p++ = mt;
+	}
+	return(msg);
+}
+
+int
+alert_voip(iapplication_t *ap, bchannel_t *bc)
+{
+	msg_t	*msg;
+
+	if (!ap->con)
+		return(-EBUSY);
+	msg = make_msg_head(1024, MT_ALERTING);
+	if (msg) {
+		MsgAddIE(msg, IE_FACILITY, bc->fac, 1);
+		MsgAddIE(msg, IE_DISPLAY, bc->display, 1);
+		MsgAddIE(msg, IE_USER_USER, bc->uu, 1);
+		msg_queue_tail(&ap->con->aqueue, msg);
+		return(SendCtrl(ap));
+	}
+	return(-ENOMEM);
+}
+
+int
+facility_voip(iapplication_t *ap, bchannel_t *bc)
+{
+	msg_t	*msg;
+
+	if (!ap->con)
+		return(-EBUSY);
+	msg = make_msg_head(1024, MT_FACILITY);
+	if (msg) {
+		MsgAddIE(msg, IE_FACILITY, bc->fac, 1);
+		MsgAddIE(msg, IE_DISPLAY, bc->display, 1);
+		msg_queue_tail(&ap->con->aqueue, msg);
+		return(SendCtrl(ap));
+	}
+	return(-ENOMEM);
+}
+
+
+int
+useruser_voip(iapplication_t *ap, bchannel_t *bc)
+{
+	msg_t	*msg;
+
+	if (!ap->con)
+		return(-EBUSY);
+	msg = make_msg_head(1024, MT_USER_INFORMATION);
+	if (msg) {
+		MsgAddIE(msg, IE_USER_USER, bc->uu, 1);
+		msg_queue_tail(&ap->con->aqueue, msg);
+		return(SendCtrl(ap));
+	}
+	return(-ENOMEM);
+}
+
+
+int
+connect_voip(iapplication_t *ap, bchannel_t *bc)
+{
+	int	ret;
+	msg_t	*msg;
+
+	if (!ap->con)
+		return(-EBUSY);
+	ret = setup_voip(ap, bc);
+	if (ret) {
+		bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
+		bc->cause_val = CAUSE_NO_ROUTE;
+		ap->mgr->app_bc(ap->mgr, PR_APP_HANGUP, bc);
+		return(-EBUSY);
+	}
+	msg = make_msg_head(1024, MT_CONNECT);
+	if (msg) {
+		MsgAddIE(msg, IE_FACILITY, bc->fac, 1);
+		MsgAddIE(msg, IE_DISPLAY, bc->display, 1);
+		MsgAddIE(msg, IE_USER_USER, bc->uu, 1);
+		msg_queue_tail(&ap->con->aqueue, msg);
+		return(SendCtrl(ap));
+	}
+	return(-ENOMEM);
+}
+
+int
+disconnect_voip(iapplication_t *ap, bchannel_t *bc)
+{
+	msg_t   *msg;
+	u_char	cause[8];
+
+	if (!ap->con)
+		return(-EBUSY);
+	msg = make_msg_head(1024, MT_DISCONNECT);
+	if (msg) {
+		cause[0] = 2;
+		cause[1] = 0x80 | bc->cause_loc;
+		cause[2] = 0x80 | bc->cause_val;
+		MsgAddIE(msg, IE_CAUSE, cause, 0);
+		MsgAddIE(msg, IE_FACILITY, bc->fac, 1);
+		MsgAddIE(msg, IE_DISPLAY, bc->display, 1);
+		MsgAddIE(msg, IE_USER_USER, bc->uu, 1);
+		msg_queue_tail(&ap->con->aqueue, msg);
+		return(SendCtrl(ap));
+	}
+	return(-ENOMEM);
+}
+
+int
+release_voip(iapplication_t *ap, bchannel_t *bc)
+{
+	msg_t   *msg;
+	u_char	cause[8];
+
+	if (!ap->con)
+		return(-EBUSY);
+	msg = make_msg_head(1024, MT_RELEASE);
+	if (msg) {
+		cause[0] = 2;
+		cause[1] = 0x80 | bc->cause_loc;
+		cause[2] = 0x80 | bc->cause_val;
+		MsgAddIE(msg, IE_CAUSE, cause, 0);
+		MsgAddIE(msg, IE_FACILITY, bc->fac, 1);
+		MsgAddIE(msg, IE_DISPLAY, bc->display, 1);
+		MsgAddIE(msg, IE_USER_USER, bc->uu, 1);
+		msg_queue_tail(&ap->con->aqueue, msg);
+		return(SendCtrl(ap));
+	}
+	return(-ENOMEM);
+}
+
+int
+setup_voip_ocall(iapplication_t *ap, bchannel_t *bc) {
+	msg_t		*msg;
+	struct in_addr	addr;
+	struct hostent	*h;
+
+	if (!ap->con) {
+		if ((addr.s_addr = inet_addr(bc->usednr->name)) == -1) {
+			h = gethostbyname(bc->usednr->name);
+			if (!h) {
+				return(-ENXIO);
+			}
+			memcpy(&addr.s_addr, h->h_addr, sizeof(addr.s_addr));
+		}
+		ap->con = new_connection(ap, &addr);
+		if (!ap->con) {
+			return(-ENOMEM);
+		}
+		if (bc->usednr->flags & FLAG_GSM) {
+			ap->con->pkt_size = 640;
+			ap->con->sndflags |= SNDFLG_COMPR_GSM;
+		}
+		ap->con->own_ssrc = getnew_ssrc(ap->vapp);
+	}
+	msg = make_msg_head(1024, MT_SETUP);
+	if (msg) {
+		MsgAddIE(msg, IE_FACILITY, bc->fac, 1);
+		MsgAddIE(msg, IE_BEARER, bc->bc, 0);
+		MsgAddIE(msg, IE_DISPLAY, bc->display, 1);
+		MsgAddIE(msg, IE_CALLING_PN, bc->msn, 0);
+		MsgAddIE(msg, IE_CALLING_SUB, bc->clisub, 1);
+		MsgAddIE(msg, IE_CALLED_PN, bc->nr, 0);
+		MsgAddIE(msg, IE_CALLED_SUB, bc->cldsub, 1);
+		MsgAddIE(msg, IE_USER_USER, bc->uu, 1);
+		msg_queue_tail(&ap->con->aqueue, msg);
+		return(SendCtrl(ap));
+	}
+	return(-ENOMEM);
+}
+
+static int
+parse_isdn_extra(unsigned char *arg, int len, bchannel_t *bc)
+{
+	unsigned char	*p;
+
+	p = findie(arg, len, IE_DISPLAY, 0);
+	if (p) {
+		memcpy(bc->display, p + 1, *p);
+		bc->display[*p] = 0;
+	}
+	p = findie(arg, len, IE_USER_USER, 0);
+	if (p)
+		memcpy(bc->uu, p, *p + 1);
+	p = findie(arg, len, IE_FACILITY, 0);
+	if (p)
+		memcpy(bc->fac, p, *p + 1);
+	return(0);
+}
+
+static int
+parse_isdn_setup(iapplication_t *appl, unsigned char *arg, int len)
+{
+	manager_t	*mgr = appl->vapp->mgr_lst;
+	unsigned char	*own, *p;
+	nr_list_t	*nrx;
+	bchannel_t	*bc = NULL;
+	int		ret;
+
+	if (appl->mgr) { /* allready setup */
+		SendCtrl(appl);
+		return(-EINVAL);
+	}
+	own = findie(arg, len, IE_CALLED_PN, 0);
+	if (!own) {
+		SendCtrl(appl);
+		return(-EINVAL);
+	}
+	while(mgr) {
+		nrx = NULL;
+		if (!match_nr(mgr, own, &nrx)) {
+			ret = mgr->app_bc(mgr, PR_APP_OCHANNEL, &bc);
+			if (0 >= ret)
+				eprint( "%s: no free channel ret(%d)\n", __FUNCTION__,
+					ret);
+			if (!bc) {
+				eprint( "%s: no free channel\n", __FUNCTION__);
+			} else {
+				appl->mgr = mgr;
+				appl->data1 = bc;
+				appl->mode = AP_MODE_VOIP_ICALL;
+				bc->app = appl;
+				bc->usednr = nrx;
+				break;
+			}
+		}
+		mgr = mgr->next;
+	}
+	if (!mgr) {
+	} else {
+		p = findie(arg, len, IE_CALLING_PN, 0);
+		if (p)
+			memcpy(bc->nr, p, *p + 1);
+		p = findie(arg, len, IE_CALLING_SUB, 0);
+		if (p)
+			memcpy(bc->clisub, p, *p + 1);
+		p = findie(arg, len, IE_CALLED_SUB, 0);
+		if (p)
+			memcpy(bc->cldsub, p, *p + 1);
+		parse_isdn_extra(arg, len, bc);
+		bc->Flags |= FLG_BC_APPLICATION;
+		memcpy(bc->msn, own, own[0] + 1);
+		bc->l1_prot = ISDN_PID_L1_B_64TRANS;
+		if (!bc->display[0] && appl->con) {
+			strcpy(bc->display, appl->con->con_hostname);
+		}
+		mgr->app_bc(mgr, PR_APP_OCALL, bc);
+	}
+	SendCtrl(appl);
+	return(0);
+}
+
+static int
+parse_isdn_alert(iapplication_t *appl, unsigned char *arg, int len)
+{
+	bchannel_t	*bc = appl->data1;
+
+	if (!appl->mgr || !bc) {
+		SendCtrl(appl);
+		return(-EINVAL);
+	}
+	parse_isdn_extra(arg, len, bc);
+	if (!bc->display[0] && bc->usednr) {
+		strcpy(bc->display, bc->usednr->name);
+	}
+	bc->Flags |= FLG_BC_PROGRESS;
+	appl->mgr->app_bc(appl->mgr, PR_APP_ALERT, bc);
+	SendCtrl(appl);
+	return(0);
+}
+
+int
+parse_isdn_connect(iapplication_t *appl, unsigned char *arg, int len)
+{
+	bchannel_t	*bc = appl->data1;
+	int		ret;
+
+	if (!appl->mgr || !bc) {
+		SendCtrl(appl);
+		return(-EINVAL);
+	}
+	parse_isdn_extra(arg, len, bc);
+	ret = setup_voip(appl, bc);
+	if (ret) {
+		bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
+		bc->cause_val = CAUSE_NO_ROUTE;
+		appl->mgr->app_bc(appl->mgr, PR_APP_HANGUP, bc);
+		return(0);
+	}
+	appl->Flags |= AP_FLG_VOIP_ACTIV;
+	appl->mgr->app_bc(appl->mgr, PR_APP_CONNECT, bc);
+	SendCtrl(appl);
+	return(0);
+}
+
+static int
+parse_isdn_disc(iapplication_t *appl, unsigned char *arg, int len)
+{
+	bchannel_t	*bc = appl->data1;
+	unsigned char	*p;
+
+	if (!appl->mgr || !bc) {
+		SendCtrl(appl);
+		return(-EINVAL);
+	}
+	p = findie(arg, len, IE_CAUSE, 0);
+	if (p) {
+		if (*p++ > 1) {
+			bc->cause_loc = *p++ & 0xf;
+			bc->cause_val = *p++ & 0x7f;
+		} else {
+			bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
+			bc->cause_val = CAUSE_NORMAL_CLEARING;
+		}
+	} else {
+		bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
+		bc->cause_val = CAUSE_NORMAL_CLEARING;
+	}
+	parse_isdn_extra(arg, len, bc);
+	if (appl->Flags & AP_FLG_VOIP_ACTIV) {
+		close_voip(appl, bc);
+	}
+	bc->Flags |= FLG_BC_PROGRESS;
+	appl->mgr->app_bc(appl->mgr, PR_APP_HANGUP, bc);
+	SendCtrl(appl);
+	return(0);
+}
+
+static int
+parse_isdn_release(iapplication_t *appl, unsigned char *arg, int len)
+{
+	bchannel_t	*bc = appl->data1;
+	unsigned char	*p;
+
+	if (!appl->mgr || !bc) {
+		SendCtrl(appl);
+		return(-EINVAL);
+	}
+	p = findie(arg, len, IE_CAUSE, 0);
+	if (p) {
+		if (*p++ > 1) {
+			bc->cause_loc = *p++ & 0xf;
+			bc->cause_val = *p++ & 0x7f;
+		} else {
+			bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
+			bc->cause_val = CAUSE_NORMAL_CLEARING;
+		}
+	} else {
+		bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
+		bc->cause_val = CAUSE_NORMAL_CLEARING;
+	}
+	parse_isdn_extra(arg, len, bc);
+	if (appl->Flags & AP_FLG_VOIP_ACTIV) {
+		close_voip(appl, bc);
+	}
+	bc->Flags |= FLG_BC_PROGRESS;
+	appl->mgr->app_bc(appl->mgr, PR_APP_HANGUP, bc);
+	SendCtrl(appl);
+	return(0);
+}
+
+static int
+parse_isdn_uinfo(iapplication_t *appl, unsigned char *arg, int len)
+{
+	bchannel_t	*bc = appl->data1;
+
+	if (!appl->mgr || !bc) {
+		SendCtrl(appl);
+		return(-EINVAL);
+	}
+	parse_isdn_extra(arg, len, bc);
+	appl->mgr->app_bc(appl->mgr, PR_APP_USERUSER, bc);
+	SendCtrl(appl);
+	return(0);
+}
+
+static int
+parse_isdn_fac(iapplication_t *appl, unsigned char *arg, int len)
+{
+	bchannel_t	*bc = appl->data1;
+
+	if (!appl->mgr || !bc) {
+		SendCtrl(appl);
+		return(-EINVAL);
+	}
+	parse_isdn_extra(arg, len, bc);
+	appl->mgr->app_bc(appl->mgr, PR_APP_FACILITY, bc);
+	SendCtrl(appl);
+	return(0);
+}
+
+static int
+parse_isdn_packet(iapplication_t *appl, unsigned char *arg) {
+	unsigned char	*p, oc, pc, pr, a_pc;
+	int		len;
+	vconnection_t	*con;
+
+	con = appl->con;
+	if (!con)
+		return(-EINVAL);
+	p = arg + 2;
+	len = ntohs(*((unsigned short *)p));
+	len *= 4;
+	p = arg + 12;
+	len -= 8;
+	if (len<=0)
+		return(-EINVAL);
+	
+	oc = *p++;
+	pc = *p;
+	*p++ = 0; /* to use L3 findie, fake a dummy CR L3 frame */
+	pr = *p++;
+	dprint(DBGM_ISDN, -1,  "%s: pr(%02x) own(%d/%d) peer(%d/%d)\n", __FUNCTION__,
+		pr, oc, con->oc, pc, con->pc); 
+	a_pc = con->pc;
+	a_pc++;
+	if (con->oc == oc) {
+		if (con->amsg) {
+			free_msg(con->amsg);
+			con->amsg = NULL;
+		}
+	}
+	if (a_pc != pc) {
+	} else
+		con->pc = pc;
+
+	if (pr == 0) { /* escape to private MTs */
+		pr = *p++;
+		if (pr == 0x81) { /* RR */
+			return(0);
+		}
+		return(-EINVAL);
+	} else if (pr == MT_SETUP) {
+		return(parse_isdn_setup(appl, arg + 12, len));
+	} else if (pr == MT_ALERTING) {
+		return(parse_isdn_alert(appl, arg + 12, len));
+	} else if (pr == MT_CONNECT) {
+		return(parse_isdn_connect(appl, arg + 12, len));
+	} else if (pr == MT_DISCONNECT) {
+		return(parse_isdn_disc(appl, arg + 12, len));
+	} else if (pr == MT_RELEASE) {
+		return(parse_isdn_release(appl, arg + 12, len));
+	} else if (pr == MT_USER_INFORMATION) {
+		return(parse_isdn_uinfo(appl, arg + 12, len));
+	} else if (pr == MT_FACILITY) {
+		return(parse_isdn_fac(appl, arg + 12, len));
+	}
+	return(0);
+}
+
+int
+voip_application_handler(iapplication_t *appl, int prim, unsigned char *arg) {
+
+	dprint(DBGM_APPL, -1,  "%s(%p, %x, %p)\n", __FUNCTION__,
+		appl, prim, arg);
+
+	if (prim == AP_PR_VOIP_NEW) {
+		
+	} else if (prim == AP_PR_VOIP_ISDN) {
+		return(parse_isdn_packet(appl, arg));
+	}
+	return(-EINVAL);
+}
+

Added: misdn-user/trunk/voip/voip_timer.c
===================================================================
--- misdn-user/trunk/voip/voip_timer.c	                        (rev 0)
+++ misdn-user/trunk/voip/voip_timer.c	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,138 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/time.h>
+#include "vitimer.h"
+
+static	vi_timer_t	*timerlist = NULL;
+
+static void
+ins_vitimer(vi_timer_t *iti) {
+	iti->prev = timerlist;
+
+	iti->next = NULL;
+	if (timerlist) {
+		if (timercmp(&timerlist->tv, &iti->tv, >)) {
+			iti->prev = NULL;
+			iti->next = timerlist;
+		}
+	}
+	while(iti->prev && iti->prev->next) {
+		if (timercmp(&iti->prev->next->tv, &iti->tv, >))
+			break;
+		iti->prev = iti->prev->next;
+	}
+	if (iti->prev) {
+		iti->next = iti->prev->next;
+		iti->prev->next = iti;
+	} else {
+		timerlist = iti;
+	}
+	if (iti->next)
+		iti->next->prev = iti;
+}
+
+int
+run_vitimer(void)
+{
+	int	cnt = 0;
+	struct timeval	act, del;
+
+	gettimeofday(&act, NULL);
+	while(timerlist) {
+		if (timercmp(&timerlist->tv, &act, >))
+			break;
+		timersub(&act, &timerlist->tv, &del);
+		timerlist->func(timerlist->data, timerlist->val, &del);
+		remove_vitimer(timerlist);
+	}
+	return(cnt);
+}
+
+void
+remove_vitimer(vi_timer_t *iti) {
+	if (iti->prev)
+		iti->prev->next = iti->next;
+	if (iti->next)
+		iti->next->prev = iti->prev;
+	if (timerlist == iti)
+		timerlist = iti->next;
+	iti->prev = NULL;
+	iti->next = NULL;
+}
+
+int
+init_vitimer(vi_timer_t *iti, void *data, unsigned long val, timef_t f)
+{
+	if (!iti) {
+		return(-EINVAL);
+	}
+	iti->data = data;
+	iti->val = val;
+	iti->func = f;
+	return(0);
+}
+
+int
+add_vitimer_abs(vi_timer_t *iti, struct timeval *tv)
+{
+	if (!iti) {
+		return(-EINVAL);
+	}
+	iti->tv = *tv;
+	ins_vitimer(iti);
+	run_vitimer();
+	return(0);
+}
+
+
+int
+add_vitimer_rel(vi_timer_t *iti, struct timeval *tv)
+{
+	struct timeval	act;
+
+	gettimeofday(&act, NULL);
+	if (!iti) {
+		return(-EINVAL);
+	}
+	timeradd(&act, tv, &iti->tv);
+	ins_vitimer(iti);
+	run_vitimer();
+	return(0);
+}
+
+
+void
+clean_vitimer(void) {
+	while(timerlist)
+		remove_vitimer(timerlist);
+}
+
+struct timeval
+*get_next_vitimer_time(void)
+{
+	if (timerlist)
+		return(&timerlist->tv);
+	else
+		return(NULL);
+}
+
+int
+get_next_vitimer_dist(struct timeval *tv)
+{
+	struct timeval	act;
+
+	if (!tv)
+		return(-EINVAL);
+	if (!timerlist)
+		return(-EINVAL);
+	gettimeofday(&act, NULL);
+	if (timercmp(&timerlist->tv, &act, <)) {
+		tv->tv_sec = 0;
+		tv->tv_usec = 0;
+	} else
+		timersub(&timerlist->tv, &act, tv);
+	return(0);
+}

Added: misdn-user/trunk/voip/voipisdn.spec
===================================================================
--- misdn-user/trunk/voip/voipisdn.spec	                        (rev 0)
+++ misdn-user/trunk/voip/voipisdn.spec	2007-07-17 16:40:33 UTC (rev 3756)
@@ -0,0 +1,53 @@
+Vendor:       SuSE GmbH, Nuernberg, Germany
+Distribution: SuSE Linux 7.3 (i386)
+Name:         voipisdn
+Packager:     feedback at suse.de
+Copyright:    GPL
+Group:        Applications/Communications
+Provides:     voipisdn
+Autoreqprov:  on
+Version:      20030423
+Release:      1
+Summary:      Voice Communication Over Data Networks
+Source1:      hisax_voip-%{version}.tar.bz2
+Source2:      gsm-1.0.7.tar.gz
+BuildRoot:    /var/tmp/%{name}-build
+
+%description
+Voice Communication Over Data TCP/IP Networks ISDN gateway
+
+Authors:
+--------
+    Karsten Keil <kkeil at suse.de>
+
+SuSE series: net
+
+%prep
+%setup -T -c -n voipisdn
+%setup -n voipisdn -D -T -a 1
+%setup -n voipisdn -D -T -a 2
+
+%build
+
+cd gsm-1.0-pl6
+make
+cd ..
+
+cd hisax
+make all
+
+%install
+rm -rf RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT/usr/bin
+install -c -s -m 755 hisax/voip/voipisdn     $RPM_BUILD_ROOT/usr/bin/
+
+%{?suse_check}
+
+%clean
+rm -rf RPM_BUILD_ROOT
+
+
+%files
+%defattr(-,root,root)
+/usr/bin/*
+




More information about the Pkg-voip-commits mailing list