[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ݨ< "ì¬ë©86²ëëØ)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|äÇÄÁ¿¼»¾ÝÓìæÓ»¥©Gk 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ýÒÑ࿲¯¹Û¼¨±P4kk,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[ï°¤¬³ª§ª¡ëª¿»9k~²¦ µÕQ+#-5{»¤¡¤°y1&# "8Ùï0ÿ®ã4;û`Y6{ÄC6[À¾Ú½µ«³¾Ä²ºÚ±8kk#¹ë§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¾¢ß+k3»©¬þ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%kk&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)!$,·?XA)©
+Ö±, -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
+[00minsgesamt 0
+[mtest 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(¶.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), ¶, 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