libss7-1.0.2/0002755000000000000000000000000011074672131011417 5ustar rootrootlibss7-1.0.2/build_tools/0002755000000000000000000000000011074672131013736 5ustar rootrootlibss7-1.0.2/build_tools/make_version0000755000000000000000000000262011043717124016342 0ustar rootroot#!/bin/sh if [ -f ${1}/.version ]; then cat ${1}/.version elif [ -d .svn ]; then PARTS=`LANG=C svn info ${1} | ${GREP} URL | ${AWK} '{print $2;}' | sed -e 's:^.*/svn/libss7/::' | sed -e 's:/: :g'` BRANCH=0 TEAM=0 TAG=0 REV=`svnversion -c ${1} | cut -d: -f2` BASE=`LANG=C svn pg svnmerge-integrated ${1} | cut -d: -f1` if [ "${PARTS}" = "trunk" ] ; then echo SVN-trunk-r${REV} exit 0 fi for PART in $PARTS ; do if [ ${TAG} != 0 ] ; then if [ "${PART}" = "autotag_for_be" ] ; then continue fi if [ "${PART}" = "autotag_for_sx00i" ] ; then continue fi RESULT="${PART}" break fi if [ ${BRANCH} != 0 ] ; then if [ -z ${RESULT} ] ; then RESULT="${PART}" else RESULT="${RESULT}-${PART}" fi break fi if [ ${TEAM} != 0 ] ; then if [ -z ${RESULT} ] ; then RESULT="${PART}" else RESULT="${RESULT}-${PART}" fi continue fi if [ "${PART}" = "branches" ] ; then BRANCH=1 RESULT="branch" continue fi if [ "${PART}" = "tags" ] ; then TAG=1 continue fi if [ "${PART}" = "team" ] ; then TEAM=1 continue fi done if [ ${TAG} != 0 ] ; then echo ${RESULT} else echo SVN-${RESULT}-r${REV}${BASE:+-${BASE}} fi fi libss7-1.0.2/build_tools/make_version_c0000755000000000000000000000055611006446232016650 0ustar rootroot#!/bin/sh if [ ! -f ../.flavor ]; then EXTRA="" else aadkver=`cat ../.version` aadkflavor=`cat ../.flavor` EXTRA=" (${aadkflavor} ${aadkver})" fi cat << END /* * version.c * Automatically generated */ #include "libss7.h" static const char ss7_version[] = "${SS7VERSION}${EXTRA}"; const char *ss7_get_version(void) { return ss7_version; } END libss7-1.0.2/LICENSE0000644000000000000000000004313011046152047012421 0ustar rootroot GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy 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 Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. libss7-1.0.2/parser_debug.c0000644000000000000000000000402311046151741014220 0ustar rootroot/* * libss7: An implementation of Signalling System 7 * * Written by Matthew Fredrickson * * scheduling routines taken from libpri by Mark Spencer * * Copyright (C) 2006-2008, Digium, Inc * All Rights Reserved. */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. * * In addition, when this program is distributed with Asterisk in * any form that would qualify as a 'combined work' or as a * 'derivative work' (but not mere aggregation), you can redistribute * and/or modify the combination under the terms of the license * provided with that copy of Asterisk, instead of the license * terms granted here. */ #include #include #include "libss7.h" #include "ss7_internal.h" #include "mtp2.h" #include "isup.h" #include "mtp3.h" int main(int argc, char **argv) { FILE *fp; struct ss7 *ss7; unsigned char mybuf[512]; unsigned int tmp; int ss7type; int res = 0, i = 0, size; ss7_event *e; if (argc != 3) return -1; if (!strcasecmp(argv[1], "ansi")) ss7type = SS7_ANSI; else if (!strcasecmp(argv[1], "itu")) ss7type = SS7_ITU; else return -1; ss7 = ss7_new(ss7type); fp = fopen(argv[2], "r"); while (res != EOF) { res = fscanf(fp, "%x ", &tmp); mybuf[i++] = (unsigned char) tmp; } size = i + 1; for (i = 0; i < size; i++) { printf("%.2x ", mybuf[i]); } printf("\n"); ss7_add_link(ss7, SS7_TRANSPORT_DAHDIDCHAN, 10); ss7->debug = SS7_DEBUG_MTP2 | SS7_DEBUG_MTP3 | SS7_DEBUG_ISUP; ss7->links[0]->state = MTP_INSERVICE; mtp2_receive(ss7->links[0], mybuf, size); e = ss7_check_event(ss7); return 0; } libss7-1.0.2/ChangeLog0000644000000000000000000005644111074703727013207 0ustar rootroot2008-10-13 Matthew Fredrickson * libss7 1.0.2 released 2008-09-06 16:15 +0000 [r210] Matthew Fredrickson * README: Give the default README an 1.6.0 and DAHDI an overhaul, add 56k documentation, as well as a section on SS7 related Asterisk variables. 2008-08-12 20:50 +0000 [r209] Matthew Fredrickson * NEWS-08-12-2008 (added), ss7linktest.c: Add latest NEWS update as well as correct zap reference to dahdi 2008-08-09 16:54 +0000 [r208] Matthew Fredrickson * isup.c: Fix minor buglet in parsing code of echo_control_info_dump. If we received spare or unknown values in the hg bits, it would overwrite the dump output of the fe bits 2008-08-06 18:49 +0000 [r205-207] Jason Parker * Makefile: Remove useless SOSLINK * Makefile: ldconfig won't create these links if you're using INSTALL_PREFIX * Makefile: Make INSTALL_PREFIX consistent with libpri (read: make it use DESTDIR) 2008-08-05 22:28 +0000 [r202] Kevin P. Fleming * /, LICENSE (added): add LICENSE file 2008-08-05 Kevin P. Fleming * libss7 1.0.1 released 2008-08-05 22:28 +0000 [r201-202] Kevin P. Fleming * /, LICENSE (added): add LICENSE file * Makefile, ss7.c, ss7test.c, ss7_internal.h, isup.c, mtp2.c, parser_debug.c, ss7_sched.c, mtp3.c, isup.h, mtp2.h, libss7.h, mtp3.h, ss7linktest.c: clean up license headers explicitly grant additional license permissions when used with Asterisk build ss7test and ss7linktest when DAHDI is found, not Zaptel stop using DAHDI typedefs that no longer exist 2008-07-30 15:42 +0000 [r200] Kevin P. Fleming * Makefile, mkdep (removed), /: use new version and dependency stuff here too 2008-07-29 22:48 +0000 [r199] Jason Parker * build_tools/make_version: I believe this is what was meant. (it matches how Asterisk does it) 2008-07-19 16:08 +0000 [r198] Matthew Fredrickson * mtp2.c: Fix potential bug in which we might have lost the last MSU received, but we never checked the new FSN in the following FISUs which would cause us not to request retransmission of the lost MSU and potentially cause the remote end's T7 (message acknowledgement timer) to expire and reset the link 2008-07-18 14:58 +0000 [r197] Matthew Fredrickson * isup.c: Make sure we're populating the correct event types in FAA and CGB 2008-07-16 15:49 +0000 [r196] Matthew Fredrickson * ss7test.c: Fix ss7test.c to use new TRANSPORT definitions (#13075) 2008-07-11 21:30 Matthew Fredrickson * Libss7 1.0.0 released! 2008-07-11 21:30 +0000 [r185-186] Matthew Fredrickson * parser_debug.c, ss7linktest.c: Make linktest program work with new transport definitions * ss7.c, libss7.h: Remove DAHDI dependency from libss7 2008-06-29 01:56 +0000 [r184] Matthew Fredrickson * ss7.c, ss7test.c, ss7linktest.c: Make libss7 compatible with DAHDI. No more Zaptel (get 0.9.1 branch if you need Zaptel support, although it is not going to be maintained) 2008-06-28 14:37 +0000 [r183] Kevin P. Fleming * ss7.c: remove unnecessary include of zaptel.h 2008-06-27 19:06 +0000 [r181] Matthew Fredrickson * libss7.h: Add work around for new DAHDI name 2008-06-21 02:40 +0000 [r178-180] Matthew Fredrickson * ss7.c: Put zaptel header back in * ss7.c, isup.c: Try to make the isup_find_call and __isup_new_call logic in isup_receive less prone to instability caused by people making mistakes when writing code for new events and messages. This will make the default behavior to generate a new, unlinked call for scratchpad purposes by default. There is much less potential of free'ing an active call if we make the switch's default to do this instead of having the default finding an existing call * isup.c: Make sure we don't lose our old call if CFN comes in 2008-06-14 21:11 +0000 [r177] Matthew Fredrickson * ss7.c, isup.c: Fix bug which occurred when messages are received but no events were output. We were allocating a new event by default, which sometimes would contain an old event. If we did not fill in the newly allocated event, a duplicate of the previous event was given to the user application, which sometimes could cause a crash from an already free'd call being handed back. 2008-05-30 19:32 +0000 [r173-176] Matthew Fredrickson * NEWS-09-27-2006 (added), README, NEWS-09-11-2006 (added), NEWS-08-23-2006 (added): Add a few of the public service announcments I have made on the Asterisk-ss7 mailing list as well as update the README * NEWS-05-30-2008 (added): Add latest news update for libss7 * isup.c: Don't need to output hex since we get it in the next line (for message type) * isup.c, mtp2.c: Remove duplicate error message, also make sure we print message type and CIC before erroring out of ISUP dump 2008-05-28 14:46 +0000 [r172] Matthew Fredrickson * isup.c: jip_transmit is a FUNC_SEND, not FUNC_RECV. Also, since jip_number is a static field, we shouldn't have to check for it's existance before we check to see if something is there 2008-05-16 19:52 +0000 [r169-171] Matthew Fredrickson * isup.c, isup.h, libss7.h: Add called_party_status_ind field to event_acm * isup.c: Fixed bug in functions :-) * isup.c: Add dump for optional backward call indicator 2008-05-14 18:17 +0000 [r162-168] Matthew Fredrickson * isup.c: In order to receive CPC, we have to actually copy it into the event from which we read it :-) * isup.c, isup.h, libss7.h: Add support for receiving of calling party's category * isup.c: Don't throw an error when don't output an event for a message * isup.c: Add support for CFN (confusion) message type * isup.c: Report CIC number when debug message appears * mtp2.c: Add the write flag in a couple of more places that might need it. Basically, it needs to be set any time any MTP2 parameter changes (bib, fib, fsn, bsn) * mtp2.c: Need to update write flag everytime we receive a valid MSU since FISU's BSN needs to be updated 2008-05-10 00:59 +0000 [r160-161] Matthew Fredrickson * ss7.c, mtp2.c, mtp2.h, libss7.h, ss7linktest.c: Add support for kernel MTP2 support * mtp2.c: Remove some useless code in mtp2 2008-05-01 23:04 +0000 [r159] Brett Bryant * Makefile, build_tools (added), build_tools/make_version (added), build_tools/make_version_c (added), libss7.h: Add new API call to libss7 ( ss7_get_version ) that will return a version string. 2008-05-01 18:31 +0000 [r152-158] Matthew Fredrickson * mtp2.c: Use the correct variable name too * mtp2.c, mtp3.c: Make sure that if a link goes down during operation for any reason, that we report it to MTP3 * isup.c: Make name for generic name transmit function match all the rest of the transmit functions * isup.c: Make sure we don't send generic name unless it's actually set. * Makefile: Remove sccp object from build * Makefile: Initial 0.0.9 release 2008-04-21 18:37 +0000 [r151] Matthew Fredrickson * isup.c, libss7.h: Libss7 portion of #12484. Allow transmission of generic name. 2008-04-12 23:52 +0000 [r150] Matthew Fredrickson * isup.c, isup.h, libss7.h: Commit patch for #12325. Add support for redirecting number and generic name parameters (Rx only). Also add ANSI CVT and CVR message support 2008-03-21 21:34 +0000 [r148-149] Matthew Fredrickson * isup.c, mtp3.c, isup.h, mtp3.h: Fix ANSI sls so that is actually keeps the same sls for the duration of a call * ss7_internal.h, isup.c, mtp3.c, isup.h, mtp3.h: Some rearrangement for getting the SLS right for ANSI 2008-03-18 17:14 +0000 [r146-147] Matthew Fredrickson * isup.c: Revert previous commit because of bug * isup.c: Add new cause code and make sure we don't include variable parm length within the data dump 2008-03-15 22:54 +0000 [r145] Matthew Fredrickson * isup.c: Add more dump support for backward call indicator 2008-03-07 23:34 +0000 [r143-144] Matthew Fredrickson * isup.c, isup.h: Add support for dumping generic name * isup.c: Update continuity message indication to be correct 2008-02-21 18:22 +0000 [r142] Joshua Colp * Makefile: Only build ss7test and ss7linktest if the zaptel headers are available. 2008-02-18 21:50 +0000 [r140-141] Matthew Fredrickson * isup.c, isup.h, libss7.h: Libss7 support for #11964: add the ability to get ORIG_CALLED_NUM * isup.c, libss7.h: Fix for 11779. Allow different point codes in same linkset 2008-01-18 22:27 +0000 [r138-139] Matthew Fredrickson * mtp3.c: Fix for sometimes stupid telco SLC settings * mtp3.c: Make sure we don't send messages on links that are down on a linkset 2007-12-20 23:12 +0000 [r137] Matthew Fredrickson * README, isup.c, isup.h, libss7.h: Add support for RLT on DMS switches, JIP parameter additions, generic digits parameter, call reference parameter, facility indicator, as well as facility accept and facility reject message types. #11506 Thanks Alan. 2007-11-17 23:48 +0000 [r132-136] Matthew Fredrickson * mtp2.c: Hopefully the last update for making links automatically reconnect * mtp2.c, mtp3.c: Fix some more MTP2 automatic restart code * isup.c: Make sure CICs over 256 work. Oops. * isup.c, isup.h, libss7.h: Add generic address support. #11156. Thanks Alan! * mtp2.c: Make sure we retry realignment when we go down 2007-11-06 21:45 +0000 [r130-131] Matthew Fredrickson * ss7test.c, parser_debug.c, ss7linktest.c: Make all the API updates * ss7.c, libss7.h: Add a new transport option for eventual SS7 over IP support 2007-10-27 00:36 +0000 [r129] Matthew Fredrickson * isup.c, isup.h, libss7.h: Add circuit group query support 2007-10-25 23:23 +0000 [r127-128] Matthew Fredrickson * mtp3.c: Make sure we don't output incorrect message types for net_mng * isup.c, isup.h: Add debugging for a couple of previously unknown parameters 2007-10-19 16:22 +0000 [r126] Matthew Fredrickson * isup.c, isup.h: Add support for JIP (Juridiction Information Parameter) #11031 2007-10-16 00:29 +0000 [r125] Matthew Fredrickson * isup.c: Take some mostly unimportant data out 2007-10-12 15:03 +0000 [r116-124] Matthew Fredrickson * mtp3.c: Don't print out every MTP3 message we get * isup.c, isup.h: Add original called number dump support * isup.c, isup.h: Add dump support for redirection info parameter * isup.c: Clean up unknown paramter parsing a little more * isup.c: Take out some duplicate code, add some additional info for unkown parameters * README: Updates to README file * isup.c, isup.h, libss7.h: Remove oli preset field in favor of implicitly being present or not (-1 for not there) * isup.c: Minor coding style fix * isup.c, isup.h, libss7.h: Add support for CCR test, specifiable charge number in ANSI, and a few other things 2007-10-09 19:31 +0000 [r115] Matthew Fredrickson * mtp3.c: Make sure we display user part numerical equivalent. Also some dump formatting updates 2007-10-05 21:24 +0000 [r110-114] Matthew Fredrickson * parser_debug.c: Make it easier to switch ss7 types * mtp3.c: Make the ANSI point code format more familiar looking * Makefile: Make sure we cleanup parser debug too * isup.c: Add some more cause debug, also small update to avoid potential bugs due to return errors on parm routines * Makefile, parser_debug.c: Do some compiler trickery for big endian machines 2007-10-03 13:51 +0000 [r100-109] Matthew Fredrickson * isup.c, parser_debug.c: Add support for charge number dumping * isup.c, parser_debug.c: Add dump support for transmission medium requirements * parser_debug.c: Make sure that we use exactly the right size * isup.c: Add debugging for a couple more parameters * isup.c: Add dump support for called party number * isup.c: Continue to make dumping prettier * isup.c: Continue to make dumping prettier * isup.c: Cleanup our ISUP dumping a little bit * isup.c, parser_debug.c: Add a fix in the dump code for incorrectly sized parameter, as well as an addition to the parser debug code * Makefile, parser_debug.c (added): Add a parser debug utility 2007-09-25 23:15 +0000 [r99] Matthew Fredrickson * README: Fix type in README 2007-09-22 17:36 +0000 [r97-98] Matthew Fredrickson * README: Fix potential point of confusion * README: Update the README file 2007-09-06 16:32 +0000 [r96] Matthew Fredrickson * isup.c, isup.h, libss7.h: Patch on #10575. Adds a few more ISUP params and messages 2007-06-29 22:21 +0000 [r94-95] Matthew Fredrickson * isup.c, ss7linktest.c: Current iteration of debug enhancements. Still have more to do. * isup.c, mtp2.c, mtp3.c: Add some preliminary ISUP parameter dumping code 2007-06-28 20:31 +0000 [r92-93] Matthew Fredrickson * isup.c, ss7linktest.c: Make sure when we match we match on dpc as well as cic * isup.c: Make sure we set the cic when we get supervision messages 2007-06-25 23:07 +0000 [r90-91] Matthew Fredrickson * mtp2.c, ss7linktest.c: Forgot to update the dump size so that it looks correct * isup.c: Fix ANSI RLC code so that we don't include optional parameters 2007-06-21 17:17 +0000 [r89] Matthew Fredrickson * ss7.c, ss7_internal.h, isup.c, mtp2.c, mtp3.c, isup.h, ss7linktest.c: Fix for not setting dpc on call when we receive a new one. Also, don't parse zero length messages or messages less than MTP2's minimum message size. Remove unused default dpc code 2007-06-19 14:49 +0000 [r87-88] Matthew Fredrickson * README, isup.c, isup.h, libss7.h, ss7linktest.c: Add support for nature of address indicator, number presentation, and screening indicator (#10000) * ss7.c: Make debug output not quite as ugly (#9903) 2007-06-17 00:08 +0000 [r86] Matthew Fredrickson * isup.c, ss7linktest.c: Fix some scenarios where a call could potentially be written to while free'd already 2007-06-08 15:40 +0000 [r85] Matthew Fredrickson * ss7.c, ss7_internal.h, isup.c, mtp2.c, mtp3.c, ss7linktest.c: Updates to add better debugging support 2007-05-23 15:29 +0000 [r84] Matthew Fredrickson * isup.c, mtp2.c, libss7.h: Pass cause back up the stack for REL. Also display SLC when debug message is printed 2007-05-15 19:59 +0000 [r81-83] Matthew Fredrickson * isup.c, mtp3.c: Let's try to make the SLS field more correct in ITU networks. * mtp3.c: Make sure we update our internal state to be up when we give an up event. * mtp3.c: SLC is supposed to be shifted up four bits 2007-05-02 15:47 +0000 [r79-80] Matthew Fredrickson * ss7linktest.c: Let's make sure we get that logic right... * ss7linktest.c: Make the link test program easier to use and configure 2007-04-04 14:47 +0000 [r78] Matthew Fredrickson * isup.c: Make sure we set the DPC on group messages 2007-03-30 20:46 +0000 [r77] Matthew Fredrickson * README, isup.c, mtp3.c, isup.h, libss7.h, ss7linktest.c: Add support for mulitple DPCs and CIC groups. (#9423) 2007-03-26 16:42 +0000 [r75-76] Matthew Fredrickson * ss7linktest.c: Make sure we update the test program for the new API. Also, small bug fix * isup.c, isup.h, libss7.h: Add support for group maintenance type 2006-12-26 17:29 +0000 [r74] Matthew Fredrickson * mtp2.c: Fix bug in buffer flushing code. Thanks Petr for pointing it out! 2006-11-25 21:28 +0000 [r72-73] Matthew Fredrickson * isup.c: Make sure we do some checks before sending group messages that are out of protocol spec * isup.c: Make sure we check args if they're not used properly 2006-11-08 22:48 +0000 [r67-71] Matthew Fredrickson * isup.c, mtp2.c: Make libss7 a little less verbose when used against buggy implementations that don't know when the link has gone down. * isup.c, mtp2.c, isup.h, mtp2.h: Update retranmission counts as well as ISUP support for additional optional parameter * README: Update README files. * mtp2.c: Now we do retransmission requests on MSUs that we don't receive correctly! * mtp2.c: More MTP2 stress test/hardening. Fixed bug where we dropped MSUs after retransmission request. 2006-11-03 21:26 +0000 [r63-66] Matthew Fredrickson * mtp2.c: Make notification that retransmission was requested * mtp2.c: Forgot that our tx'd buf is in reverse order from which we need to retransmit * mtp3.c: Make sure we spell indicator correctly * ss7_internal.h, mtp2.c, mtp3.c, mtp2.h: Updates so that we can better support retransmission reqeusts. 2006-11-02 16:19 +0000 [r61-62] Matthew Fredrickson * isup.c: Make sure we reset with reason hardware failure * ss7.c, ss7_internal.h, mtp2.c, mtp3.c, mtp2.h, mtp3.h: Let's do better linkstate up and down management! 2006-10-30 17:15 +0000 [r60] Matthew Fredrickson * isup.c, mtp3.c, mtp3.h: More MTP3 debug information 2006-10-24 15:32 +0000 [r59] Matthew Fredrickson * isup.c: Make sure we default to E.164 numbering plan 2006-10-19 19:24 +0000 [r58] Matthew Fredrickson * mtp3.c: Output our point codes in decimal format for the debug 2006-10-06 17:18 +0000 [r57] Matthew Fredrickson * README, ss7.c, ss7_internal.h, mtp2.c, mtp3.c, libss7.h: Make sure my email address is my company email address 2006-09-23 21:38 +0000 [r51-56] Matthew Fredrickson * mtp3.c, mtp2.h: Sent tra at link startup * mtp3.c: Stupid me * mtp3.c: Update so that we respond to STD_TEST first. Before TRA. * ss7linktest.c: Update test program * ss7_internal.h, mtp3.c: Send TRA only once, after we get SLTM from other end * mtp2.c: Little update 2006-09-22 15:47 +0000 [r50] Matthew Fredrickson * ss7.c, ss7_internal.h, isup.c, mtp2.c, ss7_sched.c, mtp3.c, isup.h, mtp2.h, libss7.h, mtp3.h: Make sure all of our copyright notices are correct 2006-09-21 15:44 +0000 [r49] Matthew Fredrickson * README: Updates to README, including info about first ANSI switch testing. 2006-09-19 23:04 +0000 [r48] Matthew Fredrickson * README: Did an outbound ANSI call!!!! 2006-09-18 19:15 +0000 [r47] Matthew Fredrickson * isup.c, isup.h, libss7.h, ss7linktest.c: Updates for parameter debugging 2006-09-11 17:48 +0000 [r46] Matthew Fredrickson * mtp3.c: Add a little more useful output if the network indiciator is set incorrectly. 2006-09-09 19:47 +0000 [r42-45] Matthew Fredrickson * isup.c: Lets make sure we use the right character for ST * README: README updates * isup.c: Little update * isup.c: We have to use User Service Info in ANSI IAMs instead of transmission medium requirements. 2006-09-08 02:35 +0000 [r38-41] Matthew Fredrickson * mtp3.c: Use special test instead of standard test for ANSI links. * mtp3.c: Make sure we set the priority field in ansi * mtp3.c: Fixes to make MTP3 come up in ANSI. We got an ANSI link to come up!!!! *jumps up and down* * README, isup.c, isup.h, libss7.h: Add CPG message support 2006-09-06 17:14 +0000 [r37] Matthew Fredrickson * ss7.c: Fix segfault due to but in alarm handling code 2006-09-01 21:37 +0000 [r34-36] Matthew Fredrickson * ss7.c, libss7.h: Add support for alarms * ss7.c: Fix a little oops with debugging * README: Make sure we update that we support RSC 2006-08-30 21:53 +0000 [r32-33] Matthew Fredrickson * isup.c, libss7.h: Update to add call structure to RSC. * README, isup.c, libss7.h: Add support for reset messages. 2006-08-25 20:08 +0000 [r30-31] Matthew Fredrickson * README: Update to documentation * isup.c, isup.h, libss7.h, ss7linktest.c: Do blocking and unblocking right 2006-08-23 22:23 +0000 [r25-29] Matthew Fredrickson * mtp3.c, ss7linktest.c: Updates to make sure we send STD_TEST before we send TRA * isup.c, libss7.h: Add circuit group blocking/unblocking support as well as acknowledgement * ss7test.c, mtp2.c, libss7.h: More updates.... for circuit blocking/unblocking * mtp2.c: Only output debug if debug is enabled. * README, libss7.h: Add group block/unblock support. 2006-08-18 22:40 +0000 [r13-24] Matthew Fredrickson * isup.c: Forgot to add the translation of message type to string * README, isup.c, libss7.h: Add a few more messages. Update the readme * Makefile: Update to build on x86-64 correctly (#7750) * isup.h: Oh yeah, need the definition :-) * README, isup.c: Update to README file, as well as another parameter. * README: Clarify a bit better on how it works. * README: Added a tested switchtype section * isup.c: Make sure we don't do a warning on optional parameters. * isup.c: Make sure we terminate the number after we get the ST character. * isup.c: Apparently I broke it in the midst of doing ANSI support :-( * isup.c: Handle unrecognzied optional parameters more forgivingly * isup.c: Make sure we don't return -1 on unknown optional parameter 2006-08-12 22:47 +0000 [r10-12] Matthew Fredrickson * isup.c, isup.h, libss7.h: More continuity check work. * isup.c, libss7.h: Rest of continuity check and continuty check request events * README, isup.c, isup.h: Add continuity and continuity check request messages 2006-08-04 17:32 +0000 [r2-9] Matthew Fredrickson * isup.c: Fix more signedness issues. (#7658) * ss7.c, mtp2.c, mtp3.c: Make sure we consistently use signed vs unsigned types * ss7test.c: Make sure we use the correct new location for zaptel.h (#7657) * isup.c, mtp3.c: Add support for ANSI style CICs * ss7.c, mtp2.c, mtp2.h: Implement ANSI MTP2 timers. * ss7.c, isup.c, libss7.h: Add support for the connect message. * README (added): Add a small readme file * Makefile (added), ss7.c (added), ss7test.c (added), ss7_internal.h (added), mkdep (added), isup.c (added), mtp2.c (added), ss7_sched.c (added), mtp3.c (added), isup.h (added), mtp2.h (added), libss7.h (added), mtp3.h (added), ss7linktest.c (added): Inital check-in of libss7. Yay!!!! 2006-08-01 23:48 +0000 [r1] Kevin P. Fleming * / (added): create basic directory structure libss7-1.0.2/libss7.h0000644000000000000000000002761211046151741012777 0ustar rootroot/* * libss7: An implementation of Signalling System 7 * * Written by Matthew Fredrickson * * scheduling routines taken from libpri by Mark Spencer * * Copyright (C) 2006-2008, Digium, Inc * All Rights Reserved. */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. * * In addition, when this program is distributed with Asterisk in * any form that would qualify as a 'combined work' or as a * 'derivative work' (but not mere aggregation), you can redistribute * and/or modify the combination under the terms of the license * provided with that copy of Asterisk, instead of the license * terms granted here. */ #ifndef _LIBSS7_H #define _LIBSS7_H /* Internal -- MTP2 events */ #define SS7_EVENT_UP 1 #define SS7_EVENT_DOWN 2 #define MTP2_LINK_UP 3 #define MTP2_LINK_DOWN 4 #define ISUP_EVENT_IAM 5 #define ISUP_EVENT_ACM 6 #define ISUP_EVENT_ANM 7 #define ISUP_EVENT_REL 8 #define ISUP_EVENT_RLC 9 /* Circuit group reset */ #define ISUP_EVENT_GRS 10 #define ISUP_EVENT_GRA 11 #define ISUP_EVENT_CON 12 #define ISUP_EVENT_COT 13 #define ISUP_EVENT_CCR 14 #define ISUP_EVENT_BLO 15 #define ISUP_EVENT_UBL 16 #define ISUP_EVENT_BLA 17 #define ISUP_EVENT_UBA 18 #define ISUP_EVENT_CGB 19 #define ISUP_EVENT_CGU 20 #define ISUP_EVENT_CGBA 19 #define ISUP_EVENT_CGUA 20 #define ISUP_EVENT_RSC 21 #define ISUP_EVENT_CPG 22 #define ISUP_EVENT_UCIC 23 #define ISUP_EVENT_LPA 24 #define ISUP_EVENT_CQM 25 #define ISUP_EVENT_FAR 26 #define ISUP_EVENT_FAA 27 #define ISUP_EVENT_CVT 28 #define ISUP_EVENT_CVR 29 /* Different SS7 types */ #define SS7_ITU (1 << 0) #define SS7_ANSI (1 << 1) /* Debug levels */ #define SS7_DEBUG_MTP2 (1 << 0) #define SS7_DEBUG_MTP3 (1 << 1) #define SS7_DEBUG_ISUP (1 << 2) /* Network indicator */ #define SS7_NI_INT 0x00 #define SS7_NI_INT_SPARE 0x01 #define SS7_NI_NAT 0x02 #define SS7_NI_NAT_SPARE 0x03 /* Nature of Address Indicator */ #define SS7_NAI_SUBSCRIBER 0x01 #define SS7_NAI_UNKNOWN 0x02 #define SS7_NAI_NATIONAL 0x03 #define SS7_NAI_INTERNATIONAL 0x04 /* Charge Number Nature of Address Indicator ANSI */ #define SS7_ANI_CALLING_PARTY_SUB_NUMBER 0x01 /* ANI of the calling party; subscriber number */ #define SS7_ANI_NOTAVAIL_OR_NOTPROVIDED 0x02 /* ANI not available or not provided */ #define SS7_ANI_CALLING_PARTY_NATIONAL_NUMBER 0x03 /* ANI of the calling party; national number */ #define SS7_ANI_CALLED_PARTY_SUB_NUMBER 0x05 /* ANI of the called party; subscriber number */ #define SS7_ANI_CALLED_PARTY_NOT_PRESENT 0x06 /* ANI of the called party; no number present */ #define SS7_ANI_CALLED_PARTY_NATIONAL_NUMBER 0x07 /* ANT of the called patty; national number */ /* Address Presentation */ #define SS7_PRESENTATION_ALLOWED 0x00 #define SS7_PRESENTATION_RESTRICTED 0x01 #define SS7_PRESENTATION_ADDR_NOT_AVAILABLE 0x02 /* Screening */ #define SS7_SCREENING_USER_PROVIDED_NOT_VERIFIED 0x00 #define SS7_SCREENING_USER_PROVIDED 0x01 #define SS7_SCREENING_NETWORK_PROVIDED_FAILED 0x02 #define SS7_SCREENING_NETWORK_PROVIDED 0x03 /* CPG parameter types */ #define CPG_EVENT_ALERTING 0x01 #define CPG_EVENT_PROGRESS 0x02 #define CPG_EVENT_INBANDINFO 0x03 #define CPG_EVENT_CFB 0x04 #define CPG_EVENT_CFNR 0x05 #define CPG_EVENT_CFU 0x06 /* SS7 transport types */ #define SS7_TRANSPORT_DAHDIDCHAN 0 #define SS7_TRANSPORT_DAHDIMTP2 1 #define SS7_TRANSPORT_TCP 2 struct ss7; struct isup_call; typedef struct { int e; int cic; int transcap; int cot_check_required; char called_party_num[50]; unsigned char called_nai; char calling_party_num[50]; unsigned char calling_party_cat; unsigned char calling_nai; unsigned char presentation_ind; unsigned char screening_ind; char charge_number[50]; unsigned char charge_nai; unsigned char charge_num_plan; unsigned char gen_add_num_plan; unsigned char gen_add_nai; char gen_add_number[50]; unsigned char gen_add_pres_ind; unsigned char gen_add_type; char gen_dig_number[50]; unsigned char gen_dig_type; unsigned char gen_dig_scheme; char jip_number[50]; unsigned char lspi_type; unsigned char lspi_scheme; unsigned char lspi_context; unsigned char lspi_spare; char lspi_ident[50]; /* If orig_called_num contains a valid number, consider the other orig_called* values valid */ char orig_called_num[50]; unsigned char orig_called_nai; unsigned char orig_called_pres_ind; unsigned char orig_called_screening_ind; char redirecting_num[50]; unsigned char redirecting_num_nai; unsigned char redirecting_num_presentation_ind; unsigned char redirecting_num_screening_ind; unsigned char generic_name_typeofname; unsigned char generic_name_avail; unsigned char generic_name_presentation; char generic_name[50]; int oli_ani2; unsigned int opc; struct isup_call *call; } ss7_event_iam; typedef struct { int e; int cic; int cause; unsigned int opc; struct isup_call *call; } ss7_event_rel; typedef struct { int e; int cic; unsigned int opc; } ss7_event_ciconly; typedef struct { int e; int cic; unsigned int opc; struct isup_call *call; } ss7_event_con; typedef struct { int e; int cic; unsigned int opc; struct isup_call *call; } ss7_event_rsc; typedef struct { int e; int cic; unsigned int opc; struct isup_call *call; } ss7_event_anm; typedef struct { int e; int cic; unsigned int call_ref_ident; unsigned int call_ref_pc; unsigned int opc; struct isup_call *call; /* Backward call indicator */ unsigned char called_party_status_ind; } ss7_event_acm; typedef struct { int e; int startcic; int endcic; int type; unsigned int opc; unsigned char status[255]; } ss7_event_cicrange; typedef struct { int e; int cic; int passed; unsigned int opc; struct isup_call *call; } ss7_event_cot; typedef struct { int e; unsigned int data; } ss7_event_generic; typedef struct { int e; int cic; unsigned int opc; unsigned char event; } ss7_event_cpg; typedef struct { int e; int cic; unsigned int call_ref_ident; unsigned int call_ref_pc; unsigned int opc; struct isup_call *call; } ss7_event_faa; typedef struct { int e; int cic; unsigned int call_ref_ident; unsigned int call_ref_pc; unsigned int opc; struct isup_call *call; } ss7_event_far; typedef union { int e; ss7_event_generic gen; ss7_event_iam iam; ss7_event_cicrange grs; ss7_event_cicrange cqm; ss7_event_cicrange gra; ss7_event_cicrange cgb; ss7_event_cicrange cgu; ss7_event_cicrange cgba; ss7_event_cicrange cgua; ss7_event_rel rel; ss7_event_ciconly rlc; ss7_event_anm anm; ss7_event_acm acm; ss7_event_faa faa; ss7_event_far far; ss7_event_con con; ss7_event_cot cot; ss7_event_ciconly ccr; ss7_event_ciconly cvt; ss7_event_ciconly blo; ss7_event_ciconly ubl; ss7_event_ciconly bla; ss7_event_ciconly uba; ss7_event_ciconly ucic; ss7_event_rsc rsc; ss7_event_cpg cpg; ss7_event_ciconly lpa; } ss7_event; void ss7_set_message(void (*func)(struct ss7 *ss7, char *message)); void ss7_set_error(void (*func)(struct ss7 *ss7, char *message)); void ss7_set_debug(struct ss7 *ss7, unsigned int flags); /* SS7 Link control related functions */ int ss7_schedule_run(struct ss7 *ss7); struct timeval *ss7_schedule_next(struct ss7 *ss7); int ss7_add_link(struct ss7 *ss7, int transport, int fd); int ss7_set_adjpc(struct ss7 *ss7, int fd, unsigned int pc); int ss7_set_network_ind(struct ss7 *ss7, int ni); int ss7_set_pc(struct ss7 *ss7, unsigned int pc); int ss7_set_default_dpc(struct ss7 *ss7, unsigned int pc); struct ss7 *ss7_new(int switchtype); ss7_event *ss7_check_event(struct ss7 *ss7); int ss7_start(struct ss7 *ss7); int ss7_read(struct ss7 *ss7, int fd); int ss7_write(struct ss7 *ss7, int fd); void ss7_link_alarm(struct ss7 *ss7, int fd); void ss7_link_noalarm(struct ss7 *ss7, int fd); char * ss7_event2str(int event); const char *ss7_get_version(void); int ss7_pollflags(struct ss7 *ss7, int fd); /* ISUP call related message functions */ /* Send an IAM */ int isup_iam(struct ss7 *ss7, struct isup_call *c); int isup_anm(struct ss7 *ss7, struct isup_call *c); int isup_con(struct ss7 *ss7, struct isup_call *c); struct isup_call * isup_new_call(struct ss7 *ss7); int isup_acm(struct ss7 *ss7, struct isup_call *c); int isup_faa(struct ss7 *ss7, struct isup_call *c); int isup_far(struct ss7 *ss7, struct isup_call *c); int isup_rel(struct ss7 *ss7, struct isup_call *c, int cause); int isup_rlc(struct ss7 *ss7, struct isup_call *c); int isup_cpg(struct ss7 *ss7, struct isup_call *c, int event); int isup_lpa(struct ss7 *ss7, int cic, unsigned int dpc); int isup_gra(struct ss7 *ss7, int begincic, int endcic, unsigned int dpc); int isup_grs(struct ss7 *ss7, int begincic, int endcic, unsigned int dpc); int isup_cgb(struct ss7 *ss7, int begincic, int endcic, unsigned int dpc, unsigned char state[], int type); int isup_cgu(struct ss7 *ss7, int begincic, int endcic, unsigned int dpc, unsigned char state[], int type); int isup_cgba(struct ss7 *ss7, int begincic, int endcic, unsigned int dpc, unsigned char state[], int type); int isup_cgua(struct ss7 *ss7, int begincic, int endcic, unsigned int dpc, unsigned char state[], int type); int isup_blo(struct ss7 *ss7, int cic, unsigned int dpc); int isup_ubl(struct ss7 *ss7, int cic, unsigned int dpc); int isup_ccr(struct ss7 *ss7, int cic, unsigned int dpc); int isup_bla(struct ss7 *ss7, int cic, unsigned int dpc); int isup_ucic(struct ss7 *ss7, int cic, unsigned int dpc); int isup_uba(struct ss7 *ss7, int cic, unsigned int dpc); int isup_rsc(struct ss7 *ss7, int cic, unsigned int dpc); int isup_cvr(struct ss7 *ss7, int cic, unsigned int dpc); int isup_cqr(struct ss7 *ss7, int begincic, int endcic, unsigned int dpc, unsigned char status[]); /* Various call related sets */ void isup_init_call(struct ss7 *ss7, struct isup_call *c, int cic, unsigned int dpc); void isup_set_call_dpc(struct isup_call *c, unsigned int dpc); void isup_set_called(struct isup_call *c, const char *called, unsigned char called_nai, const struct ss7 *ss7); void isup_set_calling(struct isup_call *c, const char *calling, unsigned char calling_nai, unsigned char presentation_ind, unsigned char screening_ind); void isup_set_charge(struct isup_call *c, const char *charge, unsigned char charge_nai, unsigned char charge_num_plan); void isup_set_oli(struct isup_call *c, int oli_ani2); void isup_set_gen_address(struct isup_call *c, const char *gen_number, unsigned char gen_add_nai, unsigned char gen_pres_ind, unsigned char gen_num_plan, unsigned char gen_add_type); void isup_set_gen_digits(struct isup_call *c, const char *gen_number, unsigned char gen_dig_type, unsigned char gen_dig_scheme); enum { GEN_NAME_PRES_ALLOWED = 0, GEN_NAME_PRES_RESTRICTED = 1, GEN_NAME_PRES_BLOCKING_TOGGLE = 2, GEN_NAME_PRES_NO_INDICATION = 3, }; enum { GEN_NAME_AVAIL_AVAILABLE = 0, GEN_NAME_AVAIL_NOT_AVAILABLE = 1 }; enum { GEN_NAME_TYPE_CALLING_NAME = 1, GEN_NAME_TYPE_ORIG_CALLED_NAME = 2, GEN_NAME_TYPE_REDIRECTING_NAME = 3, GEN_NAME_TYPE_CONNECTED_NAME = 4, }; void isup_set_generic_name(struct isup_call *c, const char *generic_name, unsigned int typeofname, unsigned int availability, unsigned int presentation); void isup_set_jip_digits(struct isup_call *c, const char *jip_number); void isup_set_lspi(struct isup_call *c, const char *lspi_ident, unsigned char lspi_type, unsigned char lspi_scheme, unsigned char lspi_context); void isup_set_callref(struct isup_call *c, unsigned int call_ref_ident, unsigned int call_ref_pc); /* End of call related sets */ #endif /* _LIBSS7_H */ libss7-1.0.2/README0000644000000000000000000001641411060526271012301 0ustar rootrootlibss7: ======= libss7 is a userspace library that is used for providing SS7 protocol services to applications. It has a working MTP2, MTP3, and ISUP for ITU and ANSI style SS7, however it was written in a manner that will easily allow support for other various national specific variants in the future. For a working reference implementation, see the various link test programs, as well as the Asterisk Open Source PBX. License: ======== libss7 is covered under the GPL (Gnu Public License) version 2. For more information, see http://www.gnu.org/ A few tested switches: ====================== Siemens EWSD - (ITU style) MTP2 and MTP3 comes up, ISUP inbound and outbound calls work as well. DTI DXC 4K - (ANSI style) 56kbps link, MTP2 and MTP3 come up, ISUP inbound and outbound calls work as well. Huawei M800 - (ITU style) MTP2 and MTP3 comes up, ISUP National, International inbound and outbound calls work as well, CallerID presentation&screening work. and many more... Some carriers integrated with: ============================== T-Systems Germany Etel COLT Thanks to: ========== Mark Spencer, for writing Asterisk and libpri and being such a great friend and boss. Luciano Ramos, for donating a link in getting the first "real" ITU switch working. Collin Rose and John Lodden, John for introducing me to Collin, and Collin for the first "real" ANSI link and for holding my hand through the remaining changes that had to be done for ANSI switches. Alan McMillan for numerous ANSI related updates, changes, testing, and additional parameter support. To Use: ======= In order to use libss7, you must get at least the following versions of DAHDI and Asterisk: DAHDI: 2.0.x libss7: 1.0.x or trunk Asterisk: 1.6.x You must then do a `make; make install` in each of the directories that you installed in the given order (DAHDI first, libss7 second, and Asterisk last). NOTE: In order to check out the code, you must have the subversion client installed. This is how to check them out from the public subversion server. These are the commands you would type to install them: `svn co http://svn.digium.com/svn/dahdi/linux/trunk dahdi-trunk` `cd dahdi-trunk` `make; make install` `svn co http://svn.digium.com/svn/dahdi/tools/trunk dahdi-tools` `cd dahdi-tools` `./configure; make; make install` `svn co http://svn.digium.com/svn/libss7/trunk libss7-trunk` `cd libss7-trunk` `make; make install` `svn co http://svn.digium.com/svn/asterisk/branches/1.6.0 asterisk-1.6.0` `cd asterisk-1.6.0` `./configure; make; make install;` This should build DAHDI, libss7, and Asterisk with SS7 support. In the past, there was a special asterisk-ss7 branch to use which contained the SS7 code. That code has been merged back into the trunk version of Asterisk, and the old asterisk-ss7 branch has been deprecated and removed. If you are still using the asterisk-ss7 branch, it will not work against the current version of libss7, and you should switch to asterisk-trunk instead. CONFIGURATION: In /etc/dahdi/system.conf, your signalling channel(s) should be a "mtp2" (or "dchan" with a non Digium card) and your bearers should be set as "bchan". For example: span=1,1,0,esf,b8zs bchan=1-15,17-31 mtp2=16 #dchan=16 for non Digium cards NOTE: For 56k ANSI links, you must additionally set in /etc/dahdi/system.conf "56k=[channel number]" where 56k is like a flag for the mtp2 or dchan. For example: span=1,1,0,esf,b8zs bchan=1-23 mtp2=24 56k=24 In the sample config file in Asterisk-1.6, there is a sample SS7 setup which you can use to configured your link. In brief, here is a simple ss7 linkset setup: chan_dahdi.conf =========== signalling = ss7 ss7type = itu ; or ansi if you are using an ANSI link linkset = 1 ; Pick a number for your linkset identifier in chan_dahdi.conf pointcode = 28 ; The decimal form of your point code. If you are using an ; ANSI linkset, you can use the xxx-xxx-xxx notation for ; specifying your linkset pointcode. adjpointcode = 2 ; The point code of the switch adjacent to your linkset defaultdpc = 3 ; The point code of the switch you want to send your ISUP ; traffic to. A lot of the time, this is the same as your ; adjpointcode. ; Now we configure our Bearer channels (CICs) cicbeginswith = 1 ; Number to start counting the CICs from. So if DAHDI/1 to ; DAHDI/15 are CICs 1-15, you would set this to 1 before you ; declare channel=1-15 channel=1-15 ; Use DAHDI/1-15 and assign them to CICs 1-15 cicbeginswith = 17 ; Now for DAHDI/17 to DAHDI/31, they are CICs 17-31 so we initialize ; cicbeginswith to 17 before we declare those channels channel = 17-31 ; This assigns CICs 17-31 to channels 17-31 sigchan = 16 ; This is where you declare which DAHDI channel is your signalling ; channel. In our case it is DAHDI/16. You can add redundant ; signalling channels by adding additional sigchan= lines. ; If we want an alternate redundant signalling channel add this sigchan = 48 ; This would put two signalling channels in our linkset, one at ; DAHDI/16 and one at DAHDI/48 which both would be used to send/receive ; ISUP traffic. ; End of chan_dahdi.conf This is how a basic linkset is setup. For more detailed chan_dahdi.conf SS7 config information as well as other options available for that file, see the default chan_dahdi.conf that comes with the samples in asterisk. If you would like, you can do a `make samples` in your asterisk directory and it will install a sample chan_dahdi.conf for you that contains more information about SS7 setup. Asterisk channel variables which map to SS7 parameters: ======================================================= SS7_CHARGE_NUMBER SS7_GENERIC_ADDRESS SS7_JIP SS7_GENERIC_DIGITS SS7_GENERIC_DIGTYPE (type of generic digits) SS7_GENERIC_DIGSCHEME SS7_ORIG_CALLED_NUM SS7_LSPI_IDENT (these three are used for RLT support on DMS switches) SS7_CALLREF_IDENT SS7_CALLREF_PC SS7_CALLING_PARTY_CATEGORY SS7_REDIRECTING_NUMBER SS7_GENERIC_NAME Most are fairly self explanatory as far as what they contain. It is also possible to set many of these parameters on outbound calls as well by prefixing the variable with an '_' when you set it. Completed: ========== MTP2 - Retransmissions are done correctly now from both sides. Basic MTP3 Basic call messages (IAM, ACM, ANM, REL, RLC) CIC Reset (GRS, GRA, RSC) Connect message (CON) CIC Blocking/Unblocking (CGB, CGBA, CGU, CGUA, BLO, BLA) Continuity Check (COT, CCR) Call Progress message (CPG) ANSI MTP2, MTP3, and ISUP, inbound and outbound calling works now. ITU style SS7 support ANSI-style signalling support Called and Calling Nature of Address Indicator CallerID presentation&screening UCIC and LPA messages ANI2 - Originating line interface parameter (ANSI) Charge number parameter (ANSI) Hop counter parameter Carrier identification parameter - (very simple, not configurable) SS7 debug looks *MUCH* nicer Kernel level MTP2 support (woohoo!) - See NEWS-05-30-2008 for more info * Many more messages are supported than are listed. isup.c is the best place to look. TODO: ===== short term: SUS/RES RDNIS Timer for last SU received so we know if layer2 goes out under us long term: SCTP support (seems more people are interested in that than SCCP) For more information, please use the Asterisk-ss7 or Asterisk-dev mailing lists (I monitor them regularly) or email me directly. Matthew Fredrickson creslin@digium.com libss7-1.0.2/ss7.c0000644000000000000000000001572211046151741012302 0ustar rootroot/* * libss7: An implementation of Signalling System 7 * * Written by Matthew Fredrickson * * scheduling routines taken from libpri by Mark Spencer * * Copyright (C) 2006-2008, Digium, Inc * All Rights Reserved. */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. * * In addition, when this program is distributed with Asterisk in * any form that would qualify as a 'combined work' or as a * 'derivative work' (but not mere aggregation), you can redistribute * and/or modify the combination under the terms of the license * provided with that copy of Asterisk, instead of the license * terms granted here. */ #include #include #include #include #include #include #include "libss7.h" #include "ss7_internal.h" #include "mtp2.h" #include "isup.h" #include "mtp3.h" static void (*__ss7_message)(struct ss7 *ss7, char *message); static void (*__ss7_error)(struct ss7 *ss7, char *message); void ss7_set_message(void (*func)(struct ss7 *ss7, char *message)) { __ss7_message = func; } void ss7_set_error(void (*func)(struct ss7 *ss7, char *message)) { __ss7_error = func; } void ss7_message(struct ss7 *ss7, char *fmt, ...) { char tmp[1024]; va_list ap; va_start(ap, fmt); vsnprintf(tmp, sizeof(tmp), fmt, ap); va_end(ap); if (__ss7_message) __ss7_message(ss7, tmp); else fputs(tmp, stdout); } void ss7_error(struct ss7 *ss7, char *fmt, ...) { char tmp[1024]; va_list ap; va_start(ap, fmt); vsnprintf(tmp, sizeof(tmp), fmt, ap); va_end(ap); if (__ss7_error) __ss7_error(ss7, tmp); else fputs(tmp, stdout); } void ss7_set_debug(struct ss7 *ss7, unsigned int flags) { ss7->debug = flags; } void ss7_dump_buf(struct ss7 *ss7, int tabs, unsigned char *buf, int len) { int i, j = 0; char tmp[1024]; for (i = 0; i < tabs; i++) snprintf(&tmp[i], sizeof(tmp)-i, "\t"); snprintf(&tmp[i], sizeof(tmp)-i, "[ "); j = i + 2; /* some TAB + "[ " */ for (i = 0; i < len; i++) { snprintf(&tmp[3*i]+j, sizeof(tmp)-3*i-j, "%02x ", buf[i]); /* &tmp[3*i]+j - for speed optimization, don't change format! */ } ss7_message(ss7, "%s]\n", tmp); } void ss7_dump_msg(struct ss7 *ss7, unsigned char *buf, int len) { int i; char tmp[1024]; for (i = 0; i < len; i++) { snprintf(&tmp[3*i], sizeof(tmp)-3*i, "%02x ", buf[i]); /* &tmp[3*i] - for speed optimization, don't change format! */ } ss7_message(ss7, "Len = %d [ %s]\n", len, tmp); } void ss7_msg_free(struct ss7_msg *m) { free(m); } struct ss7_msg * ss7_msg_new(void) { return calloc(1, sizeof(struct ss7_msg)); } unsigned char * ss7_msg_userpart(struct ss7_msg *msg) { return msg->buf + MTP2_SIZE + SIO_SIZE; } void ss7_msg_userpart_len(struct ss7_msg *msg, int len) { msg->size = MTP2_SIZE + SIO_SIZE + len; return; } ss7_event * ss7_next_empty_event(struct ss7 *ss7) { ss7_event *e; if (ss7->ev_len == MAX_EVENTS) { ss7_error(ss7, "Event queue full!\n"); return NULL; } e = &ss7->ev_q[(ss7->ev_h + ss7->ev_len) % MAX_EVENTS]; ss7->ev_len += 1; return e; } ss7_event * ss7_check_event(struct ss7 *ss7) { ss7_event *e; if (!ss7->ev_len) return NULL; else e = &ss7->ev_q[ss7->ev_h]; ss7->ev_h += 1; ss7->ev_h %= MAX_EVENTS; ss7->ev_len -= 1; return mtp3_process_event(ss7, e); } int ss7_start(struct ss7 *ss7) { mtp3_start(ss7); return 0; } void ss7_link_alarm(struct ss7 *ss7, int fd) { mtp3_alarm(ss7, fd); } void ss7_link_noalarm(struct ss7 *ss7, int fd) { mtp3_noalarm(ss7, fd); } int ss7_add_link(struct ss7 *ss7, int transport, int fd) { struct mtp2 *m; if (ss7->numlinks >= SS7_MAX_LINKS) return -1; if (transport == SS7_TRANSPORT_TCP) { } if ((transport == SS7_TRANSPORT_DAHDIDCHAN) || (transport == SS7_TRANSPORT_DAHDIMTP2)) { int zapmtp2 = 0; if (transport == SS7_TRANSPORT_DAHDIMTP2) zapmtp2 = 1; m = mtp2_new(fd, ss7->switchtype); if (!m) return -1; m->slc = ss7->numlinks; ss7->numlinks += 1; m->master = ss7; if (zapmtp2) m->flags |= MTP2_FLAG_ZAPMTP2; ss7->links[ss7->numlinks - 1] = m; } return 0; } int ss7_pollflags(struct ss7 *ss7, int fd) { int i; int winner = -1; int flags = POLLPRI | POLLIN; for (i = 0; i < ss7->numlinks; i++) { if (ss7->links[i]->fd == fd) { winner = i; break; } } if (winner < 0) return -1; if (ss7->links[winner]->flags & MTP2_FLAG_ZAPMTP2) { if (ss7->links[winner]->flags & MTP2_FLAG_WRITE) flags |= POLLOUT; } else flags |= POLLOUT; return flags; } /* TODO: Add entry to routing table instead */ int ss7_set_adjpc(struct ss7 *ss7, int fd, unsigned int pc) { int i; int winner = -1; for (i = 0; i < ss7->numlinks; i++) { if (ss7->links[i]->fd == fd) winner = i; } if (winner > -1) ss7->links[winner]->dpc = pc; else return -1; return 0; } int ss7_set_pc(struct ss7 *ss7, unsigned int pc) { ss7->pc = pc; return 0; } int ss7_set_network_ind(struct ss7 *ss7, int ni) { ss7->ni = ni; return 0; } char * ss7_event2str(int event) { switch (event) { case SS7_EVENT_UP: return "SS7_EVENT_UP"; case SS7_EVENT_DOWN: return "SS7_EVENT_DOWN"; case ISUP_EVENT_IAM: return "ISUP_EVENT_IAM"; case ISUP_EVENT_ACM: return "ISUP_EVENT_ACM"; case ISUP_EVENT_ANM: return "ISUP_EVENT_ANM"; case ISUP_EVENT_REL: return "ISUP_EVENT_REL"; case ISUP_EVENT_RLC: return "ISUP_EVENT_RLC"; case ISUP_EVENT_GRS: return "ISUP_EVENT_GRS"; case ISUP_EVENT_GRA: return "ISUP_EVENT_GRA"; case ISUP_EVENT_CON: return "ISUP_EVENT_CON"; default: return "Unknown Event"; } } struct ss7 *ss7_new(int switchtype) { struct ss7 *s; s = calloc(1, sizeof(struct ss7)); if (!s) return NULL; /* Initialize the event queue */ s->ev_h = 0; s->ev_len = 0; s->state = SS7_STATE_DOWN; if ((switchtype == SS7_ITU) || (switchtype == SS7_ANSI)) s->switchtype = switchtype; else { free(s); return NULL; } return s; } int ss7_write(struct ss7 *ss7, int fd) { int res, i, winner = -1; for (i = 0; i < ss7->numlinks; i++) { if (ss7->links[i]->fd == fd) { winner = i; break; } } if (winner < 0) return -1; res = mtp2_transmit(ss7->links[winner]); return res; } int ss7_read(struct ss7 *ss7, int fd) { unsigned char buf[1024]; int res; int winner = -1; int i; for (i = 0; i < ss7->numlinks; i++) { if (ss7->links[i]->fd == fd) { winner = i; break; } } if (winner < 0) return -1; res = read(ss7->links[winner]->fd, buf, sizeof(buf)); if (res <= 0) { return res; } res = mtp2_receive(ss7->links[winner], buf, res); return res; } libss7-1.0.2/ss7test.c0000644000000000000000000001264011046151741013176 0ustar rootroot/* * libss7: An implementation of Signalling System 7 * * Written by Matthew Fredrickson * * scheduling routines taken from libpri by Mark Spencer * * Copyright (C) 2006-2008, Digium, Inc * All Rights Reserved. */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. * * In addition, when this program is distributed with Asterisk in * any form that would qualify as a 'combined work' or as a * 'derivative work' (but not mere aggregation), you can redistribute * and/or modify the combination under the terms of the license * provided with that copy of Asterisk, instead of the license * terms granted here. */ #include #include #include #include #include #include #include #include #include #include #include #include "libss7.h" struct linkset { struct ss7 *ss7; int linkno; int fd; } linkset[2]; int linknum = 1; #define NUM_BUFS 32 void *ss7_run(void *data) { int res = 0; unsigned char readbuf[512] = ""; struct timeval *next = NULL, tv; struct linkset *linkset = (struct linkset *) data; struct ss7 *ss7 = linkset->ss7; int ourlink = linknum; ss7_event *e = NULL; fd_set rfds; fd_set wfds; fd_set efds; printf("Starting link %d\n", linknum++); ss7_start(ss7); while(1) { if ((next = ss7_schedule_next(ss7))) { gettimeofday(&tv, NULL); tv.tv_sec = next->tv_sec - tv.tv_sec; tv.tv_usec = next->tv_usec - tv.tv_usec; if (tv.tv_usec < 0) { tv.tv_usec += 1000000; tv.tv_sec -= 1; } if (tv.tv_sec < 0) { tv.tv_sec = 0; tv.tv_usec = 0; } } FD_ZERO(&rfds); FD_SET(linkset->fd, &rfds); FD_ZERO(&wfds); FD_SET(linkset->fd, &wfds); FD_ZERO(&efds); FD_SET(linkset->fd, &efds); res = select(linkset->fd + 1, &rfds, &wfds, &efds, next ? &tv : NULL); if (res < 0) { printf("next->tv_sec = %d\n", next->tv_sec); printf("next->tv_usec = %d\n", next->tv_usec); printf("tv->tv_sec = %d\n", tv.tv_sec); printf("tv->tv_usec = %d\n", tv.tv_usec); perror("select"); } else if (!res) ss7_schedule_run(ss7); #if LINUX if (FD_ISSET(linkset->fd, &efds)) { int x; if (ioctl(linkset->fd, DAHDI_GETEVENT, &x)) { perror("Error in exception retrieval!\n"); exit(-1); } printf("Got exception %d!\n", x); } #endif if (FD_ISSET(linkset->fd, &rfds)) res = ss7_read(ss7, linkset->fd); if (FD_ISSET(linkset->fd, &wfds)) { res = ss7_write(ss7, linkset->fd); if (res < 0) { perror("Error in write"); } } if (res < 0) exit(-1); while ((e = ss7_check_event(ss7))) { if (e) { switch (e->e) { case SS7_EVENT_UP: printf("[%d] --- SS7 Up ---\n", linkset->linkno); break; case MTP2_LINK_UP: printf("[%d] MTP2 link up\n", linkset->linkno); break; default: printf("Unknown event %d\n", e->e); break; } } } if (ourlink == 1) { /* Our demo call */ } } } void myprintf(struct ss7 *ss7, char *fmt) { int i = 0; for (i = 0; i < 2; i++) { if (linkset[i].ss7 == ss7) break; } if (i == 0) printf("SS7[%d] %s", i, fmt); else printf("\t\t\t\t\tSS7[%d] %s", i, fmt); } #ifdef LINUX int zap_open(int devnum) { int fd; struct dahdi_bufferinfo bi; fd = open("/dev/dahdi/channel", O_RDWR|O_NONBLOCK, 0600); if ((fd < 0) || (ioctl(fd, DAHDI_SPECIFY, &devnum) == -1)) { printf("Could not open device %d: %s\n", strerror(errno)); return -1; } bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE; bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE; bi.numbufs = NUM_BUFS; bi.bufsize = 512; if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) { close(fd); return -1; } return fd; } #endif int main(int argc, char *argv[]) { int fds[2]; struct ss7 *ss7; pthread_t tmp, tmp2; if (argc == 2) { if (!strcasecmp(argv[1], "socketpair")) { if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds)) { perror("socketpair"); exit(1); } #ifdef LINUX } else if (!strcasecmp(argv[1], "live")) { fds[0] = zap_open(24); if (fds[0] < 0) return -1; fds[1] = zap_open(48); if (fds[1] < 0) return -1; #endif } else return -1; } else return -1; if (!(ss7 = ss7_new(SS7_ITU))) { perror("ss7_new"); exit(1); } linkset[0].ss7 = ss7; linkset[0].fd = fds[0]; linkset[0].linkno = 0; ss7_set_message(myprintf); ss7_set_error(myprintf); ss7_set_debug(ss7, 0xffffffff); if ((ss7_add_link(ss7, SS7_TRANSPORT_DAHDIDCHAN, fds[0]))) { perror("ss7_add_link"); exit(1); } if (pthread_create(&tmp, NULL, ss7_run, &linkset[0])) { perror("thread(0)"); exit(1); } if (!(ss7 = ss7_new(SS7_ITU))) { perror("ss7_new"); exit(1); } ss7_set_debug(ss7, 0xffffffff); linkset[1].linkno = 1; if ((ss7_add_link(ss7, SS7_TRANSPORT_DAHDIDCHAN, fds[1]))) { perror("ss7_add_link"); exit(1); } linkset[1].ss7 = ss7; linkset[1].fd = fds[1]; if (pthread_create(&tmp2, NULL, ss7_run, &linkset[1])) { perror("thread(0)"); exit(1); } pthread_join(tmp, NULL); pthread_join(tmp2, NULL); return 0; } libss7-1.0.2/ss7_internal.h0000644000000000000000000000612711046151741014202 0ustar rootroot/* * libss7: An implementation of Signalling System 7 * * Written by Matthew Fredrickson * * scheduling routines taken from libpri by Mark Spencer * * Copyright (C) 2006-2008, Digium, Inc * All Rights Reserved. */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. * * In addition, when this program is distributed with Asterisk in * any form that would qualify as a 'combined work' or as a * 'derivative work' (but not mere aggregation), you can redistribute * and/or modify the combination under the terms of the license * provided with that copy of Asterisk, instead of the license * terms granted here. */ #ifndef _SS7_H #define _SS7_H #include #include #include "libss7.h" /* #include "mtp2.h" */ /* #include "mtp3.h" */ /* ISUP parameters */ /* Information Transfer Capability */ #define ISUP_TRANSCAP_SPEECH 0x00 #define ISUP_TRANSCAP_UNRESTRICTED_DIGITAL 0x08 #define ISUP_TRANSCAP_RESTRICTED_DIGITAL 0x09 #define ISUP_TRANSCAP_31KHZ_AUDIO 0x10 #define ISUP_TRANSCAP_7KHZ_AUDIO 0x11 /* User Information layer 1 protocol types */ #define ISUP_L1PROT_G711ULAW 0x02 #define MAX_EVENTS 16 #define MAX_SCHED 64 #define SS7_MAX_LINKS 4 #define SS7_STATE_DOWN 0 #define SS7_STATE_UP 1 typedef unsigned int point_code; struct routing_label { unsigned int type; point_code dpc; point_code opc; unsigned char sls; }; struct ss7_msg { unsigned char buf[512]; unsigned int size; struct ss7_msg *next; }; struct ss7_sched { struct timeval when; void (*callback)(void *data); void *data; }; struct ss7 { unsigned int switchtype; unsigned int numlinks; /* Our point code */ point_code pc; unsigned char ni; unsigned char sls; int state; unsigned int debug; /* event queue */ int ev_h; int ev_t; int ev_len; ss7_event ev_q[MAX_EVENTS]; struct ss7_sched ss7_sched[MAX_SCHED]; struct isup_call *calls; unsigned int mtp2_linkstate[SS7_MAX_LINKS]; struct mtp2 *links[SS7_MAX_LINKS]; }; /* Getto hacks for developmental purposes */ struct ss7_msg * ss7_msg_new(void); void ss7_msg_free(struct ss7_msg *m); /* Scheduler functions */ int ss7_schedule_event(struct ss7 *ss7, int ms, void (*function)(void *data), void *data); ss7_event * ss7_next_empty_event(struct ss7 * ss7); void ss7_schedule_del(struct ss7 *ss7,int *id); unsigned char *ss7_msg_userpart(struct ss7_msg *m); void ss7_msg_userpart_len(struct ss7_msg *m, int len); void ss7_message(struct ss7 *ss7, char *fmt, ...); void ss7_error(struct ss7 *ss7, char *fmt, ...); void ss7_dump_buf(struct ss7 *ss7, int tabs, unsigned char *buf, int len); void ss7_dump_msg(struct ss7 *ss7, unsigned char *buf, int len); #endif /* _SS7_H */ libss7-1.0.2/isup.c0000644000000000000000000023675311047345677012575 0ustar rootroot/* * libss7: An implementation of Signalling System 7 * * Written by Matthew Fredrickson * * scheduling routines taken from libpri by Mark Spencer * * Copyright (C) 2006-2008, Digium, Inc * All Rights Reserved. */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. * * In addition, when this program is distributed with Asterisk in * any form that would qualify as a 'combined work' or as a * 'derivative work' (but not mere aggregation), you can redistribute * and/or modify the combination under the terms of the license * provided with that copy of Asterisk, instead of the license * terms granted here. */ #include #include #include "libss7.h" #include "isup.h" #include "ss7_internal.h" #include "mtp3.h" #define FUNC_DUMP(name) int ((name))(struct ss7 *ss7, int messagetype, unsigned char *parm, int len) /* Length here is paramter length */ #define FUNC_RECV(name) int ((name))(struct ss7 *ss7, struct isup_call *c, int messagetype, unsigned char *parm, int len) /* Length here is maximum length */ #define FUNC_SEND(name) int ((name))(struct ss7 *ss7, struct isup_call *c, int messagetype, unsigned char *parm, int len) #define PARM_TYPE_FIXED 0x01 #define PARM_TYPE_VARIABLE 0x02 #define PARM_TYPE_OPTIONAL 0x03 #define CODE_CCITT 0x0 #define LOC_PRIV_NET_LOCAL_USER 0x1 struct parm_func { int parm; char *name; FUNC_DUMP(*dump); FUNC_RECV(*receive); FUNC_SEND(*transmit); }; static int iam_params[] = {ISUP_PARM_NATURE_OF_CONNECTION_IND, ISUP_PARM_FORWARD_CALL_IND, ISUP_PARM_CALLING_PARTY_CAT, ISUP_PARM_TRANSMISSION_MEDIUM_REQS, ISUP_PARM_CALLED_PARTY_NUM, ISUP_PARM_CALLING_PARTY_NUM, -1}; static int ansi_iam_params[] = {ISUP_PARM_NATURE_OF_CONNECTION_IND, ISUP_PARM_FORWARD_CALL_IND, ISUP_PARM_CALLING_PARTY_CAT, ISUP_PARM_USER_SERVICE_INFO, ISUP_PARM_CALLED_PARTY_NUM, ISUP_PARM_CALLING_PARTY_NUM, ISUP_PARM_CHARGE_NUMBER, ISUP_PARM_ORIG_LINE_INFO, ISUP_PARM_GENERIC_ADDR, ISUP_PARM_GENERIC_DIGITS, ISUP_PARM_GENERIC_NAME, ISUP_PARM_JIP, ISUP_PARM_LOCAL_SERVICE_PROVIDER_IDENTIFICATION, -1}; static int acm_params[] = {ISUP_PARM_BACKWARD_CALL_IND, -1}; static int faa_params[] = {ISUP_PARM_FACILITY_IND, ISUP_PARM_CALL_REF, -1}; static int far_params[] = {ISUP_PARM_FACILITY_IND, ISUP_PARM_CALL_REF, -1}; static int anm_params[] = { -1}; static int con_params[] = { ISUP_PARM_BACKWARD_CALL_IND, -1}; static int rel_params[] = { ISUP_PARM_CAUSE, -1}; static int greset_params[] = { ISUP_PARM_RANGE_AND_STATUS, -1}; static int cot_params[] = { ISUP_PARM_CONTINUITY_IND, -1}; static int cpg_params[] = { ISUP_PARM_EVENT_INFO, -1}; static int cicgroup_params[] = { ISUP_PARM_CIRCUIT_GROUP_SUPERVISION_IND, ISUP_PARM_RANGE_AND_STATUS, -1}; static int cqr_params[] = { ISUP_PARM_RANGE_AND_STATUS, ISUP_PARM_CIRCUIT_STATE_IND, -1}; static int empty_params[] = { -1}; static struct message_data { int messagetype; int mand_fixed_params; int mand_var_params; int opt_params; int *param_list; } messages[] = { {ISUP_IAM, 4, 1, 1, iam_params}, {ISUP_ACM, 1, 0, 1, acm_params}, {ISUP_ANM, 0, 0, 1, anm_params}, {ISUP_CON, 1, 0, 1, con_params}, {ISUP_REL, 0, 1, 1, rel_params}, {ISUP_RLC, 0, 0, 1, empty_params}, {ISUP_GRS, 0, 1, 0, greset_params}, {ISUP_GRA, 0, 1, 0, greset_params}, {ISUP_CGB, 1, 1, 0, cicgroup_params}, {ISUP_CGU, 1, 1, 0, cicgroup_params}, {ISUP_CGBA, 1, 1, 0, cicgroup_params}, {ISUP_CGUA, 1, 1, 0, cicgroup_params}, {ISUP_COT, 1, 0, 0, cot_params}, {ISUP_CCR, 0, 0, 0, empty_params}, {ISUP_BLO, 0, 0, 0, empty_params}, {ISUP_LPA, 0, 0, 0, empty_params}, {ISUP_UBL, 0, 0, 0, empty_params}, {ISUP_BLA, 0, 0, 0, empty_params}, {ISUP_UBA, 0, 0, 0, empty_params}, {ISUP_RSC, 0, 0, 0, empty_params}, {ISUP_CVR, 0, 0, 0, empty_params}, {ISUP_CVT, 0, 0, 0, empty_params}, {ISUP_CPG, 1, 0, 1, cpg_params}, {ISUP_UCIC, 0, 0, 0, empty_params}, {ISUP_CQM, 0, 1, 0, greset_params}, {ISUP_CQR, 0, 2, 0, cqr_params}, {ISUP_FAA, 1, 0, 1, faa_params}, {ISUP_FAR, 1, 0, 1, far_params}, {ISUP_CFN, 0, 1, 0, rel_params} }; static int isup_send_message(struct ss7 *ss7, struct isup_call *c, int messagetype, int parms[]); static char * message2str(unsigned char message) { switch (message) { case ISUP_IAM: return "IAM"; case ISUP_ACM: return "ACM"; case ISUP_ANM: return "ANM"; case ISUP_REL: return "REL"; case ISUP_RLC: return "RLC"; case ISUP_GRS: return "GRS"; case ISUP_GRA: return "GRA"; case ISUP_COT: return "COT"; case ISUP_CCR: return "CCR"; case ISUP_BLO: return "BLO"; case ISUP_UBL: return "UBL"; case ISUP_BLA: return "BLA"; case ISUP_UBA: return "UBA"; case ISUP_CGB: return "CGB"; case ISUP_CGU: return "CGU"; case ISUP_CGBA: return "CGBA"; case ISUP_CGUA: return "CGUA"; case ISUP_RSC: return "RSC"; case ISUP_CPG: return "CPG"; case ISUP_UCIC: return "UCIC"; case ISUP_LPA: return "LPA"; case ISUP_FAA: return "FAA"; case ISUP_FAR: return "FAR"; case ISUP_FRJ: return "FRJ"; case ISUP_CVT: return "CVT"; case ISUP_CVR: return "CVR"; case ISUP_CFN: return "CFN"; default: return "Unknown"; } } static char char2digit(char localchar) { switch (localchar) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case '#': return 0xf; default: return 0; } } static char digit2char(unsigned char digit) { switch (digit & 0xf) { case 0: return '0'; case 1: return '1'; case 2: return '2'; case 3: return '3'; case 4: return '4'; case 5: return '5'; case 6: return '6'; case 7: return '7'; case 8: return '8'; case 9: return '9'; case 15: return '#'; default: return 0; } } static void isup_dump_buffer(struct ss7 *ss7, unsigned char *data, int len) { int i; ss7_message(ss7, "["); for (i = 0; i < len; i++) { ss7_message(ss7, "0x%x ", data[i]); } ss7_message(ss7, "]\n"); } static void isup_get_number(char *dest, unsigned char *src, int srclen, int oddeven) { int i; if (oddeven < 2) { /* BCD odd or even */ for (i = 0; i < ((srclen * 2) - oddeven); i++) dest[i] = digit2char(src[i/2] >> ((i % 2) ? 4 : 0)); } else { /* oddeven = 2 for IA5 characters */ for (i = 0; i < srclen; i++) dest[i] = src[i]; } dest[i] = '\0'; } static void isup_put_generic(unsigned char *dest, char *src, int *len) { int i = 0; int numlen = strlen(src); *len = numlen; while (i < numlen) { dest[i] = (src[i]); i++; } } static void isup_put_number(unsigned char *dest, char *src, int *len, int *oddeven) { int i = 0; int numlen = strlen(src); if (numlen % 2) { *oddeven = 1; *len = numlen/2 + 1; } else { *oddeven = 0; *len = numlen/2; } while (i < numlen) { if (!(i % 2)) dest[i/2] |= char2digit(src[i]) & 0xf; else dest[i/2] |= (char2digit(src[i]) << 4) & 0xf0; i++; } } static FUNC_SEND(nature_of_connection_ind_transmit) { parm[0] = 0x00; if (c->cot_check_required) parm[0] |= 0x04; return 1; /* Length plus size of type header */ } static FUNC_RECV(nature_of_connection_ind_receive) { unsigned char cci = (parm[0] >> 2) & 0x3; if (cci == 0x1) c->cot_check_required = 1; else c->cot_check_required = 0; return 1; } static FUNC_DUMP(nature_of_connection_ind_dump) { unsigned char con = parm[0]; char *continuity; ss7_message(ss7, "\t\t\tSatellites in connection: %d\n", con&0x03); con>>=2; switch (con & 0x03) { case 0: continuity = "Check not required"; break; case 1: continuity = "Check required on this circuit"; break; case 2: continuity = "Check performed on a previous circuit"; break; case 3: continuity = "spare"; break; } ss7_message(ss7, "\t\t\tContinuity Check: %s (%d)\n", continuity, con & 0x3); con>>=2; con &= 0x01; ss7_message(ss7, "\t\t\tOutgoing half echo control device: %s (%d)\n", con ? "included" : "not included", con); return 1; } static FUNC_SEND(forward_call_ind_transmit) { parm[0] = 0x60; parm[1] = 0x01; return 2; } static FUNC_RECV(forward_call_ind_receive) { return 2; } static FUNC_DUMP(forward_call_ind_dump) { char *cb_str, *hg_str, *kj_str; switch ((parm[0] >> 1) & 3) { case 0: cb_str = "no end-to-end"; break; case 1: cb_str = "pass-along"; break; case 2: cb_str = "SCCP"; break; case 3: cb_str = "pass-along and SCCP"; break; } switch ((parm[0] >> 6) & 3) { case 0: hg_str = "ISDN user part preferred all the way"; break; case 1: hg_str = "ISDN user part not preferred all the way"; break; case 2: hg_str = "ISDN user part requried all the way"; break; case 3: hg_str = "spare"; break; } switch ((parm[1] >> 1) & 3) { case 0: kj_str = "no indication"; break; case 1: kj_str = "connectionless method available"; break; case 2: kj_str = "connection oriented method available"; break; case 3: kj_str = "connectionless and connection oriented method available"; break; } ss7_message(ss7, "\t\t\tNat/Intl Call Ind: call to be treated as a %s call (%d)\n", (parm[0] & 1) ? "international" : "national", parm[0] & 1); ss7_message(ss7, "\t\t\tEnd to End Method Ind: %s method(s) available (%d)\n", cb_str, (parm[0] >> 1) & 3); ss7_message(ss7, "\t\t\tInterworking Ind: %sinterworking encountered (%d)\n", ((parm[0] >> 3) & 1) ? "" : "no ", (parm[0] >> 3) & 1); ss7_message(ss7, "\t\t\tEnd to End Info Ind: %send-to-end information available (%d)\n", ((parm[0]>>4)&1) ? "" : "no ", (parm[0] >> 4) & 1); ss7_message(ss7, "\t\t\tISDN User Part Ind: ISDN user part %sused all the way (%d)\n", ((parm[0]>>5)&1) ? "" : "not ", (parm[0] >> 5) & 1); ss7_message(ss7, "\t\t\tISDN User Part Pref Ind: %s (%d)\n", hg_str, (parm[0] >> 6) & 3); ss7_message(ss7, "\t\t\tISDN Access Ind: originating access %s (%d)\n", (parm[1] & 1) ? "ISDN" : "non-ISDN", parm[1] & 1); ss7_message(ss7, "\t\t\tSCCP Method Ind: %s (%d)\n", kj_str, (parm[1] >> 1) & 3); return 2; } static FUNC_RECV(calling_party_cat_receive) { c->calling_party_cat = parm[0]; return 1; } static FUNC_SEND(calling_party_cat_transmit) { parm[0] = 0x0a; /* Default to Ordinary calling subscriber */ return 1; } static FUNC_DUMP(calling_party_cat_dump) { char *cattype; switch (parm[0]) { case 1: cattype = "Operator, French"; break; case 2: cattype = "Operator, English"; break; case 3: cattype = "Operator, German"; break; case 4: cattype = "Operator, Russian"; break; case 5: cattype = "Operator, Spanish"; break; case 9: cattype = "Reserved"; break; case 10: cattype = "Ordinary calling subscriber"; break; case 11: cattype = "Calling subscriber with priority"; break; case 12: cattype = "Data Call (voice band data)"; break; case 13: cattype = "Test Call"; break; case 15: cattype = "Payphone"; break; default: cattype = "Unknown"; break; } ss7_message(ss7, "\t\t\tCategory: %s (%d)\n", cattype, parm[0]); return 1; } static FUNC_RECV(user_service_info_receive) { /* NoOp it for now */ return len; } static FUNC_SEND(user_service_info_transmit) { /* Default to Coding standard CCITT / 3.1 khz Audio */ parm[0] = 0x90; /* Default to Circuit mode / 64kbps */ parm[1] = 0x90; /* User Layer 1 set to ulaw */ parm[2] = 0xa2; return 3; } static FUNC_SEND(transmission_medium_reqs_transmit) { if (ss7->switchtype != SS7_ITU) return 0; /* Speech */ parm[0] = 0; return 1; } static FUNC_RECV(transmission_medium_reqs_receive) { c->transcap = parm[0] & 0x7f; return 1; } static FUNC_DUMP(transmission_medium_reqs_dump) { char *type; switch (parm[0]) { case 0: type = "Speech"; break; case 1: type = "Spare"; break; case 2: type = "64 kbit/s unrestricted"; break; case 4: type = "3.1 khz audio"; break; case 6: type = "64 kbit/s preferred"; break; case 7: type = "2 x 64 kbit/s unrestricted"; break; case 8: type = "384 kbit/s unrestricted"; break; case 9: type = "1536 kbit/s unrestricted"; break; case 10: type = "1920 kbit/s unrestricted"; break; default: type = "N x 64kbit/s unrestricted or possibly spare"; break; } ss7_message(ss7, "\t\t\t%s (%d)\n", type, parm[0]); return 1; } static FUNC_DUMP(called_party_num_dump) { int oddeven = (parm[0] >> 7) & 0x1; char numbuf[64] = ""; ss7_message(ss7, "\t\t\tNature of address: %x\n", parm[0] & 0x7f); ss7_message(ss7, "\t\t\tNI: %x\n", (parm[1] >> 7) & 0x1); ss7_message(ss7, "\t\t\tNumbering plan: %x\n", (parm[1] >> 4) & 0x7); isup_get_number(numbuf, &parm[2], len - 2, oddeven); ss7_message(ss7, "\t\t\tAddress signals: %s\n", numbuf); return len; } /* For variable length parameters we pass in the length of the parameter */ static FUNC_RECV(called_party_num_receive) { int odd = 0; if (parm[0] & 0x80) odd = 1; isup_get_number(c->called_party_num, &parm[2], len - 2, odd); c->called_nai = parm[0] & 0x7f; /* Nature of Address Indicator */ return len; } static FUNC_SEND(called_party_num_transmit) { int numlen, oddeven; isup_put_number(&parm[2], c->called_party_num, &numlen, &oddeven); parm[0] = c->called_nai & 0x7f; /* Nature of Address Indicator */ if (oddeven) parm[0] |= 0x80; /* Odd number of digits */ parm[1] = 0x1 << 4; /* Assume E.164 ISDN numbering plan, called number complete */ return numlen + 2; } static FUNC_RECV(backward_call_ind_receive) { c->called_party_status_ind = (parm[0] >> 2) & 0x3; return 2; } static FUNC_SEND(backward_call_ind_transmit) { parm[0] = 0x40; parm[1] = 0x14; return 2; } static FUNC_DUMP(backward_call_ind_dump) { unsigned char ba = parm[0] & 0x3; unsigned char dc = (parm[0] >> 2) & 0x3; unsigned char fe = (parm[0] >> 4) & 0x3; unsigned char hg = (parm[0] >> 6) & 0x3; unsigned char i = parm[1] & 0x1; unsigned char j = (parm[1] >> 1) & 0x1; unsigned char k = (parm[1] >> 2) & 0x1; unsigned char l = (parm[1] >> 3) & 0x1; unsigned char m = (parm[1] >> 4) & 0x1; unsigned char n = (parm[1] >> 5) & 0x1; unsigned char pq = (parm[1] >> 7) & 0x3; ss7_message(ss7, "\t\t\tCharge indicator: %d\n", ba); ss7_message(ss7, "\t\t\tCalled party's status indicator: %d\n", dc); ss7_message(ss7, "\t\t\tCalled party's category indicator: %d\n", fe); ss7_message(ss7, "\t\t\tEnd to End method indicator: %d\n", hg); ss7_message(ss7, "\t\t\tInterworking indicator: %d\n", i); ss7_message(ss7, "\t\t\tEnd to End information indicator: %d\n", j); ss7_message(ss7, "\t\t\tISDN user part indicator: %d\n", k); ss7_message(ss7, "\t\t\tHolding indicator: %d\n", l); ss7_message(ss7, "\t\t\tISDN access indicator: %d\n", m); ss7_message(ss7, "\t\t\tEcho control device indicator: %d\n", n); ss7_message(ss7, "\t\t\tSCCP method indicator: %d\n", pq); return 2; } static FUNC_RECV(opt_backward_call_ind_receive) { return 1; } static FUNC_DUMP(opt_backward_call_ind_dump) { unsigned char a, b, c, d; a = parm[0] & 1; b = (parm[0] >> 1) & 1; c = (parm[0] >> 2) & 1; d = (parm[0] >> 3) & 1; ss7_message(ss7, "\t\t\tIn-band information indicator: %d\n", a); ss7_message(ss7, "\t\t\tCall diversion may occur indicator: %d\n", b); ss7_message(ss7, "\t\t\tSimple segmentation indicator: %d\n", c); ss7_message(ss7, "\t\t\tMLPP user indicator: %d\n", d); return 1; } static FUNC_RECV(cause_receive) { c->causeloc = parm[0] & 0xf; c->causecode = (parm[0] & 0x60) >> 5; c->cause = (parm[1] & 0x7f); return len; } static FUNC_SEND(cause_transmit) { parm[0] = 0x80 | (c->causecode << 5) | c->causeloc; parm[1] = 0x80 | c->cause; return 2; } static FUNC_DUMP(cause_dump) { char *cause; switch (parm[1] & 0x7f) { case 1: cause = "Unallocated (unassigned) number"; break; case 2: cause = "No route to specified transit network"; break; case 3: cause = "No route to destination"; break; case 4: cause = "Send special information tone"; break; case 5: cause = "Misdialled trunk prefix"; break; case 6: cause = "Channel unacceptable"; break; case 7: cause = "Call awarded and being delivered in an established channel"; break; case 8: cause = "Preemption"; break; case 9: cause = "Preemption - circuit reserved for reuse"; break; case 16: cause = "Normal call clearing"; break; case 17: cause = "User busy"; break; case 18: cause = "No user responding"; break; case 19: cause = "No answer from user (user alerted)"; break; case 20: cause = "Subscriber absent"; break; case 21: cause = "Call rejected"; break; case 22: cause = "Number changed"; break; case 23: cause = "Redirection to new destination"; break; case 25: cause = "Exchange routing error"; break; case 26: cause = "Non-selected user clearing"; break; case 27: cause = "Destination out of order"; break; case 28: cause = "Invalid number format (address incomplete)"; break; case 29: cause = "Facility rejected"; break; case 30: cause = "Response to STATUS ENQUIRY"; break; case 31: cause = "Normal, unspecified"; break; case 34: cause = "No circuit/channel available"; break; case 38: cause = "Network out of order"; break; case 39: cause = "Permanent frame mode connection out of service"; break; case 40: cause = "Permanent frame mode connection operational"; break; case 41: cause = "Temporary failure"; break; case 42: cause = "Switching equipment congestion"; break; /* TODO: Finish the rest of these */ default: cause = "Unknown"; } ss7_message(ss7, "\t\t\tCoding Standard: %d\n", (parm[0] >> 5) & 3); ss7_message(ss7, "\t\t\tLocation: %d\n", parm[0] & 0xf); ss7_message(ss7, "\t\t\tCause Class: %d\n", (parm[1]>>4) & 0x7); ss7_message(ss7, "\t\t\tCause Subclass: %d\n", parm[1] & 0xf); ss7_message(ss7, "\t\t\tCause: %s (%d)\n", cause, parm[1] & 0x7f); return len; } static FUNC_DUMP(range_and_status_dump) { ss7_message(ss7, "\t\t\tRange: %d\n", parm[0] & 0xff); return len; } static FUNC_RECV(range_and_status_receive) { int i; int numcics; c->range = parm[0]; numcics = c->range + 1; /* No status for these messages */ if ((messagetype == ISUP_CQR) || (messagetype == ISUP_CQM) || (messagetype == ISUP_GRS)) return len; for (i = 0; i < numcics; i++) { if (parm[1 + (i/8)] & (1 << (i%8))) c->status[i] = 1; else c->status[i] = 0; } return len; } static FUNC_SEND(range_and_status_transmit) { int i, statuslen = 0; int numcics = c->range + 1; parm[0] = c->range & 0xff; /* No status for these messages */ if ((messagetype == ISUP_CQR) || (messagetype == ISUP_CQM) || (messagetype == ISUP_GRS)) return 1; statuslen = (numcics / 8) + !!(numcics % 8); if (messagetype == ISUP_GRA) { for (i = 0; i < statuslen; i++) { parm[1 + i] = 0; } } else { for (i = 0; i < numcics; i++) { if (c->status[i]) parm[1 + (i/8)] |= (1 << (i % 8)); } } return statuslen + 1; } static FUNC_DUMP(calling_party_num_dump) { int oddeven = (parm[0] >> 7) & 0x1; char numbuf[64] = ""; ss7_message(ss7, "\t\t\tNature of address: %x\n", parm[0] & 0x7f); ss7_message(ss7, "\t\t\tNI: %x\n", (parm[1] >> 7) & 0x1); ss7_message(ss7, "\t\t\tNumbering plan: %x\n", (parm[1] >> 4) & 0x7); ss7_message(ss7, "\t\t\tPresentation: %x\n", (parm[1] >> 2) & 0x3); ss7_message(ss7, "\t\t\tScreening: %x\n", parm[1] & 0x3); isup_get_number(numbuf, &parm[2], len - 2, oddeven); ss7_message(ss7, "\t\t\tAddress signals: %s\n", numbuf); return len; } static FUNC_RECV(calling_party_num_receive) { int oddeven = (parm[0] >> 7) & 0x1; isup_get_number(c->calling_party_num, &parm[2], len - 2, oddeven); c->calling_nai = parm[0] & 0x7f; /* Nature of Address Indicator */ c->presentation_ind = (parm[1] >> 2) & 0x3; c->screening_ind = parm[1] & 0x3; return len; } static FUNC_SEND(calling_party_num_transmit) { int oddeven, datalen; if (!c->calling_party_num[0]) return 0; isup_put_number(&parm[2], c->calling_party_num, &datalen, &oddeven); parm[0] = (oddeven << 7) | c->calling_nai; /* Nature of Address Indicator */ parm[1] = (1 << 4) | /* Assume E.164 ISDN numbering plan, calling number complete */ ((c->presentation_ind & 0x3) << 2) | (c->screening_ind & 0x3); return datalen + 2; } static FUNC_DUMP(originating_line_information_dump) { char *name; switch (parm[0]) { case 0: name = " Plain Old Telephone Service POTS"; break; case 1: name = " Multiparty line"; break; case 2: name = " ANI Failure"; break; case 3: case 4: case 5: name = " Unassigned"; break; case 6: name = " Station Level Rating"; break; case 7: name = " Special Operator Handling Required"; break; case 8: case 9: name = "Unassigned"; break; case 10: name = "Not assignable"; break; case 11: name = "Unassigned"; break; case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: name = "Not assignable"; break; case 20: name = "Automatic Identified Outward Dialing"; break; case 21: case 22: name = "Unassigned"; break; case 23: name = "Coin or Non-Coin"; break; case 24: case 25: name = "Toll Free Service translated to POTS"; break; case 26: name = "Unassigned"; break; case 27: name = "Pay Station using Coin Control Signalling"; break; case 28: name = "Unassigned"; break; case 29: name = "Prison/Inmate Service"; break; case 30: case 31: case 32: name = "Intercept"; break; case 33: name = "Unassigned"; break; case 34: name = "Telco Operator Handled Call"; break; case 35: case 36: case 37: case 38: case 39: name = "Unassigned"; break; case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: name = "Unrestricted Use - locally determined by carrier"; break; case 50: case 51: name = "Unassigned"; break; case 52: name = "OUTWATS"; break; case 53: case 54: case 55: case 56: case 57: case 58: case 59: name = "Unassigned"; break; case 60: name = "TRS Unrestricted Line"; break; case 61: name = "Cellular Wireless PCS Type 1"; break; case 62: name = "Cellular Wireless PCS Type 2"; break; case 63: name = "Cellular Wireless PCS Roaming"; break; case 64: case 65: name = "Unassigned"; break; case 66: name = "TRS Hotel Motel"; break; case 67: name = "TRS Restricted Line"; break; case 68: case 69: name = "Unassigned"; break; case 70: name = "Pay Station No network Coin Control Signalling"; break; case 71: case 72: case 73: case 74: case 75: case 76: case 77: case 78: case 79: name = "Unassigned"; break; case 80: case 81: case 82: case 83: case 84: case 85: case 86: case 87: case 88: case 89: name = "Reserved"; break; case 90: case 91: case 92: name = "Unassigned"; break; case 93: name = "Private Virtual Network Type of service call"; break; case 94: case 95: case 96: case 97: case 98: case 99: name = "Unassigned"; break; default: name = "Unknown to Asterisk "; } ss7_message(ss7, "\t\t\tLine info code: %s (%d)\n", name, parm[0]); return 1; } static FUNC_RECV(originating_line_information_receive) { c->oli_ani2 = parm[0]; return 1; } static FUNC_SEND(originating_line_information_transmit) { if (c->oli_ani2 < 0) { /* Allow dialplan to strip OLI parm if you don't want to resend what was received */ return 0; } else if (c->oli_ani2 < 99) { parm[0] = c->oli_ani2; return 1; } else { parm[0] = 0x00; /* This value is setting OLI equal to POTS line. */ return 1; } } static FUNC_DUMP(carrier_identification_dump) { return len; } static FUNC_RECV(carrier_identification_receive) { return len; } static FUNC_SEND(carrier_identification_transmit) { parm[0] = 0x22; /* 4 digit CIC */ parm[1] = 0x00; /* would send default 0000 */ parm[2] = 0x00; return 3; } static FUNC_DUMP(jip_dump) { char numbuf[64] = ""; isup_get_number(numbuf, &parm[0], len , 0); ss7_message(ss7, "\t\t\tJIP: %s\n", numbuf); return len; } static FUNC_RECV(jip_receive) { isup_get_number(c->jip_number, &parm[0], len, 0); return len; } static FUNC_SEND(jip_transmit) { int oddeven, datalen; if (c->jip_number[0]) { isup_put_number(&parm[0], c->jip_number, &datalen, &oddeven); return datalen; } return 0; } static FUNC_DUMP(hop_counter_dump) { return 1; } static FUNC_RECV(hop_counter_receive) { return 1; } static FUNC_SEND(hop_counter_transmit) { parm[0] = 0x01; /* would send hop counter with value of 1 */ return 1; } static FUNC_RECV(charge_number_receive) { int oddeven = (parm[0] >> 7) & 0x1; isup_get_number(c->charge_number, &parm[2], len - 2, oddeven); c->charge_nai = parm[0] & 0x7f; /* Nature of Address Indicator */ c->charge_num_plan = (parm[1] >> 4) & 0x7; return len; } static FUNC_DUMP(charge_number_dump) { int oddeven = (parm[0] >> 7) & 0x1; char numbuf[64] = ""; ss7_message(ss7, "\t\t\tNature of address: %x\n", parm[0] & 0x7f); ss7_message(ss7, "\t\t\tNumbering plan: %x\n", (parm[1] >> 4) & 0x7); isup_get_number(numbuf, &parm[2], len - 2, oddeven); ss7_message(ss7, "\t\t\tAddress signals: %s\n", numbuf); return len; } static FUNC_SEND(charge_number_transmit) //ANSI network { int oddeven, datalen; if (!c->charge_number[0]) return 0; isup_put_number(&parm[2], c->charge_number, &datalen, &oddeven); /* use the value from callerid in sip.conf to fill charge number */ parm[0] = (oddeven << 7) | c->charge_nai; /* Nature of Address Indicator = odd/even and ANI of the Calling party, subscriber number */ parm[1] = (1 << 4) | 0x0; //c->charge_num_plan /* Assume E.164 ISDN numbering plan, calling number complete and make sure reserved bits are zero */ return datalen + 2; } static FUNC_SEND(continuity_ind_transmit) { if (c->cot_check_passed) parm[0] = 0x01; else parm[0] = 0x00; return 1; } static FUNC_RECV(continuity_ind_receive) { if (0x1 & parm[0]) c->cot_check_passed = 1; else c->cot_check_passed = 0; return 1; } static FUNC_DUMP(continuity_ind_dump) { ss7_message(ss7, "\t\t\tContinuity Check: %s\n", (0x01 & parm[0]) ? "successful" : "failed"); return 1; } static FUNC_DUMP(circuit_group_supervision_dump) { char *name; switch (parm[0] & 0x3) { case 0: name = "Maintenance oriented"; break; case 1: name = "Hardware Failure oriented"; break; case 2: name = "Reserved for national use"; break; case 3: name = "Spare"; break; default: name = "Huh?!"; } ss7_message(ss7, "\t\t\tType indicator: %s\n", name); return 1; } static FUNC_RECV(circuit_group_supervision_receive) { c->cicgroupsupervisiontype = 0x3 & parm[0]; return 1; } static FUNC_SEND(circuit_group_supervision_transmit) { parm[0] = c->cicgroupsupervisiontype & 0x3; return 1; } static FUNC_DUMP(event_info_dump) { char *name; switch (parm[0]) { case 0: name = "spare"; break; case 1: name = "ALERTING"; break; case 2: name = "PROGRESS"; break; case 3: name = "In-band information or an appropriate pattern is now available"; break; case 4: name = "Call forward on busy"; break; case 5: name = "Call forward on no reply"; break; case 6: name = "Call forward unconditional"; break; default: name = "Spare"; break; } ss7_message(ss7, "\t\t\t%s\n", name); return 1; } static FUNC_RECV(event_info_receive) { c->event_info = parm[0]; return 1; } static FUNC_SEND(event_info_transmit) { parm[0] = c->event_info; return 1; } static FUNC_DUMP(redirection_info_dump) { char *redirect_ind, *orig_redir_reas, *redir_reas; switch (parm[0] & 0x7) { case 0: redirect_ind = "No Redirection (national use)"; break; case 1: redirect_ind = "Call rerouted (national use)"; break; case 2: redirect_ind = "Call rerouted, all rediection information presentation restricted (national use)"; break; case 3: redirect_ind = "Call diverted"; break; case 4: redirect_ind = "Call diverted, all redirection information presentation restricted"; break; case 5: redirect_ind = "Call rerouted, redirection number presentation restricted (national use)"; break; case 6: redirect_ind = "Call diversion, redirection number presentation restricted (national use)"; break; case 7: redirect_ind = "spare"; break; default: redirect_ind = "Unknown"; break; } ss7_message(ss7, "\t\t\tRedirecting indicator: %s (%d)\n", redirect_ind, parm[0] & 0x7); switch ((parm[0] >> 4) & 0xf) { case 0: orig_redir_reas = "Unknown/not available"; break; case 1: orig_redir_reas = "User busy (national use)"; break; case 2: orig_redir_reas = "No reply (national use)"; break; case 3: orig_redir_reas = "Unconditional (national use)"; break; default: orig_redir_reas = "spare"; break; } ss7_message(ss7, "\t\t\tOriginal redirection reason: %s (%d)\n", orig_redir_reas, (parm[0] >> 4) & 0xf); ss7_message(ss7, "\t\t\tRedirection counter: %d\n", parm[1] & 0x7); switch ((parm[1] >> 4) & 0xf) { case 0: orig_redir_reas = "Unknown/not available"; break; case 1: redir_reas = "User busy"; break; case 2: redir_reas = "No reply"; break; case 3: redir_reas = "Unconditional"; break; case 4: redir_reas = "Deflection during alerting"; break; case 5: redir_reas = "Deflection immediate response"; break; case 6: redir_reas = "Mobile subscriber not reachable"; break; default: redir_reas = "spare"; break; } ss7_message(ss7, "\t\t\tRedirecting reason: %s (%d)\n", redir_reas, (parm[1] >> 4) & 0xf); return 2; } static FUNC_RECV(redirection_info_receive) { return 2; } static FUNC_SEND(redirection_info_transmit) { return 2; } static FUNC_RECV(generic_name_receive) { c->generic_name_typeofname = (parm[0] >> 5) & 0x7; c->generic_name_avail = (parm[0] >> 4) & 0x1; c->generic_name_presentation = parm[0] & 0x3; memcpy(c->generic_name, &parm[1], len - 1); return len; } static FUNC_DUMP(generic_name_dump) { unsigned int typeofname = (parm[0] >> 5) & 0x7; unsigned int avail = (parm[0] >> 4) & 0x1; unsigned int presentation = parm[0] & 0x3; char name[ISUP_MAX_NAME + 1]; memcpy(name, &parm[1], len - 1); ss7_message(ss7, "\t\t\tType of Name: %s (%d)\n", (typeofname == 1) ? "Calling Name" : "Unknown", typeofname); ss7_message(ss7, "\t\t\tAvail: %s (%d)\n", (avail == 1) ? "Name not available" : "Name available, or availability unknown", avail); ss7_message(ss7, "\t\t\tPresentation: %d\n", presentation); ss7_message(ss7, "\t\t\tName: %s\n", name); return len; } static FUNC_SEND(generic_name_transmit) { int namelen = strlen(c->generic_name); /* Check to see if generic name is set before we try to add it */ if (!c->generic_name[0]) return 0; parm[0] = (c->generic_name_typeofname << 5) | ((c->generic_name_avail & 0x1) << 4) | (c->generic_name_presentation & 0x3); memcpy(&parm[1], c->generic_name, namelen); return namelen + 1; } static FUNC_DUMP(generic_address_dump) { int oddeven = (parm[1] >> 7) & 0x1; char numbuf[64] = ""; ss7_message(ss7, "\t\t\tType of address: %x\n", parm[0]); ss7_message(ss7, "\t\t\tNature of address: %x\n", parm[1] & 0x7f); ss7_message(ss7, "\t\t\tOddEven: %x\n", (parm[1] >> 7) & 0x1); ss7_message(ss7, "\t\t\tReserved: %x\n", parm[2] & 0x3); ss7_message(ss7, "\t\t\tPresentation: %x\n", (parm[2] >> 2) & 0x3); ss7_message(ss7, "\t\t\tNumbering plan: %x\n", (parm[2] >> 4) & 0x7); isup_get_number(numbuf, &parm[3], len - 3, oddeven); ss7_message(ss7, "\t\t\tAddress signals: %s\n", numbuf); return len; } static FUNC_RECV(generic_address_receive) { int oddeven = (parm[1] >> 7) & 0x1; c->gen_add_type = parm[0]; c->gen_add_nai = parm[1] & 0x7f; c->gen_add_pres_ind = (parm[2] >> 2) & 0x3; c->gen_add_num_plan = (parm[2] >> 4) & 0x7; isup_get_number(c->gen_add_number, &parm[3], len - 3, oddeven); return len; } static FUNC_SEND(generic_address_transmit) { int oddeven, datalen; if (!c->gen_add_number[0]) return 0; isup_put_number(&parm[3], c->gen_add_number, &datalen, &oddeven); parm[0] = c->gen_add_type; parm[1] = (oddeven << 7) | c->gen_add_nai; /* Nature of Address Indicator */ parm[2] = (c->gen_add_num_plan << 4) | ((c->gen_add_pres_ind & 0x3) << 2) | ( 0x00 & 0x3); return datalen + 3; } static FUNC_DUMP(generic_digits_dump) { int oddeven = (parm[0] >> 5) & 0x7; char numbuf[64] = ""; ss7_message(ss7, "\t\t\tType of digits: %x\n", parm[0] & 0x1f); ss7_message(ss7, "\t\t\tEncoding Scheme: %x\n", (parm[0] >> 5) & 0x7); isup_get_number(numbuf, &parm[1], len - 1, oddeven); ss7_message(ss7, "\t\t\tAddress digits: %s\n", numbuf); return len; } static FUNC_RECV(generic_digits_receive) { c->gen_dig_scheme = (parm[0] >> 5) & 0x7; c->gen_dig_type = parm[0] & 0x1f; isup_get_number(c->gen_dig_number, &parm[1], len - 1, c->gen_dig_scheme); return len; } static FUNC_SEND(generic_digits_transmit) { int oddeven, datalen; if (!c->gen_dig_number[0]) return 0; switch (c->gen_dig_type) { case 0: case 1: case 2: /* used for sending digit strings */ isup_put_number(&parm[1], c->gen_dig_number, &datalen, &oddeven); parm[0] = (oddeven << 5 ) | c->gen_dig_type; break; case 3: /*used for sending BUSINESS COMM. GROUP IDENTIY type */ isup_put_generic(&parm[1], c->gen_dig_number, &datalen); parm[0] = (c->gen_dig_scheme << 5 ) | c->gen_dig_type; break; default: isup_put_number(&parm[1], c->gen_dig_number, &datalen, &oddeven); parm[0] = (oddeven << 5 ) | c->gen_dig_type; break; } return datalen + 1; } static FUNC_DUMP(original_called_num_dump) { int oddeven = (parm[0] >> 7) & 0x1; char numbuf[64] = ""; ss7_message(ss7, "\t\t\tNature of address: %x\n", parm[0] & 0x7f); ss7_message(ss7, "\t\t\tNumbering plan: %x\n", (parm[1] >> 4) & 0x7); ss7_message(ss7, "\t\t\tPresentation: %x\n", (parm[1] >> 2) & 0x3); isup_get_number(numbuf, &parm[2], len - 2, oddeven); ss7_message(ss7, "\t\t\tAddress signals: %s\n", numbuf); return len; } static FUNC_RECV(original_called_num_receive) { int oddeven = (parm[0] >> 7) & 0x1; isup_get_number(c->orig_called_num, &parm[2], len - 2, oddeven); c->orig_called_nai = parm[0] & 0x7f; c->orig_called_pres_ind = (parm[1] >> 2) & 0x3; c->orig_called_screening_ind = parm[1] & 0x3; return len; } static FUNC_SEND(original_called_num_transmit) { return len; } static FUNC_DUMP(echo_control_info_dump) { unsigned char ba = parm[0] & 0x3; unsigned char dc = (parm[0] >> 2) & 0x3; unsigned char fe = (parm[0] >> 4) & 0x3; unsigned char hg = (parm[0] >> 6) & 0x3; char *ba_str, *dc_str, *fe_str, *hg_str; switch (ba) { case 0: ba_str = "no information"; break; case 1: ba_str = "outgoing echo control device not included and not available"; break; case 2: ba_str = "outgoing echo control device included"; break; case 3: ba_str = "outgoing echo control device not included but available"; break; default: ba_str = "unknown"; break; } switch (dc) { case 0: dc_str = "no information"; break; case 1: dc_str = "incoming echo control device not included and not available"; break; case 2: dc_str = "incoming echo control device included"; break; case 3: dc_str = "incoming echo control device not included but available"; break; default: dc_str = "unknown"; break; } switch (fe) { case 0: fe_str = "no information"; break; case 1: fe_str = "outgoing echo control device activation request"; break; case 2: fe_str = "outgoing echo control device deactivation request"; break; case 3: fe_str = "spare"; break; default: fe_str = "unknown"; break; } switch (hg) { case 0: hg_str = "no information"; break; case 1: hg_str = "incoming echo control device activation request"; break; case 2: hg_str = "incoming echo control device deactivation request"; break; case 3: hg_str = "spare"; break; default: hg_str = "unknown"; break; } ss7_message(ss7, "\t\t\tOutgoing echo control device information: %s (%d)\n", ba_str, ba); ss7_message(ss7, "\t\t\tIncoming echo control device information: %s (%d)\n", dc_str, dc); ss7_message(ss7, "\t\t\tOutgoing echo control device request: %s (%d)\n", fe_str, fe); ss7_message(ss7, "\t\t\tIncoming echo control device request: %s (%d)\n", hg_str, hg); return len; } static FUNC_DUMP(parameter_compat_info_dump) { return len; } static FUNC_DUMP(propagation_delay_cntr_dump) { ss7_message(ss7, "\t\t\tDelay: %dms\n", (unsigned short)(((parm[0] & 0xff) << 8) | (parm[0] & 0xff))); return len; } static FUNC_DUMP(circuit_state_ind_dump) { unsigned char dcbits, babits, febits; char *ba_str, *dc_str, *fe_str; int i; for (i = 0; i < len; i++) { babits = parm[i] & 0x3; dcbits = (parm[i] >> 2) & 0x3; febits = (parm[i] >> 4) & 0x3; if (dcbits == 0) { switch (babits) { case 0: ba_str = "transient"; break; case 1: case 2: ba_str = "spare"; break; case 3: ba_str = "unequipped"; break; } } else { switch (babits) { case 0: ba_str = "no blocking (active)"; break; case 1: ba_str = "locally blocked"; break; case 2: ba_str = "remotely blocked"; break; case 3: ba_str = "locally and remotely blocked"; break; } switch (dcbits) { case 1: dc_str = "circuit incoming busy"; break; case 2: dc_str = "circuit outgoing busy"; break; case 3: dc_str = "idle"; break; } switch (febits) { case 0: fe_str = "no blocking (active)"; break; case 1: fe_str = "locally blocked"; break; case 2: fe_str = "remotely blocked"; break; case 3: fe_str = "locally and remotely blocked"; break; } } ss7_message(ss7, "\t\t\tMaintenance blocking state: %s (%d)\n", ba_str, babits); if (!dcbits) continue; ss7_message(ss7, "\t\t\tCall processing state: %s (%d)\n", dc_str, dcbits); ss7_message(ss7, "\t\t\tHardware blocking state: %s (%d)\n", fe_str, febits); } return len; } static FUNC_SEND(circuit_state_ind_transmit) { int numcics = c->range + 1, i; for (i = 0; i < numcics; i++) parm[i] = c->status[i]; return numcics; } static FUNC_DUMP(tns_dump) { ss7_message(ss7, "\t\t\tType of Network: %x\n", (parm[0] >> 4) & 0x7); ss7_message(ss7, "\t\t\tNetwork ID plan: %x\n", parm[0] & 0xf); ss7_message(ss7, "\t\t\tNetwork ID: %x %x\n", parm[1], parm[2]); ss7_message(ss7, "\t\t\tCircuit Code: %x\n", (parm[3] >> 4) & 0xf); return len; } static FUNC_SEND(tns_transmit) { return 0; } static FUNC_RECV(tns_receive) { return len; } static FUNC_SEND(lspi_transmit) { /* On Nortel this needs to be set to ARM the RLT functionality. */ /* This causes the Nortel switch to return the CALLREFERENCE Parm on the ACM of the outgoing call */ /* This parm has more fields that can be set but Nortel DMS-250/500 needs it set as below */ if (c->lspi_scheme) { parm[0] = c->lspi_scheme << 5 | c->lspi_type; /* only setting parms for NORTEL RLT on IMT trktype */ return 1; } return 0; } static FUNC_RECV(lspi_receive) { c->lspi_type = parm[0] & 0x1f; c->lspi_scheme = parm[0] >> 5 & 0x7; c->lspi_context = parm[1] & 0xf; isup_get_number(c->lspi_ident, &parm[2], len - 2, c->lspi_scheme); return len; } static FUNC_DUMP(lspi_dump) { ss7_message(ss7, "\t\t\tLSPI Type: %x\n", parm[0] & 0x1f); ss7_message(ss7, "\t\t\tEncoding Scheme: %x\n", (parm[0] >> 5) & 0x7); ss7_message(ss7, "\t\t\tContext ID: %x\n", parm[1] & 0xf); ss7_message(ss7, "\t\t\tSpare: %x\n", (parm[1] >> 4) & 0xf); ss7_message(ss7, "\t\t\tLSP Identity: %x\n", parm[2]); return len; } static FUNC_DUMP(call_ref_dump) { unsigned int ptc, callr; callr = parm[0] | (parm[1] << 8) | (parm[2] << 16); if (ss7->switchtype == SS7_ANSI) ptc = parm[3] | (parm[4] << 8) | (parm[5] << 16); else ptc = parm[3] | (parm[4] << 8); ss7_message(ss7, "\t\t\tCall identity: %d\n", callr); if (ss7->switchtype == SS7_ANSI) ss7_message(ss7, "\t\t\tPC: Net-CLstr-Mbr: %d-%d-%d\n",(ptc >> 16) & 0xff, (ptc >> 8) & 0xff, ptc & 0xff); else ss7_message(ss7, "\t\t\tPC: 0x%x\n", ptc); return len; } static FUNC_SEND(call_ref_transmit) { if (c->call_ref_ident) { if (ss7->switchtype == SS7_ANSI) { parm[0] = c->call_ref_ident & 0xff; parm[1] = (c->call_ref_ident >> 8) & 0xff; parm[2] = (c->call_ref_ident >> 16) & 0xff; parm[3] = c->call_ref_pc & 0xff; parm[4] = (c->call_ref_pc >> 8) & 0xff; parm[5] = (c->call_ref_pc >> 16) & 0xff; return 6; } else { parm[0] = c->call_ref_ident & 0xff; parm[1] = (c->call_ref_ident >> 8) & 0xff; parm[2] = (c->call_ref_ident >> 16) & 0xff; parm[3] = c->call_ref_pc & 0xff; parm[4] = (c->call_ref_pc >> 8) & 0x3f; return 5; } } return 0; } static FUNC_RECV(call_ref_receive) { if (ss7->switchtype == SS7_ANSI) { c->call_ref_ident = parm[0] | (parm[1] << 8) | (parm[2] << 16); c->call_ref_pc = parm[3] | (parm[4] << 8) | (parm[5] << 16); } else { c->call_ref_ident = parm[0] | (parm[1] << 8) | (parm[2] << 16); c->call_ref_pc = parm[3] | ((parm[4] & 0x3f) << 8); } return len; } static FUNC_DUMP(facility_ind_dump) { ss7_message(ss7, "\t\t\tFacility Indicator: %x\n", parm[0]); return 1; } static FUNC_RECV(facility_ind_receive) { return 1; } static FUNC_SEND(facility_ind_transmit) { parm[0] = 0x10; /* Setting Value to Nortel DMS-250/500 needs for RLT */ return 1; } static FUNC_DUMP(redirecting_number_dump) { int oddeven = (parm[0] >> 7) & 0x1; char numbuf[64] = ""; ss7_message(ss7, "\t\t\tNature of address: %x\n", parm[0] & 0x7f); ss7_message(ss7, "\t\t\tNI: %x\n", (parm[1] >> 7) & 0x1); ss7_message(ss7, "\t\t\tNumbering plan: %x\n", (parm[1] >> 4) & 0x7); ss7_message(ss7, "\t\t\tPresentation: %x\n", (parm[1] >> 2) & 0x3); ss7_message(ss7, "\t\t\tScreening: %x\n", parm[1] & 0x3); isup_get_number(numbuf, &parm[2], len - 2, oddeven); ss7_message(ss7, "\t\t\tAddress signals: %s\n", numbuf); return len; } static FUNC_RECV(redirecting_number_receive) { int oddeven = (parm[0] >> 7) & 0x1; isup_get_number(c->redirecting_num, &parm[2], len - 2, oddeven); c->redirecting_num_nai = parm[0] & 0x7f; /* Nature of Address Indicator */ c->redirecting_num_presentation_ind = (parm[1] >> 2) & 0x3; c->redirecting_num_screening_ind = parm[1] & 0x3; return len; } static FUNC_SEND(redirecting_number_transmit) { return 0; } static FUNC_DUMP(access_transport_dump) { return len; } static FUNC_RECV(access_transport_receive) { return len; } static FUNC_SEND(access_transport_transmit) { return len; } static struct parm_func parms[] = { {ISUP_PARM_NATURE_OF_CONNECTION_IND, "Nature of Connection Indicator", nature_of_connection_ind_dump, nature_of_connection_ind_receive, nature_of_connection_ind_transmit }, {ISUP_PARM_FORWARD_CALL_IND, "Forward Call Indicators", forward_call_ind_dump, forward_call_ind_receive, forward_call_ind_transmit }, {ISUP_PARM_CALLING_PARTY_CAT, "Calling Party's Category", calling_party_cat_dump, calling_party_cat_receive, calling_party_cat_transmit}, {ISUP_PARM_TRANSMISSION_MEDIUM_REQS, "Transmission Medium Requirements", transmission_medium_reqs_dump, transmission_medium_reqs_receive, transmission_medium_reqs_transmit}, {ISUP_PARM_USER_SERVICE_INFO, "User Service Information", NULL, user_service_info_receive, user_service_info_transmit}, {ISUP_PARM_CALLED_PARTY_NUM, "Called Party Number", called_party_num_dump, called_party_num_receive, called_party_num_transmit}, {ISUP_PARM_CAUSE, "Cause Indicator", cause_dump, cause_receive, cause_transmit}, {ISUP_PARM_CONTINUITY_IND, "Continuity Indicator", continuity_ind_dump, continuity_ind_receive, continuity_ind_transmit}, {ISUP_PARM_ACCESS_TRANS, "Access Transport", access_transport_dump, access_transport_receive, access_transport_transmit}, {ISUP_PARM_BUSINESS_GRP, "Business Group"}, {ISUP_PARM_CALL_REF, "Call Reference", call_ref_dump, call_ref_receive, call_ref_transmit}, {ISUP_PARM_CALLING_PARTY_NUM, "Calling Party Number", calling_party_num_dump, calling_party_num_receive, calling_party_num_transmit}, {ISUP_PARM_CARRIER_ID, "Carrier Identification", carrier_identification_dump, carrier_identification_receive, carrier_identification_transmit}, {ISUP_PARM_SELECTION_INFO, "Selection Information"}, {ISUP_PARM_CHARGE_NUMBER, "Charge Number", charge_number_dump, charge_number_receive, charge_number_transmit}, {ISUP_PARM_CIRCUIT_ASSIGNMENT_MAP, "Circuit Assignment Map"}, {ISUP_PARM_CONNECTION_REQ, "Connection Request"}, {ISUP_PARM_CUG_INTERLOCK_CODE, "Interlock Code"}, {ISUP_PARM_EGRESS_SERV, "Egress Service"}, {ISUP_PARM_GENERIC_ADDR, "Generic Address", generic_address_dump, generic_address_receive, generic_address_transmit}, {ISUP_PARM_GENERIC_DIGITS, "Generic Digits", generic_digits_dump, generic_digits_receive, generic_digits_transmit}, {ISUP_PARM_GENERIC_NAME, "Generic Name", generic_name_dump, generic_name_receive, generic_name_transmit}, {ISUP_PARM_TRANSIT_NETWORK_SELECTION, "Transit Network Selection", tns_dump, tns_receive, tns_transmit}, {ISUP_PARM_GENERIC_NOTIFICATION_IND, "Generic Notification Indication"}, {ISUP_PARM_PROPAGATION_DELAY, "Propagation Delay Counter", propagation_delay_cntr_dump}, {ISUP_PARM_HOP_COUNTER, "Hop Counter", hop_counter_dump, hop_counter_receive, hop_counter_transmit}, {ISUP_PARM_BACKWARD_CALL_IND, "Backward Call Indicator", backward_call_ind_dump, backward_call_ind_receive, backward_call_ind_transmit}, {ISUP_PARM_OPT_BACKWARD_CALL_IND, "Optional Backward Call Indicator", opt_backward_call_ind_dump, opt_backward_call_ind_receive, NULL}, {ISUP_PARM_CIRCUIT_GROUP_SUPERVISION_IND, "Circuit Group Supervision Indicator", circuit_group_supervision_dump, circuit_group_supervision_receive, circuit_group_supervision_transmit}, {ISUP_PARM_RANGE_AND_STATUS, "Range and status", range_and_status_dump, range_and_status_receive, range_and_status_transmit}, {ISUP_PARM_EVENT_INFO, "Event Information", event_info_dump, event_info_receive, event_info_transmit}, {ISUP_PARM_OPT_FORWARD_CALL_INDICATOR, "Optional forward call indicator"}, {ISUP_PARM_LOCATION_NUMBER, "Location Number"}, {ISUP_PARM_ORIG_LINE_INFO, "Originating line information", originating_line_information_dump, originating_line_information_receive, originating_line_information_transmit}, {ISUP_PARM_REDIRECTION_INFO, "Redirection Information", redirection_info_dump, redirection_info_receive, redirection_info_transmit}, {ISUP_PARM_ORIGINAL_CALLED_NUM, "Original called number", original_called_num_dump, original_called_num_receive, original_called_num_transmit}, {ISUP_PARM_JIP, "Jurisdiction Information Parameter", jip_dump, jip_receive, jip_transmit}, {ISUP_PARM_ECHO_CONTROL_INFO, "Echo Control Information", echo_control_info_dump, NULL, NULL}, {ISUP_PARM_PARAMETER_COMPAT_INFO, "Parameter Compatibility Information", parameter_compat_info_dump, NULL, NULL}, {ISUP_PARM_CIRCUIT_STATE_IND, "Circuit State Indicator", circuit_state_ind_dump, NULL, circuit_state_ind_transmit}, {ISUP_PARM_LOCAL_SERVICE_PROVIDER_IDENTIFICATION, "Local Service Provider ID", lspi_dump, lspi_receive, lspi_transmit}, {ISUP_PARM_FACILITY_IND, "Facility Indicator", facility_ind_dump, facility_ind_receive, facility_ind_transmit}, {ISUP_PARM_REDIRECTING_NUMBER, "Redirecting Number", redirecting_number_dump, redirecting_number_receive, redirecting_number_transmit}, {ISUP_PARM_ACCESS_DELIVERY_INFO, "Access Delivery Information", }, }; static char * param2str(int parm) { int x; int totalparms = sizeof(parms)/sizeof(struct parm_func); for (x = 0; x < totalparms; x++) if (parms[x].parm == parm) return parms[x].name; return "Unknown"; } static void init_isup_call(struct isup_call *c) { c->oli_ani2 = -1; } static struct isup_call * __isup_new_call(struct ss7 *ss7, int nolink) { struct isup_call *c, *cur; c = calloc(1, sizeof(struct isup_call)); if (!c) return NULL; init_isup_call(c); if (nolink) return c; else { cur = ss7->calls; if (cur) { while (cur->next) cur = cur->next; cur->next = c; } else ss7->calls = c; return c; } } struct isup_call * isup_new_call(struct ss7 *ss7) { return __isup_new_call(ss7, 0); } void isup_set_call_dpc(struct isup_call *c, unsigned int dpc) { c->dpc = dpc; } void isup_set_called(struct isup_call *c, const char *called, unsigned char called_nai, const struct ss7 *ss7) { if (called && called[0]) { if (ss7->switchtype == SS7_ITU) snprintf(c->called_party_num, sizeof(c->called_party_num), "%s#", called); else snprintf(c->called_party_num, sizeof(c->called_party_num), "%s", called); c->called_nai = called_nai; } } void isup_set_oli(struct isup_call *c, int oli_ani2) { c->oli_ani2 = oli_ani2; } void isup_set_calling(struct isup_call *c, const char *calling, unsigned char calling_nai, unsigned char presentation_ind, unsigned char screening_ind) { if (calling && calling[0]) { strncpy(c->calling_party_num, calling, sizeof(c->calling_party_num)); c->calling_nai = calling_nai; c->presentation_ind = presentation_ind; c->screening_ind = screening_ind; } } void isup_set_charge(struct isup_call *c, const char *charge, unsigned char charge_nai, unsigned char charge_num_plan) { if (charge && charge[0]) { strncpy(c->charge_number, charge, sizeof(c->charge_number)); c->charge_nai = charge_nai; c->charge_num_plan = charge_num_plan; } } void isup_set_gen_address(struct isup_call *c, const char *gen_number, unsigned char gen_add_nai, unsigned char gen_pres_ind, unsigned char gen_num_plan, unsigned char gen_add_type) { if (gen_number && gen_number[0]) { strncpy(c->gen_add_number, gen_number, sizeof(c->gen_add_number)); c->gen_add_nai = gen_add_nai; c->gen_add_pres_ind = gen_pres_ind; c->gen_add_num_plan = gen_num_plan; c->gen_add_type = gen_add_type; } } void isup_set_gen_digits(struct isup_call *c, const char *gen_number, unsigned char gen_dig_type, unsigned char gen_dig_scheme) { if (gen_number && gen_number[0]) { strncpy(c->gen_dig_number, gen_number, sizeof(c->gen_dig_number)); c->gen_dig_type = gen_dig_type; c->gen_dig_scheme = gen_dig_scheme; } } void isup_set_generic_name(struct isup_call *c, const char *generic_name, unsigned int typeofname, unsigned int availability, unsigned int presentation) { if (generic_name && generic_name[0]) { strncpy(c->generic_name, generic_name, sizeof(c->generic_name)); /* Terminate this just in case */ c->generic_name[ISUP_MAX_NAME - 1] = '\0'; c->generic_name_typeofname = typeofname; c->generic_name_avail = availability; c->generic_name_presentation = presentation; } } void isup_set_jip_digits(struct isup_call *c, const char *jip_number) { if (jip_number && jip_number[0]) { strncpy(c->jip_number, jip_number, sizeof(c->jip_number)); } } void isup_set_lspi(struct isup_call *c, const char *lspi_ident, unsigned char lspi_type, unsigned char lspi_scheme, unsigned char lspi_context) { if (lspi_ident && lspi_ident[0]) { strncpy(c->lspi_ident, lspi_ident, sizeof(c->lspi_ident)); c->lspi_context = lspi_context; c->lspi_scheme = lspi_scheme; c->lspi_type = lspi_type; } } void isup_set_callref(struct isup_call *c, unsigned int call_ref_ident, unsigned int call_ref_pc) { c->call_ref_ident = call_ref_ident; c->call_ref_pc = call_ref_pc; } void isup_init_call(struct ss7 *ss7, struct isup_call *c, int cic, unsigned int dpc) { c->cic = cic; c->dpc = dpc; if (ss7->switchtype == SS7_ANSI) c->sls = ansi_sls_next(ss7); else c->sls = cic & 0xf; } static struct isup_call * isup_find_call(struct ss7 *ss7, struct routing_label *rl, int cic) { struct isup_call *cur, *winner = NULL; cur = ss7->calls; while (cur) { if ((cur->cic == cic) && (cur->dpc == rl->opc)) { winner = cur; break; } cur = cur->next; } if (!winner) { winner = __isup_new_call(ss7, 0); winner->cic = cic; winner->dpc = rl->opc; winner->sls = rl->sls; } return winner; } static void isup_free_call(struct ss7 *ss7, struct isup_call *c) { struct isup_call *cur, *prev = NULL, *winner = NULL; cur = ss7->calls; while (cur) { if (cur == c) { winner = cur; break; } prev = cur; cur = cur->next; } if (winner) { if (!prev) ss7->calls = winner->next; else prev->next = winner->next; } free(c); return; } static int do_parm(struct ss7 *ss7, struct isup_call *c, int message, int parm, unsigned char *parmbuf, int maxlen, int parmtype, int tx) { struct isup_parm_opt *optparm = NULL; int x; int res = 0; int totalparms = sizeof(parms)/sizeof(struct parm_func); for (x = 0; x < totalparms; x++) { if (parms[x].parm == parm) { if ((tx && parms[x].transmit) || (!tx && parms[x].receive)) { switch (parmtype) { case PARM_TYPE_FIXED: if (tx) return parms[x].transmit(ss7, c, message, parmbuf, maxlen); else return parms[x].receive(ss7, c, message, parmbuf, maxlen); case PARM_TYPE_VARIABLE: if (tx) { res = parms[x].transmit(ss7, c, message, parmbuf + 1, maxlen); if (res > 0) { parmbuf[0] = res; return res + 1; } return res; } else { parms[x].receive(ss7, c, message, parmbuf + 1, parmbuf[0]); return 1 + parmbuf[0]; } case PARM_TYPE_OPTIONAL: optparm = (struct isup_parm_opt *)parmbuf; if (tx) { optparm->type = parms[x].parm; res = parms[x].transmit(ss7, c, message, optparm->data, maxlen); if (res > 0) { optparm->len = res; } else return res; } else res = parms[x].receive(ss7, c, message, optparm->data, optparm->len); return res + 2; } } } } return -1; } static int dump_parm(struct ss7 *ss7, int message, int parm, unsigned char *parmbuf, int maxlen, int parmtype) { struct isup_parm_opt *optparm = NULL; int x; int len = 0; int totalparms = sizeof(parms)/sizeof(struct parm_func); char *parmname = "Unknown Parm"; for (x = 0; x < totalparms; x++) { if (parms[x].parm == parm) { if (parms[x].name) parmname = parms[x].name; ss7_message(ss7, "\t\t%s:\n", parms[x].name ? parms[x].name : "Unknown"); if (parms[x].dump) { switch (parmtype) { case PARM_TYPE_FIXED: len = parms[x].dump(ss7, message, parmbuf, maxlen); break; case PARM_TYPE_VARIABLE: parms[x].dump(ss7, message, parmbuf + 1, parmbuf[0]); len = 1 + parmbuf[0]; break; case PARM_TYPE_OPTIONAL: optparm = (struct isup_parm_opt *)parmbuf; parms[x].dump(ss7, message, optparm->data, optparm->len); len = 2 + optparm->len; break; } } else { switch (parmtype) { case PARM_TYPE_VARIABLE: len = parmbuf[0] + 1; break; case PARM_TYPE_OPTIONAL: optparm = (struct isup_parm_opt *)parmbuf; len = optparm->len + 2; break; } } ss7_dump_buf(ss7, 3, parmbuf, len); return len; } } /* This is if we don't find it.... */ optparm = (struct isup_parm_opt *)parmbuf; ss7_message(ss7, "\t\tUnknown Parameter (0x%x):\n", optparm->type); ss7_dump_buf(ss7, 3, optparm->data, optparm->len); return optparm->len + 2; } static int isup_send_message(struct ss7 *ss7, struct isup_call *c, int messagetype, int parms[]) { struct ss7_msg *msg; struct isup_h *mh = NULL; unsigned char *rlptr; int ourmessage = -1; int rlsize; unsigned char *varoffsets = NULL, *opt_ptr; int fixedparams = 0, varparams = 0, optparams = 0; int len = sizeof(struct ss7_msg); struct routing_label rl; int res = 0; int offset = 0; int x = 0; int i = 0; /* Do init stuff */ msg = ss7_msg_new(); if (!msg) { ss7_error(ss7, "Allocation failed!\n"); return -1; } rlptr = ss7_msg_userpart(msg); rl.opc = ss7->pc; /* use CIC's DPC instead of linkset's DPC */ rl.dpc = c->dpc; rl.sls = c->sls; rl.type = ss7->switchtype; rlsize = set_routinglabel(rlptr, &rl); mh = (struct isup_h *)(rlptr + rlsize); /* Note to self, do NOT put a typecasted pointer next to an addition operation */ /* Set the CIC - ITU style */ if (ss7->switchtype == SS7_ITU) { mh->cic[0] = c->cic & 0xff; mh->cic[1] = (c->cic >> 8) & 0x0f; } else { mh->cic[0] = c->cic & 0xff; mh->cic[1] = (c->cic >> 8) & 0x03f; } mh->type = messagetype; /* Find the metadata for our message */ for (x = 0; x < sizeof(messages)/sizeof(struct message_data); x++) if (messages[x].messagetype == messagetype) ourmessage = x; if (ourmessage < 0) { ss7_error(ss7, "Unable to find message %d in message list!\n", mh->type); return -1; } fixedparams = messages[ourmessage].mand_fixed_params; varparams = messages[ourmessage].mand_var_params; optparams = messages[ourmessage].opt_params; /* Again, the ANSI exception */ if (ss7->switchtype == SS7_ANSI) { if (messages[ourmessage].messagetype == ISUP_IAM) { fixedparams = 3; varparams = 2; } else if (messages[ourmessage].messagetype == ISUP_RLC) { optparams = 0; } } /* Add fixed params */ for (x = 0; x < fixedparams; x++) { res = do_parm(ss7, c, mh->type, parms[x], (void *)(mh->data + offset), len, PARM_TYPE_FIXED, 1); if (res < 0) { ss7_error(ss7, "!! Unable to add mandatory fixed parameter '%s'\n", param2str(parms[x])); return -1; } len -= res; offset += res; } varoffsets = &mh->data[offset]; /* Make sure we grab our opional parameters */ if (optparams) { opt_ptr = &mh->data[offset + varparams]; offset += varparams + 1; /* add one for the optionals */ len -= varparams + 1; } else { offset += varparams; len -= varparams; } /* Whew, some complicated math for all of these offsets and different sections */ for (; (x - fixedparams) < varparams; x++) { varoffsets[i] = &mh->data[offset] - &varoffsets[i]; i++; res = do_parm(ss7, c, mh->type, parms[x], (void *)(mh->data + offset), len, PARM_TYPE_VARIABLE, 1); if (res < 0) { ss7_error(ss7, "!! Unable to add mandatory variable parameter '%s'\n", param2str(parms[x])); return -1; } len -= res; offset += res; } /* Optional parameters */ if (optparams) { int addedparms = 0; int offsetbegins = offset; while (parms[x] > -1) { res = do_parm(ss7, c, mh->type, parms[x], (void *)(mh->data + offset), len, PARM_TYPE_OPTIONAL, 1); x++; if (res < 0) { ss7_error(ss7, "!! Unable to add optional parameter '%s'\n", param2str(parms[x])); return -1; } if (res > 0) addedparms++; len -= res; offset += res; } if (addedparms) { *opt_ptr = &mh->data[offsetbegins] - opt_ptr; /* Add end of optional parameters */ mh->data[offset++] = 0; } else *opt_ptr = 0; } ss7_msg_userpart_len(msg, offset + rlsize + CIC_SIZE + 1); /* Message type length is 1 */ return mtp3_transmit(ss7, SIG_ISUP, rl.sls, msg); } int isup_dump(struct ss7 *ss7, struct mtp2 *link, unsigned char *buf, int len) { struct isup_h *mh; unsigned short cic; int ourmessage = -1; int *parms = NULL; int offset = 0; int fixedparams = 0, varparams = 0, optparams = 0; int res, x; unsigned char *opt_ptr = NULL; mh = (struct isup_h*) buf; if (ss7->switchtype == SS7_ITU) { cic = mh->cic[0] | ((mh->cic[1] & 0x0f) << 8); } else { cic = mh->cic[0] | ((mh->cic[1] & 0x3f) << 8); } ss7_message(ss7, "\t\tCIC: %d\n", cic); ss7_dump_buf(ss7, 2, buf, 2); ss7_message(ss7, "\t\tMessage Type: %s\n", message2str(mh->type), mh->type & 0xff); ss7_dump_buf(ss7, 2, &buf[2], 1); /* Find us in the message list */ for (x = 0; x < sizeof(messages)/sizeof(struct message_data); x++) if (messages[x].messagetype == mh->type) ourmessage = x; if (ourmessage < 0) { ss7_error(ss7, "!! Unable to handle message of type 0x%x\n", mh->type); return -1; } fixedparams = messages[ourmessage].mand_fixed_params; varparams = messages[ourmessage].mand_var_params; parms = messages[ourmessage].param_list; optparams = messages[ourmessage].opt_params; if (ss7->switchtype == SS7_ANSI) { /* Check for the ANSI IAM exception */ if (messages[ourmessage].messagetype == ISUP_IAM) { /* Stupid ANSI SS7, they just had to be different, didn't they? */ fixedparams = 3; varparams = 2; parms = ansi_iam_params; } else if (messages[ourmessage].messagetype == ISUP_RLC) { optparams = 0; } } if (fixedparams) ss7_message(ss7, "\t\t--FIXED LENGTH PARMS[%d]--\n", fixedparams); /* Parse fixed parms */ for (x = 0; x < fixedparams; x++) { res = dump_parm(ss7, mh->type, parms[x], (void *)(mh->data + offset), len, PARM_TYPE_FIXED); if (res < 0) { ss7_error(ss7, "!! Unable to parse mandatory fixed parameter '%s'\n", param2str(parms[x])); return -1; } len -= res; offset += res; } if (varparams) { offset += varparams; /* add one for the optionals */ len -= varparams; } if (optparams) { opt_ptr = &mh->data[offset++]; len++; } if (varparams) ss7_message(ss7, "\t\t--VARIABLE LENGTH PARMS[%d]--\n", varparams); for (; (x - fixedparams) < varparams; x++) { res = dump_parm(ss7, mh->type, parms[x], (void *)(mh->data + offset), len, PARM_TYPE_VARIABLE); if (res < 0) { ss7_error(ss7, "!! Unable to parse mandatory variable parameter '%s'\n", param2str(parms[x])); return -1; } len -= res; offset += res; } /* Optional paramter parsing code */ if (optparams && *opt_ptr) { if (len > 0) ss7_message(ss7, "\t\t--OPTIONAL PARMS--\n"); while ((len > 0) && (mh->data[offset] != 0)) { struct isup_parm_opt *optparm = (struct isup_parm_opt *)(mh->data + offset); res = dump_parm(ss7, mh->type, optparm->type, (void *)(mh->data + offset), optparm->len, PARM_TYPE_OPTIONAL); if (res < 0) { #if 0 ss7_message(ss7, "Unhandled optional parameter 0x%x '%s'\n", optparm->type, param2str(optparm->type)); isup_dump_buffer(ss7, optparm->data, optparm->len); #endif res = optparm->len + 2; } len -= res; offset += res; } } return 0; } int isup_receive(struct ss7 *ss7, struct mtp2 *link, struct routing_label *rl, unsigned char *buf, int len) { unsigned short cic; struct isup_h *mh; struct isup_call *c; int i; int *parms = NULL; int offset = 0; int ourmessage = -1; int fixedparams = 0, varparams = 0, optparams = 0; int res, x; unsigned char *opt_ptr = NULL; unsigned int opc = rl->opc; ss7_event *e; mh = (struct isup_h*) buf; if (ss7->switchtype == SS7_ITU) { cic = mh->cic[0] | ((mh->cic[1] & 0x0f) << 8); } else { cic = mh->cic[0] | ((mh->cic[1] & 0x3f) << 8); } /* Find us in the message list */ for (x = 0; x < sizeof(messages)/sizeof(struct message_data); x++) if (messages[x].messagetype == mh->type) ourmessage = x; if (ourmessage < 0) { ss7_error(ss7, "!! Unable to handle message of type 0x%x on CIC %d\n", mh->type, cic); return -1; } fixedparams = messages[ourmessage].mand_fixed_params; varparams = messages[ourmessage].mand_var_params; parms = messages[ourmessage].param_list; optparams = messages[ourmessage].opt_params; if (ss7->switchtype == SS7_ANSI) { /* Check for the ANSI IAM exception */ if (messages[ourmessage].messagetype == ISUP_IAM) { /* Stupid ANSI SS7, they just had to be different, didn't they? */ fixedparams = 3; varparams = 2; parms = ansi_iam_params; } else if (messages[ourmessage].messagetype == ISUP_RLC) { optparams = 0; } } /* Make sure we don't hijack a call associated isup_call for non call * associated messages */ switch (mh->type) { /* All of these messages are ones where a persistent call is associated with them and should not generate a new, unlinked call, or free a call (unless explicitly done, link in RLC) */ case ISUP_IAM: case ISUP_ANM: case ISUP_ACM: case ISUP_CPG: case ISUP_COT: case ISUP_CON: case ISUP_REL: case ISUP_RLC: case ISUP_RSC: case ISUP_FAA: case ISUP_FAR: c = isup_find_call(ss7, rl, cic); break; default: c = __isup_new_call(ss7, 1); c->dpc = rl->opc; c->cic = cic; break; } if (!c) { ss7_error(ss7, "Huh? No call!!!???\n"); return -1; } /* Parse fixed parms */ for (x = 0; x < fixedparams; x++) { res = do_parm(ss7, c, mh->type, parms[x], (void *)(mh->data + offset), len, PARM_TYPE_FIXED, 0); if (res < 0) { ss7_error(ss7, "!! Unable to parse mandatory fixed parameter '%s'\n", param2str(parms[x])); return -1; } len -= res; offset += res; } if (varparams) { offset += varparams; /* add one for the optionals */ res -= varparams; } if (optparams) { /* ANSI doesn't have optional parameters on RLC */ opt_ptr = &mh->data[offset++]; } for (; (x - fixedparams) < varparams; x++) { res = do_parm(ss7, c, mh->type, parms[x], (void *)(mh->data + offset), len, PARM_TYPE_VARIABLE, 0); if (res < 0) { ss7_error(ss7, "!! Unable to parse mandatory variable parameter '%s'\n", param2str(parms[x])); return -1; } len -= res; offset += res; } /* Optional paramter parsing code */ if (optparams && *opt_ptr) { while ((len > 0) && (mh->data[offset] != 0)) { struct isup_parm_opt *optparm = (struct isup_parm_opt *)(mh->data + offset); res = do_parm(ss7, c, mh->type, optparm->type, mh->data + offset, len, PARM_TYPE_OPTIONAL, 0); if (res < 0) { ss7_message(ss7, "Unhandled optional parameter 0x%x '%s'\n", optparm->type, param2str(optparm->type)); isup_dump_buffer(ss7, optparm->data, optparm->len); res = optparm->len + 2; } len -= res; offset += res; } } switch (mh->type) { case ISUP_IAM: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_IAM; e->iam.cic = c->cic; e->iam.transcap = c->transcap; e->iam.cot_check_required = c->cot_check_required; strncpy(e->iam.called_party_num, c->called_party_num, sizeof(e->iam.called_party_num)); e->iam.called_nai = c->called_nai; strncpy(e->iam.calling_party_num, c->calling_party_num, sizeof(e->iam.calling_party_num)); e->iam.calling_nai = c->calling_nai; e->iam.presentation_ind = c->presentation_ind; e->iam.screening_ind = c->screening_ind; strncpy(e->iam.charge_number, c->charge_number, sizeof(e->iam.charge_number)); e->iam.charge_nai = c->charge_nai; e->iam.charge_num_plan = c->charge_num_plan; e->iam.oli_ani2 = c->oli_ani2; e->iam.gen_add_nai = c->gen_add_nai; e->iam.gen_add_num_plan = c->gen_add_num_plan; strncpy(e->iam.gen_add_number, c->gen_add_number, sizeof(e->iam.gen_add_number)); e->iam.gen_add_pres_ind = c->gen_add_pres_ind; e->iam.gen_add_type = c->gen_add_type; strncpy(e->iam.gen_dig_number, c->gen_dig_number, sizeof(e->iam.gen_dig_number)); e->iam.gen_dig_type = c->gen_dig_type; e->iam.gen_dig_scheme = c->gen_dig_scheme; strncpy(e->iam.jip_number, c->jip_number, sizeof(e->iam.jip_number)); strncpy(e->iam.generic_name, c->generic_name, sizeof(e->iam.generic_name)); e->iam.generic_name_typeofname = c->generic_name_typeofname; e->iam.generic_name_avail = c->generic_name_avail; e->iam.generic_name_presentation = c->generic_name_presentation; e->iam.lspi_type = c->lspi_type; e->iam.lspi_scheme = c->lspi_scheme; e->iam.lspi_context = c->lspi_context; strncpy(e->iam.lspi_ident, c->lspi_ident, sizeof(e->iam.lspi_ident)); strncpy(e->iam.orig_called_num, c->orig_called_num, sizeof(e->iam.orig_called_num)); e->iam.orig_called_nai = c->orig_called_nai; e->iam.orig_called_pres_ind = c->orig_called_pres_ind; e->iam.orig_called_screening_ind = c->orig_called_screening_ind; strncpy(e->iam.redirecting_num, c->redirecting_num, sizeof(e->iam.redirecting_num)); e->iam.redirecting_num_nai = c->redirecting_num_nai; e->iam.redirecting_num_presentation_ind = c->redirecting_num_presentation_ind; e->iam.redirecting_num_screening_ind = c->redirecting_num_screening_ind; e->iam.calling_party_cat = c->calling_party_cat; e->iam.call = c; e->iam.opc = opc; /* keep OPC information */ return 0; case ISUP_CQM: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_CQM; e->cqm.startcic = cic; e->cqm.endcic = cic + c->range; e->cqm.opc = opc; /* keep OPC information */ isup_free_call(ss7, c); /* Won't need this again */ return 0; case ISUP_GRS: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_GRS; e->grs.startcic = cic; e->grs.endcic = cic + c->range; isup_free_call(ss7, c); /* Won't need this again */ e->grs.opc = opc; /* keep OPC information */ return 0; case ISUP_GRA: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_GRA; e->gra.startcic = cic; e->gra.endcic = cic + c->range; for (i = 0; i < (c->range + 1); i++) e->gra.status[i] = c->status[i]; e->gra.opc = opc; /* keep OPC information */ isup_free_call(ss7, c); /* Won't need this again */ return 0; case ISUP_RSC: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_RSC; e->rsc.cic = cic; e->rsc.call = c; e->rsc.opc = opc; /* keep OPC information */ return 0; case ISUP_REL: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_REL; e->rel.cic = c->cic; e->rel.call = c; e->rel.cause = c->cause; e->rel.opc = opc; /* keep OPC information */ return 0; case ISUP_ACM: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_ACM; e->acm.cic = c->cic; e->acm.call_ref_ident = c->call_ref_ident; e->acm.call_ref_pc = c->call_ref_pc; e->acm.call = c; e->acm.opc = opc; /* keep OPC information */ e->acm.called_party_status_ind = c->called_party_status_ind; return 0; case ISUP_CON: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_CON; e->con.cic = c->cic; e->con.call = c; e->con.opc = opc; /* keep OPC information */ return 0; case ISUP_ANM: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_ANM; e->anm.cic = c->cic; e->anm.call = c; e->anm.opc = opc; /* keep OPC information */ return 0; case ISUP_RLC: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_RLC; e->rlc.cic = c->cic; e->rlc.opc = opc; /* keep OPC information */ isup_free_call(ss7, c); return 0; case ISUP_COT: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_COT; e->cot.cic = c->cic; e->cot.passed = c->cot_check_passed; e->cot.call = c; e->cot.opc = opc; /* keep OPC information */ return 0; case ISUP_CCR: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_CCR; e->ccr.cic = c->cic; e->ccr.opc = opc; /* keep OPC information */ isup_free_call(ss7, c); return 0; case ISUP_CVT: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_CVT; e->cvt.cic = c->cic; isup_free_call(ss7, c); return 0; case ISUP_BLO: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_BLO; e->blo.cic = c->cic; e->blo.opc = opc; /* keep OPC information */ isup_free_call(ss7, c); return 0; case ISUP_UBL: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_UBL; e->ubl.cic = c->cic; e->ubl.opc = opc; /* keep OPC information */ isup_free_call(ss7, c); return 0; case ISUP_BLA: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_BLA; e->bla.cic = c->cic; e->bla.opc = opc; /* keep OPC information */ isup_free_call(ss7, c); return 0; case ISUP_LPA: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_LPA; e->lpa.cic = c->cic; e->lpa.opc = opc; /* keep OPC information */ isup_free_call(ss7, c); return 0; case ISUP_UBA: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_UBA; e->uba.cic = c->cic; e->uba.opc = opc; /* keep OPC information */ isup_free_call(ss7, c); return 0; case ISUP_CGB: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_CGB; e->cgb.startcic = cic; e->cgb.endcic = cic + c->range; e->cgb.type = c->cicgroupsupervisiontype; for (i = 0; i < (c->range + 1); i++) e->cgb.status[i] = c->status[i]; e->cgb.opc = opc; /* keep OPC information */ isup_free_call(ss7, c); return 0; case ISUP_CGU: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_CGU; e->cgu.startcic = cic; e->cgu.endcic = cic + c->range; e->cgu.type = c->cicgroupsupervisiontype; for (i = 0; i < (c->range + 1); i++) e->cgu.status[i] = c->status[i]; e->cgu.opc = opc; /* keep OPC information */ isup_free_call(ss7, c); return 0; case ISUP_CPG: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_CPG; e->cpg.cic = c->cic; e->cpg.opc = opc; /* keep OPC information */ e->cpg.event = c->event_info; return 0; case ISUP_UCIC: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_UCIC; e->ucic.cic = c->cic; e->ucic.opc = opc; /* keep OPC information */ isup_free_call(ss7, c); return 0; case ISUP_FAA: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_FAA; e->faa.cic = c->cic; e->faa.call_ref_ident = c->call_ref_ident; e->faa.call_ref_pc = c->call_ref_pc; e->faa.opc = opc; /* keep OPC information */ e->faa.call = c; return 0; case ISUP_FAR: e = ss7_next_empty_event(ss7); if (!e) { isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_FAR; e->far.cic = c->cic; e->far.call_ref_ident = c->call_ref_ident; e->far.call_ref_pc = c->call_ref_pc; e->ucic.opc = opc; /* keep OPC information */ e->far.call = c; return 0; default: isup_free_call(ss7, c); return 0; } } static int isup_send_cicgroupmessage(struct ss7 *ss7, int messagetype, int begincic, int endcic, unsigned int dpc, unsigned char status[], int type) { struct isup_call call; int i; for (i = 0; (i + begincic) <= endcic; i++) call.status[i] = status[i]; call.cic = begincic; call.range = endcic - begincic; call.cicgroupsupervisiontype = type; call.dpc = dpc; if (call.range > 31) return -1; return isup_send_message(ss7, &call, messagetype, cicgroup_params); } int isup_cqr(struct ss7 *ss7, int begincic, int endcic, unsigned int dpc, unsigned char status[]) { struct isup_call call; int i; for (i = 0; (i + begincic) <= endcic; i++) call.status[i] = status[i]; call.cic = begincic; call.range = endcic - begincic; call.dpc = dpc; if (call.range > 31) return -1; return isup_send_message(ss7, &call, ISUP_CQR, cqr_params); } int isup_grs(struct ss7 *ss7, int begincic, int endcic, unsigned int dpc) { struct isup_call call; if (!ss7) return -1; call.cic = begincic; call.range = endcic - begincic; call.dpc = dpc; if (call.range > 31) return -1; return isup_send_message(ss7, &call, ISUP_GRS, greset_params); } int isup_gra(struct ss7 *ss7, int begincic, int endcic, unsigned int dpc) { struct isup_call call; if (!ss7) return -1; call.cic = begincic; call.range = endcic - begincic; call.dpc = dpc; if (call.range > 31) return -1; return isup_send_message(ss7, &call, ISUP_GRA, greset_params); } int isup_cgb(struct ss7 *ss7, int begincic, int endcic, unsigned int dpc, unsigned char state[], int type) { if (!ss7) return -1; return isup_send_cicgroupmessage(ss7, ISUP_CGB, begincic, endcic, dpc, state, type); } int isup_cgu(struct ss7 *ss7, int begincic, int endcic, unsigned int dpc, unsigned char state[], int type) { if (!ss7) return -1; return isup_send_cicgroupmessage(ss7, ISUP_CGU, begincic, endcic, dpc, state, type); } int isup_cgba(struct ss7 *ss7, int begincic, int endcic, unsigned int dpc, unsigned char state[], int type) { if (!ss7) return -1; return isup_send_cicgroupmessage(ss7, ISUP_CGBA, begincic, endcic, dpc, state, type); } int isup_cgua(struct ss7 *ss7, int begincic, int endcic, unsigned int dpc, unsigned char state[], int type) { if (!ss7) return -1; return isup_send_cicgroupmessage(ss7, ISUP_CGUA, begincic, endcic, dpc, state, type); } int isup_iam(struct ss7 *ss7, struct isup_call *c) { if (!ss7 || !c) return -1; if (ss7->switchtype == SS7_ITU) return isup_send_message(ss7, c, ISUP_IAM, iam_params); else return isup_send_message(ss7, c, ISUP_IAM, ansi_iam_params); } int isup_acm(struct ss7 *ss7, struct isup_call *c) { if (!ss7 || !c) return -1; return isup_send_message(ss7, c, ISUP_ACM, acm_params); } int isup_faa(struct ss7 *ss7, struct isup_call *c) { if (!ss7 || !c) return -1; return isup_send_message(ss7, c, ISUP_FAA, faa_params); } int isup_far(struct ss7 *ss7, struct isup_call *c) { if (!ss7 || !c) return -1; if (c->next && c->next->call_ref_ident) { c->call_ref_ident = c->next->call_ref_ident; c->call_ref_pc = c->next->call_ref_pc; return isup_send_message(ss7, c, ISUP_FAR, far_params); } return -1; } int isup_anm(struct ss7 *ss7, struct isup_call *c) { if (!ss7 || !c) return -1; return isup_send_message(ss7, c, ISUP_ANM, anm_params); } int isup_con(struct ss7 *ss7, struct isup_call *c) { if (!ss7 || !c) return -1; return isup_send_message(ss7, c, ISUP_CON, con_params); } int isup_rel(struct ss7 *ss7, struct isup_call *c, int cause) { if (!ss7 || !c) return -1; if (cause < 0) cause = 16; c->cause = cause; c->causecode = CODE_CCITT; c->causeloc = LOC_PRIV_NET_LOCAL_USER; return isup_send_message(ss7, c, ISUP_REL, rel_params); } int isup_rlc(struct ss7 *ss7, struct isup_call *c) { int res; if (!ss7 || !c) return -1; res = isup_send_message(ss7, c, ISUP_RLC, empty_params); isup_free_call(ss7, c); return res; } static int isup_send_message_ciconly(struct ss7 *ss7, int messagetype, int cic, unsigned int dpc) { int res; struct isup_call c; c.cic = cic; c.dpc = dpc; res = isup_send_message(ss7, &c, messagetype, empty_params); return res; } int isup_cpg(struct ss7 *ss7, struct isup_call *c, int event) { if (!ss7 || !c) return -1; c->event_info = event; return isup_send_message(ss7, c, ISUP_CPG, cpg_params); } int isup_rsc(struct ss7 *ss7, int cic, unsigned int dpc) { if (!ss7) return -1; return isup_send_message_ciconly(ss7, ISUP_RSC, cic, dpc); } int isup_blo(struct ss7 *ss7, int cic, unsigned int dpc) { if (!ss7) return -1; return isup_send_message_ciconly(ss7, ISUP_BLO, cic, dpc); } int isup_ubl(struct ss7 *ss7, int cic, unsigned int dpc) { if (!ss7) return -1; return isup_send_message_ciconly(ss7, ISUP_UBL, cic, dpc); } int isup_bla(struct ss7 *ss7, int cic, unsigned int dpc) { if (!ss7) return -1; return isup_send_message_ciconly(ss7, ISUP_BLA, cic, dpc); } int isup_lpa(struct ss7 *ss7, int cic, unsigned int dpc) { if (!ss7) return -1; return isup_send_message_ciconly(ss7, ISUP_LPA, cic, dpc); } int isup_ucic(struct ss7 *ss7, int cic, unsigned int dpc) { if (!ss7) return -1; return isup_send_message_ciconly(ss7, ISUP_UCIC, cic, dpc); } int isup_uba(struct ss7 *ss7, int cic, unsigned int dpc) { if (!ss7) return -1; return isup_send_message_ciconly(ss7, ISUP_UBA, cic, dpc); } int isup_cvr(struct ss7 *ss7, int cic, unsigned int dpc) { if (!ss7) return -1; return isup_send_message_ciconly(ss7, ISUP_CVR, cic, dpc); } /* Janelle is the bomb (Again) */ libss7-1.0.2/mtp2.c0000644000000000000000000004670511046151741012455 0ustar rootroot/* * libss7: An implementation of Signalling System 7 * * Written by Matthew Fredrickson * * scheduling routines taken from libpri by Mark Spencer * * Copyright (C) 2006-2008, Digium, Inc * All Rights Reserved. */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. * * In addition, when this program is distributed with Asterisk in * any form that would qualify as a 'combined work' or as a * 'derivative work' (but not mere aggregation), you can redistribute * and/or modify the combination under the terms of the license * provided with that copy of Asterisk, instead of the license * terms granted here. */ #include "ss7_internal.h" #include "mtp3.h" #include #include #include #include #include #include "mtp2.h" #define mtp_error ss7_error #define mtp_message ss7_message static inline int len_txbuf(struct mtp2 *link) { int res = 0; struct ss7_msg *cur = link->tx_buf; while (cur) { res++; cur = cur->next; } return res; } static inline char * linkstate2str(int linkstate) { char *statestr = NULL; switch (linkstate) { case 0: statestr = "IDLE"; break; case 1: statestr = "NOTALIGNED"; break; case 2: statestr = "ALIGNED"; break; case 3: statestr = "PROVING"; break; case 4: statestr = "ALIGNEDREADY"; break; case 5: statestr = "INSERVICE"; break; } return statestr; } static inline void init_mtp2_header(struct mtp2 *link, struct mtp_su_head *h, int new, int nack) { if (new) { link->curfsn += 1; link->flags |= MTP2_FLAG_WRITE; } h->fib = link->curfib; h->fsn = link->curfsn; if (nack) { link->curbib = !link->curbib; link->flags |= MTP2_FLAG_WRITE; } h->bib = link->curbib; h->bsn = link->lastfsnacked; } static inline int lssu_type(struct mtp_su_head *h) { return h->data[0]; } static void flush_bufs(struct mtp2 *link) { struct ss7_msg *list, *cur; list = link->tx_buf; link->tx_buf = NULL; while (list) { cur = list; list = list->next; free(cur); } list = link->tx_q; link->tx_q = NULL; while (list) { cur = list; list = list->next; free(cur); } link->retransmit_pos = NULL; } static void reset_mtp(struct mtp2 *link) { link->curfsn = 127; link->curfib = 1; link->curbib = 1; link->lastfsnacked = 127; link->retransmissioncount = 0; link->flags |= MTP2_FLAG_WRITE; flush_bufs(link); } static void mtp2_request_retransmission(struct mtp2 *link) { link->retransmissioncount++; link->curbib = !link->curbib; link->flags |= MTP2_FLAG_WRITE; } static int mtp2_queue_su(struct mtp2 *link, struct ss7_msg *m) { struct ss7_msg *cur; if (!link->tx_q) { link->tx_q = m; m->next = NULL; return 0; } cur = link->tx_q; for (cur = link->tx_q; cur->next; cur = cur->next); cur->next = m; m->next = NULL; return 0; } static void make_lssu(struct mtp2 *link, unsigned char *buf, unsigned int *size, int lssu_status) { struct mtp_su_head *head; *size = LSSU_SIZE; memset(buf, 0, LSSU_SIZE); head = (struct mtp_su_head *)buf; head->li = 1; switch (lssu_status) { case LSSU_SIOS: case LSSU_SIO: reset_mtp(link); case LSSU_SIN: case LSSU_SIE: case LSSU_SIPO: case LSSU_SIB: head->bib = link->curbib; head->bsn = link->lastfsnacked; head->fib = link->curfib; head->fsn = link->curfsn; break; } head->data[0] = lssu_status; } static void make_fisu(struct mtp2 *link, unsigned char *buf, unsigned int *size, int nack) { struct mtp_su_head *h; *size = FISU_SIZE; h = (struct mtp_su_head *)buf; memset(buf, 0, *size); init_mtp2_header(link, h, 0, nack); h->li = 0; } static void add_txbuf(struct mtp2 *link, struct ss7_msg *m) { m->next = link->tx_buf; link->tx_buf = m; #if 0 mtp_message(link->master, "Txbuf contains %d items\n", len_txbuf(link)); #endif } static void update_retransmit_pos(struct mtp2 *link) { struct ss7_msg *cur, *prev = NULL; /* Our txbuf is in reversed order from the order we need to retransmit in */ cur = link->tx_buf; while (cur) { if (cur == link->retransmit_pos) break; prev = cur; cur = cur->next; } link->retransmit_pos = prev; } static void mtp2_retransmit(struct mtp2 *link) { struct ss7_msg *m; link->flags |= MTP2_FLAG_WRITE; /* Have to invert the current fib */ link->curfib = !link->curfib; m = link->tx_buf; if (!m) { ss7_error(link->master, "Huh!? Asked to retransmit but we don't have anything in the tx buffer\n"); return; } while (m->next) m = m->next; link->retransmit_pos = m; } int mtp2_transmit(struct mtp2 *link) { int res = 0; unsigned char *h; unsigned char buf[64]; unsigned int size; struct ss7_msg *m = NULL; int retransmit = 0; if (link->retransmit_pos) { struct mtp_su_head *h1; m = link->retransmit_pos; retransmit = 1; if (!m) { ss7_error(link->master, "Huh, requested to retransmit, but nothing in retransmit buffer?!!\n"); return -1; } h = m->buf; size = m->size; h1 = (struct mtp_su_head *)h; /* Update the FIB and BSN since they aren't the same */ h1->fib = link->curfib; h1->bsn = link->lastfsnacked; } else { if (link->tx_q) m = link->tx_q; if (m) { h = m->buf; size = m->size; } else { size = sizeof(buf); if (link->autotxsutype == FISU) make_fisu(link, buf, &size, 0); else make_lssu(link, buf, &size, link->autotxsutype); h = buf; } } res = write(link->fd, h, size); /* Add 2 for FCS */ if (res > 0) { mtp2_dump(link, '>', h, size - 2); if (retransmit) { /* Update our retransmit positon since it transmitted */ update_retransmit_pos(link); } else { if (m) { /* Advance to next MSU to be transmitted */ link->tx_q = m->next; /* Add it to the tx'd message queue (MSUs that haven't been acknowledged) */ add_txbuf(link, m); } } if (h == buf) { /* We just sent a non MSU */ link->flags &= ~MTP2_FLAG_WRITE; } } return res; } int mtp2_msu(struct mtp2 *link, struct ss7_msg *m) { int len = m->size - MTP2_SIZE; struct mtp_su_head *h = (struct mtp_su_head *) m->buf; link->flags |= MTP2_FLAG_WRITE; init_mtp2_header(link, h, 1, 0); if (len > MTP2_LI_MAX) h->li = MTP2_LI_MAX; else h->li = len; m->size += 2; /* For CRC */ mtp2_queue_su(link, m); /* Just in case */ m->next = NULL; return 0; } static int mtp2_lssu(struct mtp2 *link, int lssu_status) { link->flags |= MTP2_FLAG_WRITE; link->autotxsutype = lssu_status; return 0; } static int mtp2_fisu(struct mtp2 *link, int nack) { link->flags |= MTP2_FLAG_WRITE; link->autotxsutype = FISU; return 0; } static void update_txbuf(struct mtp2 *link, unsigned char upto) { struct mtp_su_head *h; struct ss7_msg *prev = NULL, *cur; struct ss7_msg *frlist = NULL; /* Make a list, frlist that will be the SUs to free */ /* Empty list */ if (!link->tx_buf) { return; } cur = link->tx_buf; while (cur) { h = (struct mtp_su_head *)cur->buf; if (h->fsn == upto) { frlist = cur; if (!prev) /* Head of list */ link->tx_buf = NULL; else prev->next = NULL; frlist = cur; break; } prev = cur; cur = cur->next; } while (frlist) { cur = frlist; frlist = frlist->next; free(cur); } return; } static int fisu_rx(struct mtp2 *link, struct mtp_su_head *h, int len) { if (link->lastsurxd == FISU) return 0; else link->lastsurxd = FISU; switch (link->state) { case MTP_PROVING: return mtp2_setstate(link, MTP_ALIGNEDREADY); /* Just in case our timers are a little off */ case MTP_ALIGNEDREADY: mtp2_setstate(link, MTP_INSERVICE); case MTP_INSERVICE: if (h->fsn != link->lastfsnacked) { mtp_message(link->master, "Received out of sequence FISU w/ fsn of %d, lastfsnacked = %d, requesting retransmission\n", h->fsn, link->lastfsnacked); mtp2_request_retransmission(link); } break; default: mtp_message(link->master, "Huh?! Got FISU in link state %d\n", link->state); return -1; } return 0; } static void t1_expiry(void *data) { struct mtp2 *link = data; mtp2_setstate(link, MTP_IDLE); return; } static void t2_expiry(void * data) { struct mtp2 *link = data; mtp2_setstate(link, MTP_IDLE); return; } static void t3_expiry(void * data) { struct mtp2 *link = data; mtp2_setstate(link, MTP_IDLE); return; } static void t4_expiry(void * data) { struct mtp2 *link = data; if (link->master->debug & SS7_DEBUG_MTP2) ss7_message(link->master, "T4 expired!\n"); mtp2_setstate(link, MTP_ALIGNEDREADY); return; } static int to_idle(struct mtp2 *link) { link->state = MTP_IDLE; if (mtp2_lssu(link, LSSU_SIOS)) { mtp_error(link->master, "Could not transmit LSSU\n"); return -1; } mtp2_setstate(link, MTP_NOTALIGNED); return 0; } int mtp2_setstate(struct mtp2 *link, int newstate) { ss7_event *e; if (link->master->debug & SS7_DEBUG_MTP2) mtp_message(link->master, "Link state change: %s -> %s\n", linkstate2str(link->state), linkstate2str(newstate)); switch (link->state) { case MTP_IDLE: link->t2 = ss7_schedule_event(link->master, link->timers.t2, t2_expiry, link); if (mtp2_lssu(link, LSSU_SIO)) { mtp_error(link->master, "Unable to transmit initial LSSU\n"); return -1; } link->state = MTP_NOTALIGNED; return 0; case MTP_NOTALIGNED: ss7_schedule_del(link->master, &link->t2); switch (newstate) { case MTP_IDLE: return to_idle(link); case MTP_ALIGNED: case MTP_PROVING: if (newstate == MTP_ALIGNED) link->t3 = ss7_schedule_event(link->master, link->timers.t3, t3_expiry, link); else link->t4 = ss7_schedule_event(link->master, link->provingperiod, t4_expiry, link); if (link->emergency) { if (mtp2_lssu(link, LSSU_SIE)) { mtp_error(link->master, "Couldn't tx LSSU_SIE\n"); return -1; } } else { if (mtp2_lssu(link, LSSU_SIN)) { mtp_error(link->master, "Couldn't tx LSSU_SIE\n"); return -1; } } break; } link->state = newstate; return 0; case MTP_ALIGNED: ss7_schedule_del(link->master, &link->t3); switch (newstate) { case MTP_IDLE: return to_idle(link); case MTP_PROVING: link->t4 = ss7_schedule_event(link->master, link->provingperiod, t4_expiry, link); } link->state = newstate; return 0; case MTP_PROVING: ss7_schedule_del(link->master, &link->t4); switch (newstate) { case MTP_IDLE: return to_idle(link); case MTP_PROVING: link->t4 = ss7_schedule_event(link->master, link->provingperiod, t4_expiry, link); break; case MTP_ALIGNED: if (link->emergency) { if (mtp2_lssu(link, LSSU_SIE)) { mtp_error(link->master, "Could not transmit LSSU\n"); return -1; } } else { if (mtp2_lssu(link, LSSU_SIN)) { mtp_error(link->master, "Could not transmit LSSU\n"); return -1; } } break; case MTP_ALIGNEDREADY: link->t1 = ss7_schedule_event(link->master, link->timers.t1, t1_expiry, link); if (mtp2_fisu(link, 0)) { mtp_error(link->master, "Could not transmit FISU\n"); return -1; } break; } link->state = newstate; return 0; case MTP_ALIGNEDREADY: ss7_schedule_del(link->master, &link->t1); /* Our timer expired, it should be cleaned up already */ switch (newstate) { case MTP_IDLE: return to_idle(link); case MTP_ALIGNEDREADY: link->t1 = ss7_schedule_event(link->master, link->timers.t1, t1_expiry, link); if (mtp2_fisu(link, 0)) { mtp_error(link->master, "Could not transmit FISU\n"); return -1; } break; case MTP_INSERVICE: ss7_schedule_del(link->master, &link->t1); e = ss7_next_empty_event(link->master); if (!e) { mtp_error(link->master, "Could not queue event\n"); return -1; } e->gen.e = MTP2_LINK_UP; e->gen.data = link->slc; break; default: mtp_error(link->master, "Don't know how to handle state change from %d to %d\n", link->state, newstate); break; } link->state = newstate; return 0; case MTP_INSERVICE: if (newstate != MTP_INSERVICE) { e = ss7_next_empty_event(link->master); if (!e) { mtp_error(link->master, "Could not queue event\n"); return -1; } e->gen.e = MTP2_LINK_DOWN; e->gen.data = link->slc; return to_idle(link); } break; } return 0; } static int lssu_rx(struct mtp2 *link, struct mtp_su_head *h, int len) { unsigned char lssutype = lssu_type(h); if (len > (LSSU_SIZE + 2)) /* FCS is two bytes */ mtp_error(link->master, "Received LSSU with length %d longer than expected\n", len); if (link->lastsurxd == lssutype) return 0; else link->lastsurxd = lssutype; if (lssutype == LSSU_SIE) link->emergency = 1; switch (link->state) { case MTP_IDLE: case MTP_NOTALIGNED: if ((lssutype != LSSU_SIE) && (lssutype != LSSU_SIN) && (lssutype != LSSU_SIO)) return mtp2_setstate(link, MTP_NOTALIGNED); if ((link->emergency) || (lssutype == LSSU_SIE)) link->provingperiod = link->timers.t4e; else link->provingperiod = link->timers.t4; if ((lssutype == LSSU_SIE) || (lssutype == LSSU_SIN)) return mtp2_setstate(link, MTP_PROVING); else return mtp2_setstate(link, MTP_ALIGNED); case MTP_ALIGNED: if (lssutype == LSSU_SIOS) return mtp2_setstate(link, MTP_IDLE); if ((link->emergency) || (lssutype == LSSU_SIE)) link->provingperiod = link->timers.t4e; else link->provingperiod = link->timers.t4; if ((link->provingperiod == link->timers.t4) && ((link->emergency) || (lssutype == LSSU_SIE))) link->provingperiod = link->timers.t4e; return mtp2_setstate(link, MTP_PROVING); case MTP_PROVING: if (lssutype == LSSU_SIOS) return mtp2_setstate(link, MTP_IDLE); if (lssutype == LSSU_SIO) return mtp2_setstate(link, MTP_ALIGNED); mtp_message(link->master, "Don't handle any other conditions in state %d\n", link->state); break; case MTP_ALIGNEDREADY: case MTP_INSERVICE: if ((lssutype != LSSU_SIOS) && (lssutype != LSSU_SIO)) mtp_message(link->master, "Got LSSU of type %d while link is in state %d. Re-Aligning\n", lssutype, link->state); return mtp2_setstate(link, MTP_IDLE); } return 0; } static int msu_rx(struct mtp2 *link, struct mtp_su_head *h, int len) { int res = 0; switch (link->state) { case MTP_ALIGNEDREADY: mtp2_setstate(link, MTP_INSERVICE); break; case MTP_INSERVICE: break; default: mtp_error(link->master, "Received MSU in invalid state %d\n", link->state); return -1; } /* If we're still waiting for our retranmission acknownledgement, we'll just ignore subsequent MSUs until it starts */ if (h->fib != link->curbib) { mtp_message(link->master, "MSU received, though still waiting for retransmission start. Dropping.\n"); return 0; } if (h->fsn == link->lastfsnacked) { /* Discard */ mtp_message(link->master, "Received double MSU, dropping\n"); return 0; } if (h->fsn != ((link->lastfsnacked+1) % 128)) { mtp_message(link->master, "Received out of sequence MSU w/ fsn of %d, lastfsnacked = %d, requesting retransmission\n", h->fsn, link->lastfsnacked); mtp2_request_retransmission(link); return 0; } /* Ok, it's a valid MSU now and we can accept it */ link->lastfsnacked = h->fsn; /* Set write flag since we need to update the FISUs with our new BSN */ link->flags |= MTP2_FLAG_WRITE; /* The big function */ res = mtp3_receive(link->master, link, h->data, len - MTP2_SU_HEAD_SIZE); return res; } int mtp2_start(struct mtp2 *link, int emergency) { link->emergency = emergency; if (link->state == MTP_IDLE) return mtp2_setstate(link, MTP_NOTALIGNED); else return 0; } int mtp2_stop(struct mtp2 *link) { return mtp2_setstate(link, MTP_IDLE); } struct mtp2 * mtp2_new(int fd, unsigned int switchtype) { struct mtp2 * new = calloc(1, sizeof(struct mtp2)); if (!new) return NULL; reset_mtp(new); new->fd = fd; new->autotxsutype = LSSU_SIOS; new->lastsurxd = -1; new->lastsutxd = -1; if (switchtype == SS7_ITU) { new->timers.t1 = ITU_TIMER_T1; new->timers.t2 = ITU_TIMER_T2; new->timers.t3 = ITU_TIMER_T3; new->timers.t4 = ITU_TIMER_T4_NORMAL; new->timers.t4e = ITU_TIMER_T4_EMERGENCY; } else if (switchtype == SS7_ANSI) { new->timers.t1 = ANSI_TIMER_T1; new->timers.t2 = ANSI_TIMER_T2; new->timers.t3 = ANSI_TIMER_T3; new->timers.t4 = ANSI_TIMER_T4_NORMAL; new->timers.t4e = ANSI_TIMER_T4_EMERGENCY; } return new; } void mtp2_dump(struct mtp2 *link, char prefix, unsigned char *buf, int len) { struct mtp_su_head *h = (struct mtp_su_head *)buf; unsigned char mtype; char *mtypech = NULL; if (!(link->master->debug & SS7_DEBUG_MTP2)) return; switch (h->li) { case 0: mtype = 0; break; case 1: case 2: mtype = 1; break; default: mtype = 2; break; } switch (mtype) { case 0: if (prefix == '<' && link->lastsurxd == FISU) return; if (prefix == '>' && link->lastsutxd == FISU) return; else link->lastsutxd = FISU; ss7_dump_msg(link->master, buf, len); ss7_message(link->master, "FSN: %d FIB %d\n", h->fsn, h->fib); ss7_message(link->master, "BSN: %d BIB %d\n", h->bsn, h->bib); ss7_message(link->master, "%c[%d] FISU\n", prefix, link->slc); break; case 1: if (prefix == '<' && link->lastsurxd == h->data[0]) return; if (prefix == '>' && link->lastsutxd == h->data[0]) return; else link->lastsutxd = h->data[0]; switch (h->data[0]) { case LSSU_SIOS: mtypech = "SIOS"; break; case LSSU_SIO: mtypech = "SIO"; break; case LSSU_SIN: mtypech = "SIN"; break; case LSSU_SIE: mtypech = "SIE"; break; case LSSU_SIPO: mtypech = "SIPO"; break; case LSSU_SIB: mtypech = "SIB"; break; } ss7_dump_msg(link->master, buf, len); ss7_message(link->master, "FSN: %d FIB %d\n", h->fsn, h->fib); ss7_message(link->master, "BSN: %d BIB %d\n", h->bsn, h->bib); ss7_message(link->master, "%c[%d] LSSU %s\n", prefix, link->slc, mtypech); break; case 2: ss7_dump_msg(link->master, buf, len); ss7_message(link->master, "FSN: %d FIB %d\n", h->fsn, h->fib); ss7_message(link->master, "BSN: %d BIB %d\n", h->bsn, h->bib); ss7_message(link->master, "%c[%d] MSU\n", prefix, link->slc); ss7_dump_buf(link->master, 0, buf, 3); mtp3_dump(link->master, link, h->data, len - MTP2_SU_HEAD_SIZE); break; } ss7_message(link->master, "\n"); } /* returns an event */ int mtp2_receive(struct mtp2 *link, unsigned char *buf, int len) { struct mtp_su_head *h = (struct mtp_su_head *)buf; len -= 2; /* Strip the CRC off */ if (len < MTP2_SIZE) { ss7_message(link->master, "Got message smaller than the minimum SS7 SU length. Dropping\n"); return 0; } mtp2_dump(link, '<', buf, len); update_txbuf(link, h->bsn); /* Check for retransmission request */ if ((link->state == MTP_INSERVICE) && (h->bib != link->curfib)) { /* Negative ack */ ss7_message(link->master, "Got retransmission request sequence numbers greater than %d. Retransmitting %d message(s).\n", h->bsn, len_txbuf(link)); mtp2_retransmit(link); } switch (h->li) { case 0: /* FISU */ return fisu_rx(link, h, len); case 1: case 2: /* LSSU */ return lssu_rx(link, h, len); default: /* MSU */ return msu_rx(link, h, len); } return 0; } libss7-1.0.2/.version0000644000000000000000000000000611074703727013105 0ustar rootroot1.0.2 libss7-1.0.2/ss7_sched.c0000644000000000000000000000614511046151741013447 0ustar rootroot/* * libss7: An implementation of Signalling System 7 * * Written by Matthew Fredrickson * * scheduling routines taken from libpri by Mark Spencer * * Copyright (C) 2006-2008, Digium, Inc * All Rights Reserved. */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. * * In addition, when this program is distributed with Asterisk in * any form that would qualify as a 'combined work' or as a * 'derivative work' (but not mere aggregation), you can redistribute * and/or modify the combination under the terms of the license * provided with that copy of Asterisk, instead of the license * terms granted here. */ #include "libss7.h" #include "ss7_internal.h" #include "mtp3.h" #include /* Scheduler routines */ int ss7_schedule_event(struct ss7 *ss7, int ms, void (*function)(void *data), void *data) { int x; struct timeval tv; for (x=1;xss7_sched[x].callback) break; if (x == MAX_SCHED) { ss7_error(ss7, "No more room in scheduler\n"); return -1; } gettimeofday(&tv, NULL); tv.tv_sec += ms / 1000; tv.tv_usec += (ms % 1000) * 1000; if (tv.tv_usec > 1000000) { tv.tv_usec -= 1000000; tv.tv_sec += 1; } ss7->ss7_sched[x].when = tv; ss7->ss7_sched[x].callback = function; ss7->ss7_sched[x].data = data; return x; } struct timeval *ss7_schedule_next(struct ss7 *ss7) { struct timeval *closest = NULL; int x; /* Check subchannels */ for (x=1;xss7_sched[x].callback && (!closest || (closest->tv_sec > ss7->ss7_sched[x].when.tv_sec) || ((closest->tv_sec == ss7->ss7_sched[x].when.tv_sec) && (closest->tv_usec > ss7->ss7_sched[x].when.tv_usec)))) closest = &ss7->ss7_sched[x].when; } return closest; } static int __ss7_schedule_run(struct ss7 *ss7, struct timeval *tv) { int x; void (*callback)(void *); void *data; for (x=1;xss7_sched[x].callback && ((ss7->ss7_sched[x].when.tv_sec < tv->tv_sec) || ((ss7->ss7_sched[x].when.tv_sec == tv->tv_sec) && (ss7->ss7_sched[x].when.tv_usec <= tv->tv_usec)))) { callback = ss7->ss7_sched[x].callback; data = ss7->ss7_sched[x].data; ss7->ss7_sched[x].callback = NULL; ss7->ss7_sched[x].data = NULL; callback(data); } } return 0; } int ss7_schedule_run(struct ss7 *ss7) { int res; struct timeval tv; gettimeofday(&tv, NULL); res = __ss7_schedule_run(ss7, &tv); return res; } void ss7_schedule_del(struct ss7 *ss7, int *id) { if ((*id >= MAX_SCHED)) ss7_error(ss7, "Asked to delete sched id %d???\n", *id); if (*id < 0) /* Item already deleted */ return; ss7->ss7_sched[*id].callback = NULL; *id = -1; /* "Delete" the event */ } libss7-1.0.2/mtp3.c0000644000000000000000000003642011046151741012447 0ustar rootroot/* * libss7: An implementation of Signalling System 7 * * Written by Matthew Fredrickson * * scheduling routines taken from libpri by Mark Spencer * * Copyright (C) 2006-2008, Digium, Inc * All Rights Reserved. */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. * * In addition, when this program is distributed with Asterisk in * any form that would qualify as a 'combined work' or as a * 'derivative work' (but not mere aggregation), you can redistribute * and/or modify the combination under the terms of the license * provided with that copy of Asterisk, instead of the license * terms granted here. */ #include #include #include #include "libss7.h" #include "ss7_internal.h" #include "mtp2.h" #include "mtp3.h" #include "isup.h" #define mtp_error ss7_error #define mtp_message ss7_message char testmessage[] = "2564286288"; #define mtp3_size(ss7) (((ss7)->switchtype == SS7_ITU) ? 5 : 8) /* Routing label size */ #define rl_size(ss7) (((ss7)->switchtype == SS7_ITU) ? 4 : 7) static char * userpart2str(unsigned char userpart) { switch (userpart) { case SIG_NET_MNG: return "NET_MNG"; case SIG_STD_TEST: return "STD_TEST"; case SIG_SPEC_TEST: return "SPEC_TEST"; case SIG_SCCP: return "SCCP"; case SIG_ISUP: return "ISUP"; default: return "Unknown"; } } static char * ss7_ni2str(unsigned char ni) { switch (ni) { case SS7_NI_INT: return "international"; case SS7_NI_INT_SPARE: return "international_spare"; case SS7_NI_NAT: return "national"; case SS7_NI_NAT_SPARE: return "national_spare"; default: return "Unknown"; } } static int get_routinglabel(unsigned int switchtype, unsigned char *sif, struct routing_label *rl) { unsigned char *buf = sif; rl->type = switchtype; if (switchtype == SS7_ANSI) { rl->dpc = buf[0] | (buf[1] << 8) | (buf[2] << 16); rl->opc = buf[3] | (buf[4] << 8) | (buf[5] << 16); rl->sls = buf[6]; return 7; } else { /* ITU style */ /* more complicated. Stupid ITU with their programmer unfriendly point codes. */ rl->dpc = (buf[0] | (buf[1] << 8)) & 0x3fff; /* 14 bits long */ rl->opc = ((buf[1] >> 6) | (buf[2] << 2) | (buf[3] << 10)) & 0x3fff; rl->sls = buf[3] >> 4; return 4; } } unsigned char ansi_sls_next(struct ss7 *ss7) { unsigned char res = ss7->sls; ss7->sls = (ss7->sls + 1) % 256; return res; } static unsigned char get_userpart(unsigned char sio) { return sio & 0xf; } static inline unsigned char get_ni(unsigned char sio) { return (sio >> 6) & 0x3; } static inline unsigned char get_priority(unsigned char sio) { return (sio >> 4) & 0x3; } int set_routinglabel(unsigned char *sif, struct routing_label *rl) { unsigned char *buf = sif; switch (rl->type) { case SS7_ANSI: /* Cake */ buf[0] = rl->dpc & 0xff; buf[1] = (rl->dpc >> 8) & 0xff; buf[2] = (rl->dpc >> 16) & 0xff; buf[3] = rl->opc & 0xff; buf[4] = (rl->opc >> 8) & 0xff; buf[5] = (rl->opc >> 16) & 0xff; buf[6] = rl->sls & 0xff; return 7; case SS7_ITU: /* Stupid ITU point codes. This would be a lot easier if compilers could come up with a standard for doing bit field packing within data structures. But alas, they all have their differences. So bit shifting it is. */ buf[0] = rl->dpc & 0xff; buf[1] = ((rl->dpc >> 8) & 0x3f) | ((rl->opc << 6) & 0xc0); buf[2] = (rl->opc >> 2) & 0xff; buf[3] = ((rl->opc >> 10) & 0x0f) | ((rl->sls << 4) & 0xf0); return 4; default: return -1; } } /* Hopefully it'll be the bottom 4 bits */ static inline void set_h0(unsigned char *h0, unsigned char val) { (*h0) |= (val & 0xf); } static inline unsigned char get_h0(unsigned char *byte) { return (*byte) & 0xf; } static inline void set_h1(unsigned char *h1, unsigned char val) { (*h1) |= ((val << 4) & 0xf0); } static inline unsigned char get_h1(unsigned char *byte) { return (((*byte) & 0xf0) >> 4); } static inline struct mtp2 * sls_to_link(struct ss7 *ss7, unsigned char sls) { if (ss7->mtp2_linkstate[sls % ss7->numlinks] == MTP2_LINKSTATE_UP) return ss7->links[sls % ss7->numlinks]; else { struct mtp2 *winner = ss7->links[0]; int i; for (i = 0; i < ss7->numlinks; i++) { if (ss7->mtp2_linkstate[i] == MTP2_LINKSTATE_UP) { winner = ss7->links[i]; break; } } return winner; } } struct net_mng_message net_mng_messages[] = { { 1, 1, "COO"}, { 1, 2, "COA"}, { 1, 5, "CBD"}, { 1, 6, "CBA"}, { 2, 1, "ECO"}, { 2, 2, "ECA"}, { 3, 1, "RCT"}, { 3, 2, "TFC"}, { 4, 1, "TFP"}, { 4, 2, "TCP"}, { 4, 3, "TFR"}, { 4, 4, "TCR"}, { 4, 5, "TFA"}, { 4, 6, "TCA"}, { 5, 1, "RST/RSP"}, { 5, 2, "RSR"}, { 5, 3, "RCP"}, { 5, 4, "RCR"}, { 6, 1, "LIN"}, { 6, 2, "LUN"}, { 6, 3, "LIA"}, { 6, 4, "LUA"}, { 6, 5, "LID"}, { 6, 6, "LFU"}, { 6, 7, "LLT/LLI"}, { 6, 8, "LRT/LRI"}, { 7, 1, "TRA"}, { 7, 2, "TRW"}, { 8, 1, "DLC"}, { 8, 2, "CSS"}, { 8, 3, "CNS"}, { 8, 4, "CNP"}, { 0xa, 1, "UPU"}, }; static void mtp3_setstate_mtp2link(struct ss7 *ss7, struct mtp2 *link, int newstate) { int i; for (i = 0; i < ss7->numlinks; i++) { if (ss7->links[i] == link) ss7->mtp2_linkstate[i] = newstate; } } static char * net_mng_message2str(int h0, int h1) { int i; for (i = 0; i < (sizeof(net_mng_messages) / sizeof(struct net_mng_message)); i++) { if ((net_mng_messages[i].h0 == h0) && (net_mng_messages[i].h1 == h1)) return net_mng_messages[i].name; } return "Unknown"; } static int net_mng_dump(struct ss7 *ss7, struct mtp2 *mtp2, unsigned char userpart, unsigned char *buf, int len) { unsigned char *headerptr = buf + rl_size(ss7); unsigned char h1, h0; h1 = h0 = *headerptr; h1 = get_h1(headerptr); h0 = get_h0(headerptr); ss7_message(ss7, "\tH0: %x H1: %x\n", h0, h1); if (userpart == SIG_NET_MNG) ss7_message(ss7, "\tMessage type: %s\n", net_mng_message2str(h0, h1)); ss7_dump_buf(ss7, 1, headerptr, 1); return 0; } static void std_test_send(struct mtp2 *link) { struct ss7_msg *m; unsigned char *layer4; struct routing_label rl; struct ss7 *ss7 = link->master; int rllen = 0; unsigned char testlen = strlen(testmessage); m = ss7_msg_new(); if (!m) { ss7_error(link->master, "Malloc failed on ss7_msg!. Unable to transmit STD_TEST\n"); return; } layer4 = ss7_msg_userpart(m); rl.type = ss7->switchtype; rl.opc = ss7->pc; rl.dpc = link->dpc; rl.sls = link->slc; rllen = set_routinglabel(layer4, &rl); layer4 += rllen; set_h0(layer4, 1); set_h1(layer4, 1); layer4[1] = (testlen << 4); memcpy(&layer4[2], testmessage, testlen); ss7_msg_userpart_len(m, rllen + testlen + 2); mtp3_transmit(link->master, (ss7->switchtype == SS7_ITU) ? SIG_STD_TEST : SIG_SPEC_TEST, link->slc, m); } static int net_mng_receive(struct ss7 *ss7, struct mtp2 *mtp2, unsigned char *buf, int len) { unsigned char *headerptr = buf + rl_size(ss7); unsigned char h1, h0; h1 = h0 = *headerptr; h1 = get_h1(headerptr); h0 = get_h0(headerptr); /* Check to see if it's a TRA */ if ((h0 == 7) && (h1 == 1)) { ss7_event *e; mtp3_setstate_mtp2link(ss7, mtp2, MTP2_LINKSTATE_UP); if (ss7->state != SS7_STATE_UP) { e = ss7_next_empty_event(ss7); if (!e) { mtp_error(ss7, "Event queue full\n"); return -1; } e->e = SS7_EVENT_UP; ss7->state = SS7_STATE_UP; } return 0; } else { #if 0 ss7_message(ss7, "NET MNG message type %s received\n", net_mng_message2str(h0, h1)); #endif return 0; } } static void net_mng_send_tra(struct mtp2 *link) { struct ss7_msg *m; unsigned char *layer4; struct routing_label rl; struct ss7 *ss7 = link->master; int rllen = 0; m = ss7_msg_new(); if (!m) { ss7_error(link->master, "Malloc failed on ss7_msg!. Unable to transmit NET_MNG TRA\n"); return; } layer4 = ss7_msg_userpart(m); rl.type = ss7->switchtype; rl.opc = ss7->pc; rl.dpc = link->dpc; rl.sls = link->slc; rllen = set_routinglabel(layer4, &rl); layer4 += rllen; set_h0(layer4, 7); set_h1(layer4, 1); ss7_msg_userpart_len(m, rllen + 1); mtp3_transmit(link->master, SIG_NET_MNG, link->slc, m); } static int std_test_receive(struct ss7 *ss7, struct mtp2 *mtp2, unsigned char *buf, int len) { unsigned char *sif = buf; unsigned char *headerptr = buf + rl_size(ss7); unsigned char h1, h0; int testpatsize = 0; struct routing_label rl; get_routinglabel(ss7->switchtype, sif, &rl); if (rl.dpc != ss7->pc) goto fail; h1 = h0 = *headerptr; h1 = get_h1(headerptr); h0 = get_h0(headerptr); if (h0 != 1) goto fail; if (h1 == 1) { struct ss7_msg *m; struct routing_label drl; unsigned char *layer4; ss7_event *e; int rllen; m = ss7_msg_new(); if (!m) { ss7_error(ss7, "Unable to allocate message buffer!\n"); return -1; } drl.type = ss7->switchtype; drl.dpc = rl.opc; drl.opc = ss7->pc; #if 0 drl.sls = mtp2->slc; #else /* * I hate that we would have to do this, but it would seem that * some telcos set things up stupid enough that we have to */ drl.sls = rl.sls; #endif layer4 = ss7_msg_userpart(m); rllen = set_routinglabel(layer4, &drl); layer4 += rllen; testpatsize = (headerptr[1] >> 4) & 0xf; /* Success! */ set_h0(layer4, 1); set_h1(layer4, 2); layer4[1] = (testpatsize << 4); memcpy(&layer4[2], &headerptr[2], testpatsize); ss7_msg_userpart_len(m, rllen + testpatsize + 2); mtp3_transmit(ss7, (ss7->switchtype == SS7_ITU) ? SIG_STD_TEST : SIG_SPEC_TEST, mtp2->slc, m); /* Update linkstate */ mtp3_setstate_mtp2link(ss7, mtp2, MTP2_LINKSTATE_UP); if (ss7->state != SS7_STATE_UP) { e = ss7_next_empty_event(ss7); if (!e) { mtp_error(ss7, "Event queue full\n"); return -1; } e->e = SS7_EVENT_UP; } return 0; } else if (h1 == 2) { return 0; } else ss7_error(ss7, "Unhandled STD_TEST message: h0 = %x h1 = %x", h0, h1); fail: return -1; } int mtp3_transmit(struct ss7 *ss7, unsigned char userpart, unsigned char sls, struct ss7_msg *m) { unsigned char *sio; unsigned char *sif; struct mtp2 *winner; int priority = 3; sio = m->buf + MTP2_SIZE; sif = sio + 1; winner = sls_to_link(ss7, sls); if (ss7->switchtype == SS7_ITU) (*sio) = (ss7->ni << 6) | userpart; else (*sio) = (ss7->ni << 6) | (priority << 4) | userpart; return mtp2_msu(winner, m); } int mtp3_dump(struct ss7 *ss7, struct mtp2 *link, void *msg, int len) { unsigned char *buf = (unsigned char *)msg; unsigned char *sio = &buf[0]; unsigned char *sif = &buf[1]; unsigned char ni = get_ni(*sio); unsigned char priority = get_priority(*sio); unsigned char userpart = get_userpart(*sio); struct routing_label rl; unsigned int siflen = len - 1; int rlsize; ss7_message(ss7, "\tNetwork Indicator: %d Priority: %d User Part: %s (%d)\n", ni, priority, userpart2str(userpart), userpart); ss7_dump_buf(ss7, 1, sio, 1); rlsize = get_routinglabel(ss7->switchtype, sif, &rl); if (ss7->switchtype == SS7_ANSI) ss7_message(ss7, "\tOPC %d-%d-%d DPC %d-%d-%d SLS %d\n", (rl.opc >> 16) & 0xff, (rl.opc >> 8) & 0xff, rl.opc & 0xff, (rl.dpc >> 16) & 0xff, (rl.dpc >> 8) & 0xff, rl.dpc & 0xff, rl.sls); else ss7_message(ss7, "\tOPC %d DPC %d SLS %d\n", rl.opc, rl.dpc, rl.sls); ss7_dump_buf(ss7, 1, sif, rlsize); /* Pass it to the correct user part */ switch (userpart) { case SIG_NET_MNG: case SIG_STD_TEST: case SIG_SPEC_TEST: return net_mng_dump(ss7, link, userpart, sif, siflen); case SIG_ISUP: return isup_dump(ss7, link, sif + rlsize, siflen - rlsize); case SIG_SCCP: default: return 0; } return 0; } int mtp3_receive(struct ss7 *ss7, struct mtp2 *link, void *msg, int len) { unsigned char *buf = (unsigned char *)msg; unsigned char *sio = &buf[0]; unsigned char *sif = &buf[1]; unsigned int siflen = len - 1; unsigned char ni = get_ni(*sio); unsigned char userpart = get_userpart(*sio); struct routing_label rl; int rlsize; /* Check NI to make sure it's set correct */ if (ss7->ni != ni) { mtp_error(ss7, "Received MSU with network indicator of %s, but we are %s\n", ss7_ni2str(ni), ss7_ni2str(ss7->ni)); return -1; } /* Check point codes to make sure the message is destined for us */ rlsize = get_routinglabel(ss7->switchtype, sif, &rl); if (ss7->pc != rl.dpc) { mtp_error(ss7, "Received message destined for point code 0x%x but we're 0x%x. Dropping\n", rl.dpc, ss7->pc); return -1; } /* TODO: find out what to do with the priority in ANSI networks */ /* Pass it to the correct user part */ switch (userpart) { case SIG_STD_TEST: case SIG_SPEC_TEST: return std_test_receive(ss7, link, sif, siflen); case SIG_ISUP: /* Skip the routing label */ return isup_receive(ss7, link, &rl, sif + rlsize, siflen - rlsize); case SIG_NET_MNG: return net_mng_receive(ss7, link, sif, siflen); case SIG_SCCP: default: mtp_message(ss7, "Unable to process message destined for userpart %d; dropping message\n", userpart); return 0; } } static void mtp3_event_link_up(struct mtp2 * link) { if (!link->sent_tra) { net_mng_send_tra(link); link->sent_tra = 1; } std_test_send(link); } static void mtp3_event_link_down(struct mtp2 *link) { struct ss7 *ss7 = link->master; /* Make sure we notify MTP3 that the link went down beneath us */ mtp3_setstate_mtp2link(ss7, link, MTP2_LINKSTATE_DOWN); } static struct mtp2 * slc_to_mtp2(struct ss7 *ss7, unsigned int slc) { int i = 0; struct mtp2 *link = NULL; for (i = 0; i < ss7->numlinks; i++) { if (ss7->links[i]->slc == slc) link = ss7->links[i]; } return link; } ss7_event * mtp3_process_event(struct ss7 *ss7, ss7_event *e) { struct mtp2 *link; /* Check to see if there is no event to process */ if (!e) return NULL; switch (e->e) { case MTP2_LINK_UP: link = slc_to_mtp2(ss7, e->gen.data); mtp3_event_link_up(link); return e; case MTP2_LINK_DOWN: link = slc_to_mtp2(ss7, e->gen.data); mtp3_event_link_down(link); return e; default: return e; } return e; } void mtp3_start(struct ss7 *ss7) { int i; for (i = 0; i < ss7->numlinks; i++) { if ((ss7->mtp2_linkstate[i] == MTP2_LINKSTATE_DOWN)) { mtp2_start(ss7->links[i], 1); ss7->mtp2_linkstate[i] = MTP2_LINKSTATE_ALIGNING; } } return; } void mtp3_alarm(struct ss7 *ss7, int fd) { int i; int winner = -1; int linksup = 0; for (i = 0; i < ss7->numlinks; i++) { if (ss7->links[i]->fd == fd) { winner = i; break; } } if (winner > -1) { ss7->mtp2_linkstate[winner] = MTP2_LINKSTATE_INALARM; mtp2_stop(ss7->links[winner]); } for (i = 0; i < ss7->numlinks; i++) { /* Let's count how many links are up while we're going through them */ if (ss7->mtp2_linkstate[i] == MTP2_LINKSTATE_UP) linksup++; } if (!linksup) { ss7->state = SS7_STATE_DOWN; ss7_event *e = ss7_next_empty_event(ss7); if (!e) { ss7_error(ss7, "Event queue full!"); return; } e->e = SS7_EVENT_DOWN; return; } } void mtp3_noalarm(struct ss7 *ss7, int fd) { int i; int winner = -1; for (i = 0; i < ss7->numlinks; i++) { if (ss7->links[i]->fd == fd) { winner = i; break; } } if (winner > -1) { ss7->mtp2_linkstate[winner] = MTP2_LINKSTATE_ALIGNING; mtp2_start(ss7->links[winner], 1); } } libss7-1.0.2/NEWS-05-30-20080000644000000000000000000000727611020047416013152 0ustar rootrootHey all, It has been a while since I have made a status update with regards to libss7, so I think it is about time that I should do so. Library Related Updates: ======================== Many things have changed since the last status update. Some of the highlights include are listed. Lots of additional parameters and messages are supported and dumped.... Many new channel variables are now added in chan_zap to receive SS7 specific information: SS7_CHARGE_NUMBER SS7_GENERIC_ADDRESS SS7_JIP SS7_GENERIC_DIGITS SS7_GENERIC_DIGTYPE (type of generic digits) SS7_GENERIC_DIGSCHEME SS7_ORIG_CALLED_NUM SS7_LSPI_IDENT (these three are used for RLT support on DMS switches) SS7_CALLREF_IDENT SS7_CALLREF_PC SS7_CALLING_PARTY_CATEGORY SS7_REDIRECTING_NUMBER SS7_GENERIC_NAME Most are fairly self explanatory as far as what they contain. It is also possible to set many of these parameters on outbound calls as well by prefixing the variable with an '_' when you set it. In addition, ANSI SS7 support has been improved extensively, thanks to Alan McMillan and Joseph (on this list). RLT support has been added for DMS switch types. *NOTE*: It is also recommended to all of you that are still using the trunk version of Asterisk for SS7 support to switch to the 1.6.0 branch (http://svn.digium.com/svn/asterisk/branches/1.6.0 to checkout via svn). When it is released it will be the first release branch to contain SS7 support. I am continuing to maintain and bugfix both 1.6.0 and trunk branches. Cool New Feature That You Should Use: ===================================== Also, as many of you may have noticed, there was a new Zaptel release (1.4.11). So you maybe asking yourself, "Why should I care about a new Zaptel release, this is the asterisk-ss7 mailing list". In case you were, this is why: I recently added a new channel type to zaptel which performs most of the real time work required to keep an MTP2 link alive in the kernel instead of in Asterisk/libss7. What does this mean for you? It means your links are going to be much more stable under system load. For most cases, the only thing now that will be able to knock your SS7 link down is if you are trying to echo cancel more channels than your CPU can handle (as echo cancellation is done in the same place as the kernel level MTP2). So if you have link stability problems still, it is likely your echo cancellation load is too high and you need to get a better CPU or a hardware echo canceller. Now, in order to update to use it, you need to get the latest version of Zaptel (1.4.11), libss7, and asterisk-1.6.0 (or Asterisk-trunk if you really still want to use it). Compile them in that order, and in zaptel.conf where you have the "dchan=" line for the signalling channel, change that to "mtp2=", run ztcfg, and, Voila!, it is done. Your existing zapata.conf should require no changes. This update is highly recommended, since the kernel is a much more appropriate place to do the work of a real time task like keeping FISUs and LSSUs constantly being sent on the line. For those that want the technical details of the new channel type, here is an explanation. Basically, it is similar to a dchan, so it does all you HDLC encoding and decoding, as well as CRC calculation and checking. The difference is that when you write messages on that channel, it automatically repeats the last one written. On the receive side, it compares the most recently received message with the last one received off the signalling link, and if it is different, it wakes up the Asterisk/libss7 process. If it is the same, it ignores it (so as not to have excessive and unnecessary user/kernel context switches). As always, if you have any questions, I am available on this list to answer them. libss7-1.0.2/isup.h0000644000000000000000000001455211046151741012553 0ustar rootroot/* * libss7: An implementation of Signalling System 7 * * Written by Matthew Fredrickson * * scheduling routines taken from libpri by Mark Spencer * * Copyright (C) 2006-2008, Digium, Inc * All Rights Reserved. */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. * * In addition, when this program is distributed with Asterisk in * any form that would qualify as a 'combined work' or as a * 'derivative work' (but not mere aggregation), you can redistribute * and/or modify the combination under the terms of the license * provided with that copy of Asterisk, instead of the license * terms granted here. */ #ifndef _SS7_ISUP_H #define _SS7_ISUP_H #include "ss7_internal.h" /* ISUP messages */ #define ISUP_IAM 0x01 #define ISUP_SAM 0x02 #define ISUP_INR 0x03 #define ISUP_INF 0x04 #define ISUP_COT 0x05 #define ISUP_ACM 0x06 #define ISUP_CON 0x07 #define ISUP_FOT 0x08 #define ISUP_ANM 0x09 #define ISUP_REL 0x0c #define ISUP_SUS 0x0d #define ISUP_RES 0x0e #define ISUP_RLC 0x10 #define ISUP_CCR 0x11 #define ISUP_RSC 0x12 #define ISUP_BLO 0x13 #define ISUP_UBL 0x14 #define ISUP_BLA 0x15 #define ISUP_UBA 0x16 #define ISUP_GRS 0x17 #define ISUP_CGB 0x18 #define ISUP_CGU 0x19 #define ISUP_CGBA 0x1a #define ISUP_CGUA 0x1b #define ISUP_CMR 0x1c #define ISUP_CMC 0x1d #define ISUP_CMRJ 0x1e #define ISUP_FAR 0x1f #define ISUP_FAA 0x20 #define ISUP_FRJ 0x21 #define ISUP_FAD 0x22 #define ISUP_FAI 0x23 #define ISUP_LPA 0x24 #define ISUP_CSVR 0x25 #define ISUP_CSVS 0x26 #define ISUP_DRS 0x27 #define ISUP_PAM 0x28 #define ISUP_GRA 0x29 #define ISUP_CQM 0x2a #define ISUP_CQR 0x2b #define ISUP_CPG 0x2c #define ISUP_USR 0x2d #define ISUP_UCIC 0x2e #define ISUP_CFN 0x2f #define ISUP_OLM 0x30 #define ISUP_CRG 0x31 #define ISUP_FAC 0x33 #define ISUP_CRA 0xe9 #define ISUP_CRM 0xea #define ISUP_CVR 0xeb #define ISUP_CVT 0xec #define ISUP_EXM 0xed /* ISUP Parameters */ #define ISUP_PARM_NATURE_OF_CONNECTION_IND 0x06 #define ISUP_PARM_FORWARD_CALL_IND 0x07 #define ISUP_PARM_CALLING_PARTY_CAT 0x09 #define ISUP_PARM_USER_SERVICE_INFO 0x1d #define ISUP_PARM_TRANSMISSION_MEDIUM_REQS 0x02 #define ISUP_PARM_CALLED_PARTY_NUM 0x04 #define ISUP_PARM_ACCESS_TRANS 0x03 #define ISUP_PARM_BUSINESS_GRP 0xc6 #define ISUP_PARM_CALL_REF 0x01 #define ISUP_PARM_CALLING_PARTY_NUM 0x0a #define ISUP_PARM_CARRIER_ID 0xc5 #define ISUP_PARM_SELECTION_INFO 0xee #define ISUP_PARM_CHARGE_NUMBER 0xeb #define ISUP_PARM_CIRCUIT_ASSIGNMENT_MAP 0x25 #define ISUP_PARM_OPT_BACKWARD_CALL_IND 0x29 #define ISUP_PARM_CONNECTION_REQ 0x0d #define ISUP_PARM_CONTINUITY_IND 0x10 #define ISUP_PARM_CUG_INTERLOCK_CODE 0x1c #define ISUP_PARM_EGRESS_SERV 0xc3 #define ISUP_PARM_GENERIC_ADDR 0xc0 #define ISUP_PARM_GENERIC_DIGITS 0xc1 #define ISUP_PARM_GENERIC_NAME 0xc7 #define ISUP_PARM_GENERIC_NOTIFICATION_IND 0x2c #define ISUP_PARM_BACKWARD_CALL_IND 0x11 #define ISUP_PARM_CAUSE 0x12 #define ISUP_PARM_CIRCUIT_GROUP_SUPERVISION_IND 0x15 #define ISUP_PARM_RANGE_AND_STATUS 0x16 #define ISUP_PARM_PROPAGATION_DELAY 0x31 #define ISUP_PARM_EVENT_INFO 0x24 #define ISUP_PARM_HOP_COUNTER 0x3d #define ISUP_PARM_OPT_FORWARD_CALL_INDICATOR 0x08 #define ISUP_PARM_LOCATION_NUMBER 0x3f #define ISUP_PARM_ORIG_LINE_INFO 0xea #define ISUP_PARM_REDIRECTION_INFO 0x13 #define ISUP_PARM_ORIGINAL_CALLED_NUM 0x28 #define ISUP_PARM_JIP 0xc4 #define ISUP_PARM_ECHO_CONTROL_INFO 0x37 #define ISUP_PARM_PARAMETER_COMPAT_INFO 0x39 #define ISUP_PARM_CIRCUIT_STATE_IND 0x26 #define ISUP_PARM_TRANSIT_NETWORK_SELECTION 0x23 #define ISUP_PARM_LOCAL_SERVICE_PROVIDER_IDENTIFICATION 0xe4 #define ISUP_PARM_FACILITY_IND 0x18 #define ISUP_PARM_REDIRECTING_NUMBER 0x0b #define ISUP_PARM_ACCESS_DELIVERY_INFO 0x2e /* ISUP Parameter Pseudo-type */ struct isup_parm_opt { unsigned char type; unsigned char len; unsigned char data[0]; }; struct isup_h { unsigned char cic[2]; unsigned char type; unsigned char data[0]; /* This is the contents of the message */ }; #define CIC_SIZE 2 #define ISUP_MAX_NUM 64 /* From GR-317 for the generic name filed: 15 + 1 */ #define ISUP_MAX_NAME 16 struct mtp2; struct isup_call { char called_party_num[ISUP_MAX_NUM]; unsigned char called_nai; char calling_party_num[ISUP_MAX_NUM]; unsigned char calling_party_cat; unsigned char calling_nai; unsigned char presentation_ind; unsigned char screening_ind; char charge_number[ISUP_MAX_NUM]; unsigned char charge_nai; unsigned char charge_num_plan; unsigned char gen_add_num_plan; unsigned char gen_add_nai; char gen_add_number[ISUP_MAX_NUM]; unsigned char gen_add_pres_ind; unsigned char gen_add_type; char gen_dig_number[ISUP_MAX_NUM]; unsigned char gen_dig_type; unsigned char gen_dig_scheme; char jip_number[ISUP_MAX_NUM]; unsigned char lspi_type; unsigned char lspi_scheme; unsigned char lspi_context; unsigned char lspi_spare; char lspi_ident[ISUP_MAX_NUM]; int oli_ani2; unsigned int call_ref_ident; unsigned int call_ref_pc; char orig_called_num[ISUP_MAX_NUM]; unsigned char orig_called_nai; unsigned char orig_called_pres_ind; unsigned char orig_called_screening_ind; char redirecting_num[ISUP_MAX_NUM]; unsigned char redirecting_num_nai; unsigned char redirecting_num_presentation_ind; unsigned char redirecting_num_screening_ind; unsigned char generic_name_typeofname; unsigned char generic_name_avail; unsigned char generic_name_presentation; char generic_name[ISUP_MAX_NAME]; int range; unsigned char status[255]; int transcap; int l1prot; int cause; int causecode; int causeloc; int cot_check_passed; int cot_check_required; int cicgroupsupervisiontype; unsigned char event_info; unsigned short cic; unsigned char sls; struct isup_call *next; /* set DPC according to CIC's DPC, not linkset */ unsigned int dpc; /* Backward Call Indicator variables */ unsigned char called_party_status_ind; }; int isup_receive(struct ss7 *ss7, struct mtp2 *sl, struct routing_label *rl, unsigned char *sif, int len); int isup_dump(struct ss7 *ss7, struct mtp2 *sl, unsigned char *sif, int len); #endif /* _SS7_ISUP_H */ libss7-1.0.2/NEWS-09-11-20060000644000000000000000000000435711020053142013141 0ustar rootrootHey all, long time no see, but I just wanted to give a status update on what is going on with libss7. Last week I was able to commit my alarm detection code (in case you get an alarm on your spans that have signalling channels). It should restart the link when it comes out of alarm fine. I think I need to get some more testing in though, since I mostly just wrote the code and did very rudimentary testing on it. I also just added today support in zapata.conf for national_spare and international_spare networkindicator options in case your link uses the spare network indicator values (someone on the list today had a problem with that). On an entirely different note, I got an ANSI style link working this week!!!! I didn't ask permission to see if they minded being mentioned, so I won't mention any names for now, however it was a night to remember. It was over a 56kbps link channel, using an older switch. It went surprisingly easier than I thought it would. MTP2 was already working well, MTP3 only had slight modifications, and ISUP had the most changes. Other than the fact that I'd never seen a 56kbps link before. Basically, the difference was that they don't use the top bit in a DS0 timeslot for HDLC code. So if you want to try out libss7 on your ANSI link, this is how you do it: Disclaimer: You have to be using either a TE2xxp or TE4xxp for this to work, since I used the hardware hdlc features of the framer of that card to do the 56kbps link. Get current zaptel-trunk, libss7, and asterisk-ss7 from svn (You may also have to get libpri, I haven't checked if chan_zap compiles cleanly without libpri installed) Build them, and install them. If you are using 56kbps links, when you load the wct4xxp.ko module, you have to pass it the parameter hardhdlcmode=0x7f and instead of using "dchan" in zaptel.conf for your signalling channel, you need to use "hardhdlc" on that channel. In zapata.conf, setup your link following the pattern in the sample zapata.conf that comes with asterisk-ss7 and set your ss7type=ansi. That should pretty much be it. All the rest of the configuration is the same. As always, if you have any more questions, comments, requests, or anything else that matter, let me know. I'd love to get feedback. Matthew Fredrickson libss7-1.0.2/mtp2.h0000644000000000000000000000745411046151741012460 0ustar rootroot/* * libss7: An implementation of Signalling System 7 * * Written by Matthew Fredrickson * * scheduling routines taken from libpri by Mark Spencer * * Copyright (C) 2006-2008, Digium, Inc * All Rights Reserved. */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. * * In addition, when this program is distributed with Asterisk in * any form that would qualify as a 'combined work' or as a * 'derivative work' (but not mere aggregation), you can redistribute * and/or modify the combination under the terms of the license * provided with that copy of Asterisk, instead of the license * terms granted here. */ #ifndef _SS7_MTP_H #define _SS7_MTP_H #include "ss7_internal.h" /* Code for extended length of message, i.e. greater than 62 octects */ #define MTP2_LI_MAX 63 /* janelle is the bombdiggity - jnizzle */ #define SIF_MAX_SIZE 272 #define MTP2_SU_HEAD_SIZE 3 #define MTP2_SIZE MTP2_SU_HEAD_SIZE /* MTP2 Timers */ /* For ITU 64kbps links */ #define ITU_TIMER_T1 45000 #define ITU_TIMER_T2 50000 #define ITU_TIMER_T3 1500 #define ITU_TIMER_T4_NORMAL 8500 #define ITU_TIMER_T4_EMERGENCY 500 /* ANSI links */ #define ANSI_TIMER_T1 16000 #define ANSI_TIMER_T2 11500 #define ANSI_TIMER_T3 11500 #define ANSI_TIMER_T4_NORMAL 2300 #define ANSI_TIMER_T4_EMERGENCY 600 /* Bottom 3 bits in LSSU status field */ #define LSSU_SIO 0 /* Out of alignment */ #define LSSU_SIN 1 /* Normal alignament */ #define LSSU_SIE 2 /* Emergency alignment */ #define LSSU_SIOS 3 /* Out of Service */ #define LSSU_SIPO 4 /* MTP2 cannot reach MTP3, useless for us */ #define LSSU_SIB 5 /* MTP2 congestion */ #define FISU 6 /* More MTP2 definitions */ /* Various sizes */ #define MTP_MAX_SIZE 277 /* 276 + 1 for RSIS */ #define LSSU_SIZE 6 #define FISU_SIZE 5 /* MTP2 Link states */ #define MTP_IDLE 0 #define MTP_NOTALIGNED 1 #define MTP_ALIGNED 2 #define MTP_PROVING 3 #define MTP_ALIGNEDREADY 4 #define MTP_INSERVICE 5 struct mtp_su_head { /* Common header for all signaling units */ unsigned char bsn:7; unsigned char bib:1; unsigned char fsn:7; unsigned char fib:1; unsigned char li:6; unsigned char spare:2; unsigned char data[0]; } __attribute__((packed)); struct ss7; struct mtp2_timers { int t1; int t2; int t3; int t4; int t4e; }; struct mtp2 { int state; unsigned char curfsn:7; unsigned char curfib:1; unsigned char lastfsnacked:7; unsigned char curbib:1; int fd; int flags; /* Timers */ int t1; int t2; int t3; int t4; struct mtp2_timers timers; int slc; int emergency; int provingperiod; unsigned int dpc; int autotxsutype; int lastsurxd; int lastsutxd; int sent_tra; /* Line related stats */ unsigned int retransmissioncount; struct ss7_msg *tx_buf; struct ss7_msg *tx_q; struct ss7_msg *retransmit_pos; struct ss7 *master; }; /* Flags for the struct mtp2 flags parameter */ #define MTP2_FLAG_ZAPMTP2 (1 << 0) #define MTP2_FLAG_WRITE (1 << 1) /* Initialize MTP link */ int mtp2_start(struct mtp2 *link, int emergency); int mtp2_stop(struct mtp2 *link); int mtp2_setstate(struct mtp2 *link, int state); struct mtp2 * mtp2_new(int fd, unsigned int switchtype); int mtp2_transmit(struct mtp2 *link); int mtp2_receive(struct mtp2 *link, unsigned char *buf, int len); int mtp2_msu(struct mtp2 *link, struct ss7_msg *m); void mtp2_dump(struct mtp2 *link, char prefix, unsigned char *buf, int len); #endif /* _SS7_MTP_H */ libss7-1.0.2/NEWS-08-23-20060000644000000000000000000000325111020053142013133 0ustar rootrootHey all, just wanted to let anybody know that attempted to test libss7/asterisk-ss7 this last weekend, that if you had any build problems, they should be resolved now. In the course of some major merges that went into asterisk-trunk this last weekend, automerge failed on most of the developer branches (including my asterisk-ss7 branch). I just got it fixed this morning, so everything should work now and build properly. For the record, in case nobody noticed, thanks to Luciano Ramos on the asterisk-ss7 list, libss7 was tested and successfully was able to receive a call on a Siemens EWSD switch running the ITU variant of SS7. I added a section to the README file which gives the tested switch types that I have tested libss7 on. As soon as we got that done, I started working on circuit blocking/unblocking support. That should be in the asterisk-ss7 branch now to be tested. I still haven't gotten an ANSI link to work on, so that is still in the works, however I seem to be getting a lot of good feedback and interest from everybody for testing. Also, if nobody noticed the message I wrote this last week, I added another option to zapata.conf called defaultdpc which is for layer4 message routing, in case your desired destination point code is not the same as your adjacent node's point code (i.e. you have an STP or something between you and the remote end of your bearer channels, or simple A link support). That's pretty much all I can remember for now, but I'll try to keep the feature list documented in the README file for libss7. For all of you that offered links and resources, thanks again! You have been a tremendous help. Stay tuned for more soon :-) Matthew Fredrickson libss7-1.0.2/NEWS-08-12-20080000644000000000000000000000555311050373604013155 0ustar rootrootHey all, It's that time again, time for a news/status update for what's going on with libss7. 1.0.0 Release: ============== First of all, to let everyone know, we had a 1.0.0 release of libss7 a few weeks ago (and recently a 1.0.1 as well), so that's a good thing. I also would like to thank all of you that have had issues that have come to me with them. Because of one person on this list in particular, I think we have eliminating all the remaining critical bugs in libss7 that were causing crash related problems (under particular circumstances). Astricon 2008: ============== For all of you that did not see my post about it earlier, I would love to see as many of you as can show up at Astricon this year (end of September). Like I mentioned, I'm going to be giving a talk about Asterisk and SS7. I'm planning on discussing basic configuration setup, common configuration problems that people run into and debugging techniques which can be used, as well as advanced topics such as the current "state of the art" with where libss7 is and some potential directions for future development with Asterisk and SS7. Also, I would like to (if there is enough interest) try to get together with some of you sometime that week to talk about the status of Asterisk and SS7 and what kinds of things that we can improve upon and work on in the future. Confidence Boosters: ==================== There are some very good and very interesting things that have been happening. If any of you know Joseph on this list, he works for a mobile phone company in Kentucky. He is using Asterisk with libss7 to provide voicemail services to his mobile subscribers. He has quite a good setup for helping me find issues, and is also a good indicator for how well libss7 is doing stability and scalability wise. Well the news is that running a current version of libss7/Asterisk-1.6.0 branch he has been running a load over 100,000 calls per day for close to a month, with no link related stability problems and no Asterisk issues. I have heard much positive feedback from many of you about the more recent versions of libss7/Asterisk-1.6.0. If there are any of you out there with a setup that you would like to share about (especially if you think your setup is unusual in any way, whether it be high number of T1/E1s or high volume of call traffic) I personally would be very interested in hearing about them, publicly or privately if you do not feel you can disclose it to the list. New Features and Changes: ========================= - Aside from the few outstanding bugs that were fixed, there is not much to talk about. We are getting quite a robust set of supported messages and parameters, which is making this section less prone to change. :-) As always, any of you have any questions or concern, please let me know. You can get in contact with me with my contact information below. libss7-1.0.2/mtp3.h0000644000000000000000000000457011046151741012455 0ustar rootroot/* * libss7: An implementation of Signalling System 7 * * Written by Matthew Fredrickson * * scheduling routines taken from libpri by Mark Spencer * * Copyright (C) 2006-2008, Digium, Inc * All Rights Reserved. */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. * * In addition, when this program is distributed with Asterisk in * any form that would qualify as a 'combined work' or as a * 'derivative work' (but not mere aggregation), you can redistribute * and/or modify the combination under the terms of the license * provided with that copy of Asterisk, instead of the license * terms granted here. */ #ifndef _MTP3_H #define _MTP3_H #include "ss7_internal.h" /* Service Indicator bits for Service Information Octet */ /* Bits 4-1 */ #define SIG_NET_MNG 0x00 #define SIG_STD_TEST 0x01 #define SIG_SPEC_TEST 0x02 #define SIG_SCCP 0x03 #define SIG_ISUP 0x05 /* Bits 6-5 -- ANSI networks only */ #define PRIORITY_0 0x00 #define PRIORITY_1 0x01 #define PRIORITY_2 0x02 #define PRIORITY_3 0x03 #define SIO_SIZE 1 #define MTP2_LINKSTATE_DOWN 0 #define MTP2_LINKSTATE_INALARM 1 #define MTP2_LINKSTATE_ALIGNING 2 #define MTP2_LINKSTATE_UP 3 struct net_mng_message { int h0; int h1; char *name; }; /* Process any MTP2 events that occur */ ss7_event* mtp3_process_event(struct ss7 *ss7, ss7_event *e); /* The main receive function for MTP3 */ int mtp3_receive(struct ss7 *ss7, struct mtp2 *link, void *msg, int len); int mtp3_dump(struct ss7 *ss7, struct mtp2 *link, void *msg, int len); /* Transmit */ int mtp3_transmit(struct ss7 *ss7, unsigned char userpart, unsigned char sls, struct ss7_msg *m); void mtp3_alarm(struct ss7 *ss7, int fd); void mtp3_noalarm(struct ss7 *ss7, int fd); void mtp3_start(struct ss7 *ss7); unsigned char ansi_sls_next(struct ss7 *ss7); int set_routinglabel(unsigned char *sif, struct routing_label *rl); unsigned char sls_next(struct ss7 *ss7); #endif /* _MTP3_H */ libss7-1.0.2/ss7linktest.c0000644000000000000000000001726511050373604014063 0ustar rootroot/* * libss7: An implementation of Signalling System 7 * * Written by Matthew Fredrickson * * scheduling routines taken from libpri by Mark Spencer * * Copyright (C) 2006-2008, Digium, Inc * All Rights Reserved. */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. * * In addition, when this program is distributed with Asterisk in * any form that would qualify as a 'combined work' or as a * 'derivative work' (but not mere aggregation), you can redistribute * and/or modify the combination under the terms of the license * provided with that copy of Asterisk, instead of the license * terms granted here. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libss7.h" struct linkset { struct ss7 *ss7; int linkno; int fd; } linkset[2]; int linknum = 1; int callcount = 0; unsigned int opc; unsigned int dpc; #define NUM_BUFS 32 void ss7_call(struct ss7 *ss7) { int i; struct isup_call *c; c = isup_new_call(ss7); if (c) { isup_set_called(c, "12345", SS7_NAI_NATIONAL, ss7); isup_set_calling(c, "7654321", SS7_NAI_NATIONAL, SS7_PRESENTATION_ALLOWED, SS7_SCREENING_USER_PROVIDED); isup_init_call(ss7, c, (callcount % 12) + 1, dpc); isup_iam(ss7, c); printf("Callcount = %d\n ", ++callcount); } } void *ss7_run(void *data) { int res = 0; unsigned char readbuf[512] = ""; struct timeval *next = NULL, tv; struct linkset *linkset = (struct linkset *) data; struct ss7 *ss7 = linkset->ss7; int ourlink = linknum; ss7_event *e = NULL; struct pollfd poller; int nextms; int x; printf("Starting link %d\n", linknum++); ss7_start(ss7); while(1) { if ((next = ss7_schedule_next(ss7))) { gettimeofday(&tv, NULL); tv.tv_sec = next->tv_sec - tv.tv_sec; tv.tv_usec = next->tv_usec - tv.tv_usec; if (tv.tv_usec < 0) { tv.tv_usec += 1000000; tv.tv_sec -= 1; } if (tv.tv_sec < 0) { tv.tv_sec = 0; tv.tv_usec = 0; } nextms = tv.tv_sec * 1000; nextms += tv.tv_usec / 1000; } poller.fd = linkset->fd; poller.events = ss7_pollflags(ss7, linkset->fd); poller.revents = 0; res = poll(&poller, 1, nextms); if (res < 0) { printf("next->tv_sec = %d\n", next->tv_sec); printf("next->tv_usec = %d\n", next->tv_usec); printf("tv->tv_sec = %d\n", tv.tv_sec); printf("tv->tv_usec = %d\n", tv.tv_usec); perror("select"); } else if (!res) { ss7_schedule_run(ss7); continue; } if (poller.revents & POLLPRI) { if (ioctl(linkset->fd, DAHDI_GETEVENT, &x)) { perror("Error in exception retrieval!\n"); } switch (x) { case DAHDI_EVENT_OVERRUN: printf("Overrun detected!\n"); break; case DAHDI_EVENT_BADFCS: printf("Bad FCS!\n"); break; case DAHDI_EVENT_ABORT: printf("HDLC Abort!\n"); break; default: printf("Got exception %d!\n", x); break; } } if (poller.revents & POLLIN) res = ss7_read(ss7, linkset->fd); if (poller.revents & POLLOUT) { res = ss7_write(ss7, linkset->fd); if (res < 0) { printf("Error in write %s", strerror(errno)); } } #if 0 if (res < 0) exit(-1); #endif while ((e = ss7_check_event(ss7))) { if (e) { switch (e->e) { case SS7_EVENT_UP: printf("[%d] --- SS7 Up ---\n", linkset->linkno); isup_grs(ss7, 1, 24, dpc); break; case MTP2_LINK_UP: printf("[%d] MTP2 link up\n", linkset->linkno); break; case ISUP_EVENT_GRS: printf("Got GRS from cic %d to %d: Acknowledging\n", e->grs.startcic, e->grs.endcic); isup_gra(ss7, e->grs.startcic, e->grs.endcic, dpc); break; case ISUP_EVENT_RSC: isup_rlc(ss7, e->rsc.call); break; case ISUP_EVENT_GRA: printf("Got GRA from cic %d to %d.\n", e->gra.startcic, e->gra.endcic); ss7_call(ss7); break; case ISUP_EVENT_BLO: isup_bla(ss7, e->blo.cic, dpc); break; case ISUP_EVENT_CGB: isup_cgba(ss7, e->cgb.startcic, e->cgb.endcic, dpc, e->cgb.status, e->cgb.type); break; case ISUP_EVENT_CGU: isup_cgua(ss7, e->cgu.startcic, e->cgu.endcic, dpc, e->cgu.status, e->cgu.type); break; case ISUP_EVENT_IAM: printf("Got IAM for cic %d and number %s\n", e->iam.cic, e->iam.called_party_num); printf("CallerID is %s\n", e->iam.calling_party_num); printf("Sending ACM\n"); isup_acm(ss7, e->iam.call); printf("Sending ANM\n"); isup_anm(ss7, e->iam.call); break; case ISUP_EVENT_REL: printf("Got REL for cic %d\n", e->rel.cic); isup_rlc(ss7, e->rel.call); //ss7_call(ss7); break; case ISUP_EVENT_ACM: printf("Got ACM for cic %d\n", e->acm.cic); break; case ISUP_EVENT_ANM: printf("Got ANM for cic %d\n", e->anm.cic); isup_rel(ss7, e->anm.call, 16); break; case ISUP_EVENT_RLC: printf("Got RLC for cic %d\n", e->rlc.cic); //ss7_call(ss7); break; default: printf("Unknown event %d\n", e->e); break; } } } } } void myprintf(struct ss7 *ss7, char *fmt) { int i = 0; printf("%s", fmt); } int zap_open(int devnum, int *ismtp2) { int fd; struct dahdi_bufferinfo bi; struct dahdi_params z; fd = open("/dev/dahdi/channel", O_RDWR|O_NONBLOCK, 0600); if ((fd < 0) || (ioctl(fd, DAHDI_SPECIFY, &devnum) == -1)) { printf("Could not open device %d: %s\n", devnum, strerror(errno)); return -1; } bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE; bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE; bi.numbufs = NUM_BUFS; bi.bufsize = 512; if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) { close(fd); return -1; } if (ioctl(fd, DAHDI_GET_PARAMS, &z)) { close(fd); return -1; } if (z.sigtype == DAHDI_SIG_MTP2) *ismtp2 = 1; else *ismtp2 = 0; return fd; } void print_args(void) { printf("Incorrect arguments. Should be:\n"); printf("ss7linktest [sigchan number] [ss7 style - itu or ansi] [OPC - in decimal] [DPC - in decimal]\n"); printf("Example:\n"); printf("ss7linktest 16 itu 1 2\n"); printf("This would run the linktest program on dahdi/16 with ITU style signalling, with an OPC of 1 and a DPC of 2\n"); } int main(int argc, char *argv[]) { int fd; struct ss7 *ss7; pthread_t tmp; int channum; int ismtp2; unsigned int type; if (argc < 5) { print_args(); return -1; } channum = atoi(argv[1]); if (!strcasecmp(argv[2], "ansi")) { type = SS7_ANSI; } else if (!strcasecmp(argv[2], "itu")) { type = SS7_ITU; } else { print_args(); return -1; } opc = atoi(argv[3]); dpc = atoi(argv[4]); fd = zap_open(channum, &ismtp2); if (fd == -1) return -1; if (!(ss7 = ss7_new(type))) { perror("ss7_new"); exit(1); } linkset[0].ss7 = ss7; linkset[0].fd = fd; linkset[0].linkno = 0; ss7_set_message(myprintf); ss7_set_error(myprintf); ss7_set_network_ind(ss7, SS7_NI_NAT); ss7_set_debug(ss7, 0xfffffff); if ((ss7_add_link(ss7, ismtp2 ? SS7_TRANSPORT_DAHDIMTP2 : SS7_TRANSPORT_DAHDIDCHAN, fd))) { perror("ss7_add_link"); exit(1); } ss7_set_pc(ss7, opc); ss7_set_adjpc(ss7, fd, dpc); if (pthread_create(&tmp, NULL, ss7_run, &linkset[0])) { perror("thread(0)"); exit(1); } pthread_join(tmp, NULL); return 0; } libss7-1.0.2/NEWS-09-27-20060000644000000000000000000000604711020053142013146 0ustar rootrootHey all, long time no update. I've had a lot of my time caught up in other projects of late, so I haven't had quite as much time to make major changes, however, here is a short list of things that have changed. First of all, if you haven't been monitoring the threads, with the release of the 1.4 beta branch, I was able to commit all of my asterisk-ss7 branch changes back into trunk. No, this does not mean that it will be in 1.4, but I'll probably be maintaining a 1.4 based branch with the ss7 changes once 1.4 is officially release. For now, if you want to play with libss7 and Asterisk, you will need to check out the trunk version of asterisk (`svn co http://svn.digium.com/svn/asterisk/trunk asterisk-trunk). You still need to have the trunk versions of zaptel (`svn co http://svn.digium.com/svn/zaptel/trunk zaptel-trunk`) or the 1.4 beta release as well as the trunk version of libss7 (`svn co http://svn.digium.com/svn/libss7/trunk libss7`). Feature wise, I just added support for doing remote block requests from the asterisk command line, with the "ss7 block cic " syntax. The first number is the linkset that you want to block the CIC on (from zapata.conf) and the second is the CIC on that linkset you wish to block. There is also a parallel unblock command (ss7 unblock cic ). I have been working some more on multilink support, so that's something we'll see in the future. I actually had a conference call with a couple of members of the community about SS7 and future development directions all over an ANSI ss7 link using libss7 and asterisk. It was a quite satisfying experience :-) The primary topics of conversation were regarding making asterisk be able to handle more trunks from one point code. These were the two basic directions for doing that that we thought of: The first was to add support in chan_zap (or a layer below that) for talking to MGCP gateways and being able to control them through that interface. The CICs on them would exist as "virtual" zap channels, and would be controlled as such. The media would just come in as RTP to asterisk, and everything would work very similarly to how things work right now. RTP re-invites could probably be done do take Asterisk out of the media as needed. It would require very little functionality changes within asterisk and the dialplan for that to work. The other direction was to add support for M3UA or a similar protocol to pass ISUP messages on a signalling gateway to other Asterisk boxes that actually terminate the CIC that is relevant to that particular message. This is useful, because then you could use asterisk as a media gateway as well as a signalling gateway, and is very much how asterisk likes to be anyways. On the whole it was fairly productive, as I have thought more about the second path, but the first one I had trouble conceptualizing how it would easily integrate in until we had that call. Now it seems to be a very technically attainable idea. As always, if anyone has any comments or suggestions, peer review is always welcome. Matthew Fredrickson libss7-1.0.2/Makefile0000644000000000000000000000430511046371042013053 0ustar rootrootCC=gcc GREP=grep AWK=awk OSARCH=$(shell uname -s) INSTALL_PREFIX=$(DESTDIR) INSTALL_BASE=/usr libdir?=$(INSTALL_BASE)/lib STATIC_OBJS=mtp2.o ss7_sched.o ss7.o mtp3.o isup.o version.o DYNAMIC_OBJS=mtp2.o ss7_sched.o ss7.o mtp3.o isup.o version.o STATIC_LIBRARY=libss7.a DYNAMIC_LIBRARY=libss7.so.1.0 CFLAGS=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -g -fPIC LDCONFIG_FLAGS=-n SOFLAGS=-Wl,-hlibss7.so.1 LDCONFIG=/sbin/ldconfig UTILITIES=parser_debug ifneq ($(wildcard /usr/include/dahdi/user.h),) UTILITIES+=ss7test ss7linktest endif export SS7VERSION SS7VERSION:=$(shell GREP=$(GREP) AWK=$(AWK) build_tools/make_version .) all: $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY) $(UTILITIES) MAKE_DEPS= -MD -MT $@ -MF .$(subst /,_,$@).d -MP %.o: %.c $(CC) $(CFLAGS) $(MAKE_DEPS) -c -o $@ $< %.lo: %.c $(CC) $(CFLAGS) $(MAKE_DEPS) -c -o $@ $< clean: rm -f *.o *.so *.lo *.so.1 *.so.1.0 rm -f parser_debug ss7linktest ss7test $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY) rm -f .*.d install: $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY) mkdir -p $(INSTALL_PREFIX)$(libdir) mkdir -p $(INSTALL_PREFIX)$(INSTALL_BASE)/include install -m 644 libss7.h $(INSTALL_PREFIX)$(INSTALL_BASE)/include install -m 755 $(DYNAMIC_LIBRARY) $(INSTALL_PREFIX)$(libdir) ( cd $(INSTALL_PREFIX)$(libdir) ; ln -sf libss7.so.1 libss7.so ; ln -sf libss7.so.1.0 libss7.so.1 ) install -m 644 $(STATIC_LIBRARY) $(INSTALL_PREFIX)$(libdir) if test $$(id -u) = 0; then $(LDCONFIG); fi $(STATIC_LIBRARY): $(STATIC_OBJS) ar rcs $(STATIC_LIBRARY) $(STATIC_OBJS) ranlib $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY): $(DYNAMIC_OBJS) $(CC) -shared $(SOFLAGS) -o $@ $(DYNAMIC_OBJS) $(LDCONFIG) $(LDCONFIG_FLAGS) . ln -sf libss7.so.1 libss7.so ln -sf libss7.so.1.0 libss7.so.1 version.c: FORCE @build_tools/make_version_c > $@.tmp @cmp -s $@.tmp $@ || mv $@.tmp $@ @rm -f $@.tmp ss7test: ss7test.c $(STATIC_LIBRARY) gcc -g -o ss7test ss7test.c libss7.a -lpthread ss7linktest: ss7linktest.c $(STATIC_LIBRARY) gcc -g -o ss7linktest ss7linktest.c libss7.a -lpthread parser_debug: parser_debug.c $(STATIC_LIBRARY) gcc -g -Wall -o parser_debug parser_debug.c libss7.a libss7: ss7_mtp.o mtp.o ss7.o ss7_sched.o .PHONY: FORCE: ifneq ($(wildcard .*.d),) include .*.d endif