libss7-2.0.0/0000755000000000000000000000000012347606620011420 5ustar rootrootlibss7-2.0.0/NEWS-05-30-20080000644000000000000000000000727612010747414013156 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-2.0.0/NEWS-09-11-20060000644000000000000000000000435712010747414013154 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-2.0.0/mtp2.h0000644000000000000000000001103612010762336012446 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 #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 #define ITU_TIMER_T7 1250 /* For 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 #define ANSI_TIMER_T7 1250 /* 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 #define MTP_ALARM 6 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; int t7; }; struct mtp2 { int state; int std_test_passed; int inhibit; int changeover; unsigned int got_sent_netmsg; struct ss7_msg *co_buf; struct ss7_msg *cb_buf; unsigned char curfsn:7; unsigned char curfib:1; unsigned char lastfsnacked:7; unsigned char co_lastfsnacked:7; /* store here before reset_mtp clear */ unsigned char curbib:1; int fd; int flags; int mtp3_timer[MTP3_MAX_TIMERS]; int q707_t1_failed; /* Timers */ int t1; int t2; int t3; int t4; int t7; struct mtp2_timers timers; int slc; int net_mng_sls; int emergency; int provingperiod; unsigned int dpc; int autotxsutype; int lastsurxd; int lastsutxd; /* Line related stats */ unsigned int retransmissioncount; struct ss7_msg *tx_buf; struct ss7_msg *tx_q; struct ss7_msg *retransmit_pos; struct ss7_msg *co_tx_buf; /* store here before reset_mtp flush it */ struct ss7_msg *co_tx_q; struct adjacent_sp *adj_sp; unsigned char cb_seq; struct ss7 *master; }; /* Flags for the struct mtp2 flags parameter */ #define MTP2_FLAG_DAHDIMTP2 (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_alarm(struct mtp2 *link); int mtp2_noalarm(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); char *linkstate2strext(int linkstate); void update_txbuf(struct mtp2 *link, struct ss7_msg **buf, unsigned char upto); int len_buf(struct ss7_msg *buf); void flush_bufs(struct mtp2 *link); #endif /* _SS7_MTP_H */ libss7-2.0.0/NEWS-09-27-20060000644000000000000000000000604712010747414013161 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-2.0.0/ss7test.c0000644000000000000000000001273412010762336013201 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 static void *ss7_run(void *data) { int res = 0; 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", (int) next->tv_sec); printf("next->tv_usec = %d\n", (int) next->tv_usec); printf("tv->tv_sec = %d\n", (int) tv.tv_sec); printf("tv->tv_usec = %d\n", (int) 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 */ } } } static 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 static int dahdi_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] = dahdi_open(24); if (fds[0] < 0) { return -1; } fds[1] = dahdi_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], -1, 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], -1, 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-2.0.0/LICENSE0000644000000000000000000004313012010747414012420 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-2.0.0/NEWS-08-23-20060000644000000000000000000000325112010747414013146 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-2.0.0/ChangeLog0000644000000000000000000003402412347606610013174 0ustar rootroot2014-06-16 Asterisk Development Team * libss7 2.0.0 Released. 2014-06-16 15:17 +0000 [r324] bebuild : * / (added): Create libss7 2.0 branch 2014-06-09 19:48 +0000 [r323] Richard Mudgett * ss7_internal.h, isup.c, mtp3.c, isup.h, libss7.h, ss7linktest.c: libss7: Dual seizure improvements. * Dual seizure - check for IAM pending in addition to IAM sent. * ISUP_RSC - we should still respond to RSC. * Ignore unexpected messages when relevant timers are active and we are waiting for RLC. - Thanks to Pavel Troller for discovering and suggested fix. * Check both DPC and OPC when receiving a message to confirm it is for us. - Thanks to Pavel Troller and Gustavo Marsico for discovering. * Fixed handling of got_sent_msg flags on RSC/REL/RLC - no more stale channels or missed blocking messages. * Check for DPC only for signalling messages in mtp3_receive(). * Minor FAR message fixes, added FRJ message support. * Improve SS7 debug message decoding to know about more fields. SS7-27 Reported by: adomjan Patches: SS7-27_libss7_trunk2_v13.diff (license #5506) patch uploaded by Kaloyan Kovachev Review: https://reviewboard.asterisk.org/r/2150/ 2013-11-06 22:40 +0000 [r322] Richard Mudgett * ss7.c, mtp3.c: Fix set but not used warnings from gcc 4.6. (closes issue SS7-54) Reported by: Tzafrir Cohen 2012-10-01 20:05 +0000 [r320] Richard Mudgett * ss7linktest.c, ss7_internal.h, isup.c, mtp2.c, mtp3.c: Quiet unconditional libss7 debug messages unless enabled. Patches: SS7-27_libss7_trunk2_v3.diff (license #5506) patch uploaded by Kaloyan Kovachev With some modifications. 2012-09-26 15:58 +0000 [r319] Richard Mudgett * Makefile: Allow passing compiler flags (CFLAGS, LDFLAGS) ......... Merged -r318 from https://origsvn.digium.com/svn/libss7/branches/1.0 2012-09-14 19:05 +0000 [r317] Richard Mudgett * libss7.h, isup.c: Change isup_start_digittimeout() to return if the timer started. 2012-08-31 20:19 +0000 [r315-316] Richard Mudgett * libss7.h, isup.c: Fix ANSI double send of GRS causing message loop. * Fix got_sent_msg are flags that should be (re)set as such. (issue SS7-27) Patches: SS7-27_libss7_trunk2_v2.diff (license #5506) patch uploaded by Kaloyan Kovachev Tested by: rmudgett * isup.c: Don't kill the call if isup_far() chooses to not send the message. 2012-08-09 18:11 +0000 [r309-314] Richard Mudgett * libss7.h: Added ABI compatibility define. * isup.c, mtp2.c, parser_debug.c, mtp3.c, isup.h, mtp2.h, libss7.h, mtp3.h, ss7linktest.c, Makefile, ss7.c, ss7test.c, ss7_internal.h: Omnibus libss7 update. Kaloyan Kovachev added additional cause codes, Transmission Medium Requirement setting and connected line to CPG messages + code cleanup. Big thanks to Kaloyan Kovachev for pushing to get this completed. Large patch that improves ISUP timers and Q.764 compatibility. (issue SS7-27) Reported by: adomjan Listing other issues that are either included or addressed by this patch. I am not going to investigate each one to see if they are complete or not at this time. (issue SS7-7) (issue SS7-21) (issue SS7-28) (issue SS7-33) (issue SS7-36) (issue SS7-38) (issue SS7-39) (issue SS7-40) (issue SS7-42) (issue SS7-43) (issue SS7-45) (issue SS7-46) (issue SS7-47) (issue SS7-48) (issue SS7-49) (issue SS7-51) (issue SS7-52) (issue SS7-53) (issue SS7-54) Review: https://reviewboard.asterisk.org/r/1653/ * mtp2.h, libss7.h, mtp3.h, ss7linktest.c, Makefile, ss7.c, ss7test.c, ss7_internal.h, isup.c, isup_masq.c (removed), mtp2.c, parser_debug.c, mtp3.c, isup.h: Reset trunk to current v1.0 branch. * libss7.h, ss7test.c, ss7.c, README, ss7_internal.h, / (added), build_tools/make_version, isup.c, ss7_sched.c, mtp2.c, build_tools/make_version_c, mtp3.c, NEWS-05-30-2008, NEWS-09-11-2006, isup.h, NEWS-08-12-2008, NEWS-08-23-2006, mtp2.h, mtp3.h, ss7linktest.c, NEWS-09-27-2006, Makefile, build_tools, isup_masq.c, LICENSE, parser_debug.c: Restore trunk for further use. 2011-09-16 19:18 +0000 [r292-293] Richard Mudgett * ss7.c, ss7_internal.h: Global function pointer variables need to be declared in a similar manner to other global variables. * isup.c: Fix some uninitialized values reported by valgrind. Initialize the local isup_call structure in isup_cqr() and isup_send_message_ciconly(). 2010-11-30 17:00 +0000 [r290] Matthew Fredrickson * mtp2.c: Fix MTP2 so that we check for potential need for retransmission even on repeated FISUs. (#18393) 2009-08-21 21:49 +0000 [r272] Jason Parker * ss7.c: Correct logic in a name comparison. (closes issue #14677) Reported by: Safari 2009-08-18 18:49 +0000 [r271] Jeff Peeler * Makefile: Fix ldconfig error when building with fakeroot This patch copies the built shared libraries along with the symlinks. Also, ldconfig is always attempted with errors ignored since while using fakeroot updating the cache will fail. People running making install not as root are going to encounter problems before the removed root check anyway. (closes issue #13313) Reported by: tzafrir Patches: libss7_ldconfig.diff uploaded by tzafrir (license 46) Tested by: tzafrir 2009-07-13 14:57 +0000 [r269] Russell Bryant * README: Update LibSS7 README regarding version compatibility. (closes issue #14678) Reported by: Safari 2009-07-07 21:17 +0000 [r267] Mark Michelson * mtp2.c: Don't write past the end of the buffer. It's bad. (closes issue #14676) Reported by: Safari 2009-04-29 16:22 +0000 [r258-266] Matthew Fredrickson * isup.c: Adding in isup.c-grsfix patch from #13495 * mtp3.c, mtp3.h, ss7.c: Merge in MTP3 T21 support patch (#13495) * isup.c, isup.h: Add ISUP T8 and T24 continuity related timers * isup.c, isup.h, libss7.h: Add libss7 support for COT on previous CIC (#13495) * ss7.c, isup.c, libss7.h: Add support for setting the ISDN access indicator bits (#13495) * isup.c: Add COT check to SAM message (#13495) * isup.c, libss7.h: Add support for setting calling party category * isup.h: Fix CUG parameter number to be correct 2009-03-05 17:53 +0000 [r257] Matthew Fredrickson * isup.c, isup_masq.c (added), mtp2.c, parser_debug.c, mtp3.c, isup.h, mtp2.h, libss7.h, mtp3.h, ss7linktest.c, Makefile, ss7.c, ss7test.c, ss7_internal.h: ------------------------------------------------------------------------ r220 | mattf | 2008-12-01 12:15:08 -0600 (Mon, 01 Dec 2008) | 1 line Commit updated version of #13495 patches (with various fixes) so that we can work off of this branch ------------------------------------------------------------------------ r221 | mattf | 2008-12-01 15:09:15 -0600 (Mon, 01 Dec 2008) | 1 line Fix a couple of coding style issues in ss7.c ------------------------------------------------------------------------ r222 | mattf | 2008-12-01 16:14:54 -0600 (Mon, 01 Dec 2008) | 1 line Bunch of style related cleanups in mtp3.c ------------------------------------------------------------------------ r223 | mattf | 2008-12-03 10:18:01 -0600 (Wed, 03 Dec 2008) | 1 line Apply patch from #13495 for moving clearing of GOT_IAM flag into isup.c ------------------------------------------------------------------------ r224 | mattf | 2008-12-03 10:31:12 -0600 (Wed, 03 Dec 2008) | 1 line Fix a couple of random function definitons ------------------------------------------------------------------------ r225 | mattf | 2008-12-03 10:45:51 -0600 (Wed, 03 Dec 2008) | 1 line Remove erroneous return statement ------------------------------------------------------------------------ r226 | mattf | 2008-12-03 11:31:02 -0600 (Wed, 03 Dec 2008) | 1 line Add echo control reporting and setting ability to libss7 (#13495) ------------------------------------------------------------------------ r227 | mattf | 2008-12-03 13:47:08 -0600 (Wed, 03 Dec 2008) | 1 line ss7linktest builds again ------------------------------------------------------------------------ r228 | mattf | 2008-12-05 15:43:44 -0600 (Fri, 05 Dec 2008) | 1 line Let's not complain if we can't find the SLC specified ------------------------------------------------------------------------ r229 | mattf | 2008-12-05 15:55:23 -0600 (Fri, 05 Dec 2008) | 1 line Fix spelling error in the word adjacent ------------------------------------------------------------------------ r230 | mattf | 2008-12-05 16:30:43 -0600 (Fri, 05 Dec 2008) | 1 line Add support for SLC specification of an mtp2 link ------------------------------------------------------------------------ r231 | mattf | 2008-12-05 16:52:46 -0600 (Fri, 05 Dec 2008) | 1 line Make sure we set the optparm filed for ANSI GRA and GRS ------------------------------------------------------------------------ r232 | mattf | 2008-12-06 11:03:39 -0600 (Sat, 06 Dec 2008) | 1 line Add a new point code to string function and fix a bug in finding a link where two links have the same point code ------------------------------------------------------------------------ r233 | mattf | 2008-12-06 11:07:14 -0600 (Sat, 06 Dec 2008) | 1 line Ooops, make sure we print out the adjpc on all message types, not just FISUs ------------------------------------------------------------------------ r234 | mattf | 2008-12-06 11:40:46 -0600 (Sat, 06 Dec 2008) | 1 line Add a function that checks a link's DPC when sending MTP3 management messages ------------------------------------------------------------------------ r235 | mattf | 2008-12-06 11:50:02 -0600 (Sat, 06 Dec 2008) | 1 line Fix the point code output for ANSI networks on ss7 show linkset x ------------------------------------------------------------------------ r236 | mattf | 2008-12-06 12:45:01 -0600 (Sat, 06 Dec 2008) | 1 line Change ss7_add_link API to include the Adjacent Point Code as well ------------------------------------------------------------------------ r237 | mattf | 2008-12-08 12:04:19 -0600 (Mon, 08 Dec 2008) | 1 line Fix another mild code style problem in isup_handle_unexpected ------------------------------------------------------------------------ r238 | mattf | 2008-12-08 14:40:30 -0600 (Mon, 08 Dec 2008) | 1 line Make sure we send GRS twice on ANSI links. Why, oh why, oh why? ------------------------------------------------------------------------ r239 | mattf | 2008-12-11 11:31:07 -0600 (Thu, 11 Dec 2008) | 1 line Using this as development branch until we get ANSI support tested. Starting on ISUP masquerade and clustering support, initial check in of this code. ------------------------------------------------------------------------ r240 | mattf | 2008-12-11 11:59:26 -0600 (Thu, 11 Dec 2008) | 1 line Forgot to add the new isup_masq.c file ------------------------------------------------------------------------ r241 | mattf | 2008-12-11 13:42:57 -0600 (Thu, 11 Dec 2008) | 1 line Fix some poll flags for TCP ------------------------------------------------------------------------ r242 | mattf | 2008-12-12 11:46:16 -0600 (Fri, 12 Dec 2008) | 1 line A little more debug would help for short reads ------------------------------------------------------------------------ r243 | mattf | 2008-12-12 15:04:50 -0600 (Fri, 12 Dec 2008) | 1 line Make sure TCP links default to UP ------------------------------------------------------------------------ r244 | mattf | 2008-12-12 15:06:38 -0600 (Fri, 12 Dec 2008) | 1 line Give some sense of direction with message debug on TCP links ------------------------------------------------------------------------ r245 | mattf | 2008-12-12 15:33:40 -0600 (Fri, 12 Dec 2008) | 1 line Take some of this code out for now... ------------------------------------------------------------------------ r246 | mattf | 2008-12-23 11:52:12 -0600 (Tue, 23 Dec 2008) | 1 line Add support for working client side TCP! Note: the message format will change, this is only for testing the socket code to make sure we have good read/write socket servicing code. ------------------------------------------------------------------------ r247 | mattf | 2008-12-23 16:10:31 -0600 (Tue, 23 Dec 2008) | 1 line Add support for the new TCP message format ------------------------------------------------------------------------ r248 | mattf | 2008-12-24 17:20:01 -0600 (Wed, 24 Dec 2008) | 1 line Milestone reached. Able to forward messages to the given client properly with ISUP TCP masquerading ------------------------------------------------------------------------ r249 | mattf | 2009-01-06 18:36:40 -0600 (Tue, 06 Jan 2009) | 1 line Masquerade functionality works in both directions. Now we have to figure out what to do about TCP link state (losing the socket fd and replacing it with a new one when the link comes up again) ------------------------------------------------------------------------ r252 | mattf | 2009-01-24 15:59:06 -0600 (Sat, 24 Jan 2009) | 1 line Change API so that we are able to handle IP based links that change file descriptors when they go up and down ------------------------------------------------------------------------ r253 | mattf | 2009-01-24 16:30:31 -0600 (Sat, 24 Jan 2009) | 1 line Make sure that we pass a link down event up when the TCP link goes down ------------------------------------------------------------------------ r254 | mattf | 2009-02-11 03:50:31 -0600 (Wed, 11 Feb 2009) | 1 line Add support for ANSI message priority in transmission... ------------------------------------------------------------------------ 2009-01-16 14:38 +0000 [r251] Sean Bright * README: Properly reference the GNU GPL version 2. (closes issue #13684) Reported by: cjac libss7-2.0.0/libss7-2.0.0-summary.txt0000644000000000000000000001566712347606614015534 0ustar rootroot Release Summary libss7-2.0.0 Date: 2014-06-16 ---------------------------------------------------------------------- Table of Contents 1. Summary 2. Contributors 3. Closed Issues 4. Other Changes 5. Diffstat ---------------------------------------------------------------------- Summary [Back to Top] This release includes new features. For a list of new features that have been included with this release, please see the CHANGES file inside the source package. Since this is new major release, users are encouraged to do extended testing before upgrading to this version in a production environment. The data in this summary reflects changes that have been made since the previous release, libss7-1.0. ---------------------------------------------------------------------- Contributors [Back to Top] This table lists the people who have submitted code, those that have tested patches, as well as those that reported issues on the issue tracker that were resolved in this release. For coders, the number is how many of their patches (of any size) were committed into this release. For testers, the number is the number of times their name was listed as assisting with testing a patch. Finally, for reporters, the number is the number of issues that they reported that were closed by commits that went into this release. Coders Testers Reporters 11 rmudgett 1 tzafrir ---------------------------------------------------------------------- Closed Issues [Back to Top] This is a list of all issues from the issue tracker that were closed by changes that went into this release. Category: General SS7-54: libss7 and gcc 4.6: 'set but not used' variables Revision: 322 Reporter: tzafrir Coders: rmudgett ---------------------------------------------------------------------- Commits Not Associated with an Issue [Back to Top] This is a list of all changes that went into this release that did not directly close an issue from the issue tracker. The commits may have been marked as being related to an issue. If that is the case, the issue numbers are listed here, as well. +------------------------------------------------------------------------+ | Revision | Author | Summary | Issues Referenced | |----------+----------+------------------------------+-------------------| | 309 | rmudgett | Restore trunk for further | | | | | use. | | |----------+----------+------------------------------+-------------------| | 311 | rmudgett | Reset trunk to current v1.0 | | | | | branch. | | |----------+----------+------------------------------+-------------------| | | | | SS7-27, SS7-7, | | | | | SS7-21, SS7-28, | | | | | SS7-33, SS7-36, | | | | | SS7-38, SS7-39, | | 312 | rmudgett | Omnibus libss7 update. | SS7-40, SS7-42, | | | | | SS7-43, SS7-45, | | | | | SS7-46, SS7-47, | | | | | SS7-48, SS7-49, | | | | | SS7-51, SS7-52, | | | | | SS7-53, SS7-54 | |----------+----------+------------------------------+-------------------| | 314 | rmudgett | Added ABI compatibility | | | | | define. | | |----------+----------+------------------------------+-------------------| | | | Don't kill the call if | | | 315 | rmudgett | isup_far() chooses to not | | | | | send the message. | | |----------+----------+------------------------------+-------------------| | 316 | rmudgett | Fix ANSI double send of GRS | SS7-27 | | | | causing message loop. | | |----------+----------+------------------------------+-------------------| | | | Change | | | 317 | rmudgett | isup_start_digittimeout() to | | | | | return if the timer started. | | |----------+----------+------------------------------+-------------------| | 319 | rmudgett | Allow passing compiler flags | | | | | (CFLAGS, LDFLAGS) | | |----------+----------+------------------------------+-------------------| | | | Quiet unconditional libss7 | | | 320 | rmudgett | debug messages unless | | | | | enabled. | | |----------+----------+------------------------------+-------------------| | 323 | rmudgett | libss7: Dual seizure | | | | | improvements. | | +------------------------------------------------------------------------+ ---------------------------------------------------------------------- Diffstat Results [Back to Top] This is a summary of the changes to the source code that went into this release that was generated using the diffstat utility. Makefile | 195 ++- README | 6 isup.c | 3311 +++++++++++++++++++++++++++++++++++++++++++++++---------- isup.h | 339 ++++- libss7.h | 404 +++++- mtp2.c | 235 ++-- mtp2.h | 72 - mtp3.c | 1811 ++++++++++++++++++++++++++++--- mtp3.h | 139 ++ parser_debug.c | 16 ss7.c | 487 ++++++-- ss7_internal.h | 63 - ss7linktest.c | 66 - ss7test.c | 37 14 files changed, 6009 insertions(+), 1172 deletions(-) ---------------------------------------------------------------------- libss7-2.0.0/parser_debug.c0000644000000000000000000000415112010762336014221 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, -1, 0); ss7->debug = SS7_DEBUG_MTP2 | SS7_DEBUG_MTP3 | SS7_DEBUG_ISUP; ss7->links[0]->state = MTP_INSERVICE; mtp2_receive(ss7->links[0], mybuf, size); if ((e = ss7_check_event(ss7))) { printf("Got event: %s\n", ss7_event2str(e->e)); } return 0; } libss7-2.0.0/.version0000644000000000000000000000000612347606610013101 0ustar rootroot2.0.0 libss7-2.0.0/NEWS-08-12-20080000644000000000000000000000555312010747414013155 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-2.0.0/ss7linktest.c0000644000000000000000000001742612345407637014075 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 static void ss7_call(struct ss7 *ss7) { struct isup_call *c; c = isup_new_call(ss7, (callcount % 12) + 1, dpc, 0); 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_iam(ss7, c); printf("Callcount = %d\n ", ++callcount); } } static void *ss7_run(void *data) { int res = 0; struct timeval *next = NULL, tv; struct linkset *linkset = (struct linkset *) data; struct ss7 *ss7 = linkset->ss7; ss7_event *e = NULL; struct pollfd poller; int nextms; int x; struct isup_call *c; unsigned char state[255]; int i; for (i = 0; i < 255; i++) { state[i] = 0; } 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; } else { nextms = -1; } poller.fd = linkset->fd; poller.events = ss7_pollflags(ss7, linkset->fd); poller.revents = 0; res = poll(&poller, 1, nextms); if (res < 0) { #if 0 printf("next->tv_sec = %d\n", (int) next->tv_sec); printf("next->tv_usec = %d\n", (int) next->tv_usec); printf("tv->tv_sec = %d\n", (int) tv.tv_sec); printf("tv->tv_usec = %d\n", (int) tv.tv_usec); #endif 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); c = isup_new_call(ss7, 1, dpc, 0); isup_grs(ss7, c, 24); 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.call, e->grs.endcic, state); 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.call); break; case ISUP_EVENT_CGB: isup_cgba(ss7, e->cgb.call, e->cgb.endcic, e->cgb.status); break; case ISUP_EVENT_CGU: isup_cgua(ss7, e->cgu.call, e->cgu.endcic, e->cgu.status); 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; } } } } return NULL; } static void myprintf(struct ss7 *ss7, char *fmt) { printf("%s", fmt); } static int dahdi_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; } static 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 = dahdi_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, 0xffffffff); if ((ss7_add_link(ss7, ismtp2 ? SS7_TRANSPORT_DAHDIMTP2 : SS7_TRANSPORT_DAHDIDCHAN, fd, -1, dpc))) { perror("ss7_add_link"); exit(1); } ss7_set_pc(ss7, opc); if (pthread_create(&tmp, NULL, ss7_run, &linkset[0])) { perror("thread(0)"); exit(1); } pthread_join(tmp, NULL); return 0; } libss7-2.0.0/ss7.c0000644000000000000000000003555012236542503012304 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 "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_notinservice)(struct ss7 *ss7, int cic, unsigned int dpc); int (*ss7_hangup)(struct ss7 *ss7, int cic, unsigned int dpc, int cause, int do_hangup); void (*ss7_call_null)(struct ss7 *ss7, struct isup_call *c, int lock); 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_set_notinservice(void (*func)(struct ss7 *ss7, int cic, unsigned int dpc)) { ss7_notinservice = func; } void ss7_set_hangup(int (*func)(struct ss7 *ss7, int cic, unsigned int dpc, int cause, int do_hangup)) { ss7_hangup = func; } /* not called in normal operation */ void ss7_set_call_null(void (*func)(struct ss7 *ss7, struct isup_call *c, int lock)) { ss7_call_null = func; } void ss7_message(struct ss7 *ss7, const 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, const 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) { /* Should never happen. If it does, very bad things can happen to the call. */ ss7_error(ss7, "Event queue full! Very bad!\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); } /* TODO: Add entry to routing table instead */ static int ss7_set_adjpc(struct mtp2 *mtp2, unsigned int pc) { mtp2->dpc = pc; mtp3_add_adj_sp(mtp2); return 0; } int ss7_add_link(struct ss7 *ss7, int transport, int fd, int slc, unsigned int adjpc) { if (ss7->numlinks >= SS7_MAX_LINKS) { return -1; } if ((transport == SS7_TRANSPORT_DAHDIDCHAN) || (transport == SS7_TRANSPORT_DAHDIMTP2)) { struct mtp2 *m; m = mtp2_new(fd, ss7->switchtype); if (!m) { return -1; } m->master = ss7; if (transport == SS7_TRANSPORT_DAHDIMTP2) { m->flags |= MTP2_FLAG_DAHDIMTP2; } m->slc = (slc > -1) ? slc : ss7->numlinks; ss7->numlinks++; ss7->links[ss7->numlinks - 1] = m; ss7_set_adjpc(ss7->links[ss7->numlinks-1], adjpc); return 0; } return -1; } int ss7_find_link_index(struct ss7 *ss7, int fd) { int i; for (i = 0; i < ss7->numlinks && ss7->links[i]->fd != fd; i++); return ((i != ss7->numlinks) ? i : -1); } struct mtp2 * ss7_find_link(struct ss7 *ss7, int fd) { int i = ss7_find_link_index(ss7, fd); return ((i != -1) ? ss7->links[i] : NULL); } int ss7_pollflags(struct ss7 *ss7, int fd) { int flags = POLLPRI | POLLIN; int winner = ss7_find_link_index(ss7, fd); if (winner < 0) { return -1; } if (ss7->links[winner]->flags & MTP2_FLAG_DAHDIMTP2) { if (ss7->links[winner]->flags & MTP2_FLAG_WRITE) { flags |= POLLOUT; } } else { flags |= POLLOUT; } return flags; } 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 MTP2_LINK_UP: return "MTP2_LINK_UP"; case MTP2_LINK_DOWN: return "MTP2_LINK_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"; case ISUP_EVENT_COT: return "ISUP_EVENT_COT"; case ISUP_EVENT_CCR: return "ISUP_EVENT_CCR"; case ISUP_EVENT_BLO: return "ISUP_EVENT_BLO"; case ISUP_EVENT_UBL: return "ISUP_EVENT_UBL"; case ISUP_EVENT_BLA: return "ISUP_EVENT_BLA"; case ISUP_EVENT_UBA: return "ISUP_EVENT_UBA"; case ISUP_EVENT_CGB: return "ISUP_EVENT_CGB"; case ISUP_EVENT_CGU: return "ISUP_EVENT_CGU"; case ISUP_EVENT_RSC: return "ISUP_EVENT_RSC"; case ISUP_EVENT_CPG: return "ISUP_EVENT_CPG"; case ISUP_EVENT_UCIC: return "ISUP_EVENT_UCIC"; case ISUP_EVENT_LPA: return "ISUP_EVENT_LPA"; case ISUP_EVENT_CQM: return "ISUP_EVENT_CQM"; case ISUP_EVENT_FAR: return "ISUP_EVENT_FAR"; case ISUP_EVENT_FAA: return "ISUP_EVENT_FAA"; case ISUP_EVENT_CVT: return "ISUP_EVENT_CVT"; case ISUP_EVENT_CVR: return "ISUP_EVENT_CVR"; case ISUP_EVENT_SUS: return "ISUP_EVENT_SUS"; case ISUP_EVENT_RES: return "ISUP_EVENT_RES"; case ISUP_EVENT_CGBA: return "ISUP_EVENT_CGBA"; case ISUP_EVENT_CGUA: return "ISUP_EVENT_CGUA"; case ISUP_EVENT_SAM: return "ISUP_EVENT_SAM"; case ISUP_EVENT_DIGITTIMEOUT: return "ISUP_EVENT_DIGITTIMEOUT"; default: return "Unknown Event"; } } struct ss7 *ss7_new(int switchtype) { struct ss7 *s; int x; if (((switchtype != SS7_ITU) && (switchtype != SS7_ANSI)) || !(s = calloc(1, sizeof(struct ss7)))) { return NULL; } /* Initialize the event queue */ s->ev_h = 0; s->ev_len = 0; s->state = SS7_STATE_DOWN; s->switchtype = switchtype; for (x = 0; x < ISUP_MAX_TIMERS; x++) { s->isup_timers[x] = 0; } s->linkset_up_timer = -1; s->flags = SS7_ISDN_ACCESS_INDICATOR; s->sls_shift = 0; s->cause_location = LOC_PRIV_NET_LOCAL_USER; return s; } void ss7_destroy(struct ss7 *ss7) { int i; if (!ss7) { return; } /* ISUP */ isup_free_all_calls(ss7); /* MTP3 */ for (i = 0; i > ss7->numsps; i++) { mtp3_destroy_all_routes(ss7->adj_sps[i]); free(ss7->adj_sps[i]); } for (i = 0; i > ss7->numlinks; i++) { flush_bufs(ss7->links[i]); mtp3_free_co(ss7->links[i]); free(ss7->links[i]); } free(ss7); } void ss7_set_sls_shift(struct ss7 *ss7, unsigned char shift) { if (!ss7) { return; } ss7->sls_shift = shift; } void ss7_set_flags(struct ss7 *ss7, unsigned int flags) { if (!ss7) { return; } ss7->flags |= flags; } void ss7_clear_flags(struct ss7 *ss7, unsigned int flags) { if (!ss7) { return; } ss7->flags &= ~flags; } void ss7_set_cause_location(struct ss7 *ss7, unsigned char location) { if (!ss7) { return; } ss7->cause_location = 0x0f & location; } int ss7_write(struct ss7 *ss7, int fd) { int res; int winner = ss7_find_link_index(ss7, fd); if (winner < 0) { return -1; } res = mtp2_transmit(ss7->links[winner]); return res; } int ss7_read(struct ss7 *ss7, int fd) { int res; int winner = ss7_find_link_index(ss7, fd); unsigned char buf[1024]; 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; } static inline char * changeover2str(int state) { switch(state) { case NO_CHANGEOVER: return "NO"; case CHANGEOVER_COMPLETED: return "COMPLETED"; case CHANGEOVER_IN_PROGRESS: return "IN PROGRESS"; case CHANGEOVER_INITIATED: return "CHANGEOVER INITIATED"; case CHANGEBACK_INITIATED: return "CHANGEBACK INITIATED"; case CHANGEBACK: return "IN CHANGEBACK"; default: return "UNKNOWN"; } } static inline char * got_sent2str(char * buf, unsigned int got_sent) { buf[0] = '\0'; if (got_sent & SENT_LIN) { strcat(buf, " sentLIN"); } if (got_sent & SENT_LUN) { strcat(buf, " sentLUN"); } if (got_sent & SENT_COO) { strcat(buf, " sentCOO"); } if (got_sent & SENT_ECO) { strcat(buf, " sentECO"); } if (got_sent & SENT_CBD) { strcat(buf, " sentCBD"); } if (got_sent & SENT_LFU) { strcat(buf, " sentLFU"); } return buf; } static inline char * mtp2state2str(struct ss7 *ss7, struct mtp2 *link) { int i; for (i = 0; i < ss7->numlinks; i++) { if (ss7->links[i] == link) { break; } } if (i == ss7->numlinks) { return "UNKNOWN"; } switch (ss7->mtp2_linkstate[i]) { case MTP2_LINKSTATE_DOWN: return "DOWN"; case MTP2_LINKSTATE_INALARM: return "INALARM"; case MTP2_LINKSTATE_ALIGNING: return "ALIGNING"; case MTP2_LINKSTATE_UP: return "UP"; default: return "UNKNOWN"; } } static inline char * mtp3_state(int state) { switch (state) { case MTP3_DOWN: return "DOWN"; case MTP3_UP: return "UP"; default: return "UNKNOWN"; } } static inline char * route_state(int state) { switch (state) { case TFP: return "TFP"; case TFA: return "TFA"; case TFR_NON_ACTIVE: return "TFR NON ACTIVE"; case TFR_ACTIVE: return "TFR ACTIVE"; default: return "Unknown"; } } void ss7_pc_to_str(int ss7type, unsigned int pc, char *str) { if (ss7type == SS7_ITU) { sprintf(str, "%d", pc); } else { sprintf(str, "%d-%d-%d", (pc >> 16) & 0xff, (pc >> 8) & 0xff, pc & 0xff); } } void ss7_show_linkset(struct ss7 *ss7, ss7_printf_cb cust_printf, int fd) { int j, i, x; char *p; char got_sent_buf[256], timers[512]; struct adjacent_sp *adj_sp; struct mtp2 *link; struct mtp3_route *cur; char pc_str[64]; ss7_pc_to_str(ss7->switchtype, ss7->pc, pc_str); cust_printf(fd, "Switch type: %s\n", (ss7->switchtype == SS7_ITU) ? "ITU" : "ANSI"); cust_printf(fd, "Our point code: %s\n", pc_str); cust_printf(fd, "SLS shift: %i\n", ss7->sls_shift); cust_printf(fd, "numlinks: %i\n", ss7->numlinks); cust_printf(fd, "numsps: %i\n", ss7->numsps); for (j = 0; j < ss7->numsps; j++) { adj_sp = ss7->adj_sps[j]; ss7_pc_to_str(ss7->switchtype, adj_sp->adjpc, pc_str); cust_printf(fd, " ---------------------------------\n Adjacent SP PC: %s STATE: %s\n", pc_str, mtp3_state(adj_sp->state)); cust_printf(fd, " TRA: %s%s T19: %s T21: %s\n", (adj_sp->tra & GOT) ? "GOT " : "", (adj_sp->tra & SENT) ? "SENT" : "", (adj_sp->timer_t19 > -1) ? "running" : "not running", (adj_sp->timer_t21 > -1) ? "running" : "not running"); cust_printf(fd, " Routes:\n"); cust_printf(fd, " DPC State T6 T10\n"); cur = adj_sp->routes; while (cur) { ss7_pc_to_str(ss7->switchtype, cur->dpc, pc_str); cust_printf(fd, "%s %12s%10s%10s\n", pc_str, route_state(cur->state), (cur->t6 > -1) ? "running" : "-", (cur->t10 > -1) ? "running" : "-"); cur = cur->next; } for (i = 0; i < adj_sp->numlinks; i++) { link = adj_sp->links[i]; timers[0] = '\0'; p = timers; for (x = 0; x < MTP3_MAX_TIMERS; x++) { if (link->mtp3_timer[x] > -1) { strcpy(p, mtp3_timer2str(x)); p += strlen(p); sprintf(p, "(%lis)%c", ss7->ss7_sched[ss7->links[i]->mtp3_timer[x]].when.tv_sec - time(NULL), ss7->ss7_sched[ss7->links[i]->mtp3_timer[x]].callback ? ' ' : '!'); p += strlen(p); } } ss7_pc_to_str(ss7->switchtype, link->adj_sp->adjpc, pc_str); cust_printf(fd, " Link ADJ_PC:SLC: %s:%i NetMngSLS: %i\n", pc_str, link->slc, link->net_mng_sls); cust_printf(fd, " State: %s, %s\n", linkstate2strext(link->state), mtp2state2str(ss7, link)); cust_printf(fd, " STD Test: %s\n", link->std_test_passed ? "passed" : "failed"); cust_printf(fd, " Got, sent :%s\n", got_sent2str(got_sent_buf, link->got_sent_netmsg)); cust_printf(fd, " Inhibit: %s%s\n", (link->inhibit & INHIBITED_LOCALLY) ? "Locally " : " ", (ss7->links[i]->inhibit & INHIBITED_REMOTELY) ? "Remotely" : ""); cust_printf(fd, " Changeover: %s\n", changeover2str(link->changeover)); cust_printf(fd, " Tx buffer: %i\n", len_buf(link->tx_buf)); cust_printf(fd, " Tx queue: %i\n", len_buf(link->tx_q)); cust_printf(fd, " Retrans pos %i\n", len_buf(link->retransmit_pos)); cust_printf(fd, " CO buffer: %i\n", len_buf(link->co_buf)); cust_printf(fd, " CB buffer: %i\n", len_buf(link->cb_buf)); cust_printf(fd, " Last FSN: %i\n", link->lastfsnacked); cust_printf(fd, " MTP3timers: %s\n", timers); } /* links */ } /* sps */ } libss7-2.0.0/mtp2.c0000644000000000000000000005231112032373604012442 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 int len_buf(struct ss7_msg *buf) { int res = 0; struct ss7_msg *cur = buf; while (cur) { res++; cur = cur->next; } return res; } static inline char * linkstate2str(int linkstate) { char *statestr = NULL; switch (linkstate) { case MTP_IDLE: statestr = "IDLE"; break; case MTP_NOTALIGNED: statestr = "NOTALIGNED"; break; case MTP_ALIGNED: statestr = "ALIGNED"; break; case MTP_PROVING: statestr = "PROVING"; break; case MTP_ALIGNEDREADY: statestr = "ALIGNEDREADY"; break; case MTP_INSERVICE: statestr = "INSERVICE"; break; case MTP_ALARM: statestr = "ALARM"; break; default: statestr = "UNKNOWN"; } return statestr; } char *linkstate2strext(int linkstate) { return linkstate2str(linkstate); } 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]; } 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; #if 0 ss7_message(link->master, "Lastfsn: %i txbuflen: %i SLC: %i ADJPC: %i\n", link->lastfsnacked, len_buf(link->tx_buf), link->slc, link->dpc); #endif 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; } 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_buf(link->tx_buf)); #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; } static void t7_expiry(void *data) { struct mtp2 *link = data; ss7_error(link->master, "T7 expired on link SLC: %i ADJPC: %i\n", link->slc, link->dpc); link->t7 = -1; mtp2_setstate(link, MTP_IDLE); } 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; init_mtp2_header(link, (struct mtp_su_head *) h, 1, 0); /* in changeover we may manipulate the buffers!!! */ size = m->size; /* 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 (link->t7 == -1) { link->t7 = ss7_schedule_event(link->master, link->timers.t7, t7_expiry, link); } } 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); } if (h == buf) { /* We just sent a non MSU */ link->flags &= ~MTP2_FLAG_WRITE; } } else { ss7_error(link->master, "mtp2_transmit: write returned %d, errno=%d\n", res, errno); if (!retransmit && m) { /* We need to retransmit, but on retransmit, we'll just try again later */ link->retransmit_pos = link->tx_buf; } } 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; } void update_txbuf(struct mtp2 *link, struct ss7_msg **buf, 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 (!*buf) { return; } cur = *buf; while (cur) { h = (struct mtp_su_head *)cur->buf; if (h->fsn == upto) { frlist = cur; if (!prev) { /* Head of list */ *buf = NULL; } else { prev->next = NULL; } frlist = cur; break; } prev = cur; cur = cur->next; } if (link && frlist && link->t7 > -1) { ss7_schedule_del(link->master, &link->t7); if (link->tx_buf) { link->t7 = ss7_schedule_event(link->master, link->timers.t7, &t7_expiry, link); } } 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->state == MTP_INSERVICE) && (h->fsn != link->lastfsnacked) && (h->fib == link->curbib)) { 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); } 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: 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; ss7_debug_msg(link->master, SS7_DEBUG_MTP2, "MTP2 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; ss7_debug_msg(link->master, SS7_DEBUG_MTP2, "Link state change: %s -> %s\n", linkstate2str(link->state), linkstate2str(newstate)); switch (link->state) { case MTP_ALARM: return 0; 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) { return -1; } e->link.e = MTP2_LINK_UP; e->link.link = link; 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) { return -1; } e->link.e = MTP2_LINK_DOWN; e->link.link = link; 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); /* Q.703 11.1.2 LSSU can be one or two bytes. Only one is used for now and the second should be ignored for compatibility reasons */ if (len > (LSSU_SIZE + 1)) { 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) { reset_mtp(link); link->emergency = emergency; if (link->state == MTP_IDLE) { return mtp2_setstate(link, MTP_NOTALIGNED); } return 0; } int mtp2_stop(struct mtp2 *link) { return mtp2_setstate(link, MTP_IDLE); } int mtp2_alarm(struct mtp2 *link) { link->state = MTP_ALARM; return 0; } int mtp2_noalarm(struct mtp2 *link) { link->state = MTP_IDLE; return 0; } struct mtp2 * mtp2_new(int fd, unsigned int switchtype) { struct mtp2 * new = calloc(1, sizeof(struct mtp2)); int x; 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; new->timers.t7 = ITU_TIMER_T7; } 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; new->timers.t7 = ANSI_TIMER_T7; } for (x = 0; x < MTP3_MAX_TIMERS; x++) { new->mtp3_timer[x] = -1; } 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; char pc_str[64]; if (!(link->master->debug & SS7_DEBUG_MTP2)) { return; } ss7_pc_to_str(link->master->switchtype, link->adj_sp->adjpc, pc_str); 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[%s:%d] FISU\n", prefix, pc_str, 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[%s:%d] LSSU %s\n", prefix, pc_str, 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[%s:%d] MSU\n", prefix, pc_str, 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, &link->tx_buf, 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_buf(link->tx_buf)); 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-2.0.0/ss7_internal.h0000644000000000000000000001035212345407637014207 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 */ /* ISUP Timers */ #define ISUP_MAX_TIMERS 64 /* 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 512 /* need a lot cause of isup timers... */ #define SS7_MAX_LINKS 8 #define SS7_MAX_ADJSPS 8 #define SS7_STATE_DOWN 0 #define SS7_STATE_UP 1 /* delay to starting sending GRS when linkset came up */ #define LINKSET_UP_DELAY 500 /* MTP3 timers */ #define MTP3_MAX_TIMERS 32 #define LOC_PRIV_NET_LOCAL_USER 0x1 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 numsps; 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]; struct adjacent_sp *adj_sps[SS7_MAX_ADJSPS]; int isup_timers[ISUP_MAX_TIMERS]; int mtp3_timers[MTP3_MAX_TIMERS]; unsigned char sls_shift; unsigned int flags; unsigned char cb_seq; int linkset_up_timer; unsigned char cause_location; }; /* 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); int ss7_find_link_index(struct ss7 *ss7, int fd); struct mtp2 * ss7_find_link(struct ss7 *ss7, int fd); 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, const char *fmt, ...) __attribute__((format(printf, 2, 3))); void ss7_error(struct ss7 *ss7, const char *fmt, ...) __attribute__((format(printf, 2, 3))); #define ss7_debug_msg(ctrl, flags, ...) \ do { \ if ((ctrl)->debug & (flags)) { \ ss7_message(ctrl, __VA_ARGS__); \ } \ } while (0) 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); extern void (*ss7_notinservice)(struct ss7 *ss7, int cic, unsigned int dpc); extern int (*ss7_hangup)(struct ss7 *ss7, int cic, unsigned int dpc, int cause, int do_hangup); extern void (*ss7_call_null)(struct ss7 *ss7, struct isup_call *c, int lock); #endif /* _SS7_H */ libss7-2.0.0/ss7_sched.c0000644000000000000000000000614512010747414013446 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-2.0.0/mtp3.h0000644000000000000000000001236612010762336012456 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 #define MTP3_DOWN 0 #define MTP3_UP 1 #define GOT (1 << 0) #define SENT (1 << 1) /* Prohibited, restricted states */ #define TFP 1 #define TFA 2 #define TFR_NON_ACTIVE 3 #define TFR_ACTIVE 4 /* Net mngs h0 h1 */ #define NET_MNG_COO (0x01 | 0x10) #define NET_MNG_COA (0x01 | 0x20) #define NET_MNG_CBD (0x01 | 0x50) #define NET_MNG_CBA (0x01 | 0x60) #define NET_MNG_ECO (0x02 | 0x10) #define NET_MNG_ECA (0x02 | 0x20) #define NET_MNG_RCT (0x03 | 0x10) #define NET_MNG_TFC (0x03 | 0x20) #define NET_MNG_TFP (0x04 | 0x10) #define NET_MNG_TFR (0x04 | 0x30) #define NET_MNG_TFA (0x04 | 0x50) #define NET_MNG_RST (0x05 | 0x10) #define NET_MNG_RSR (0x05 | 0x20) #define NET_MNG_LIN (0x06 | 0x10) #define NET_MNG_LUN (0x06 | 0x20) #define NET_MNG_LIA (0x06 | 0x30) #define NET_MNG_LUA (0x06 | 0x40) #define NET_MNG_LID (0x06 | 0x50) #define NET_MNG_LFU (0x06 | 0x60) #define NET_MNG_LLT (0x06 | 0x70) #define NET_MNG_LRT (0x06 | 0x80) #define NET_MNG_TRA (0x07 | 0x10) #define NET_MNG_DLC (0x08 | 0x10) #define NET_MNG_CSS (0x08 | 0x20) #define NET_MNG_CNS (0x08 | 0x30) #define NET_MNG_CNP (0x08 | 0x40) #define NET_MNG_UPU (0x0a | 0x10) /* INHIBIT states */ #define INHIBITED_REMOTELY (1 << 0) #define INHIBITED_LOCALLY (1 << 1) /* Got, Sent netmsgs */ #define SENT_LUN (1 << 0) #define SENT_LIN (1 << 1) #define SENT_COO (1 << 2) #define SENT_ECO (1 << 3) #define SENT_CBD (1 << 4) #define SENT_LFU (1 << 5) /* Chaneover states */ #define NO_CHANGEOVER 0 #define CHANGEOVER_INITIATED 1 #define CHANGEOVER_IN_PROGRESS 2 #define CHANGEOVER_COMPLETED 3 #define CHANGEBACK_INITIATED 4 #define CHANGEBACK 5 /* MTP3 timers */ #define MTP3_TIMER_T1 1 #define MTP3_TIMER_T2 2 #define MTP3_TIMER_T3 3 #define MTP3_TIMER_T4 4 #define MTP3_TIMER_T5 5 #define MTP3_TIMER_T6 6 #define MTP3_TIMER_T7 7 #define MTP3_TIMER_T8 8 #define MTP3_TIMER_T10 9 #define MTP3_TIMER_T12 10 #define MTP3_TIMER_T13 11 #define MTP3_TIMER_T14 12 #define MTP3_TIMER_T19 13 #define MTP3_TIMER_T21 14 #define MTP3_TIMER_T22 15 #define MTP3_TIMER_T23 16 #define MTP3_TIMER_Q707_T1 17 #define MTP3_TIMER_Q707_T2 18 #define AUTORL(rl, link) \ struct routing_label rl; \ rl.sls = link->net_mng_sls; \ rl.dpc = link->dpc; \ rl.opc = link->master->pc struct net_mng_message { int h0; int h1; char *name; }; struct mtp3_route { int state; unsigned int dpc; int t6; int t10; struct ss7_msg *q; struct adjacent_sp *owner; struct mtp3_route *next; }; struct adjacent_sp { int state; unsigned int adjpc; struct mtp2 *links[SS7_MAX_LINKS]; unsigned int numlinks; int timer_t19; int timer_t21; unsigned int tra; struct ss7 *master; struct mtp3_route *routes; }; int net_mng_send(struct mtp2 *link, unsigned char h0h1, struct routing_label rl, unsigned int param); /* 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, struct routing_label rl, int priority, struct ss7_msg *m, struct mtp2 *link); 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); char * mtp3_timer2str(int mtp3_timer); void mtp3_add_adj_sp(struct mtp2 *link); void mtp3_free_co(struct mtp2 *link); void mtp3_destroy_all_routes(struct adjacent_sp *adj_sp); #endif /* _MTP3_H */ libss7-2.0.0/isup.h0000644000000000000000000003114712345407637012564 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 /*!< Initial address */ #define ISUP_SAM 0x02 /*!< Subsequent address */ #define ISUP_INR 0x03 /*!< Information request (national use) */ #define ISUP_INF 0x04 /*!< Information (national use) */ #define ISUP_COT 0x05 /*!< Continuity */ #define ISUP_ACM 0x06 /*!< Address complete */ #define ISUP_CON 0x07 /*!< Connect */ #define ISUP_FOT 0x08 /*!< Forward transfer */ #define ISUP_ANM 0x09 /*!< Answer */ #define ISUP_REL 0x0c /*!< Release */ #define ISUP_SUS 0x0d /*!< Suspend */ #define ISUP_RES 0x0e /*!< Resume */ #define ISUP_RLC 0x10 /*!< Release complete */ #define ISUP_CCR 0x11 /*!< Continuity check request */ #define ISUP_RSC 0x12 /*!< Reset circuit */ #define ISUP_BLO 0x13 /*!< Blocking */ #define ISUP_UBL 0x14 /*!< Unblocking */ #define ISUP_BLA 0x15 /*!< Blocking acknowledgement */ #define ISUP_UBA 0x16 /*!< Unblocking acknowledgement */ #define ISUP_GRS 0x17 /*!< Circuit group reset */ #define ISUP_CGB 0x18 /*!< Circuit group blocking */ #define ISUP_CGU 0x19 /*!< Circuit group unblocking */ #define ISUP_CGBA 0x1a /*!< Circuit group blocking acknowledgement */ #define ISUP_CGUA 0x1b /*!< Circuit group unblocking acknowledgement */ #define ISUP_CMR 0x1c /*!< Reserved (used in 1988 version) */ #define ISUP_CMC 0x1d /*!< Reserved (used in 1988 version) */ #define ISUP_CMRJ 0x1e /*!< Reserved (used in 1988 version) */ #define ISUP_FAR 0x1f /*!< Facility request */ #define ISUP_FAA 0x20 /*!< Facility accepted */ #define ISUP_FRJ 0x21 /*!< Facility reject */ #define ISUP_FAD 0x22 /*!< Reserved (used in 1984 version) */ #define ISUP_FAI 0x23 /*!< Reserved (used in 1984 version) */ #define ISUP_LPA 0x24 /*!< Loop back acknowledgement (national use) */ #define ISUP_CSVR 0x25 /*!< Reserved (used in 1984 version) */ #define ISUP_CSVS 0x26 /*!< Reserved (used in 1984 version) */ #define ISUP_DRS 0x27 /*!< Reserved (used in 1988 version) */ #define ISUP_PAM 0x28 /*!< Pass-along (national use) */ #define ISUP_GRA 0x29 /*!< Circuit group reset acknowledgement */ #define ISUP_CQM 0x2a /*!< Circuit group query (national use) */ #define ISUP_CQR 0x2b /*!< Circuit group query response (national use) */ #define ISUP_CPG 0x2c /*!< Call progress */ #define ISUP_USR 0x2d /*!< User-to-user information */ #define ISUP_UCIC 0x2e /*!< Unequipped CIC (national use) */ #define ISUP_CFN 0x2f /*!< Confusion */ #define ISUP_OLM 0x30 /*!< Overload (national use) */ #define ISUP_CRG 0x31 /*!< Charge information (national use) */ #define ISUP_FAC 0x33 /*!< Facility */ #define ISUP_CRA 0xe9 /*!< ??? */ #define ISUP_CRM 0xea /*!< ??? */ #define ISUP_CVR 0xeb /*!< ???Used??? */ #define ISUP_CVT 0xec /*!< ???Used??? */ #define ISUP_EXM 0xed /*!< ??? */ /* ISUP Parameters ITU-T Q.763 */ #define ISUP_PARM_CALL_REF 0x01 #define ISUP_PARM_TRANSMISSION_MEDIUM_REQS 0x02 #define ISUP_PARM_ACCESS_TRANS 0x03 #define ISUP_PARM_CALLED_PARTY_NUM 0x04 #define ISUP_PARM_SUBSEQUENT_NUMBER 0x05 #define ISUP_PARM_NATURE_OF_CONNECTION_IND 0x06 #define ISUP_PARM_FORWARD_CALL_IND 0x07 #define ISUP_PARM_OPT_FORWARD_CALL_INDICATOR 0x08 #define ISUP_PARM_CALLING_PARTY_CAT 0x09 #define ISUP_PARM_CALLING_PARTY_NUM 0x0a #define ISUP_PARM_REDIRECTING_NUMBER 0x0b #define ISUP_PARM_REDIRECTION_NUMBER 0x0c #define ISUP_PARM_CONNECTION_REQ 0x0d #define ISUP_PARM_INR_IND 0x0e #define ISUP_PARM_INF_IND 0x0f #define ISUP_PARM_CONTINUITY_IND 0x10 #define ISUP_PARM_BACKWARD_CALL_IND 0x11 #define ISUP_PARM_CAUSE 0x12 #define ISUP_PARM_REDIRECTION_INFO 0x13 /* 0x14 is Reserved / Event information */ #define ISUP_PARM_CIRCUIT_GROUP_SUPERVISION_IND 0x15 #define ISUP_PARM_RANGE_AND_STATUS 0x16 #define ISUP_PARM_CALL_MODIFICATION_IND 0x17 #define ISUP_PARM_FACILITY_IND 0x18 /* 0x19 is Reserved */ #define ISUP_PARM_CUG_INTERLOCK_CODE 0x1a /* 0x1b is Reserved */ /* 0x1c is Reserved */ #define ISUP_PARM_USER_SERVICE_INFO 0x1d #define ISUP_PARM_SIGNALLING_PC 0x1e /* 0x1f is Reserved */ #define ISUP_PARM_USER_TO_USER_INFO 0x20 #define ISUP_CONNECTED_NUMBER 0x21 #define ISUP_PARM_SUSPEND_RESUME_IND 0x22 #define ISUP_PARM_TRANSIT_NETWORK_SELECTION 0x23 #define ISUP_PARM_EVENT_INFO 0x24 #define ISUP_PARM_CIRCUIT_ASSIGNMENT_MAP 0x25 #define ISUP_PARM_CIRCUIT_STATE_IND 0x26 #define ISUP_PARAM_AUTOMATIC_CONGESTION_LEVEL 0x27 #define ISUP_PARM_ORIGINAL_CALLED_NUM 0x28 #define ISUP_PARM_OPT_BACKWARD_CALL_IND 0x29 #define ISUP_PARM_USER_TO_USER_IND 0x2a #define ISUP_PARM_ORIGINATION_ISC_PC 0x2b #define ISUP_PARM_GENERIC_NOTIFICATION_IND 0x2c #define ISUP_PARM_CALL_HISTORY_INFO 0x2d #define ISUP_PARM_ACCESS_DELIVERY_INFO 0x2e #define ISUP_PARM_NETWORK_SPECIFIC_FACILITY 0x2f #define ISUP_PARM_USER_SERVICE_INFO_PRIME 0x30 #define ISUP_PARM_PROPAGATION_DELAY 0x31 #define ISUP_PARM_REMOTE_OPERATIONS 0x32 #define ISUP_PARM_SERVICE_ACTIVATION 0x33 #define ISUP_PARM_USER_TELESERVICE_INFO 0x34 #define ISUP_PARM_TRANSMISSION_MEDIUM_USED 0x35 #define ISUP_PARM_CALL_DIVERSION_INFO 0x36 #define ISUP_PARM_ECHO_CONTROL_INFO 0x37 #define ISUP_PARM_MESSAGE_COMPAT_INFO 0x38 #define ISUP_PARM_PARAMETER_COMPAT_INFO 0x39 #define ISUP_PARM_MLPP_PRECEDENCE 0x3a #define ISUP_PARM_MCID_REQUEST_IND 0x3b #define ISUP_PARM_MCID_RESPONSE_IND 0x3c #define ISUP_PARM_HOP_COUNTER 0x3d #define ISUP_PARM_TRANSMISSION_MEDIUM_REQ_PRIME 0x3e #define ISUP_PARM_LOCATION_NUMBER 0x3f #define ISUP_PARM_REDIRECTION_NUM_RESTRICTION 0x40 #define ISUP_PARM_CALL_TRANSFER_REFERENCE 0x43 #define ISUP_PARM_LOOP_PREVENTION_IND 0x44 #define ISUP_PARM_CALL_TRANSFER_NUMBER 0x45 #define ISUP_PARM_CCSS 0x4b #define ISUP_PARM_FORWARD_GVNS 0x4c #define ISUP_PARM_BACKWARD_GVNS 0x4d #define ISUP_PARM_REDIRECT_CAPABILITY 0x4e #define ISUP_PARM_NETWORK_MANAGEMENT_CONTROL 0x5b #define ISUP_PARM_CORRELATION_ID 0x65 #define ISUP_PARM_SCF_ID 0x66 #define ISUP_PARM_CALL_DIVERSION_TREATMENT_IND 0x6e #define ISUP_PARM_CALLED_IN_NUMBER 0x6f #define ISUP_PARM_CALL_OFFERING_TREATMENT_IND 0x70 #define ISUP_PARM_CHARGED_PARTY_IDENT 0x71 #define ISUP_PARM_CONFERENCE_TREATMENT_IND 0x72 #define ISUP_PARM_DISPLAY_INFO 0x73 #define ISUP_PARM_UID_ACTION_IND 0x74 #define ISUP_PARM_UID_CAPABILITY_IND 0x75 #define ISUP_PARM_REDIRECT_COUNTER 0x77 #define ISUP_PARM_APPLICATION_TRANSPORT 0x78 #define ISUP_PARM_COLLECT_CALL_REQUEST 0x79 #define ISUP_PARM_CCNR_POSSIBLE_IND 0x7a #define ISUP_PARM_PIVOT_CAPABILITY 0x7b #define ISUP_PARM_PIVOT_ROUTING_IND 0x7c #define ISUP_PARM_CALLED_DIRECTORY_NUMBER 0x7d #define ISUP_PARM_ORIGINAL_CALLED_IN_NUM 0x7f /* 0x80 reserved for future extension */ #define ISUP_PARM_CALLING_GEODETIC_LOCATION 0x81 #define ISUP_PARM_HTR_INFO 0x82 #define ISUP_PARM_NETWORK_ROUTING_NUMBER 0x84 #define ISUP_PARM_QUERY_ON_RELEASE_CAPABILITY 0x85 #define ISUP_PARM_PIVOT_STATUS 0x86 #define ISUP_PARM_PIVOT_COUNTER 0x87 #define ISUP_PARM_PIVOT_ROUTING_FORWARD_IND 0x88 #define ISUP_PARM_PIVOT_ROUTING_BACKWARD_IND 0x89 #define ISUP_PARM_REDIRECT_STATUS 0x8a #define ISUP_PARM_REDIRECT_FORWARD_INFO 0x8b #define ISUP_PARM_REDIRECT_BACKWARD_INFO 0x8c #define ISUP_PARM_NUM_PORTABILITY_FORWARD_INFO 0x8d #define ISUP_PARM_GENERIC_ADDR 0xc0 #define ISUP_PARM_GENERIC_DIGITS 0xc1 #define ISUP_PARM_EGRESS_SERV 0xc3 #define ISUP_PARM_JIP 0xc4 #define ISUP_PARM_CARRIER_ID 0xc5 #define ISUP_PARM_BUSINESS_GRP 0xc6 #define ISUP_PARM_GENERIC_NAME 0xc7 #define ISUP_PARM_LOCAL_SERVICE_PROVIDER_IDENTIFICATION 0xe4 #define ISUP_PARM_ORIG_LINE_INFO 0xea #define ISUP_PARM_CHARGE_NUMBER 0xeb #define ISUP_PARM_SELECTION_INFO 0xee /* ISUP TIMERS */ #define ISUP_TIMER_T1 1 #define ISUP_TIMER_T2 2 #define ISUP_TIMER_T5 5 #define ISUP_TIMER_T6 6 #define ISUP_TIMER_T7 7 #define ISUP_TIMER_T8 8 #define ISUP_TIMER_T10 10 #define ISUP_TIMER_T12 12 #define ISUP_TIMER_T13 13 #define ISUP_TIMER_T14 14 #define ISUP_TIMER_T15 15 #define ISUP_TIMER_T16 16 #define ISUP_TIMER_T17 17 #define ISUP_TIMER_T18 18 #define ISUP_TIMER_T19 19 #define ISUP_TIMER_T20 20 #define ISUP_TIMER_T21 21 #define ISUP_TIMER_T22 22 #define ISUP_TIMER_T23 23 #define ISUP_TIMER_T27 27 #define ISUP_TIMER_T33 33 #define ISUP_TIMER_T35 35 /* 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 redirect_counter; unsigned char redirect_info; unsigned char redirect_info_ind; unsigned char redirect_info_orig_reas; unsigned char redirect_info_counter; unsigned char redirect_info_reas; unsigned char generic_name_typeofname; unsigned char generic_name_avail; unsigned char generic_name_presentation; char connected_num[ISUP_MAX_NUM]; unsigned char connected_nai; unsigned char connected_presentation_ind; unsigned char connected_screening_ind; char generic_name[ISUP_MAX_NAME]; int range; unsigned char sent_cgb_status[255]; unsigned char sent_cgu_status[255]; unsigned char status[255]; int transcap; int l1prot; int cause; int causecode; int causeloc; int cot_check_passed; int cot_check_required; int cot_performed_on_previous_cic; int cicgroupsupervisiontype; unsigned char event_info; unsigned short cic; unsigned char sls; unsigned long got_sent_msg; /* flags for sent msgs */ int sent_cgb_type; int sent_cgu_type; int sent_grs_endcic; int sent_cgb_endcic; int sent_cgu_endcic; 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; unsigned char local_echocontrol_ind; unsigned char echocontrol_ind; /* Suspend/Resume Indicator */ int network_isdn_indicator; unsigned char inr_ind[2]; unsigned char inf_ind[2]; unsigned char cug_indicator; unsigned col_req; char cug_interlock_ni[5]; unsigned short cug_interlock_code; unsigned char interworking_indicator; unsigned char forward_indicator_pmbits; int timer[ISUP_MAX_TIMERS]; }; 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); void isup_free_all_calls(struct ss7 *ss7); #endif /* _SS7_ISUP_H */ libss7-2.0.0/mtp3.c0000644000000000000000000017146712345407637012474 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" 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 struct mtp2 * slc_to_mtp2(struct ss7 *ss7, unsigned int slc); 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 int link_available(struct ss7 *ss7, int linkid, struct ss7_msg ***buffer, struct routing_label rl) { if ((ss7->mtp2_linkstate[linkid] == MTP2_LINKSTATE_UP && ss7->links[linkid]->adj_sp->state == MTP3_UP && ss7->links[linkid]->changeover != CHANGEOVER_COMPLETED) || (ss7->links[linkid]->changeover == CHANGEOVER_IN_PROGRESS) || ss7->links[linkid]->changeover == CHANGEBACK_INITIATED) { struct mtp3_route *route = ss7->links[linkid]->adj_sp->routes; while (route) { if (route->dpc == rl.dpc) { if (route->t6 > -1) { /* T6 is running, buffering */ *buffer = &route->q; return 1; } if (route->state == TFR_NON_ACTIVE || route->state == TFA) { break; } else { *buffer = NULL; return 0; } } route = route->next; } switch (ss7->links[linkid]->changeover) { case CHANGEOVER_IN_PROGRESS: case CHANGEOVER_INITIATED: *buffer = &ss7->links[linkid]->co_buf; return 1; case CHANGEBACK_INITIATED: case CHANGEBACK: *buffer = &ss7->links[linkid]->cb_buf; return 1; default: *buffer = NULL; return 1; } } else { *buffer = NULL; return 0; } } static inline struct mtp2 * rl_to_link(struct ss7 *ss7, struct routing_label rl, struct ss7_msg ***buffer) { int linkid; linkid = (rl.sls >> ss7->sls_shift) % ss7->numlinks; if (link_available(ss7, linkid, buffer, rl)) { return ss7->links[linkid]; } else { struct mtp2 *winner = NULL; int i; for (i = 0; i < ss7->numlinks; i++) { if (link_available(ss7, i, buffer, rl)) { 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, len - rl_size(ss7)); return 0; } static void q707_t1_expiry(void *data); 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->net_mng_sls; rllen = set_routinglabel(layer4, &rl); layer4 += rllen; set_h0(layer4, 1); set_h1(layer4, 1); if (ss7->switchtype == SS7_ANSI) { layer4[1] = (testlen << 4) | (link->slc & 0xf); } else { layer4[1] = (testlen << 4); } memcpy(&layer4[2], testmessage, testlen); ss7_msg_userpart_len(m, rllen + testlen + 2); if (mtp3_transmit(link->master, (ss7->switchtype == SS7_ITU) ? SIG_STD_TEST : SIG_SPEC_TEST, rl, 3, m, link) > -1 && link->master->mtp3_timers[MTP3_TIMER_Q707_T1] > 0) { if (link->mtp3_timer[MTP3_TIMER_Q707_T1] > -1) { ss7_schedule_del(ss7, &link->mtp3_timer[MTP3_TIMER_Q707_T1]); } link->mtp3_timer[MTP3_TIMER_Q707_T1] = ss7_schedule_event(ss7, link->master->mtp3_timers[MTP3_TIMER_Q707_T1], q707_t1_expiry, link); } } static void mtp3_event_link_down(struct mtp2 *link); static void q707_t1_expiry(void *data) { struct mtp2 *link = data; link->q707_t1_failed++; link->mtp3_timer[MTP3_TIMER_Q707_T1] = -1; if (link->q707_t1_failed > 1) { ss7_error(link->master, "Q707 T1 timer expired 2nd time on link SLC: %i PC: %i\n", link->slc, link->dpc); link->q707_t1_failed = 0; if (link->mtp3_timer[MTP3_TIMER_Q707_T2] > -1) { ss7_schedule_del(link->master, &link->mtp3_timer[MTP3_TIMER_Q707_T2]); } mtp3_event_link_down(link); } std_test_send(link); } static inline void ss7_linkset_up_event(struct ss7 *ss7) { ss7_event *e = ss7_next_empty_event(ss7); if (!e) { return; } e->e = SS7_STATE_UP; } static void linkset_up_expired(void *data) { struct ss7 *ss7 = data; ss7->linkset_up_timer = -1; ss7_linkset_up_event(ss7); } static int available_links(struct ss7 *ss7, int dpc, int ignore_inhibit) { int res = 0, i; struct mtp3_route *route; for (i = 0; i < ss7->numlinks; i++) { if (ss7->links[i]->std_test_passed && ((ignore_inhibit && ss7->links[i]->inhibit) ? 1 : (ss7->links[i]->changeover == NO_CHANGEOVER || ss7->links[i]->changeover == CHANGEBACK))) { if (dpc == -1) { res++; } else { route = ss7->links[i]->adj_sp->routes; while (route) { if (route->dpc == dpc ) { if (route->state == TFA || route->state == TFR_NON_ACTIVE) { res++; } break; } route = route->next; } } } } return res; } static int ss7_check(struct ss7 *ss7) { int i, j, mtp3_up = 0; int av_links = available_links(ss7, -1, 0); for (i = 0; i < ss7->numsps; i++) { if (ss7->adj_sps[i]->state == MTP3_UP) { mtp3_up = 1; break; } } if (!av_links && mtp3_up) { /* find a locally inhibited link */ for (i = 0; i < ss7->numlinks; i++) { if (ss7->links[i]->inhibit & INHIBITED_LOCALLY) { if (!(ss7->links[i]->got_sent_netmsg & SENT_LUN)) { AUTORL(rl, ss7->links[i]); net_mng_send(ss7->links[i], NET_MNG_LUN, rl, 0); ss7_message(ss7, "Uninhibiting locally inhibited link (no more signalling links are in service) SLC: %i ADJPC: %i\n", ss7->links[i]->slc, ss7->links[i]->dpc); } if (ss7->links[i]->inhibit & INHIBITED_REMOTELY) { i = ss7->numlinks; /* in this case force remote uninhibit too ! */ } break; } } /* try force uninhibit */ if (i == ss7->numlinks) { for (i = 0; i < ss7->numlinks; i++) { if (ss7->links[i]->inhibit & INHIBITED_REMOTELY) { if (!(ss7->links[i]->got_sent_netmsg & SENT_LFU)) { AUTORL(rl, ss7->links[i]); net_mng_send(ss7->links[i], NET_MNG_LFU, rl, 0); ss7_message(ss7, "Forced uninhibiting remotely inhibited link (no more signalling links are in service) SLC: %i ADJPC: %i\n", ss7->links[i]->slc, ss7->links[i]->dpc); } break; } } } } if (ss7->state != SS7_STATE_UP && mtp3_up) { ss7->state = SS7_STATE_UP; if (LINKSET_UP_DELAY > -1) { if (ss7->linkset_up_timer > -1) { ss7_schedule_del(ss7, &ss7->linkset_up_timer); } ss7->linkset_up_timer = ss7_schedule_event(ss7, LINKSET_UP_DELAY, &linkset_up_expired, ss7); ss7_message(ss7, "LINKSET UP DELAYING RESETTING\n"); } else { ss7_linkset_up_event(ss7); } /* Set links to changeover state which are not came up yet */ for (i = 0; i < ss7->numlinks; i++) { if (!ss7->links[i]->std_test_passed) { ss7->links[i]->changeover = CHANGEOVER_COMPLETED; } } } if (ss7->state != SS7_STATE_DOWN && !mtp3_up) { ss7->state = SS7_STATE_DOWN; if (ss7->linkset_up_timer == -1) { struct mtp2 *link; ss7_event *e = ss7_next_empty_event(ss7); if (!e) { return -1; } e->e = SS7_EVENT_DOWN; isup_free_all_calls(ss7); for (i = 0; i < ss7->numlinks; i++) { link = ss7->links[i]; if (link->inhibit & INHIBITED_LOCALLY) { link->changeover = CHANGEOVER_COMPLETED; /* because will be stopped all of the timers and flushed the buffers */ } else { link->changeover = NO_CHANGEOVER; } mtp3_free_co(link); for (j = 0; j < MTP3_MAX_TIMERS; j++) { if (link->mtp3_timer[j] > -1) { ss7_schedule_del(ss7, &link->mtp3_timer[j]); } } } } else { ss7_schedule_del(ss7, &ss7->linkset_up_timer); } } return 0; } static void mtp3_stop_all_timers_except_cocb(struct mtp2 *link) { int x; for (x = 0; x < MTP3_MAX_TIMERS; x++) { if (link->mtp3_timer[x] > -1 && x != MTP3_TIMER_T1 && x != MTP3_TIMER_T3 && x != MTP3_TIMER_T2 && x != MTP3_TIMER_T4 && x != MTP3_TIMER_T5 && x != MTP3_TIMER_T22 && x != MTP3_TIMER_T23) { ss7_schedule_del(link->master, &link->mtp3_timer[x]); ss7_debug_msg(link->master, SS7_DEBUG_MTP3, "Stopped MTP3 timer %s on link SLC: %i PC: %i\n", mtp3_timer2str(x), link->slc, link->dpc); } } } static void mtp3_timer_q707_t2_expiry(void *data) { struct mtp2 *link = data; std_test_send(link); link->mtp3_timer[MTP3_TIMER_Q707_T2] = ss7_schedule_event(link->master, link->master->mtp3_timers[MTP3_TIMER_Q707_T2], mtp3_timer_q707_t2_expiry, link); } static void mtp3_event_link_up(struct mtp2 * link) { std_test_send(link); if (link->master->mtp3_timers[MTP3_TIMER_Q707_T2] > 0) { if (link->mtp3_timer[MTP3_TIMER_Q707_T2] > -1) { ss7_schedule_del(link->master, &link->mtp3_timer[MTP3_TIMER_Q707_T2]); } link->mtp3_timer[MTP3_TIMER_Q707_T2] = ss7_schedule_event(link->master, link->master->mtp3_timers[MTP3_TIMER_Q707_T2], mtp3_timer_q707_t2_expiry, link); } } static void mtp3_move_buffer(struct ss7 *ss7, struct mtp2 *link, struct ss7_msg **from, struct ss7_msg **to, int dpc, int fsn) { struct ss7_msg *cur, *prev, *next, *dst; unsigned char *buf; unsigned char userpart; struct routing_label rl; if (fsn != -1) { update_txbuf(NULL, from, fsn); } prev = NULL; cur = *from; if (to && *to) { for (dst = *to; dst->next; dst = dst->next); } else { dst = NULL; } while (cur) { buf = cur->buf; userpart = get_userpart(buf[MTP2_SIZE]); get_routinglabel(ss7->switchtype, buf + MTP2_SIZE + 1, &rl); next = cur->next; if (userpart > 3 && (dpc == -1 || rl.dpc == dpc)) { if (cur == link->retransmit_pos) { link->retransmit_pos = cur->next; } if (*from == link->tx_buf || *from == link->tx_q || *from == link->co_tx_buf || *from == link->co_tx_q) { cur->size -= 2; /* mtp2_msu increased it before!!! */ } if (prev) { prev->next = cur->next; } else { *from = cur->next; } if (to) { if (dst) { dst->next = cur; dst = dst->next; } else { *to = cur; dst = cur; } dst->next = NULL; } else { free (cur); } } else { prev = cur; } cur = next; } } static void mtp3_transmit_buffer(struct ss7 *ss7, struct ss7_msg **buf) { unsigned char userpart; struct routing_label rl; struct ss7_msg *cur = *buf, *next; int priority = -1; while (cur) { next = cur->next; userpart = get_userpart(cur->buf[MTP2_SIZE]); priority = get_priority(cur->buf[MTP2_SIZE]); get_routinglabel(ss7->switchtype, cur->buf + MTP2_SIZE + 1, &rl); mtp3_transmit(ss7, userpart, rl, priority, cur, NULL); cur = next; } *buf = NULL; } void mtp3_free_co(struct mtp2 *link) { struct ss7_msg *cur; while (link->co_tx_buf) { cur = link->co_tx_buf; link->co_tx_buf = link->co_tx_buf->next; free(cur); } while (link->co_tx_q) { cur = link->co_tx_q; link->co_tx_q = link->co_tx_q->next; free(cur); } } static void mtp3_cancel_changeover(struct mtp2 *link) { if (link->mtp3_timer[MTP3_TIMER_T1] > -1) { ss7_schedule_del(link->master, &link->mtp3_timer[MTP3_TIMER_T1]); } if (link->mtp3_timer[MTP3_TIMER_T2] > -1) { ss7_schedule_del(link->master, &link->mtp3_timer[MTP3_TIMER_T2]); } link->got_sent_netmsg &= ~(SENT_COO | SENT_ECO); mtp3_move_buffer(link->master, link, &link->co_tx_q, &link->cb_buf, -1, -1); mtp3_move_buffer(link->master, link, &link->co_buf, &link->cb_buf, -1, -1); link->changeover = NO_CHANGEOVER; mtp3_free_co(link); ss7_message(link->master, "Changeover cancelled on link SLC %i PC %i\n", link->slc, link->dpc); } static void mtp3_check(struct adjacent_sp *adj_sp) { if (!adj_sp) { return; } struct ss7 *ss7 = adj_sp->master; int i, count = 0; for (i = 0; i < adj_sp->numlinks; i++) { if (adj_sp->links[i]->std_test_passed) { count++; } } if (!count && adj_sp->state != MTP3_DOWN) { adj_sp->state = MTP3_DOWN; adj_sp->tra = 0; if (adj_sp->timer_t19 > -1) { ss7_schedule_del(ss7, &adj_sp->timer_t19); ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T19 timer stopped PC: %i\n", adj_sp->adjpc); } if (adj_sp->timer_t21 > -1) { ss7_schedule_del(ss7, &adj_sp->timer_t21); ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T21 timer stopped PC: %i\n", adj_sp->adjpc); } for (i = 0; i < adj_sp->numlinks; i++) { adj_sp->links[i]->got_sent_netmsg = 0; mtp3_stop_all_timers_except_cocb(adj_sp->links[i]); adj_sp->links[i]->inhibit &= ~INHIBITED_REMOTELY; } mtp3_destroy_all_routes(adj_sp); ss7_error(ss7, "Adjacent SP PC: %i DOWN!!!\n", adj_sp->adjpc); ss7_check(ss7); return; } if (count && adj_sp->state != MTP3_UP && adj_sp->tra & GOT && adj_sp->tra & SENT) { adj_sp->state = MTP3_UP; ss7_message(ss7, "Adjacent SP PC: %i UP!!!\n", adj_sp->adjpc); ss7_check(ss7); } } static int mtp3_init(struct mtp2 *link) { int res; struct adjacent_sp *adj_sp = link->adj_sp; if (adj_sp->state == MTP3_DOWN) { AUTORL(rl, link); if (link->inhibit & INHIBITED_LOCALLY) { return net_mng_send(link, NET_MNG_LIN, rl, 0); } else if (!(adj_sp->tra & SENT)) { res = net_mng_send(link, NET_MNG_TRA, rl, 0); mtp3_check(adj_sp); return res; } } return 0; } static void mtp3_restart(struct mtp2 *link) { struct adjacent_sp *adj_sp = link->adj_sp; int i; adj_sp->state = MTP3_DOWN; adj_sp->tra = 0; for (i = 0; i < adj_sp->numlinks; i++) { adj_sp->links[i]->inhibit &= ~INHIBITED_REMOTELY ; adj_sp->links[i]->got_sent_netmsg = 0; mtp3_stop_all_timers_except_cocb(adj_sp->links[i]); } mtp3_destroy_all_routes(adj_sp); for (i = 0; i < adj_sp->numlinks; i++) { if (!mtp3_init(adj_sp->links[i])) { break; } } ss7_check(link->master); } void mtp3_init_restart(struct ss7 *ss7, int slc) { struct mtp2 *link = slc_to_mtp2(ss7, slc); if (!link) { ss7_error(ss7, "signalling link does not exist\n"); return; } { struct adjacent_sp *adj_sp = link->adj_sp; if (adj_sp->timer_t19 > -1) { ss7_schedule_del(ss7, &adj_sp->timer_t19); } if (adj_sp->timer_t21 > -1) { ss7_schedule_del(ss7, &adj_sp->timer_t21); } } mtp3_restart(link); } static void mtp3_t3_expired(void *data) { struct mtp2 *link = data; link->mtp3_timer[MTP3_TIMER_T3] = -1; link->changeover = NO_CHANGEOVER; mtp3_transmit_buffer(link->master, &link->cb_buf); ss7_check(link->master); ss7_message(link->master, "Changeback completed on link SLC: %i PC: %i\n", link->slc, link->dpc); mtp3_free_co(link); } static void mtp3_changeback(struct mtp2 *link) { if (link->inhibit) { ss7_message(link->master, "Change back requested inhibited link, ignore SLC: %i PC: %i\n", link->slc, link->dpc); return; } if (link->changeover == CHANGEOVER_IN_PROGRESS || link->changeover == CHANGEOVER_INITIATED) { mtp3_cancel_changeover(link); } else if (link->changeover != CHANGEBACK && link->changeover != NO_CHANGEOVER) { mtp3_move_buffer(link->master, link, &link->tx_q, &link->cb_buf, -1, -1); link->changeover = CHANGEBACK; link->mtp3_timer[MTP3_TIMER_T3] = ss7_schedule_event(link->master, link->master->mtp3_timers[MTP3_TIMER_T3], &mtp3_t3_expired, link); ss7_message(link->master, "Changeback started on link SLC %i PC %i\n", link->slc, link->dpc); } mtp3_check(link->adj_sp); } static void mtp3_cancel_changeback(struct mtp2 *link) { mtp3_move_buffer(link->master, link, &link->cb_buf, &link->co_buf, -1, -1); link->changeover = NO_CHANGEOVER; if (link->mtp3_timer[MTP3_TIMER_T3] > -1) { ss7_schedule_del(link->master, &link->mtp3_timer[MTP3_TIMER_T3]); } if (link->mtp3_timer[MTP3_TIMER_T4] > -1) { ss7_schedule_del(link->master, &link->mtp3_timer[MTP3_TIMER_T4]); } if (link->mtp3_timer[MTP3_TIMER_T5] > -1) { ss7_schedule_del(link->master, &link->mtp3_timer[MTP3_TIMER_T5]); } ss7_message(link->master, "Changeback cancelled on link SLC %i PC %i\n", link->slc, link->dpc); mtp3_check(link->adj_sp); } static void mtp3_t1_expired(void *data) { struct mtp2 *link = data; link->mtp3_timer[MTP3_TIMER_T1] = -1; link->changeover = CHANGEOVER_COMPLETED; mtp3_transmit_buffer(link->master, &link->co_buf); ss7_message(link->master, "Changeover completed on link SLC: %i PC: %i\n", link->slc, link->dpc); mtp3_free_co(link); } static void mtp3_timed_changeover(struct mtp2 *link) { if (link->changeover == CHANGEBACK || link->changeover == CHANGEBACK_INITIATED) { mtp3_cancel_changeback(link); } if (link->changeover == NO_CHANGEOVER) { link->changeover = CHANGEOVER_IN_PROGRESS; mtp3_move_buffer(link->master, link, &link->tx_q, &link->co_buf, -1, -1); ss7_message(link->master, "Time controlled changeover initiated on link SLC: %i PC: %i\n", link->slc, link->dpc); link->changeover = CHANGEOVER_IN_PROGRESS; if (link->mtp3_timer[MTP3_TIMER_T1] > -1) { ss7_schedule_del(link->master, &link->mtp3_timer[MTP3_TIMER_T1]); } link->mtp3_timer[MTP3_TIMER_T1] = ss7_schedule_event(link->master, link->master->mtp3_timers[MTP3_TIMER_T1], &mtp3_t1_expired, link); mtp3_free_co(link); } } static void mtp3_changeover(struct mtp2 *link, unsigned char fsn) { struct ss7_msg *tmp = NULL; if (link->changeover == CHANGEBACK || link->changeover == CHANGEBACK_INITIATED) { mtp3_cancel_changeback(link); } if (link->changeover == NO_CHANGEOVER || link->changeover == CHANGEOVER_INITIATED) { mtp3_move_buffer(link->master, link, &link->co_tx_buf, &tmp, -1, fsn); mtp3_move_buffer(link->master, link, &link->co_tx_q, &tmp, -1, -1); mtp3_move_buffer(link->master, link, &link->co_buf, &tmp, -1, -1); mtp3_transmit_buffer(link->master, &tmp); link->changeover = CHANGEOVER_COMPLETED; ss7_message (link->master, "Changeover completed on link SLC: %i PC: %i FSN: %i\n", link->slc, link->dpc, fsn); mtp3_free_co(link); mtp3_check(link->adj_sp); } } static void mtp3_prepare_changeover(struct mtp2 *link) { if (link->changeover == CHANGEBACK || link->changeover == CHANGEBACK_INITIATED) { mtp3_cancel_changeback(link); } if (link->changeover != CHANGEOVER_INITIATED) { link->changeover = CHANGEOVER_INITIATED; link->co_lastfsnacked = link->lastfsnacked; link->co_tx_buf = link->tx_buf; link->tx_buf = NULL; link->co_tx_q = link->tx_q; link->tx_q = NULL; link->retransmit_pos = NULL; } #if 0 ss7_message(link->master, "Prepare changeover co_tx_buf:%i (%i) co_buf:%i (%i) %i\n", link->co_tx_buf, len_buf(link->co_tx_buf), link->co_buf, len_buf(link->co_buf), link->co_tx_q); #endif } static void mtp3_t19_expiry(void * data) { struct adjacent_sp *adj_sp = data; adj_sp->timer_t19 = -1; ss7_debug_msg(adj_sp->master, SS7_DEBUG_MTP3, "MTP3 T19 timer expired PC:%i\n", adj_sp->adjpc); } static void mtp3_t21_expiry(void * data) { struct adjacent_sp *adj_sp = data; adj_sp->timer_t21 = -1; adj_sp->tra |= GOT; ss7_debug_msg(adj_sp->master, SS7_DEBUG_MTP3, "MTP3 T21 timer expired on PC:%i. Started accepting traffic.\n", adj_sp->adjpc); mtp3_check(adj_sp); } static void mtp3_t22_expired(void *data) { struct mtp2 *link = data; struct ss7 *ss7 = link->master; if (link->inhibit & INHIBITED_LOCALLY) { AUTORL(rl, link); net_mng_send(link, NET_MNG_LLT, rl, 0); link->mtp3_timer[MTP3_TIMER_T22] = ss7_schedule_event(ss7, ss7->mtp3_timers[MTP3_TIMER_T22], &mtp3_t22_expired, link); } else { link->mtp3_timer[MTP3_TIMER_T22] = -1; } } static void mtp3_t23_expired(void *data) { struct mtp2 *link = data; struct ss7 *ss7 = link->master; if (link->inhibit & INHIBITED_REMOTELY) { AUTORL(rl, link); net_mng_send(link, NET_MNG_LRT, rl, 0); link->mtp3_timer[MTP3_TIMER_T23] = ss7_schedule_event(ss7, ss7->mtp3_timers[MTP3_TIMER_T23], &mtp3_t23_expired, link); } else { link->mtp3_timer[MTP3_TIMER_T23] = -1; } } static inline unsigned int pc2int(unsigned int switchtype, unsigned char *p) { /* from get_routinglabel() */ if (switchtype == SS7_ANSI) { return p[0] | (p[1] << 8) | (p[2] << 16); } else { return (p[0] | (p[1] << 8)) & 0x3fff; } } static void mtp3_t10_expired(void *data) { struct mtp3_route *route = data; struct adjacent_sp *adj_sp = route->owner; struct ss7 *ss7 = adj_sp->master; struct routing_label rl; rl.dpc = adj_sp->adjpc; rl.opc = ss7->pc; rl.sls = adj_sp->links[0]->net_mng_sls; net_mng_send(adj_sp->links[0], NET_MNG_RST, rl, route->dpc); route->t10 = ss7_schedule_event(ss7, ss7->mtp3_timers[MTP3_TIMER_T10], &mtp3_t10_expired, route); } static void mtp3_forced_reroute(struct adjacent_sp *adj_sp, struct mtp3_route *route) { int i = 0; struct ss7 *ss7 = adj_sp->master; struct mtp2 *link; for (i = 0; i < adj_sp->numlinks; i++) { link = adj_sp->links[i]; mtp3_move_buffer(ss7, link, &link->tx_q, &route->q, route->dpc, -1); mtp3_move_buffer(ss7, link, &link->co_tx_q, &route->q, route->dpc, -1); mtp3_move_buffer(ss7, link, &link->co_buf, &route->q, route->dpc, -1); mtp3_move_buffer(ss7, link, &link->cb_buf, &route->q, route->dpc, -1); mtp3_move_buffer(ss7, link, &link->tx_buf, NULL, route->dpc, -1); mtp3_move_buffer(ss7, link, &link->co_tx_buf, NULL, route->dpc, -1); } if (route->t6 > -1) { ss7_schedule_del(ss7, &route->t6); } if (route->t10 > -1) { ss7_schedule_del(ss7, &route->t10); } if (ss7->mtp3_timers[MTP3_TIMER_T10] > 0) { route->t10 = ss7_schedule_event(ss7, ss7->mtp3_timers[MTP3_TIMER_T10], &mtp3_t10_expired, route); } mtp3_transmit_buffer(ss7, &route->q); } static void mtp3_destroy_route(struct adjacent_sp *adj_sp, struct mtp3_route *route) { struct mtp3_route *prev; if (route == adj_sp->routes) { adj_sp->routes = route->next; } else { prev = adj_sp->routes; while (prev) { if (prev->next == route) { prev->next = route->next; break; } prev = prev->next; } } if (route->t6 > -1) { ss7_schedule_del(adj_sp->master, &route->t6); } if (route->t10 > -1) { ss7_schedule_del(adj_sp->master, &route->t10); } mtp3_move_buffer(adj_sp->master, adj_sp->links[0], &route->q, NULL, -1, -1); free(route); } static void mtp3_t6_expired(void *data) { struct mtp3_route *route = data; struct adjacent_sp *adj_sp = route->owner; route->t6 = -1; mtp3_transmit_buffer(adj_sp->master, &route->q); if (route->state == TFA) { mtp3_destroy_route(adj_sp, route); } } static void mtp3_controlled_reroute(struct adjacent_sp *adj_sp, struct mtp3_route *route) { int i = 0; struct ss7 *ss7 = adj_sp->master; struct mtp2 *link; for (i = 0; i < adj_sp->numlinks; i++) { link = adj_sp->links[i]; mtp3_move_buffer(ss7, link, &link->tx_q, &route->q, route->dpc, -1); mtp3_move_buffer(ss7, link, &link->co_buf, &route->q, route->dpc, -1); mtp3_move_buffer(ss7, link, &link->cb_buf, &route->q, route->dpc, -1); mtp3_move_buffer(ss7, link, &link->co_tx_q, &route->q, route->dpc, -1); } if (route->t6 > -1) { ss7_schedule_del(ss7, &route->t6); } if (route->t10 > -1) { ss7_schedule_del(ss7, &route->t10); } route->t6 = ss7_schedule_event(ss7, ss7->mtp3_timers[MTP3_TIMER_T6], &mtp3_t6_expired, route); } static void mtp3_add_set_route(struct adjacent_sp *adj_sp, unsigned short dpc, int state) { struct mtp3_route *cur = adj_sp->routes; struct mtp3_route *prev = adj_sp->routes; int set = 0; while (cur) { if (cur->dpc == dpc) { set = 1; cur->state = state; break; } prev = cur; cur = cur->next; } if (!set && state == TFA) { return; } if (!set) { cur = calloc(1, sizeof(struct mtp3_route)); if (!cur) { ss7_error(adj_sp->master, "calloc failed!!!\n"); return; } if (prev) { prev->next = cur; } else { adj_sp->routes = cur; } cur->owner = adj_sp; cur->dpc = dpc; cur->state = state; cur->t6 = -1; cur->t10 = -1; cur->next = NULL; } if (state == TFP) { mtp3_forced_reroute(adj_sp, cur); } else if (state == TFA || state == TFR_ACTIVE) { mtp3_controlled_reroute(adj_sp, cur); } } static struct mtp2 * netmng_adjpc_sls_to_mtp2(struct ss7 *ss7, unsigned int adjpc, unsigned int sls) { int i = 0; struct mtp2 *link = NULL; for (i = 0; i < ss7->numlinks; i++) { if (ss7->links[i]->net_mng_sls == sls && ss7->links[i]->dpc == adjpc) { link = ss7->links[i]; } } return link; } static int net_mng_receive(struct ss7 *ss7, struct mtp2 *mtp2, struct routing_label *rl, unsigned char *buf, int len) { unsigned char *headerptr = buf + rl_size(ss7); unsigned char *paramptr = headerptr + 1; struct routing_label rlr; struct mtp2 *winner = netmng_adjpc_sls_to_mtp2(mtp2->master, rl->opc, rl->sls); /* changeover, changeback!!! */ if (!winner && *headerptr != NET_MNG_TRA && *headerptr != NET_MNG_TFA && *headerptr != NET_MNG_TFP && *headerptr != NET_MNG_TFR) { /* Could not find the given slc and the message is not allowed to any slc as per Q.704 13.3.1 */ /* http://lists.digium.com/pipermail/asterisk-ss7/2009-November/003197.html */ return 0; } rlr.sls = rl->sls; rlr.dpc = rl->opc; rlr.opc = rl->dpc; switch (*headerptr) { case NET_MNG_TRA: if (mtp2->adj_sp->timer_t19 == -1 && mtp2->adj_sp->state != MTP3_DOWN) { ss7_message(ss7, "***** MTP3 restart initiated by remote peer on SLC: %i PC: %i\n", mtp2->slc, mtp2->dpc); mtp2->adj_sp->tra = GOT; mtp3_restart(mtp2); } if (mtp2->adj_sp->timer_t19 > -1) { ss7_message(ss7, "Got TRA while T19 has been running on link SLC: %i PC: %i ignoring\n", mtp2->slc, mtp2->dpc); break; } if (ss7->mtp3_timers[MTP3_TIMER_T19] > 0 && mtp2->adj_sp->timer_t19 == -1) { mtp2->adj_sp->timer_t19 = ss7_schedule_event(ss7, ss7->mtp3_timers[MTP3_TIMER_T19], mtp3_t19_expiry, mtp2->adj_sp); ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T19 timer started PC: %i\n", mtp2->adj_sp->adjpc); } if (mtp2->adj_sp->timer_t21 > -1) { ss7_schedule_del(ss7, &mtp2->adj_sp->timer_t21); ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T21 timer stopped PC: %i\n", mtp2->adj_sp->adjpc); } mtp2->adj_sp->tra |= GOT; mtp3_check(mtp2->adj_sp); return 0; case NET_MNG_COO: if (winner->changeover == NO_CHANGEOVER || winner->changeover == CHANGEOVER_INITIATED) { net_mng_send(mtp2, NET_MNG_COA, rlr, (winner->changeover == CHANGEOVER_INITIATED) ? winner->co_lastfsnacked : winner->lastfsnacked); } else { net_mng_send(mtp2, NET_MNG_ECA, rlr, 0); } if (winner->changeover != CHANGEOVER_COMPLETED || winner->changeover != CHANGEOVER_INITIATED) { mtp3_prepare_changeover(winner); mtp3_changeover(winner, *paramptr); } return 0; case NET_MNG_COA: if (!(winner->got_sent_netmsg & (SENT_COO | SENT_ECO))) { ss7_error(ss7, "Got COA on SLC %i ADJPC %i but we haven't sent COO or ECO\n", winner->slc, winner->dpc); return -1; } if (winner->mtp3_timer[MTP3_TIMER_T2] > -1) { ss7_schedule_del(ss7, &winner->mtp3_timer[MTP3_TIMER_T2]); ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T2 timer stopped on link SLC: %i ADJPC: %i\n", winner->slc, winner->dpc); } winner->got_sent_netmsg &= ~(SENT_COO | SENT_ECO); mtp3_changeover(winner, *paramptr); return 0; case NET_MNG_CBD: net_mng_send(mtp2, NET_MNG_CBA, rlr, (unsigned int) *paramptr); mtp3_changeback(winner); return 0; case NET_MNG_CBA: if (!(winner->got_sent_netmsg & SENT_CBD)) { ss7_error(ss7, "Got CBA on SLC %i ADJPC %i but we haven't sent CBD\n", winner->slc, winner->dpc); return -1; } winner->got_sent_netmsg &= ~SENT_CBD; if (winner->mtp3_timer[MTP3_TIMER_T4] > -1) { ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T4 timer stopped on link SLC: %i ADJPC: %i\n", winner->slc, winner->dpc); ss7_schedule_del(ss7, &winner->mtp3_timer[MTP3_TIMER_T4]); } if (winner->mtp3_timer[MTP3_TIMER_T5] > -1) { ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T5 timer stopped on link SLC: %i ADJPC: %i\n", winner->slc, winner->dpc); ss7_schedule_del(ss7, &winner->mtp3_timer[MTP3_TIMER_T5]); } mtp3_changeback(winner); return 0; case NET_MNG_ECO: /* ECO cancel the COO!!! */ if ((winner->got_sent_netmsg & SENT_ECO) && winner->mtp3_timer[MTP3_TIMER_T2] > -1) { ss7_schedule_del(ss7, &winner->mtp3_timer[MTP3_TIMER_T2]); } if (winner->mtp3_timer[MTP3_TIMER_T1] > -1) { ss7_schedule_del(ss7, &winner->mtp3_timer[MTP3_TIMER_T1]); } winner->got_sent_netmsg &= ~(SENT_CBD | SENT_COO); if (winner->got_sent_netmsg & SENT_ECO) { net_mng_send(mtp2, NET_MNG_ECA, rlr, 0); /* If we sent previously ECO we must answer now with ECA!!! */ } else { if (winner->changeover == NO_CHANGEOVER) { net_mng_send(mtp2, NET_MNG_COA, rlr, winner->lastfsnacked); } else { net_mng_send(mtp2, NET_MNG_ECA, rlr, 0); } } mtp3_timed_changeover(winner); return 0; case NET_MNG_ECA: if (winner->mtp3_timer[MTP3_TIMER_T2] > -1) { ss7_schedule_del(ss7, &winner->mtp3_timer[MTP3_TIMER_T2]); ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T2 timer stopped on link SLC: %i ADJPC: %i\n", winner->slc, winner->dpc); } winner->got_sent_netmsg &= ~(SENT_ECO | SENT_COO); mtp3_timed_changeover(winner); return 0; case NET_MNG_LIN: if (available_links(ss7, -1, 0) > 1 || winner->inhibit || !winner->std_test_passed) { net_mng_send(mtp2, NET_MNG_LIA, rlr, 0); winner->inhibit |= INHIBITED_REMOTELY; mtp3_timed_changeover(winner); if (ss7->mtp3_timers[MTP3_TIMER_T23] > 0) { ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T23 timer started on link SLC: %i ADJPC %i\n", winner->slc, winner->dpc); winner->mtp3_timer[MTP3_TIMER_T23] = ss7_schedule_event(ss7, ss7->mtp3_timers[MTP3_TIMER_T23], &mtp3_t23_expired, winner); } } else { ss7_error(ss7, "Link inhibit requested on link SLC: %i ADJPC: %i - denied\n", winner->slc, winner->dpc); net_mng_send(mtp2, NET_MNG_LID, rlr, 0); } return 0; case NET_MNG_LFU: if (!(winner->got_sent_netmsg & SENT_LUN)) { /* dont send LUN again */ net_mng_send(mtp2, NET_MNG_LUN, rlr, 0); } return 0; case NET_MNG_LUN: winner->got_sent_netmsg &= ~SENT_LFU; net_mng_send(mtp2, NET_MNG_LUA, rlr, (unsigned int) *paramptr); winner->inhibit &= ~INHIBITED_REMOTELY; mtp3_changeback(winner); if (winner->mtp3_timer[MTP3_TIMER_T23] > -1) { ss7_schedule_del(ss7, &winner->mtp3_timer[MTP3_TIMER_T23]); ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T23 timer stopped on link SLC: %i ADJPC %i\n", winner->slc, winner->dpc); } if (winner->mtp3_timer[MTP3_TIMER_T13] > -1) { ss7_schedule_del(ss7, &winner->mtp3_timer[MTP3_TIMER_T13]); ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T13 timer stopped on link SLC: %i ADJPC %i\n", winner->slc, winner->dpc); } return 0; case NET_MNG_LIA: if (winner->got_sent_netmsg & SENT_LIN) { mtp3_timed_changeover(winner); winner->got_sent_netmsg &= ~SENT_LIN; winner->inhibit |= INHIBITED_LOCALLY; mtp3_timed_changeover(winner); if (!(mtp2->adj_sp->tra & SENT) && mtp2 == winner) { net_mng_send(mtp2, NET_MNG_TRA, rlr, 0); ss7_check(ss7); } if (ss7->mtp3_timers[MTP3_TIMER_T22] > 0) { ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T22 timer started on link SLC: %i ADJPC %i\n", winner->slc, winner->dpc); winner->mtp3_timer[MTP3_TIMER_T22] = ss7_schedule_event(ss7, ss7->mtp3_timers[MTP3_TIMER_T22], &mtp3_t22_expired, winner); } if (winner->mtp3_timer[MTP3_TIMER_T14] > 0) { ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T14 timer stopped on link SLC: %i ADJPC %i\n", winner->slc, winner->dpc); ss7_schedule_del(ss7, &winner->mtp3_timer[MTP3_TIMER_T14]); } } return 0; case NET_MNG_LUA: if (winner->got_sent_netmsg & SENT_LUN) { winner->got_sent_netmsg &= ~SENT_LUN; winner->inhibit &= ~INHIBITED_LOCALLY; mtp3_changeback(winner); if (winner->mtp3_timer[MTP3_TIMER_T12] > -1) { ss7_schedule_del(ss7, &winner->mtp3_timer[MTP3_TIMER_T12]); ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T12 timer stopped on link SLC: %i ADJPC %i\n", winner->slc, winner->dpc); } if (winner->mtp3_timer[MTP3_TIMER_T22] > -1) { ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T22 timer stopped on link SLC: %i ADJPC %i\n", winner->slc, winner->dpc); ss7_schedule_del(ss7, &winner->mtp3_timer[MTP3_TIMER_T22]); } } return 0; case NET_MNG_LLT: if (!(winner->inhibit & INHIBITED_REMOTELY)) { ss7_message(ss7, "Link SLC: %i ADJPC: %i not inhibited remotely, forced uninhibit\n", winner->slc, winner->dpc); net_mng_send(mtp2, NET_MNG_LFU, rlr, 0); } return 0; case NET_MNG_LRT: if (!(winner->inhibit & INHIBITED_LOCALLY)) { ss7_message(ss7, "Link SLC: %i ADJPC: %i not inhibited locally, uninhibit\n", winner->slc, winner->dpc); net_mng_send(mtp2, NET_MNG_LUN, rlr, 0); } return 0; case NET_MNG_LID: ss7_error(ss7, "Our inhibit request denied on link SLC: %i ADJPC: %i\n", winner->slc, winner->dpc); winner->got_sent_netmsg &= ~SENT_LIN; if (winner->mtp3_timer[MTP3_TIMER_T14] > 0) { ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T14 timer stopped on link SLC: %i ADJPC %i\n", winner->slc, winner->dpc); ss7_schedule_del(ss7, &winner->mtp3_timer[MTP3_TIMER_T14]); } return 0; case NET_MNG_TFP: mtp3_add_set_route(mtp2->adj_sp, pc2int(ss7->switchtype, paramptr), TFP); return 0; case NET_MNG_TFR: return 0; case NET_MNG_TFA: mtp3_add_set_route(mtp2->adj_sp, pc2int(ss7->switchtype, paramptr), TFA); return 0; default: ss7_error(ss7, "Unkonwn NET MNG %u on link SLC: %i from ADJPC: %i\n", *headerptr, winner->slc, winner->dpc); } #if 0 ss7_message(ss7, "NET MNG message type %s received\n", net_mng_message2str(h0, h1)); #endif return 0; } static void mtp3_t2_expired(void * data) { struct mtp2 *link = data; struct ss7_msg *tmp = NULL; link->mtp3_timer[MTP3_TIMER_T2] = -1; link->got_sent_netmsg &= ~(SENT_COO | SENT_ECO); mtp3_move_buffer(link->master, link, &link->co_tx_q, &tmp, -1, -1); mtp3_move_buffer(link->master, link, &link->co_buf, &tmp, -1, -1); mtp3_transmit_buffer(link->master, &tmp); link->changeover = CHANGEOVER_COMPLETED; mtp3_free_co(link); mtp3_check(link->adj_sp); ss7_message(link->master, "MTP3 T2 timer expired on link SLC: %i ADJPC: %i changeover completed\n", link->slc, link->dpc); } static void mtp3_t5_expired(void *data) { struct mtp2 *link = data; struct ss7 *ss7 = link->master; link->mtp3_timer[MTP3_TIMER_T5] = -1; link->got_sent_netmsg &= ~SENT_CBD; ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T5 timer expired on link SLC: %i ADJPC: %i\n", link->slc, link->dpc); mtp3_t3_expired(link); } static void mtp3_t4_expired(void *data) { struct mtp2 *link = data; struct ss7 *ss7 = link->master; ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T4 timer expired on link SLC: %i ADJPC: %i\n", link->slc, link->dpc); AUTORL(rl, link); net_mng_send(link, NET_MNG_CBD, rl, link->cb_seq); link->mtp3_timer[MTP3_TIMER_T4] = -1; if (ss7->mtp3_timers[MTP3_TIMER_T5] > 0) { link->mtp3_timer[MTP3_TIMER_T5] = ss7_schedule_event(link->master, ss7->mtp3_timers[MTP3_TIMER_T5], &mtp3_t5_expired, link); ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T5 timer started on link SLC: %i ADJPC: %i\n", link->slc, link->dpc); } } static void mtp3_t14_expired(void *data) { struct mtp2 *link = data; AUTORL(rl, link); net_mng_send(link, NET_MNG_LIN, rl, 0); } static void mtp3_t14_expired_2nd(void *data) { struct mtp2 *link = data; ss7_error(link->master, "MTP3 T14 timer expired 2nd time on link SLC: %i ADJPC: %i\n", link->slc, link->dpc); link->mtp3_timer[MTP3_TIMER_T14] = -1; link->inhibit &= ~INHIBITED_LOCALLY; link->got_sent_netmsg &= ~SENT_LIN; } static void mtp3_t13_expired(void *data) { struct mtp2 *link = data; AUTORL(rl, link); net_mng_send(link, NET_MNG_LFU, rl, 0); } static void mtp3_t13_expired_2nd(void *data) { struct mtp2 *link = data; ss7_error(link->master, "MTP3 T13 timer expired 2nd time on link SLC: %i ADJPC: %i\n", link->slc, link->dpc); link->mtp3_timer[MTP3_TIMER_T13] = -1; } static void mtp3_t12_expired(void *data) { struct mtp2 *link = data; AUTORL(rl, link); net_mng_send(link, NET_MNG_LUN, rl, 0); } static void mtp3_t12_expired_2nd(void *data) { struct mtp2 *link = data; ss7_error(link->master, "MTP3 T12 timer expired 2nd time on link SLC: %i ADJPC: %i\n", link->slc, link->dpc); link->mtp3_timer[MTP3_TIMER_T12] = -1; link->got_sent_netmsg &= ~SENT_LUN; } int net_mng_send(struct mtp2 *link, unsigned char h0h1, struct routing_label rl, unsigned int param) { struct ss7_msg *m; unsigned char *layer4; struct ss7 *ss7 = link->master; int rllen = 0; int i, res; m = ss7_msg_new(); if (!m) { ss7_error(link->master, "Malloc failed on ss7_msg!. Unable to transmit NET_MNG\n"); return -1; } layer4 = ss7_msg_userpart(m); rl.type = ss7->switchtype; rl.opc = ss7->pc; rllen = set_routinglabel(layer4, &rl); layer4 += rllen; *layer4 = h0h1; layer4++; switch (h0h1) { case NET_MNG_CBD: link->got_sent_netmsg |= SENT_CBD; if (ss7->mtp3_timers[MTP3_TIMER_T4] > 0 && link->mtp3_timer[MTP3_TIMER_T4] == -1) { /* if 0 called from mtp3_t4_expired() */ link->mtp3_timer[MTP3_TIMER_T4] = ss7_schedule_event(ss7, ss7->mtp3_timers[MTP3_TIMER_T4], &mtp3_t4_expired, link); ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T4 timer started on link SLC: %i ADJPC: %i\n", link->slc, link->dpc); } link->cb_seq = (unsigned char) param; /* save the CBD sequence, we may need on retransmit */ /* No break here */ case NET_MNG_CBA: *layer4 = (unsigned char) param; /* CB code */ ss7_msg_userpart_len(m, rllen + 1 + 1); /* rl + CB code */ break; case NET_MNG_COO: link->got_sent_netmsg |= SENT_COO; if (ss7->mtp3_timers[MTP3_TIMER_T2]) { if (link->mtp3_timer[MTP3_TIMER_T2] > 0) { ss7_schedule_del(ss7, &link->mtp3_timer[MTP3_TIMER_T2]); } link->mtp3_timer[MTP3_TIMER_T2] = ss7_schedule_event(ss7, ss7->mtp3_timers[MTP3_TIMER_T2], &mtp3_t2_expired, link); ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T2 timer started on link SLC: %i ADJPC: %i\n", link->slc, link->dpc); } /* No break here */ case NET_MNG_COA: *layer4 = (unsigned char) param; /* FSN of last accepted MSU */ ss7_msg_userpart_len(m, rllen + 1 + 1); /* rl + FSN of last accepted MSU */ break; case NET_MNG_LUN: link->got_sent_netmsg |= SENT_LUN; ss7_msg_userpart_len(m, rllen + 1); /* no more params */ if (ss7->mtp3_timers[MTP3_TIMER_T14] > 0) { ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T12 timer started on link SLC: %i ADJPC: %i\n", link->slc, link->dpc); if (link->mtp3_timer[MTP3_TIMER_T12] == -1) { link->mtp3_timer[MTP3_TIMER_T12] = ss7_schedule_event(ss7, ss7->mtp3_timers[MTP3_TIMER_T12], &mtp3_t12_expired, link); } else { link->mtp3_timer[MTP3_TIMER_T12] = ss7_schedule_event(ss7, ss7->mtp3_timers[MTP3_TIMER_T12], &mtp3_t12_expired_2nd, link); } } break; case NET_MNG_LIN: link->got_sent_netmsg |= SENT_LIN; ss7_msg_userpart_len(m, rllen + 1); /* no more params */ if (ss7->mtp3_timers[MTP3_TIMER_T14] > 0) { ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T14 timer started on link SLC: %i ADJPC: %i\n", link->slc, link->dpc); if (link->mtp3_timer[MTP3_TIMER_T14] == -1) { link->mtp3_timer[MTP3_TIMER_T14] = ss7_schedule_event(ss7, ss7->mtp3_timers[MTP3_TIMER_T14], &mtp3_t14_expired, link); } else { link->mtp3_timer[MTP3_TIMER_T14] = ss7_schedule_event(ss7, ss7->mtp3_timers[MTP3_TIMER_T14], &mtp3_t14_expired_2nd, link); } } break; case NET_MNG_TRA: /* we are not an stp, so we can start the T21 now */ if (ss7->mtp3_timers[MTP3_TIMER_T21] > 0 && link->adj_sp->timer_t21 == -1) { link->adj_sp->timer_t21 = ss7_schedule_event(ss7, ss7->mtp3_timers[MTP3_TIMER_T21], &mtp3_t21_expiry, link->adj_sp); } link->adj_sp->tra |= SENT; ss7_msg_userpart_len(m, rllen + 1); /* no more params */ break; case NET_MNG_ECO: link->got_sent_netmsg |= SENT_ECO; if (ss7->mtp3_timers[MTP3_TIMER_T2]) { if (link->mtp3_timer[MTP3_TIMER_T2] > -1) { ss7_schedule_del(ss7, &link->mtp3_timer[MTP3_TIMER_T2]); } link->mtp3_timer[MTP3_TIMER_T2] = ss7_schedule_event(ss7, ss7->mtp3_timers[MTP3_TIMER_T2], &mtp3_t2_expired, link); ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T2 timer started on link SLC: %i ADJPC: %i\n", link->slc, link->dpc); } ss7_msg_userpart_len(m, rllen + 1); /* no more params */ break; case NET_MNG_ECA: ss7_msg_userpart_len(m, rllen + 1); /* no more params */ break; case NET_MNG_LFU: link->got_sent_netmsg |= SENT_LFU; if (ss7->mtp3_timers[MTP3_TIMER_T13] > 0) { ss7_debug_msg(ss7, SS7_DEBUG_MTP3, "MTP3 T13 timer started on link SLC: %i ADJPC: %i\n", link->slc, link->dpc); if (link->mtp3_timer[MTP3_TIMER_T13] == -1) { link->mtp3_timer[MTP3_TIMER_T13] = ss7_schedule_event(ss7, ss7->mtp3_timers[MTP3_TIMER_T13], &mtp3_t13_expired, link); } else { link->mtp3_timer[MTP3_TIMER_T13] = ss7_schedule_event(ss7, ss7->mtp3_timers[MTP3_TIMER_T13], &mtp3_t13_expired_2nd, link); } } break; case NET_MNG_LIA: case NET_MNG_LUA: case NET_MNG_LID: case NET_MNG_LLT: case NET_MNG_LRT: ss7_msg_userpart_len(m, rllen + 1); /* no more params */ break; case NET_MNG_TFP: case NET_MNG_TFA: case NET_MNG_TFR: case NET_MNG_RST: case NET_MNG_RSR: /* TODO: ANSI!!!! */ layer4[0] = (unsigned char) (param & 0xff); layer4[1] = (unsigned char) ((param >> 8) & 0xff); ss7_msg_userpart_len(m, rllen + 1 + 2); break; default: ss7_error(link->master, "Invalid or unimplemented NET MSG!\n"); free (m); return -1; } if (link->std_test_passed) { return mtp3_transmit(ss7, SIG_NET_MNG, rl, 3, m, link); } else { /* we may use another link to the same adjacent sp */ res = -1; for (i = 0; i < link->adj_sp->numlinks; i++) { if (link->adj_sp->links[i]->std_test_passed) { res = mtp3_transmit(ss7, SIG_NET_MNG, rl, 3, m, link->adj_sp->links[i]); } } if (res != -1) { return res; } else { /* if we couldn't send changeover.... */ if (link->got_sent_netmsg & (SENT_COO | SENT_ECO)) { link->got_sent_netmsg &= ~(SENT_COO | SENT_ECO); if (link->mtp3_timer[MTP3_TIMER_T2] > 0) { ss7_schedule_del(ss7, &link->mtp3_timer[MTP3_TIMER_T2]); } ss7_message(ss7, "No more signalling link to adjacent sp %d, timed changeover initiated\n", link->dpc); mtp3_timed_changeover(link); free (m); return -1; } /* cancel changeback */ if (link->got_sent_netmsg & SENT_CBD) { link->got_sent_netmsg &= ~SENT_CBD; mtp3_cancel_changeback(link); } } } ss7_error(link->master, "No signalling link available for NET MNG: %s !!!\n", net_mng_message2str(h0h1 & 0x0f, h0h1 >> 4)); free (m); return -1; } static void mtp3_link_failed(struct mtp2 *link) { link->std_test_passed = 0; if (link->master->numlinks > 1 && available_links(link->master, -1, 1) && (link->changeover == NO_CHANGEOVER || link->changeover == CHANGEBACK)) { AUTORL(rl, link); mtp3_prepare_changeover(link); net_mng_send(link, NET_MNG_COO, rl, link->co_lastfsnacked); } /* stop sending SLTM */ if (link->mtp3_timer[MTP3_TIMER_Q707_T1] > -1) { ss7_schedule_del(link->master, &link->mtp3_timer[MTP3_TIMER_Q707_T1]); } if (link->mtp3_timer[MTP3_TIMER_Q707_T2] > -1) { ss7_schedule_del(link->master, &link->mtp3_timer[MTP3_TIMER_Q707_T2]); } mtp3_check(link->adj_sp); } static int std_test_receive(struct ss7 *ss7, struct mtp2 *mtp2, struct routing_label rl, unsigned char *buf, int len) { unsigned char *headerptr = buf + rl_size(ss7); unsigned char h1, h0; int testpatsize = 0; struct routing_label drl; /* just reverse the routing label - mtp3_receive() have checked it is correct */ drl.type = rl.type; drl.dpc = rl.opc; drl.opc = rl.dpc; drl.sls = rl.sls; h1 = h0 = *headerptr; h1 = get_h1(headerptr); h0 = get_h0(headerptr); if (h0 != 1) { goto fail; } if (h1 == 1) { struct ss7_msg *m; unsigned char *layer4; int rllen; m = ss7_msg_new(); if (!m) { ss7_error(ss7, "Unable to allocate message buffer!\n"); return -1; } 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); if (ss7->switchtype == SS7_ANSI) { layer4[1] = (testpatsize << 4) | (mtp2->slc & 0xf); } else { 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, drl, 3, m, mtp2); /* Update linkstate */ mtp3_setstate_mtp2link(ss7, mtp2, MTP2_LINKSTATE_UP); return 0; } else if (h1 == 2) { if (mtp2->mtp3_timer[MTP3_TIMER_Q707_T1] > -1) { ss7_schedule_del(ss7, &mtp2->mtp3_timer[MTP3_TIMER_Q707_T1]); } if (!memcmp(&headerptr[2], testmessage, (headerptr[1] >> 4) & 0xf)) { mtp2->q707_t1_failed = 0; if (!mtp2->std_test_passed) { mtp2->std_test_passed = 1; if (!mtp2->inhibit && mtp2->changeover != NO_CHANGEOVER && mtp2->changeover != CHANGEBACK && mtp2->changeover != CHANGEBACK_INITIATED) { net_mng_send(mtp2, NET_MNG_CBD, drl, ss7->cb_seq); ss7->cb_seq++; if (mtp2->changeover == CHANGEOVER_IN_PROGRESS || mtp2->changeover == CHANGEOVER_INITIATED) { mtp3_cancel_changeover(mtp2); } mtp2->changeover = CHANGEBACK_INITIATED; } } if (mtp2->adj_sp->state == MTP3_DOWN) { return mtp3_init(mtp2); } } else { ss7_error(ss7, "Missmatch the SLTA on link SLC: %i ADJPC %i\n", mtp2->slc, mtp2->dpc); mtp2->std_test_passed = 0; mtp2->q707_t1_failed++; mtp3_link_failed(mtp2); if (ss7->mtp3_timers[MTP3_TIMER_Q707_T2] > 0 && mtp2->mtp3_timer[MTP3_TIMER_Q707_T2] == -1) { mtp2->mtp3_timer[MTP3_TIMER_Q707_T2] = ss7_schedule_event(ss7, ss7->mtp3_timers[MTP3_TIMER_Q707_T2], mtp3_timer_q707_t2_expiry, mtp2); } } return 0; } else { ss7_error(ss7, "Unhandled STD_TEST message: h0 = %x h1 = %x", h0, h1); } fail: return -1; } static int mtp3_to_buffer(struct ss7_msg **buf, struct ss7_msg *m) { m->next = NULL; if (!(*buf)) { *buf = m; return 0; } { struct ss7_msg *cur = *buf; for (cur = *buf; cur->next; cur = cur->next); cur->next = m; } return 0; } int mtp3_transmit(struct ss7 *ss7, unsigned char userpart, struct routing_label rl, int priority, struct ss7_msg *m, struct mtp2 *link) { unsigned char *sio; struct mtp2 *winner; struct ss7_msg **buffer = NULL; sio = m->buf + MTP2_SIZE; if (userpart == SIG_ISUP) { winner = rl_to_link(ss7, rl, &buffer); } else { winner = link; } if (ss7->switchtype == SS7_ITU) { (*sio) = (ss7->ni << 6) | userpart; } else { (*sio) = (ss7->ni << 6) | (priority << 4) | userpart; } if (winner) { if (buffer) { return mtp3_to_buffer(buffer, m); } else { return mtp2_msu(winner, m); } } else { ss7_error(ss7, "No siganlling link available sending message!\n"); free(m); return -1; } } 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) { ss7_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) { ss7_error(ss7, "Received message destined for point code 0x%x, but we are 0x%x. Dropping\n", rl.dpc, ss7->pc); return -1; } else if (userpart == SIG_STD_TEST || userpart == SIG_SPEC_TEST || userpart == SIG_NET_MNG) { if (link->dpc != rl.opc) { ss7_error(ss7, "Received message from point code 0x%x but we are connected to DPC 0x%x. Dropping\n", rl.opc, link->dpc); return -1; } if (link->slc != rl.sls) { ss7_error(ss7, "Received message for slc 0x%x, but we are 0x%x. Dropping\n", rl.sls, link->slc); 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, rl, sif, siflen); case SIG_ISUP: /* Skip the routing label */ if (link->adj_sp->state == MTP3_UP) { return isup_receive(ss7, link, &rl, sif + rlsize, siflen - rlsize); } else { ss7_error(ss7, "Got ISUP message on link while MTP3 state is not UP!\n"); return 0; } case SIG_NET_MNG: return net_mng_receive(ss7, link, &rl, sif, siflen); case SIG_SCCP: default: ss7_message(ss7, "Unable to process message destined for userpart %d; dropping message\n", userpart); return 0; } } 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); mtp3_link_failed(link); } static struct mtp2 * slc_to_mtp2(struct ss7 *ss7, unsigned int slc) { int i = 0; for (i = 0; i < ss7->numlinks; i++) { if (ss7->links[i]->slc == slc) { return ss7->links[i]; } } return NULL; } ss7_event * mtp3_process_event(struct ss7 *ss7, ss7_event *e) { /* Check to see if there is no event to process */ if (!e) { return NULL; } switch (e->e) { case MTP2_LINK_UP: mtp3_event_link_up(e->link.link); return e; case MTP2_LINK_DOWN: mtp3_event_link_down(e->link.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) { if (fd > -1) { int winner = ss7_find_link_index(ss7, fd); if (winner > -1) { ss7->mtp2_linkstate[winner] = MTP2_LINKSTATE_INALARM; mtp2_alarm(ss7->links[winner]); mtp3_link_failed(ss7->links[winner]); } } ss7_check(ss7); } void mtp3_noalarm(struct ss7 *ss7, int fd) { int winner = ss7_find_link_index(ss7, fd); if (winner > -1) { ss7->mtp2_linkstate[winner] = MTP2_LINKSTATE_ALIGNING; mtp2_noalarm(ss7->links[winner]); mtp2_start(ss7->links[winner], 1); } } const char * mtp3_net_mng(struct ss7 *ss7, unsigned int slc, const char *cmd, unsigned int param) { struct mtp2 *link; unsigned char h0h1; link = slc_to_mtp2(ss7, slc); if (!link) { return "Invalid slc!\n"; } if (!strcasecmp("coo", cmd)) { h0h1 = NET_MNG_COO; } else if (!strcasecmp("coa", cmd)) { h0h1 = NET_MNG_COA; } else if (!strcasecmp("cbd", cmd)) { h0h1 = NET_MNG_CBD; } else if (!strcasecmp("cba", cmd)) { h0h1 = NET_MNG_CBA; } else if (!strcasecmp("eco", cmd)) { h0h1 = NET_MNG_ECO; } else if (!strcasecmp("eco", cmd)) { h0h1 = NET_MNG_ECA; } else if (!strcasecmp("lin", cmd)) { if (available_links(ss7, -1, 0) > 1 || link->inhibit || !link->std_test_passed) { h0h1 = NET_MNG_LIN; } else { return "Inhibit request discarded, no more available links!\n"; } } else if (!strcasecmp("lun", cmd)) { h0h1 = NET_MNG_LUN; } else if (!strcasecmp("lia", cmd)) { h0h1 = NET_MNG_LIA; } else if (!strcasecmp("lua", cmd)) { h0h1 = NET_MNG_LUA; } else if (!strcasecmp("lfu", cmd)) { h0h1 = NET_MNG_LFU; } else if (!strcasecmp("tfa", cmd)) { h0h1 = NET_MNG_TFA; } else if (!strcasecmp("tfp", cmd)) { h0h1 = NET_MNG_TFP; } else if (!strcasecmp("tfr", cmd)) { h0h1 = NET_MNG_TFR; } else { return "Unknown msg\n"; } AUTORL(rl, link); net_mng_send(link, h0h1, rl, param); return "OK\n"; } int ss7_set_mtp3_timer(struct ss7 *ss7, char *name, int ms) { if (!strcasecmp(name, "t1")) { ss7->mtp3_timers[MTP3_TIMER_T1] = ms; } else if (!strcasecmp(name, "t2")) { ss7->mtp3_timers[MTP3_TIMER_T2] = ms; } else if (!strcasecmp(name, "t3")) { ss7->mtp3_timers[MTP3_TIMER_T3] = ms; } else if (!strcasecmp(name, "t4")) { ss7->mtp3_timers[MTP3_TIMER_T4] = ms; } else if (!strcasecmp(name, "t5")) { ss7->mtp3_timers[MTP3_TIMER_T5] = ms; } else if (!strcasecmp(name, "t6")) { ss7->mtp3_timers[MTP3_TIMER_T6] = ms; } else if (!strcasecmp(name, "t7")) { ss7->mtp3_timers[MTP3_TIMER_T7] = ms; } else if (!strcasecmp(name, "t10")) { ss7->mtp3_timers[MTP3_TIMER_T10] = ms; } else if (!strcasecmp(name, "t12")) { ss7->mtp3_timers[MTP3_TIMER_T12] = ms; } else if (!strcasecmp(name, "t13")) { ss7->mtp3_timers[MTP3_TIMER_T13] = ms; } else if (!strcasecmp(name, "t14")) { ss7->mtp3_timers[MTP3_TIMER_T14] = ms; } else if (!strcasecmp(name, "t19")) { ss7->mtp3_timers[MTP3_TIMER_T19] = ms; } else if (!strcasecmp(name, "t21")) { ss7->mtp3_timers[MTP3_TIMER_T21] = ms; } else if (!strcasecmp(name, "t22")) { ss7->mtp3_timers[MTP3_TIMER_T22] = ms; } else if (!strcasecmp(name, "t23")) { ss7->mtp3_timers[MTP3_TIMER_T23] = ms; } else if (!strcasecmp(name, "q707_t1")) { ss7->mtp3_timers[MTP3_TIMER_Q707_T1] = ms; } else if (!strcasecmp(name, "q707_t2")) { ss7->mtp3_timers[MTP3_TIMER_Q707_T2] = ms; } else { ss7_message(ss7, "Unknown MTP3 timer: %s\n", name); return 0; } ss7_message(ss7, "MTP3 timer %s = %ims\n", name, ms); return 1; } char * mtp3_timer2str(int mtp3_timer) { switch (mtp3_timer) { case MTP3_TIMER_T1: return "T1"; case MTP3_TIMER_T2: return "T2"; case MTP3_TIMER_T3: return "T3"; case MTP3_TIMER_T4: return "T5"; case MTP3_TIMER_T6: return "T6"; case MTP3_TIMER_T7: return "T7"; case MTP3_TIMER_T10: return "T10"; case MTP3_TIMER_T12: return "T12"; case MTP3_TIMER_T13: return "T13"; case MTP3_TIMER_T14: return "T14"; case MTP3_TIMER_T19: return "T19"; case MTP3_TIMER_T21: return "T21"; case MTP3_TIMER_T22: return "T22"; case MTP3_TIMER_T23: return "T23"; case MTP3_TIMER_Q707_T1: return "Q707_T1"; case MTP3_TIMER_Q707_T2: return "Q707_T2"; } return "Unknown"; } static inline void mtp3_add_link_adjsps(struct adjacent_sp *adj_sp, struct mtp2 *link) { int i; link->adj_sp = adj_sp; adj_sp->numlinks++; for (i = 0; i < adj_sp->numlinks; i++) { if (!adj_sp->links[i]) { adj_sp->links[i] = link; adj_sp->links[i]->net_mng_sls = adj_sp->numlinks - 1; break; } } } static inline void mtp3_new_adjsp(struct ss7 *ss7, struct mtp2 *link) { struct adjacent_sp *new; if (ss7->numsps == SS7_MAX_ADJSPS) { ss7_error(ss7, "Couldn't add new adjacent sp, reached the %i limit", SS7_MAX_ADJSPS); return; } new = calloc(1, sizeof(struct adjacent_sp)); if (!new) { ss7_error(ss7, "Couldn't allocate new adjacent SP\n"); return; } ss7->adj_sps[ss7->numsps] = new; new->timer_t19 = -1; new->timer_t21 = -1; new->master = ss7; new->links[0] = link; new->numlinks = 1; new->adjpc = link->dpc; link->adj_sp = new; ss7->numsps++; } void mtp3_add_adj_sp(struct mtp2 *link) { struct ss7 *ss7 = link->master; int i; for (i = 0; i < ss7->numsps; i++) { if (ss7->adj_sps[i] && link->dpc == ss7->adj_sps[i]->adjpc) { mtp3_add_link_adjsps(ss7->adj_sps[i], link); break; } } if (i == ss7->numsps) { mtp3_new_adjsp(ss7, link); } } void mtp3_destroy_all_routes(struct adjacent_sp *adj_sp) { struct mtp3_route *next; while (adj_sp->routes) { next = adj_sp->routes->next; mtp3_destroy_route(adj_sp, adj_sp->routes); adj_sp->routes = next; } } libss7-2.0.0/Makefile0000644000000000000000000001462112030623042013046 0ustar rootroot# # libss7: An implementation of Signaling System 7 (SS7) # # Written by Mark Spencer # # Copyright (C) 2001, Linux Support Services, Inc. # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License 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., 675 Mass Ave, Cambridge, MA 02139, USA. CC=gcc GREP=grep AWK=awk OSARCH=$(shell uname -s) PROC?=$(shell uname -m) # SONAME version; should be changed on every ABI change # please don't change it needlessly; it's perfectly fine to have a SONAME # of 1.0 and a version of 1.4.x SONAME:=2.0 STATIC_LIBRARY=libss7.a DYNAMIC_LIBRARY:=libss7.so.$(SONAME) STATIC_OBJS= \ isup.o \ mtp2.o \ mtp3.o \ ss7.o \ ss7_sched.o \ version.o DYNAMIC_OBJS= \ $(STATIC_OBJS) CFLAGS ?= -g CFLAGS += -Wall -Werror -Wstrict-prototypes -Wmissing-prototypes CFLAGS += -fPIC $(LIBSS7_OPT) $(COVERAGE_CFLAGS) INSTALL_PREFIX=$(DESTDIR) INSTALL_BASE=/usr libdir?=$(INSTALL_BASE)/lib ifneq ($(findstring Darwin,$(OSARCH)),) SOFLAGS=$(LDFLAGS) -dynamic -bundle -Xlinker -macosx_version_min -Xlinker 10.4 -Xlinker -undefined -Xlinker dynamic_lookup -force_flat_namespace ifeq ($(shell /usr/bin/sw_vers -productVersion | cut -c1-4),10.6) SOFLAGS+=/usr/lib/bundle1.o endif LDCONFIG=/usr/bin/true else SOFLAGS=$(LDFLAGS) -shared -Wl,-h$(DYNAMIC_LIBRARY) $(COVERAGE_LDFLAGS) LDCONFIG = /sbin/ldconfig endif ifneq (,$(findstring X$(OSARCH)X, XLinuxX XGNU/kFreeBSDX XGNUX)) LDCONFIG_FLAGS=-n else ifeq (${OSARCH},FreeBSD) LDCONFIG_FLAGS=-m #CFLAGS += -I../zaptel -I../zapata INSTALL_BASE=/usr/local endif endif ifeq (${OSARCH},SunOS) #CFLAGS += -DSOLARIS -I../zaptel-solaris CFLAGS += -DSOLARIS LDCONFIG = LDCONFIG_FLAGS = \# # Trick to comment out the period in the command below #INSTALL_PREFIX = /opt/asterisk # Uncomment out to install in standard Solaris location for 3rd party code endif 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 .) #The problem with sparc is the best stuff is in newer versions of gcc (post 3.0) only. #This works for even old (2.96) versions of gcc and provides a small boost either way. #A ultrasparc cpu is really v9 but the stock debian stable 3.0 gcc doesnt support it. ifeq ($(PROC),sparc64) PROC=ultrasparc LIBSS7_OPT = -mtune=$(PROC) -O3 -pipe -fomit-frame-pointer -mcpu=v8 else ifneq ($(CODE_COVERAGE),) LIBSS7_OPT= COVERAGE_CFLAGS=-ftest-coverage -fprofile-arcs COVERAGE_LDFLAGS=-ftest-coverage -fprofile-arcs else LIBSS7_OPT=-O2 endif endif ifeq ($(CPUARCH),i686) CFLAGS += -m32 SOFLAGS += -m32 endif all: $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY) $(UTILITIES) update: @if [ -d .svn ]; then \ echo "Updating from Subversion..." ; \ fromrev="`svn info | $(AWK) '/Revision: / {print $$2}'`"; \ svn update | tee update.out; \ torev="`svn info | $(AWK) '/Revision: / {print $$2}'`"; \ echo "`date` Updated from revision $${fromrev} to $${torev}." >> update.log; \ rm -f .version; \ if [ `grep -c ^C update.out` -gt 0 ]; then \ echo ; echo "The following files have conflicts:" ; \ grep ^C update.out | cut -b4- ; \ fi ; \ rm -f update.out; \ else \ echo "Not under version control"; \ fi install: $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY) mkdir -p $(INSTALL_PREFIX)$(libdir) mkdir -p $(INSTALL_PREFIX)$(INSTALL_BASE)/include ifneq (${OSARCH},SunOS) install -m 644 libss7.h $(INSTALL_PREFIX)$(INSTALL_BASE)/include install -m 755 $(DYNAMIC_LIBRARY) $(INSTALL_PREFIX)$(libdir) #if [ -x /usr/sbin/sestatus ] && ( /usr/sbin/sestatus | grep "SELinux status:" | grep -q "enabled"); then /sbin/restorecon -v $(INSTALL_PREFIX)$(libdir)/$(DYNAMIC_LIBRARY); fi ( cd $(INSTALL_PREFIX)$(libdir) ; ln -sf $(DYNAMIC_LIBRARY) libss7.so) ifeq ($(SONAME),1.0) # Add this link for historic reasons ( cd $(INSTALL_PREFIX)$(libdir) ; ln -sf $(DYNAMIC_LIBRARY) libss7.so.1) endif install -m 644 $(STATIC_LIBRARY) $(INSTALL_PREFIX)$(libdir) if test $$(id -u) = 0; then $(LDCONFIG) $(LDCONFIG_FLAGS) $(INSTALL_PREFIX)$(libdir); fi else install -f $(INSTALL_PREFIX)$(INSTALL_BASE)/include -m 644 libss7.h install -f $(INSTALL_PREFIX)$(libdir) -m 755 $(DYNAMIC_LIBRARY) ( cd $(INSTALL_PREFIX)$(libdir) ; ln -sf $(DYNAMIC_LIBRARY) libss7.so) ifeq ($(SONAME),1.0) # Add this link for historic reasons ( cd $(INSTALL_PREFIX)$(libdir) ; ln -sf $(DYNAMIC_LIBRARY) libss7.so.1) endif install -f $(INSTALL_PREFIX)$(libdir) -m 644 $(STATIC_LIBRARY) endif uninstall: @echo "Removing Libss7" rm -f $(INSTALL_PREFIX)$(libdir)/$(STATIC_LIBRARY) rm -f $(INSTALL_PREFIX)$(libdir)/libss7.so ifeq ($(SONAME),1.0) rm -f $(INSTALL_PREFIX)$(libdir)/libss7.so.1 endif rm -f $(INSTALL_PREFIX)$(libdir)/$(DYNAMIC_LIBRARY) rm -f $(INSTALL_PREFIX)$(INSTALL_BASE)/include/libss7.h ss7test: ss7test.o $(STATIC_LIBRARY) $(CC) -o $@ $< $(STATIC_LIBRARY) -lpthread $(CFLAGS) ss7linktest: ss7linktest.o $(STATIC_LIBRARY) $(CC) -o $@ $< $(STATIC_LIBRARY) -lpthread $(CFLAGS) parser_debug: parser_debug.o $(STATIC_LIBRARY) $(CC) -o $@ $< $(STATIC_LIBRARY) $(CFLAGS) MAKE_DEPS= -MD -MT $@ -MF .$(subst /,_,$@).d -MP %.o: %.c $(CC) $(CFLAGS) $(MAKE_DEPS) -c -o $@ $< %.lo: %.c $(CC) $(CFLAGS) $(MAKE_DEPS) -c -o $@ $< $(STATIC_LIBRARY): $(STATIC_OBJS) ar rcs $(STATIC_LIBRARY) $(STATIC_OBJS) ranlib $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY): $(DYNAMIC_OBJS) $(CC) $(SOFLAGS) -o $@ $(DYNAMIC_OBJS) $(LDCONFIG) $(LDCONFIG_FLAGS) . ln -sf $(DYNAMIC_LIBRARY) libss7.so ifeq ($(SONAME),1.0) # Add this link for historic reasons ln -sf $(DYNAMIC_LIBRARY) libss7.so.1 endif version.c: FORCE @build_tools/make_version_c > $@.tmp @cmp -s $@.tmp $@ || mv $@.tmp $@ @rm -f $@.tmp clean: rm -f *.o *.so *.lo ifeq ($(SONAME),1.0) rm -f *.so.1 endif rm -f $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY) rm -f parser_debug ss7linktest ss7test rm -f .*.d .PHONY: FORCE: ifneq ($(wildcard .*.d),) include .*.d endif libss7-2.0.0/README0000644000000000000000000001645512010747414012305 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 GNU GPL (General Public License) version 2. For more information, see http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 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 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-2.0.0/isup.c0000644000000000000000000043141212345407637012556 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 "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 struct parm_func { int parm; char *name; FUNC_DUMP(*dump); FUNC_RECV(*receive); FUNC_SEND(*transmit); }; struct isup_timer_param { struct ss7 *ss7; struct isup_call *c; int timer; }; 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, ISUP_PARM_REDIRECTING_NUMBER, ISUP_PARM_REDIRECTION_INFO, ISUP_PARM_REDIRECT_COUNTER, ISUP_PARM_ORIGINAL_CALLED_NUM, ISUP_PARM_OPT_FORWARD_CALL_INDICATOR, ISUP_PARM_CUG_INTERLOCK_CODE, -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, ISUP_PARM_REDIRECTION_INFO, ISUP_PARM_REDIRECTING_NUMBER, ISUP_PARM_REDIRECT_COUNTER, ISUP_PARM_ORIGINAL_CALLED_NUM, ISUP_PARM_OPT_FORWARD_CALL_INDICATOR, ISUP_PARM_CUG_INTERLOCK_CODE, -1}; static int acm_params[] = {ISUP_PARM_BACKWARD_CALL_IND, -1}; static int frj_params[] = {ISUP_PARM_FACILITY_IND, ISUP_PARM_CALL_REF, -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[] = { ISUP_CONNECTED_NUMBER, -1}; static int con_params[] = { ISUP_PARM_BACKWARD_CALL_IND, ISUP_CONNECTED_NUMBER, -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, ISUP_CONNECTED_NUMBER, -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 sus_res_params[] = { ISUP_PARM_SUSPEND_RESUME_IND, ISUP_PARM_CALL_REF, -1}; static int inr_params[] = { ISUP_PARM_INR_IND, -1}; static int inf_params[] = { ISUP_PARM_INF_IND, ISUP_PARM_CALLING_PARTY_NUM, ISUP_PARM_CALLING_PARTY_CAT, -1}; static int sam_params[] = { ISUP_PARM_SUBSEQUENT_NUMBER, -1}; static int empty_params[] = { -1}; static struct message_data { int messagetype; int mand_fixed_params; int mand_var_params; int opt_params; int ansi_priority; int *param_list; } messages[] = { {ISUP_IAM, 4, 1, 1, 0, iam_params}, {ISUP_ACM, 1, 0, 1, 1, acm_params}, {ISUP_ANM, 0, 0, 1, 2, anm_params}, {ISUP_CON, 1, 0, 1, -1, con_params}, {ISUP_REL, 0, 1, 1, 1, rel_params}, {ISUP_RLC, 0, 0, 1, 2, empty_params}, {ISUP_GRS, 0, 1, 0, 0, greset_params}, {ISUP_GRA, 0, 1, 0, 0, greset_params}, {ISUP_CGB, 1, 1, 0, 0, cicgroup_params}, {ISUP_CGU, 1, 1, 0, 0, cicgroup_params}, {ISUP_CGBA, 1, 1, 0, 0, cicgroup_params}, {ISUP_CGUA, 1, 1, 0, 0, cicgroup_params}, {ISUP_COT, 1, 0, 0, 1, cot_params}, {ISUP_CCR, 0, 0, 0, 1, empty_params}, {ISUP_BLO, 0, 0, 0, 0, empty_params}, {ISUP_LPA, 0, 0, 0, 1, empty_params}, {ISUP_UBL, 0, 0, 0, 0, empty_params}, {ISUP_BLA, 0, 0, 0, 0, empty_params}, {ISUP_UBA, 0, 0, 0, 0, empty_params}, {ISUP_RSC, 0, 0, 0, 0, empty_params}, {ISUP_CVR, 0, 0, 0, 0, empty_params}, {ISUP_CVT, 0, 0, 0, 0, empty_params}, {ISUP_CPG, 1, 0, 1, 1, cpg_params}, {ISUP_UCIC, 0, 0, 0, 1, empty_params}, {ISUP_CQM, 0, 1, 0, 0, greset_params}, {ISUP_CQR, 0, 2, 0, 0, cqr_params}, {ISUP_FRJ, 1, 0, 1, -1, frj_params}, {ISUP_FAA, 1, 0, 1, -1, faa_params}, {ISUP_FAR, 1, 0, 1, -1, far_params}, {ISUP_CFN, 0, 1, 1, 0, rel_params}, {ISUP_SUS, 1, 0, 1, 1, sus_res_params}, {ISUP_RES, 1, 0, 1, 1, sus_res_params}, {ISUP_INR, 1, 0, 0, 1, inr_params}, {ISUP_INF, 1, 0, 2, 1, inf_params}, {ISUP_SAM, 0, 1, 1, -1, sam_params} }; static int isup_send_message(struct ss7 *ss7, struct isup_call *c, int messagetype, int parms[]); static int isup_start_timer(struct ss7 *ss7, struct isup_call *c, int timer); static void isup_stop_all_timers(struct ss7 *ss7, struct isup_call *c); static void isup_stop_timer(struct ss7 *ss7, struct isup_call *c, int timer); 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_CON: return "CON"; 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"; case ISUP_SUS: return "SUS"; case ISUP_RES: return "RES"; case ISUP_INR: return "INR"; case ISUP_INF: return "INF"; case ISUP_SAM: return "SAM"; default: return "Unknown"; } } static char * isup_timer2str(int timer) { switch (timer) { case ISUP_TIMER_T1: return "t1"; case ISUP_TIMER_T2: return "t2"; case ISUP_TIMER_T5: return "t5"; case ISUP_TIMER_T6: return "t6"; case ISUP_TIMER_T7: return "t7"; case ISUP_TIMER_T8: return "t8"; case ISUP_TIMER_T10: return "t10"; case ISUP_TIMER_T12: return "t12"; case ISUP_TIMER_T13: return "t13"; case ISUP_TIMER_T14: return "t14"; case ISUP_TIMER_T15: return "t15"; case ISUP_TIMER_T16: return "t16"; case ISUP_TIMER_T17: return "t17"; case ISUP_TIMER_T18: return "t18"; case ISUP_TIMER_T19: return "t19"; case ISUP_TIMER_T20: return "t20"; case ISUP_TIMER_T21: return "t21"; case ISUP_TIMER_T22: return "t22"; case ISUP_TIMER_T23: return "t23"; case ISUP_TIMER_T27: return "t27"; case ISUP_TIMER_T33: return "t33"; case ISUP_TIMER_T35: return "t35"; default: return "unknown"; } } static char char2digit(char localchar) { switch (localchar) { case '0': return 0x0; case '1': return 0x1; case '2': return 0x2; case '3': return 0x3; case '4': return 0x4; case '5': return 0x5; case '6': return 0x6; case '7': return 0x7; case '8': return 0x8; case '9': return 0x9; case 'a': case 'A': return 0xa; case 'b': case 'B': return 0xb; case 'c': case 'C': return 0xc; case 'd': case 'D': return 0xd; case 'e': case 'E': case '*': return 0xe; case 'f': case 'F': case '#': return 0xf; default: return 0x0; } } static char digit2char(unsigned char digit) { switch (digit & 0xf) { case 0x0: return '0'; case 0x1: return '1'; case 0x2: return '2'; case 0x3: return '3'; case 0x4: return '4'; case 0x5: return '5'; case 0x6: return '6'; case 0x7: return '7'; case 0x8: return '8'; case 0x9: return '9'; case 0xa: return 'A'; case 0xb: return 'B'; case 0xc: return 'C'; case 0xd: return 'D'; case 0xe: return '*'; case 0xf: 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; } if (c->cot_performed_on_previous_cic) { parm[0] |= 0x08; } if (c->local_echocontrol_ind) { parm[0] |= 0x10; } 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; } if (cci & 0x2) { c->cot_performed_on_previous_cic = 1; } else { c->cot_performed_on_previous_cic = 0; } if (parm[0] & 0x10) { c->echocontrol_ind = 1; } else { c->echocontrol_ind = 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] = 0x0; if (ss7->flags & SS7_ISDN_ACCESS_INDICATOR) { parm [1] |= 0x01; } if (c->interworking_indicator) { parm[0] |= (1 << 3); } if (c->forward_indicator_pmbits) { parm[1] |= (c->forward_indicator_pmbits & 0xf0); } 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; 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 required 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); ss7_message(ss7, "\t\t\tP-M bits(%d) P: %d O: %d N: %d M: %d\n", (parm[1] & 0xf0), ((parm[1] >> 7) & 0x1), ((parm[1] >> 6) & 0x1), ((parm[1] >> 5) & 0x1), ((parm[1] >> 4) & 0x1)); 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] = c->calling_party_cat; 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; } parm[0] = c->transcap; 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: case 6: type = "Spare"; break; case 2: type = "64 kbit/s unrestricted"; break; case 3: type = "3.1 khz audio"; 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; c->echocontrol_ind = (parm[1] >> 5) & 0x1; return 2; } static FUNC_SEND(backward_call_ind_transmit) { parm[0] = 0x40; parm[1] = 0x04; if (c->local_echocontrol_ind) { parm[1] |= 0x20; } if (ss7->flags | SS7_ISDN_ACCESS_INDICATOR) { parm[1] |= 0x10; } 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_DUMP(opt_forward_call_ind_dump) { char *desc; switch (parm[0] & 0x03) { case ISUP_CUG_NON: desc = "non-CUG call"; break; case ISUP_CUG_OUTGOING_ALLOWED: desc = "closed user group call, outgoing access allowed"; break; case ISUP_CUG_OUTGOING_NOT_ALLOWED: desc = "closed user group call, outgoing access not allowed"; break; default: desc = "spare"; } ss7_message(ss7, "\t\t\tClosed user group call indicator: %s\n", desc); ss7_message(ss7, "\t\t\tSimple segmentation indicator: %s\n", (parm[0] & (1 << 2)) ? "additional information will be sent in segmentation message" : "no additional message will be sent"); ss7_message(ss7, "\t\t\tConnected line identify request indicator %s\n", (parm[0] & (1 << 7)) ? "requested": "not requested"); return 1; } static FUNC_SEND(opt_forward_call_ind_transmit) { if (c->col_req || c->cug_indicator) { parm[0] = (c->cug_indicator & 0x03) | (c->col_req << 7); return 1; } else { return 0; } } static FUNC_RECV(opt_forward_call_ind_receive) { c->cug_indicator = parm[0] & 0x03; c->col_req = parm[0] >> 7; 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) /* ITU-T Q.850 */ { 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; case 43: cause = "Access information discarded"; break; case 44: cause = "Requested circuit/channel not available"; break; case 46: cause = "Precedence call blocked"; break; case 47: cause = "Resource unavailable, unspecified"; break; case 49: cause = "Quality of service not available"; break; case 50: cause = "Requested facility not subscribed"; break; case 53: cause = "Outgoing calls barred within CUG"; break; case 55: cause = "Incoming calls barred within CUG"; break; case 57: cause = "Bearer capability not authorized"; break; case 58: cause = "Bearer capability not presently available"; break; case 62: cause = "Inconsistency in designated outgoing access information and subscriber class"; break; case 63: cause = "Service or option not available, unspecified"; break; case 65: cause = "Bearer capability not implemented"; break; case 66: cause = "Channel type not implemented"; break; case 69: cause = "Requested facility not implemented"; break; case 70: cause = "Only restricted digital information bearer capability is available"; break; case 79: cause = "Service or option not implemented, unspecified"; break; case 81: cause = "Invalid call reference value"; break; case 82: cause = "Identified channel does not exist"; break; case 83: cause = "A suspended call exists, but this call identity does not"; break; case 84: cause = "Call identity in use"; break; case 85: cause = "No call suspended"; break; case 86: cause = "Call having the requested call identity has been cleared"; break; case 87: cause = "User not member of CUG"; break; case 88: cause = "Incompatible destination"; break; case 90: cause = "Non-existent CUG"; break; case 91: cause = "Invalid transit network selection"; break; case 95: cause = "Invalid message, unspecified"; break; case 96: cause = "Mandatory information element is missing"; break; case 97: cause = "Message type non-existent or not implemented"; break; case 98: cause = "Message not compatible with call state or message type non-existent or not implemented"; break; case 99: cause = "Information element /parameter non-existent or not implemented"; break; case 100: cause = "Invalid information element contents"; break; case 101: cause = "Message not compatible with call state"; break; case 102: cause = "Recovery on timer expiry"; break; case 103: cause = "Parameter non-existent or not implemented, passed on"; break; case 110: cause = "Message with unrecognized parameter, discarded"; break; case 111: cause = "Protocol error, unspecified"; break; case 127: cause = "Interworking, unspecified"; break; 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); for (i = 0; i < numcics; i++) { if (!(i % 8)) { parm[1 + (i/8)] = '\0'; } 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] && c->presentation_ind != SS7_PRESENTATION_ADDR_NOT_AVAILABLE) { return 0; } if (c->calling_party_num[0] && c->presentation_ind != SS7_PRESENTATION_ADDR_NOT_AVAILABLE) { isup_put_number(&parm[2], c->calling_party_num, &datalen, &oddeven); } else { datalen = 0; oddeven = 0; c->calling_nai = 0; } parm[0] = (oddeven << 7) | c->calling_nai; /* Nature of Address Indicator */ /* Assume E.164 ISDN numbering plan, calling number complete */ parm[1] = ((c->presentation_ind == SS7_PRESENTATION_ADDR_NOT_AVAILABLE) ? 0 : (1 << 4)) | ((c->presentation_ind & 0x3) << 2) | (c->screening_ind & 0x3); return datalen + 2; } static FUNC_DUMP(connected_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); 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(connected_num_receive) { int oddeven = (parm[0] >> 7) & 0x1; isup_get_number(c->connected_num, &parm[2], len - 2, oddeven); c->connected_nai = parm[0] & 0x7f; /* Nature of Address Indicator */ c->connected_presentation_ind = (parm[1] >> 2) & 0x3; c->connected_screening_ind = parm[1] & 0x3; return len; } static FUNC_SEND(connected_num_transmit) { int oddeven = 0, datalen = 0; if (!c->col_req) { return 0; /* if they don't ask we won't tell */ } if (!c->connected_num[0]) { c->connected_presentation_ind = SS7_PRESENTATION_ADDR_NOT_AVAILABLE; } else { isup_put_number(&parm[2], c->connected_num, &datalen, &oddeven); } parm[0] = (oddeven << 7) | c->connected_nai; /* Nature of Address Indicator */ /* Assume E.164 ISDN numbering plan, calling number complete */ parm[1] = ((c->connected_presentation_ind & 0x3) << 2) | (c->connected_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: 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) { c->redirect_info = 1; c->redirect_info_ind = parm[0] & 0x7; c->redirect_info_orig_reas = (parm[0] >> 4) & 0xf; c->redirect_info_counter = parm[1] & 0x7; c->redirect_info_reas = (parm[1] >> 4) & 0xf; return 2; } static FUNC_SEND(redirection_info_transmit) { if (!c->redirect_info) { return 0; } parm[0] = (c->redirect_info_ind & 0x7) | ((c->redirect_info_orig_reas << 4) & 0xf0); parm[1] = (c->redirect_info_counter & 0x7) | ((c->redirect_info_reas << 4) & 0xf0); 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); 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(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) { int oddeven, datalen; if (!c->orig_called_num[0]) { return 0; } isup_put_number(&parm[2], c->orig_called_num, &datalen, &oddeven); parm[0] = (oddeven << 7) | c->orig_called_nai; /* Nature of Address Indicator */ parm[1] = (1 << 4) | /* Assume E.164 ISDN numbering plan, calling number complete */ ((c->orig_called_pres_ind & 0x3) << 2) | (c->orig_called_screening_ind & 0x3); return datalen + 2; } 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; ba_str = dc_str = fe_str = ""; 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_DUMP(generic_notification_ind_dump) { int pos = 0; ss7_message(ss7, "\t\t\tNotification indicator: "); while (pos < len && (pos || !(parm[pos - 1] & 0x80))) { switch (parm[pos] & 0x7f) { case 0x00: ss7_message(ss7, "user suspended; "); break; case 0x01: ss7_message(ss7, "user resumed; "); break; case 0x02: ss7_message(ss7, "bearer service change; "); break; case 0x03: ss7_message(ss7, "discriminator for extension to ASN.1; "); break; case 0x04: ss7_message(ss7, "call completion delay; "); break; case 0x42: ss7_message(ss7, "conference established; "); break; case 0x43: ss7_message(ss7, "conference disconnected; "); break; case 0x44: ss7_message(ss7, "other party added; "); break; case 0x45: ss7_message(ss7, "isolated; "); break; case 0x46: ss7_message(ss7, "reattached; "); break; case 0x47: ss7_message(ss7, "other party isolated; "); break; case 0x48: ss7_message(ss7, "other party reattached; "); break; case 0x49: ss7_message(ss7, "other party split; "); break; case 0x4a: ss7_message(ss7, "other party disconnected; "); break; case 0x4b: ss7_message(ss7, "other party floating; "); break; case 0x60: ss7_message(ss7, "call is a waiting call; "); break; case 0x68: ss7_message(ss7, "diversion activated; "); break; case 0x69: ss7_message(ss7, "call transfer, alerting; "); break; case 0x6a: ss7_message(ss7, "call transfer, active; "); break; case 0x79: ss7_message(ss7, "remote hold; "); break; case 0x7a: ss7_message(ss7, "remote retrieval; "); break; case 0x7b: ss7_message(ss7, "remote is diverting; "); break; default: ss7_message(ss7, "reserved; "); } pos++; } ss7_message(ss7, "\n"); return len; } static FUNC_SEND(generic_notification_ind_transmit) { return 0; } static FUNC_RECV(generic_notification_ind_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) { int oddeven, datalen; if (!c->redirecting_num[0]) { return 0; } isup_put_number(&parm[2], c->redirecting_num, &datalen, &oddeven); parm[0] = (oddeven << 7) | c->redirecting_num_nai; /* Nature of Address Indicator */ parm[1] = (1 << 4) | /* Assume E.164 ISDN numbering plan, calling number complete */ ((c->redirecting_num_presentation_ind & 0x3) << 2) | (c->redirecting_num_screening_ind & 0x3); return datalen + 2; } static FUNC_DUMP(redirect_counter_dump) { ss7_message(ss7, "\t\t\tRedirect count: %i\n", parm[0] & 0x1f); return 1; } static FUNC_RECV(redirect_counter_receive) { c->redirect_counter = parm[0] & 0x1f; return 1; } static FUNC_SEND(redirect_counter_transmit) { if (!c->redirect_counter) { return 0; } parm[0] = c->redirect_counter & 0x1f; return 1; } static FUNC_DUMP(inr_ind_dump) { ss7_message(ss7, "\t\t\tCalling party address %srequested\n", (parm[0] & 0x1) ? "" : "not "); ss7_message(ss7, "\t\t\tHolding %srequested\n", (parm[0] & 0x2) ? "" : "not "); ss7_message(ss7, "\t\t\tCalling party category %srequested\n", (parm[0] & 0x8) ? "" : "not "); ss7_message(ss7, "\t\t\tCharge information %srequested\n", (parm[0] & 0x10) ? "" : "not "); ss7_message(ss7, "\t\t\tMalicous call identification %srequested\n", (parm[0] & 0x80) ? "" : "not "); return 2; } static FUNC_RECV(inr_ind_receive) { c->inr_ind[0] = parm[0]; c->inr_ind[1] = parm[1]; return 2; } static FUNC_SEND(inr_ind_transmit) { parm[0] = c->inr_ind[0]; parm[1] = c->inr_ind[1]; return 2; } static FUNC_DUMP(inf_ind_dump) { ss7_message(ss7, "\t\t\tCalling party address: %s\n", (parm[0] & 0x2) ? ((parm[0] & 0x1) ? "included" : "spare" ) : ((parm[0] & 0x1) ? "not available" : "not included") ); ss7_message(ss7, "\t\t\tHold: %sprovided\n", (parm[0] & 0x4) ? "" : "not "); ss7_message(ss7, "\t\t\tCalling party's category %sincluded\n", (parm[0] & 0x20) ? "" : "not "); ss7_message(ss7, "\t\t\tCharge information %sincluded\n", (parm[0] & 0x40) ? "" : "not "); ss7_message(ss7, "\t\t\t%s\n", (parm[0] & 0x80) ? "Unsolicated" : "Solicated"); return 2; } static FUNC_RECV(inf_ind_receive) { c->inf_ind[0] = parm[0]; c->inf_ind[1] = parm[1]; if ((parm[0] & 0x3) == 0x1) { c->presentation_ind = SS7_PRESENTATION_ADDR_NOT_AVAILABLE; } return 2; } static FUNC_SEND(inf_ind_transmit) { parm[0] = c->inf_ind[0]; parm[1] = c->inf_ind[1]; return 2; } 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 FUNC_DUMP(suspend_resume_ind_dump) { int indicator = parm[0] & 1; ss7_message(ss7, "\t\t\tSUS/RES indicator: %s (%d)", indicator ? "Network initiated" : "ISDN Subscriber initiated", indicator); return 1; } static FUNC_RECV(suspend_resume_ind_receive) { c->network_isdn_indicator = parm[0] & 1; return 1; } static FUNC_SEND(suspend_resume_ind_transmit) { parm[0] = c->network_isdn_indicator & 1; return 1; } static FUNC_DUMP(subs_num_dump) { int oddeven = (parm[0] >> 7) & 0x1; char numbuf[64]; isup_get_number(numbuf, &parm[1], len - 1, oddeven); ss7_message(ss7, "\t\t\tSubsequent signals: %s\n", numbuf); return len; } static FUNC_RECV(subs_num_receive) { int oddeven = (parm[0] >> 7) & 0x1; isup_get_number(c->called_party_num, &parm[1], len - 1, oddeven); return len; } static FUNC_SEND(subs_num_transmit) { int oddeven, datalen; isup_put_number(&parm[1], c->called_party_num, &datalen, &oddeven); parm[0] = (oddeven << 7); return datalen + 1; } static FUNC_DUMP(cug_interlock_code_dump) { char ni[5]; unsigned short code; ni[0] = digit2char(parm[0] >> 4); ni[1] = digit2char(parm[0] & 0x0f); ni[2] = digit2char(parm[1] >> 4); ni[3] = digit2char(parm[1] & 0x0f); ni[4] = '\0'; code = (parm[2] << 8) | parm [3]; ss7_message(ss7, "\t\t\tNetwork Identify: %s\n", ni); ss7_message(ss7, "\t\t\tBinary Code: %d\n", code); return 4; } static FUNC_RECV(cug_interlock_code_receive) { c->cug_interlock_ni[0] = digit2char(parm[0] >> 4); c->cug_interlock_ni[1] = digit2char(parm[0] & 0x0f); c->cug_interlock_ni[2] = digit2char(parm[1] >> 4); c->cug_interlock_ni[3] = digit2char(parm[1] & 0x0f); c->cug_interlock_ni[4] = '\0'; c->cug_interlock_code = (parm[2] << 8) | parm [3]; return 4; } static FUNC_SEND(cug_interlock_code_transmit) { if (!(c->cug_indicator == ISUP_CUG_OUTGOING_ALLOWED || c->cug_indicator == ISUP_CUG_OUTGOING_NOT_ALLOWED)) { return 0; } parm[0] = (char2digit(c->cug_interlock_ni[0]) << 4) | char2digit(c->cug_interlock_ni[1]); parm[1] = (char2digit(c->cug_interlock_ni[2]) << 4) | char2digit(c->cug_interlock_ni[3]); parm[2] = c->cug_interlock_code >> 8; parm[3] = c->cug_interlock_code & 0xff; return 4; } static struct parm_func parms[] = { {ISUP_PARM_CALL_REF, "Call Reference", call_ref_dump, call_ref_receive, call_ref_transmit}, {ISUP_PARM_TRANSMISSION_MEDIUM_REQS, "Transmission Medium Requirements", transmission_medium_reqs_dump, transmission_medium_reqs_receive, transmission_medium_reqs_transmit}, {ISUP_PARM_ACCESS_TRANS, "Access Transport", access_transport_dump, access_transport_receive, access_transport_transmit}, {ISUP_PARM_CALLED_PARTY_NUM, "Called Party Number", called_party_num_dump, called_party_num_receive, called_party_num_transmit}, {ISUP_PARM_SUBSEQUENT_NUMBER, "Subsequent Number", subs_num_dump, subs_num_receive, subs_num_transmit}, {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_OPT_FORWARD_CALL_INDICATOR, "Optional forward call indicator", opt_forward_call_ind_dump, opt_forward_call_ind_receive, opt_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_CALLING_PARTY_NUM, "Calling Party Number", calling_party_num_dump, calling_party_num_receive, calling_party_num_transmit}, {ISUP_PARM_REDIRECTING_NUMBER, "Redirecting Number", redirecting_number_dump, redirecting_number_receive, redirecting_number_transmit}, {ISUP_PARM_REDIRECTION_NUMBER, "Redirection Number"}, {ISUP_PARM_CONNECTION_REQ, "Connection Request"}, {ISUP_PARM_INR_IND, "Information Request Indicators", inr_ind_dump, inr_ind_receive, inr_ind_transmit}, {ISUP_PARM_INF_IND, "Information Indicators", inf_ind_dump, inf_ind_receive, inf_ind_transmit}, {ISUP_PARM_CONTINUITY_IND, "Continuity Indicator", continuity_ind_dump, continuity_ind_receive, continuity_ind_transmit}, {ISUP_PARM_BACKWARD_CALL_IND, "Backward Call Indicator", backward_call_ind_dump, backward_call_ind_receive, backward_call_ind_transmit}, {ISUP_PARM_CAUSE, "Cause Indicator", cause_dump, cause_receive, cause_transmit}, {ISUP_PARM_REDIRECTION_INFO, "Redirection Information", redirection_info_dump, redirection_info_receive, redirection_info_transmit}, {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_CALL_MODIFICATION_IND, "Call modification indicators"}, {ISUP_PARM_FACILITY_IND, "Facility Indicator", facility_ind_dump, facility_ind_receive, facility_ind_transmit}, {ISUP_PARM_CUG_INTERLOCK_CODE, "CUG Interlock Code", cug_interlock_code_dump, cug_interlock_code_receive, cug_interlock_code_transmit}, {ISUP_PARM_USER_SERVICE_INFO, "User Service Information", NULL, user_service_info_receive, user_service_info_transmit}, {ISUP_PARM_SIGNALLING_PC, "Signalling point code"}, {ISUP_PARM_USER_TO_USER_INFO, "User to user information"}, {ISUP_CONNECTED_NUMBER, "Connected Number", connected_num_dump, connected_num_receive, connected_num_transmit}, {ISUP_PARM_SUSPEND_RESUME_IND, "Suspend/Resume Indicators", suspend_resume_ind_dump, suspend_resume_ind_receive, suspend_resume_ind_transmit}, {ISUP_PARM_TRANSIT_NETWORK_SELECTION, "Transit Network Selection", tns_dump, tns_receive, tns_transmit}, {ISUP_PARM_EVENT_INFO, "Event Information", event_info_dump, event_info_receive, event_info_transmit}, {ISUP_PARM_CIRCUIT_ASSIGNMENT_MAP, "Circuit Assignment Map"}, {ISUP_PARM_CIRCUIT_STATE_IND, "Circuit State Indicator", circuit_state_ind_dump, NULL, circuit_state_ind_transmit}, {ISUP_PARAM_AUTOMATIC_CONGESTION_LEVEL, "Automatic congestion level"}, {ISUP_PARM_ORIGINAL_CALLED_NUM, "Original called number", original_called_num_dump, original_called_num_receive, original_called_num_transmit}, {ISUP_PARM_OPT_BACKWARD_CALL_IND, "Optional Backward Call Indicator", opt_backward_call_ind_dump, opt_backward_call_ind_receive, NULL}, {ISUP_PARM_USER_TO_USER_IND, "User to user indicators"}, {ISUP_PARM_ORIGINATION_ISC_PC, "Origination ISC point code"}, {ISUP_PARM_GENERIC_NOTIFICATION_IND, "Generic Notification Indication", generic_notification_ind_dump, generic_notification_ind_receive, generic_notification_ind_transmit}, {ISUP_PARM_CALL_HISTORY_INFO, "Call history information"}, {ISUP_PARM_ACCESS_DELIVERY_INFO, "Access Delivery Information", }, {ISUP_PARM_NETWORK_SPECIFIC_FACILITY, "Network specific facility"}, {ISUP_PARM_USER_SERVICE_INFO_PRIME, "User service information prime"}, {ISUP_PARM_PROPAGATION_DELAY, "Propagation Delay Counter", propagation_delay_cntr_dump}, {ISUP_PARM_REMOTE_OPERATIONS, "Remote operations"}, {ISUP_PARM_SERVICE_ACTIVATION, "Service activation"}, {ISUP_PARM_USER_TELESERVICE_INFO, "User teleservice information"}, {ISUP_PARM_TRANSMISSION_MEDIUM_USED, "Transmission medium used"}, {ISUP_PARM_CALL_DIVERSION_INFO, "Call diversion information"}, {ISUP_PARM_ECHO_CONTROL_INFO, "Echo Control Information", echo_control_info_dump, NULL, NULL}, {ISUP_PARM_MESSAGE_COMPAT_INFO, "Message compatibility information"}, {ISUP_PARM_PARAMETER_COMPAT_INFO, "Parameter Compatibility Information", parameter_compat_info_dump, NULL, NULL}, {ISUP_PARM_MLPP_PRECEDENCE, "MLPP precedence"}, {ISUP_PARM_MCID_REQUEST_IND, "MCID request indicators"}, {ISUP_PARM_MCID_RESPONSE_IND, "MCID response indicators"}, {ISUP_PARM_HOP_COUNTER, "Hop Counter", hop_counter_dump, hop_counter_receive, hop_counter_transmit}, {ISUP_PARM_TRANSMISSION_MEDIUM_REQ_PRIME, "Transmission medium requirement prime"}, {ISUP_PARM_LOCATION_NUMBER, "Location Number"}, {ISUP_PARM_REDIRECTION_NUM_RESTRICTION, "Redirection number restriction"}, {ISUP_PARM_CALL_TRANSFER_REFERENCE, "Call transfer reference"}, {ISUP_PARM_LOOP_PREVENTION_IND, "Loop prevention indicators"}, {ISUP_PARM_CALL_TRANSFER_NUMBER, "Call transfer number"}, {ISUP_PARM_CCSS, "CCSS"}, {ISUP_PARM_FORWARD_GVNS, "Forward GVNS"}, {ISUP_PARM_BACKWARD_GVNS, "Backward GVNS"}, {ISUP_PARM_REDIRECT_CAPABILITY, "Redirect capability"}, {ISUP_PARM_NETWORK_MANAGEMENT_CONTROL, "Network management controls"}, {ISUP_PARM_CORRELATION_ID, "Correlation id"}, {ISUP_PARM_SCF_ID, "SCF id"}, {ISUP_PARM_CALL_DIVERSION_TREATMENT_IND, "Call diversion treatment indicators"}, {ISUP_PARM_CALLED_IN_NUMBER, "Called IN number"}, {ISUP_PARM_CALL_OFFERING_TREATMENT_IND, "Call offering treatment indicators"}, {ISUP_PARM_CHARGED_PARTY_IDENT, "Charged party identification"}, {ISUP_PARM_CONFERENCE_TREATMENT_IND, "Conference treatment indicators"}, {ISUP_PARM_DISPLAY_INFO, "Display information"}, {ISUP_PARM_UID_ACTION_IND, "UID action indicators"}, {ISUP_PARM_UID_CAPABILITY_IND, "UID capability indicators"}, {ISUP_PARM_REDIRECT_COUNTER, "Redirect Counter", redirect_counter_dump, redirect_counter_receive, redirect_counter_transmit}, {ISUP_PARM_APPLICATION_TRANSPORT, "Application transport"}, {ISUP_PARM_COLLECT_CALL_REQUEST, "Collect call request"}, {ISUP_PARM_CCNR_POSSIBLE_IND, "CCNR possible indicator"}, {ISUP_PARM_PIVOT_CAPABILITY, "Pivot capability"}, {ISUP_PARM_PIVOT_ROUTING_IND, "Pivot routing indicators"}, {ISUP_PARM_CALLED_DIRECTORY_NUMBER, "Called directory number"}, {ISUP_PARM_ORIGINAL_CALLED_IN_NUM, "Original called IN number"}, {ISUP_PARM_CALLING_GEODETIC_LOCATION, "Calling geodetic location"}, {ISUP_PARM_HTR_INFO, "HTR information"}, {ISUP_PARM_NETWORK_ROUTING_NUMBER, "Network routing number"}, {ISUP_PARM_QUERY_ON_RELEASE_CAPABILITY, "Query on release capability"}, {ISUP_PARM_PIVOT_STATUS, "Pivot status"}, {ISUP_PARM_PIVOT_COUNTER, "Pivot counter"}, {ISUP_PARM_PIVOT_ROUTING_FORWARD_IND, "Pivot routing forward information"}, {ISUP_PARM_PIVOT_ROUTING_BACKWARD_IND, "Pivot routing backward information"}, {ISUP_PARM_REDIRECT_STATUS, "Redirect status"}, {ISUP_PARM_REDIRECT_FORWARD_INFO, "Redirect forward information"}, {ISUP_PARM_REDIRECT_BACKWARD_INFO, "Redirect backward information"}, {ISUP_PARM_NUM_PORTABILITY_FORWARD_INFO, "Number portability forward information"}, {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_EGRESS_SERV, "Egress Service"}, {ISUP_PARM_JIP, "Jurisdiction Information Parameter", jip_dump, jip_receive, jip_transmit}, {ISUP_PARM_CARRIER_ID, "Carrier Identification", carrier_identification_dump, carrier_identification_receive, carrier_identification_transmit}, {ISUP_PARM_BUSINESS_GRP, "Business Group"}, {ISUP_PARM_GENERIC_NAME, "Generic Name", generic_name_dump, generic_name_receive, generic_name_transmit}, {ISUP_PARM_LOCAL_SERVICE_PROVIDER_IDENTIFICATION, "Local Service Provider ID", lspi_dump, lspi_receive, lspi_transmit}, {ISUP_PARM_ORIG_LINE_INFO, "Originating line information", originating_line_information_dump, originating_line_information_receive, originating_line_information_transmit}, {ISUP_PARM_CHARGE_NUMBER, "Charge Number", charge_number_dump, charge_number_receive, charge_number_transmit}, {ISUP_PARM_SELECTION_INFO, "Selection 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) { int x; for (x = 0; x < ISUP_MAX_TIMERS; x++) { c->timer[x] = -1; } c->oli_ani2 = -1; c->range = 0; c->got_sent_msg = 0; c->calling_party_cat = 0x0a; /* Default to Ordinary calling subscriber */ } static 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_new_call(struct ss7 *ss7, int nolink) { struct isup_call *c, *cur; c = calloc(1, sizeof(*c)); if (!c) { return NULL; } init_isup_call(c); if (nolink) { return c; } 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, int cic, unsigned int dpc, int outgoing) { struct isup_call *c = __isup_new_call(ss7, 0); if (c) { isup_init_call(ss7, c, cic, dpc); if (outgoing) { c->got_sent_msg |= ISUP_PENDING_IAM; } } return c; } 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_tmr(struct isup_call *c, int tmr) { c->transcap = tmr; } 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]) || presentation_ind == SS7_PRESENTATION_ADDR_NOT_AVAILABLE) { if (calling) { strncpy(c->calling_party_num, calling, sizeof(c->calling_party_num)); } else { c->calling_party_num[0] = '\0'; } c->calling_nai = calling_nai; c->presentation_ind = presentation_ind; c->screening_ind = screening_ind; } } void isup_set_connected(struct isup_call *c, const char *connected, unsigned char connected_nai, unsigned char connected_presentation_ind, unsigned char connected_screening_ind) { if ((connected && connected[0]) || connected_presentation_ind == SS7_PRESENTATION_ADDR_NOT_AVAILABLE) { if (connected) { strncpy(c->connected_num, connected, sizeof(c->connected_num)); } else { c->connected_num[0] = '\0'; } c->connected_nai = connected_nai; c->connected_presentation_ind = connected_presentation_ind; c->connected_screening_ind = connected_screening_ind; } } void isup_set_redirecting_number(struct isup_call *c, const char *redirecting_number, unsigned char redirecting_num_nai, unsigned char redirecting_num_presentation_ind, unsigned char redirecting_num_screening_ind) { if (redirecting_number && redirecting_number[0]) { strncpy(c->redirecting_num, redirecting_number, sizeof(c->redirecting_num)); c->redirecting_num_nai = redirecting_num_nai; c->redirecting_num_presentation_ind = redirecting_num_presentation_ind; c->redirecting_num_screening_ind = redirecting_num_screening_ind; } } void isup_set_redirection_info(struct isup_call *c, unsigned char redirect_info_ind, unsigned char redirect_info_orig_reas, unsigned char redirect_info_counter, unsigned char redirect_info_reas) { c->redirect_info = 1; c->redirect_info_ind = redirect_info_ind; c->redirect_info_orig_reas = redirect_info_orig_reas; c->redirect_info_counter = redirect_info_counter; c->redirect_info_reas = redirect_info_reas; } void isup_set_redirect_counter(struct isup_call *c, unsigned char redirect_counter) { c->redirect_counter = redirect_counter; } void isup_set_orig_called_num(struct isup_call *c, const char *orig_called_num, unsigned char orig_called_nai, unsigned char orig_called_pres_ind, unsigned char orig_called_screening_ind) { if (orig_called_num && orig_called_num[0]) { strncpy(c->orig_called_num, orig_called_num, sizeof(c->orig_called_num)); c->orig_called_nai = orig_called_nai; c->orig_called_pres_ind = orig_called_pres_ind; c->orig_called_screening_ind = orig_called_screening_ind; } } void isup_set_col_req(struct isup_call *c) { c->col_req = 1; } void isup_set_cug(struct isup_call *c, unsigned char cug_indicator, const char *cug_interlock_ni, unsigned short cug_interlock_code) { c->cug_indicator = cug_indicator; strncpy(c->cug_interlock_ni, cug_interlock_ni, sizeof(c->cug_interlock_ni)); c->cug_interlock_code = cug_interlock_code; } void isup_set_interworking_indicator(struct isup_call *c, unsigned char interworking_indicator) { c->interworking_indicator = interworking_indicator; } void isup_set_forward_indicator_pmbits(struct isup_call *c, unsigned char pmbits) { c->forward_indicator_pmbits = pmbits; } void isup_set_echocontrol(struct isup_call *c, unsigned char ec) { c->local_echocontrol_ind = ec; } 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_set_calling_party_category(struct isup_call *c, unsigned int category) { c->calling_party_cat = category; } static struct isup_call * isup_find_call(struct ss7 *ss7, struct routing_label *rl, int cic) { struct isup_call *cur = ss7->calls; while (cur && (cur->cic != cic || cur->dpc != rl->opc)) { cur = cur->next; } if (!cur) { cur = __isup_new_call(ss7, 0); cur->cic = cic; cur->dpc = rl->opc; cur->sls = rl->sls; } return cur; } void isup_free_call(struct ss7 *ss7, struct isup_call *c) { struct isup_call *cur, *prev = NULL; if (!ss7 || !c) { return; } cur = ss7->calls; while (cur && cur != c) { prev = cur; cur = cur->next; } if (cur) { if (!prev) { ss7->calls = cur->next; } else { prev->next = cur->next; } isup_stop_all_timers(ss7, c); free(c); } else { ss7_error(ss7, "Requested free an unlinked call!!!\n"); } } 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); for (x = 0; x < totalparms; x++) { if (parms[x].parm == parm) { 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; int priority = -1; /* 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; priority = messages[ourmessage].ansi_priority; /* 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; } else if (messages[ourmessage].messagetype == ISUP_GRS) { optparams = 1; } else if (messages[ourmessage].messagetype == ISUP_GRA) { optparams = 1; } } /* 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 { opt_ptr = NULL; 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, priority, msg, NULL); } 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 *param_pointer = NULL; mh = (struct isup_h*) buf; len -= 3; /* ISUP msg header size !*/ 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(0x%02x)\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 (len < 1) { return 0; } if (varparams || optparams) { param_pointer = &mh->data[offset]; } else { return 0; } if (varparams) { ss7_message(ss7, "\t\t--VARIABLE LENGTH PARMS[%d]--\n", varparams); for (x = 0; x < varparams && len > 0; x++) { if (!param_pointer[0]) { return 0; } res = dump_parm(ss7, mh->type, parms[fixedparams + x], (void *)(param_pointer + param_pointer[0]), len, PARM_TYPE_VARIABLE); if (res < 0) { ss7_error(ss7, "!! Unable to parse mandatory variable parameter '%s'\n", param2str(parms[fixedparams + x])); return -1; } len -= (res + 1); /* 1byte for pointer */ param_pointer++; offset++; } } if (len < 1 || !param_pointer[0]) { return 0; } /* Optional paramter parsing code */ if (optparams) { ss7_message(ss7, "\t\t--OPTIONAL PARMS--\n"); offset += param_pointer[0]; len-- ; /* optional parameter pointer */ 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; } /* Checking we whether got more 1 bits back in the status */ static int isup_check_status(unsigned char *sent_status, unsigned char *got_status, int range) { int i; for (i = 0; i <= range; i++) { if (got_status[i] > sent_status[i]) { return 1; } } return 0; } static int isup_handle_unexpected(struct ss7 *ss7, struct isup_call *c, unsigned int opc) { int res; if ((c->got_sent_msg & (ISUP_CALL_CONNECTED)) || (c->got_sent_msg & (ISUP_SENT_REL | ISUP_SENT_RSC) && (ss7->isup_timers[ISUP_TIMER_T1] && ss7->isup_timers[ISUP_TIMER_T5] && ss7->isup_timers[ISUP_TIMER_T16] && ss7->isup_timers[ISUP_TIMER_T17]))) { ss7_message(ss7, "ignoring... \n"); } else { ss7_message(ss7, "reseting the cic\n"); res = ss7_hangup(ss7, c->cic, opc, 16, SS7_HANGUP_SEND_RSC); if (res == SS7_CIC_IDLE) { isup_rsc(ss7, c); } else if (res == SS7_CIC_NOT_EXISTS) { isup_free_call(ss7, c); } } 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 *param_pointer = NULL; unsigned int opc = rl->opc; ss7_event *e; mh = (struct isup_h*) buf; len -= 3; /* ISUP msg header size !*/ 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; } else if (messages[ourmessage].messagetype == ISUP_GRS) { optparams = 1; } else if (messages[ourmessage].messagetype == ISUP_GRA) { optparams = 1; } } c = isup_find_call(ss7, rl, cic); 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])); ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } len -= res; offset += res; } if (varparams || optparams) param_pointer = &mh->data[offset]; if (varparams && len > 0) { for (x = 0; x < varparams && len && param_pointer[0]; x++) { res = do_parm(ss7, c, mh->type, parms[fixedparams + x], (void *)(param_pointer + param_pointer[0]), len, PARM_TYPE_VARIABLE, 0); if (res < 0) { ss7_error(ss7, "!! Unable to parse mandatory variable parameter '%s'\n", param2str(parms[fixedparams + x])); ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } len -= (res + 1); /* 1byte for pointer */ param_pointer++; offset++; } } /* Optional paramter parsing code */ if (optparams && len > 0 && param_pointer[0]) { offset += param_pointer[0]; len-- ; /* optional parameter pointer */ 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: return isup_event_iam(ss7, c, opc); case ISUP_SAM: if (!(c->got_sent_msg & ISUP_GOT_IAM)) { ss7_message(ss7, "Got unexpected SAM on CIC %d PC %d ", c->cic, opc); return isup_handle_unexpected(ss7, c, opc); } e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_SAM; e->sam.cic = c->cic; e->sam.call = c; e->sam.opc = opc; /* keep OPC information */ strncpy(e->sam.called_party_num, c->called_party_num, sizeof(e->sam.called_party_num)); e->sam.called_nai = c->called_nai; e->sam.got_sent_msg = c->got_sent_msg; e->sam.cot_check_passed = c->cot_check_passed; e->sam.cot_check_required = c->cot_check_required; e->sam.cot_performed_on_previous_cic = c->cot_performed_on_previous_cic; isup_start_timer(ss7, c, ISUP_TIMER_T35); return 0; case ISUP_INF: if (!(c->got_sent_msg & ISUP_SENT_INR) && !(c->inf_ind[0] & 0x80)) { ss7_message(ss7, "Got solicated INF but we didn't send INR on CIC %d PC %d ", c->cic, opc); return isup_handle_unexpected(ss7, c, opc); } if ((ss7->flags & SS7_INR_IF_NO_CALLING) && !c->calling_party_num[0] && c->presentation_ind != SS7_PRESENTATION_ADDR_NOT_AVAILABLE) { isup_rel(ss7, c, 16); return 0; } if (c->inf_ind[0] & 0x80) { /* unsolicated */ if (!isup_free_call_if_clear(ss7, c)) { ss7_call_null(ss7, c, 1); } return 0; } else { isup_stop_timer(ss7, c, ISUP_TIMER_T33); c->got_sent_msg &= ~ISUP_SENT_INR; return isup_event_iam(ss7, c, opc); } case ISUP_INR: if (!(c->got_sent_msg & ISUP_SENT_IAM)) { ss7_message(ss7, "Got INR but no outgoing call on CIC %d PC %d ", c->cic, opc); return isup_handle_unexpected(ss7, c, opc); } if (!c->calling_party_num[0]) { isup_inf(ss7, c, 0x21, 0); /* Calling party category included, solicated (0x20). Calling party address not available */ } else { isup_inf(ss7, c, 0x23, 0); /* Calling party category included, solicated (0x20). Calling party address included */ } if (!isup_free_call_if_clear(ss7, c)) { ss7_call_null(ss7, c, 1); } return 0; case ISUP_CQM: e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); 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 */ e->cqm.call = c; return 0; case ISUP_GRS: e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_GRS; e->grs.startcic = cic; e->grs.endcic = cic + c->range; e->grs.opc = opc; /* keep OPC information */ e->grs.call = c; return 0; case ISUP_GRA: if (!(c->got_sent_msg & ISUP_SENT_GRS)) { ss7_message(ss7, "Got GRA but we didn't send GRS on CIC %d PC %d ", c->cic, opc); return isup_handle_unexpected(ss7, c, opc); } /* checking the answer */ if (c->range != c->sent_grs_endcic - c->cic) { ss7_message(ss7, "Got GRA doesn't match with the sent GRS on CIC %d DPC %d\n", c->cic, opc); return 0; } e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); 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 */ e->gra.call = c; e->gra.sent_endcic = c->sent_grs_endcic; e->gra.got_sent_msg = c->got_sent_msg; if (c->got_sent_msg & ISUP_SENT_GRS2) { c->got_sent_msg &= ~ISUP_SENT_GRS2; } else { c->got_sent_msg &= ~ISUP_SENT_GRS; } isup_stop_timer(ss7, c, ISUP_TIMER_T22); isup_stop_timer(ss7, c, ISUP_TIMER_T23); return 0; case ISUP_RSC: if (c->got_sent_msg & ISUP_SENT_RSC) { ss7_debug_msg(ss7, SS7_DEBUG_ISUP, "Got RSC on CIC %d DPC %d, but we have sent RSC too.\n", c->cic, opc); return isup_send_message(ss7, c, ISUP_RLC, empty_params); } e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } isup_stop_all_timers(ss7, c); e->e = ISUP_EVENT_RSC; e->rsc.cic = cic; e->rsc.call = c; e->rsc.opc = opc; /* keep OPC information */ e->rsc.got_sent_msg = c->got_sent_msg; c->got_sent_msg = 0; return 0; case ISUP_REL: e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } isup_stop_timer(ss7, c, ISUP_TIMER_T7); isup_stop_timer(ss7, c, ISUP_TIMER_T2); isup_stop_timer(ss7, c, ISUP_TIMER_T6); isup_stop_timer(ss7, c, ISUP_TIMER_T35); isup_stop_timer(ss7, c, ISUP_TIMER_T10); c->got_sent_msg &= ~(ISUP_CALL_CONNECTED | ISUP_CALL_PENDING); 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 */ e->rel.got_sent_msg = c->got_sent_msg; return 0; case ISUP_ACM: if (!(c->got_sent_msg & ISUP_SENT_IAM)) { ss7_message(ss7, "Got ACM but we didn't send IAM on CIC %d PC %d ", c->cic, opc); return isup_handle_unexpected(ss7, c, opc); } e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } isup_stop_timer(ss7, c, ISUP_TIMER_T7); c->got_sent_msg |= ISUP_GOT_ACM; 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; e->acm.echocontrol_ind = c->echocontrol_ind; e->acm.got_sent_msg = c->got_sent_msg; return 0; case ISUP_CON: if (!(c->got_sent_msg & ISUP_SENT_IAM)) { ss7_message(ss7, "Got CON but we didn't send IAM on CIC %d PC %d ", c->cic, opc); return isup_handle_unexpected(ss7, c, opc); } e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } isup_stop_timer(ss7, c, ISUP_TIMER_T7); c->got_sent_msg |= ISUP_GOT_CON; e->e = ISUP_EVENT_CON; e->con.cic = c->cic; e->con.call = c; e->con.opc = opc; /* keep OPC information */ e->con.connected_nai = c->connected_nai; e->con.connected_presentation_ind = c->connected_presentation_ind; e->con.connected_screening_ind = c->connected_screening_ind; strncpy(e->con.connected_num, c->connected_num, sizeof(e->con.connected_num)); e->con.echocontrol_ind = c->echocontrol_ind; e->con.got_sent_msg = c->got_sent_msg; return 0; case ISUP_ANM: if (!(c->got_sent_msg & ISUP_SENT_IAM)) { ss7_message(ss7, "Got ANM but we didn't send IAM on CIC %d PC %d ", c->cic, opc); return isup_handle_unexpected(ss7, c, opc); } e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } c->got_sent_msg |= ISUP_GOT_ANM; e->e = ISUP_EVENT_ANM; e->anm.cic = c->cic; e->anm.call = c; e->anm.opc = opc; /* keep OPC information */ e->anm.connected_nai = c->connected_nai; e->anm.connected_presentation_ind = c->connected_presentation_ind; e->anm.connected_screening_ind = c->connected_screening_ind; strncpy(e->anm.connected_num, c->connected_num, sizeof(e->anm.connected_num)); e->anm.echocontrol_ind = c->echocontrol_ind; e->anm.got_sent_msg = c->got_sent_msg; return 0; case ISUP_RLC: if (!(c->got_sent_msg & (ISUP_SENT_REL | ISUP_SENT_RSC))) { ss7_message(ss7, "Got RLC but we didn't send REL/RSC on CIC %d PC %d ", c->cic, opc); return isup_handle_unexpected(ss7, c, opc); } e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_RLC; e->rlc.cic = c->cic; e->rlc.opc = opc; /* keep OPC information */ e->rlc.call = c; e->rlc.got_sent_msg = c->got_sent_msg; if (c->got_sent_msg & ISUP_SENT_RSC) { c->got_sent_msg &= ~(ISUP_SENT_REL | ISUP_SENT_RSC | ISUP_CALL_CONNECTED | ISUP_CALL_PENDING); } else { c->got_sent_msg &= ~(ISUP_SENT_REL | ISUP_SENT_RSC); } isup_stop_timer(ss7, c, ISUP_TIMER_T1); isup_stop_timer(ss7, c, ISUP_TIMER_T2); isup_stop_timer(ss7, c, ISUP_TIMER_T5); isup_stop_timer(ss7, c, ISUP_TIMER_T6); isup_stop_timer(ss7, c, ISUP_TIMER_T16); isup_stop_timer(ss7, c, ISUP_TIMER_T17); return 0; case ISUP_COT: /* Got we CCR or CCR in IAM ?*/ if (!(c->got_sent_msg & ISUP_GOT_CCR) & !c->cot_performed_on_previous_cic) { ss7_message(ss7, "Got COT but we didn't got CCR previously on CIC %d PC %d ", c->cic, opc); return isup_handle_unexpected(ss7, c, opc); } e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); 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.cot_performed_on_previous_cic = c->cot_performed_on_previous_cic; if (!c->cot_check_passed) { c->got_sent_msg &= ~ISUP_GOT_IAM; /* we will get a new IAM but we are kepping the call */ } e->cot.call = c; e->cot.opc = opc; /* keep OPC information */ e->cot.got_sent_msg = c->got_sent_msg; c->got_sent_msg &= ~ISUP_GOT_CCR; isup_stop_timer(ss7, c, ISUP_TIMER_T8); if (!c->cot_check_passed) { isup_start_timer(ss7, c, ISUP_TIMER_T27); } return 0; case ISUP_CCR: e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } c->got_sent_msg |= ISUP_GOT_CCR; e->e = ISUP_EVENT_CCR; e->ccr.cic = c->cic; e->ccr.opc = opc; /* keep OPC information */ e->ccr.call = c; e->ccr.got_sent_msg = c->got_sent_msg; isup_stop_timer(ss7, c, ISUP_TIMER_T27); return 0; case ISUP_CVT: e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_CVT; e->cvt.cic = c->cic; e->cvt.call = c; return 0; case ISUP_BLO: e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_BLO; e->blo.cic = c->cic; e->blo.opc = opc; /* keep OPC information */ e->blo.call = c; e->blo.got_sent_msg = c->got_sent_msg; return 0; case ISUP_UBL: e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_UBL; e->ubl.cic = c->cic; e->ubl.opc = opc; /* keep OPC information */ e->ubl.call = c; return 0; case ISUP_BLA: if (!(c->got_sent_msg & ISUP_SENT_BLO)) { ss7_message(ss7, "Got BLA but we didn't send BLO on CIC %d PC %d ", c->cic, opc); return isup_handle_unexpected(ss7, c, opc); } e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } isup_stop_timer(ss7, c, ISUP_TIMER_T12); isup_stop_timer(ss7, c, ISUP_TIMER_T13); e->e = ISUP_EVENT_BLA; e->bla.cic = c->cic; e->bla.opc = opc; /* keep OPC information */ e->bla.call = c; e->bla.got_sent_msg = c->got_sent_msg; c->got_sent_msg &= ~ISUP_SENT_BLO; return 0; case ISUP_LPA: e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_LPA; e->lpa.cic = c->cic; e->lpa.opc = opc; /* keep OPC information */ e->lpa.call = c; return 0; case ISUP_UBA: if (!(c->got_sent_msg & ISUP_SENT_UBL)) { ss7_message(ss7, "Got UBA but we didn't send UBL on CIC %d PC %d ", c->cic, opc); return isup_handle_unexpected(ss7, c, opc); } e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } isup_stop_timer(ss7, c, ISUP_TIMER_T14); isup_stop_timer(ss7, c, ISUP_TIMER_T15); e->e = ISUP_EVENT_UBA; e->uba.cic = c->cic; e->uba.opc = opc; /* keep OPC information */ e->uba.call = c; e->uba.got_sent_msg = c->got_sent_msg; c->got_sent_msg &= ~ISUP_SENT_UBL; return 0; case ISUP_CGB: e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); 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 */ e->cgb.call = c; return 0; case ISUP_CGU: e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); 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 */ e->cgu.call = c; return 0; case ISUP_CPG: if (!(c->got_sent_msg & ISUP_SENT_IAM)) { ss7_message(ss7, "Got CPG but we didn't send IAM on CIC %d PC %d ", c->cic, opc); return isup_handle_unexpected(ss7, c, opc); } e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); 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; e->cpg.call = c; e->cpg.got_sent_msg = c->got_sent_msg; e->cpg.echocontrol_ind = c->echocontrol_ind; e->cpg.connected_nai = c->connected_nai; e->cpg.connected_presentation_ind = c->connected_presentation_ind; e->cpg.connected_screening_ind = c->connected_screening_ind; strncpy(e->cpg.connected_num, c->connected_num, sizeof(e->cpg.connected_num)); return 0; case ISUP_UCIC: e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_UCIC; e->ucic.cic = c->cic; e->ucic.opc = opc; /* keep OPC information */ e->ucic.call = c; return 0; case ISUP_FRJ: e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_FRJ; e->frj.cic = c->cic; e->frj.call_ref_ident = c->call_ref_ident; e->frj.call_ref_pc = c->call_ref_pc; e->frj.opc = opc; /* keep OPC information */ e->frj.call = c; return 0; case ISUP_FAA: e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); 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) { ss7_call_null(ss7, c, 1); 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->far.opc = opc; /* keep OPC information */ e->far.call = c; return 0; case ISUP_CGBA: if (!(c->got_sent_msg & ISUP_SENT_CGB)) { ss7_message(ss7, "Got CGBA but we didn't send CGB on CIC %d PC %d ", c->cic, opc); return isup_handle_unexpected(ss7, c, opc); } /* checking the answer */ if (c->range != c->sent_cgb_endcic - c->cic || c->cicgroupsupervisiontype != c->sent_cgb_type || isup_check_status(c->sent_cgb_status, c->status, c->range)) { ss7_message(ss7, "Got CGBA doesn't match with the sent CGB on CIC %d DPC %d\n", c->cic, opc); return 0; } e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_CGBA; e->cgba.startcic = c->cic; e->cgba.endcic = c->cic + c->range; e->cgba.sent_endcic = c->sent_cgb_endcic; e->cgba.type = c->cicgroupsupervisiontype; e->cgba.sent_type = c->sent_cgb_type; for (i = 0; i < (c->range + 1); i++) { e->cgba.status[i] = c->status[i]; e->cgba.sent_status[i] = c->sent_cgb_status[i]; } e->cgba.got_sent_msg = c->got_sent_msg; e->cgba.opc = opc; e->cgba.call = c; isup_clear_callflags(ss7, c, ISUP_SENT_CGB); return 0; case ISUP_CGUA: if (!(c->got_sent_msg & ISUP_SENT_CGU)) { ss7_message(ss7, "Got CGUA but we didn't send CGU on CIC %d PC %d ", c->cic, opc); return isup_handle_unexpected(ss7, c, opc); } /* checking the answer */ if (c->range != c->sent_cgu_endcic - c->cic || c->cicgroupsupervisiontype != c->sent_cgu_type || isup_check_status(c->sent_cgu_status, c->status, c->range)) { ss7_message(ss7, "Got CGUA doesn't match with the sent CGU on CIC %d DPC %d\n", c->cic, opc); return 0; } e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } e->e = ISUP_EVENT_CGUA; e->cgua.startcic = c->cic; e->cgua.endcic = c->cic + c->range; e->cgua.sent_endcic = c->sent_cgu_endcic; e->cgua.type = c->cicgroupsupervisiontype; e->cgua.sent_type = c->sent_cgu_type; for (i = 0; i < (c->range + 1); i++) { e->cgua.status[i] = c->status[i]; e->cgua.sent_status[i] = c->sent_cgu_status[i]; } e->cgua.got_sent_msg = c->got_sent_msg; e->cgua.opc = opc; e->cgua.call = c; isup_clear_callflags(ss7, c, ISUP_SENT_CGU); return 0; case ISUP_SUS: if (c->got_sent_msg & (ISUP_SENT_RSC | ISUP_SENT_REL)) { return 0; /* ignoring SUS we are in hangup now */ } if (!(c->got_sent_msg & (ISUP_GOT_IAM | ISUP_SENT_IAM))) { ss7_message(ss7, "Got SUS but no call on CIC %d PC %d ", c->cic, opc); return isup_handle_unexpected(ss7, c, opc); } e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } if (c->network_isdn_indicator) { isup_start_timer(ss7, c, ISUP_TIMER_T6); /* network */ } else { isup_start_timer(ss7, c, ISUP_TIMER_T2); } e->e = ISUP_EVENT_SUS; e->sus.cic = c->cic; e->sus.opc = opc; /* keep OPC information */ e->sus.call = c; e->sus.network_isdn_indicator = c->network_isdn_indicator; e->sus.got_sent_msg = c->got_sent_msg; return 0; case ISUP_RES: if (!(c->got_sent_msg & (ISUP_GOT_IAM | ISUP_SENT_IAM))) { ss7_message(ss7, "Got RES but no call on CIC %d PC %d ", c->cic, opc); return isup_handle_unexpected(ss7, c, opc); } e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } if (c->network_isdn_indicator) { isup_stop_timer(ss7, c, ISUP_TIMER_T6); /* network */ } else { isup_stop_timer(ss7, c, ISUP_TIMER_T2); } e->e = ISUP_EVENT_RES; e->res.cic = c->cic; e->res.opc = opc; /* keep OPC information */ e->res.call = c; e->res.network_isdn_indicator = c->network_isdn_indicator; e->res.got_sent_msg = c->got_sent_msg; return 0; default: if (!isup_free_call_if_clear(ss7, c)) { ss7_call_null(ss7, c, 1); } return 0; } } int isup_event_iam(struct ss7 *ss7, struct isup_call *c, int opc) { ss7_event *e; /* Checking dual seizure Q.764 2.9.1.4 */ if (c->got_sent_msg & (ISUP_SENT_IAM | ISUP_PENDING_IAM)) { if ((ss7->pc > opc) ? (~c->cic & 1) : (c->cic & 1)) { ss7_message(ss7, "Dual seizure on CIC %d DPC %d we are the controlling, ignore IAM\n", c->cic, opc); return 0; } else { ss7_message(ss7, "Dual seizure on CIC %d DPC %d they are the controlling, hangup our call\n", c->cic, opc); c->got_sent_msg |= ISUP_GOT_IAM; ss7_hangup(ss7, c->cic, opc, SS7_CAUSE_TRY_AGAIN, SS7_HANGUP_REEVENT_IAM); return 0; } } c->got_sent_msg |= ISUP_GOT_IAM; if ((ss7->flags & SS7_INR_IF_NO_CALLING) && !c->calling_party_num[0] && c->presentation_ind != SS7_PRESENTATION_ADDR_NOT_AVAILABLE) { c->dpc = opc; isup_inr(ss7, c, 0x1, 0); /* Calling party address requested */ return 0; } e = ss7_next_empty_event(ss7); if (!e) { ss7_call_null(ss7, c, 1); isup_free_call(ss7, c); return -1; } if (c->cot_check_required) { c->got_sent_msg |= ISUP_GOT_CCR; } e->e = ISUP_EVENT_IAM; e->iam.got_sent_msg = c->got_sent_msg; e->iam.cic = c->cic; e->iam.transcap = c->transcap; e->iam.cot_check_required = c->cot_check_required; e->iam.cot_performed_on_previous_cic = c->cot_performed_on_previous_cic; c->cot_check_passed = 0; 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.redirect_counter = c->redirect_counter; e->iam.redirect_info = c->redirect_info; e->iam.redirect_info_ind = c->redirect_info_ind; e->iam.redirect_info_orig_reas = c->redirect_info_orig_reas; e->iam.redirect_info_counter = c->redirect_info_counter; e->iam.redirect_info_reas = c->redirect_info_reas; e->iam.calling_party_cat = c->calling_party_cat; e->iam.cug_indicator = c->cug_indicator; e->iam.cug_interlock_code = c->cug_interlock_code; strncpy(e->iam.cug_interlock_ni, c->cug_interlock_ni, sizeof(e->iam.cug_interlock_ni)); e->iam.call = c; e->iam.opc = opc; /* keep OPC information */ e->iam.echocontrol_ind = c->echocontrol_ind; if (!strchr(c->called_party_num, '#')) { isup_start_timer(ss7, c, ISUP_TIMER_T35); } if (c->cot_check_required || c->cot_performed_on_previous_cic) { isup_start_timer(ss7, c, ISUP_TIMER_T8); } return 0; } int isup_cqr(struct ss7 *ss7, int begincic, int endcic, unsigned int dpc, unsigned char status[]) { struct isup_call call = {{0},}; int i, res; 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; } res = isup_send_message(ss7, &call, ISUP_CQR, cqr_params); if (res == -1) { ss7_error(ss7, "Unable to send CQR to DPC: %d\n", dpc); } return res; } int isup_grs(struct ss7 *ss7, struct isup_call *c, int endcic) { int res; if (!ss7 || !c) { return -1; } if (endcic - c->cic > 31) { return -1; } c->range = endcic - c->cic; res = isup_send_message(ss7, c, ISUP_GRS, greset_params); if (ss7->switchtype == SS7_ANSI) { /* ANSI require that we send it twice. Don't think I understand completely why. * T1.113 in 2.9.3.2 */ res = isup_send_message(ss7, c, ISUP_GRS, greset_params); } if (res > -1) { c->got_sent_msg |= ISUP_SENT_GRS; if (ss7->switchtype == SS7_ANSI) { c->got_sent_msg |= ISUP_SENT_GRS2; } c->sent_grs_endcic = endcic; isup_stop_all_timers(ss7, c); isup_start_timer(ss7, c, ISUP_TIMER_T22); isup_start_timer(ss7, c, ISUP_TIMER_T23); } else { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send GRS to DPC: %d\n", c->dpc); } return res; } int isup_gra(struct ss7 *ss7, struct isup_call *c, int endcic, unsigned char state[]) { int i, res; if (!ss7 || !c) { return -1; } if (endcic - c->cic > 31) { return -1; } c->range = endcic - c->cic; for (i = 0; (i + c->cic) <= endcic; i++) { c->status[i] = state[i]; } res = isup_send_message(ss7, c, ISUP_GRA, greset_params); if (res == -1) { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send GRA to DPC: %d\n", c->dpc); } return res; } int isup_cgb(struct ss7 *ss7, struct isup_call *c, int endcic, unsigned char state[], int type) { int i, res; if (!ss7 || !c) { return -1; } if (endcic - c->cic > 31) { return -1; } c->range = endcic - c->cic; c->sent_cgb_endcic = endcic; c->cicgroupsupervisiontype = type; c->sent_cgb_type = type; for (i = 0; (i + c->cic) <= endcic; i++) { c->status[i] = state[i]; c->sent_cgb_status[i] = state[i]; } res = isup_send_message(ss7, c, ISUP_CGB, cicgroup_params); if (res > -1) { c->got_sent_msg |= ISUP_SENT_CGB; c->sent_cgb_type = type; isup_start_timer(ss7, c, ISUP_TIMER_T18); isup_start_timer(ss7, c, ISUP_TIMER_T19); } else { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send CGB to DPC: %d\n", c->dpc); } return res; } int isup_cgu(struct ss7 *ss7, struct isup_call *c, int endcic, unsigned char state[], int type) { int i, res; if (!ss7 || !c) { return -1; } if (endcic - c->cic > 31) { return -1; } c->range = endcic - c->cic; c->sent_cgu_endcic = endcic; c->cicgroupsupervisiontype = type; c->sent_cgu_type = type; for (i = 0; (i + c->cic) <= endcic; i++) { c->status[i] = state[i]; c->sent_cgu_status[i] = state[i]; } isup_start_timer(ss7, c, ISUP_TIMER_T20); isup_start_timer(ss7, c, ISUP_TIMER_T21); res = isup_send_message(ss7, c, ISUP_CGU, cicgroup_params); if (res > -1) { c->got_sent_msg |= ISUP_SENT_CGU; isup_start_timer(ss7, c, ISUP_TIMER_T20); isup_start_timer(ss7, c, ISUP_TIMER_T21); } else { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send CGU to DPC: %d\n", c->dpc); } return res; } int isup_cgba(struct ss7 *ss7, struct isup_call *c, int endcic, unsigned char state[]) { int i, res; if (!ss7 || !c) { return -1; } if (endcic - c->cic > 31) { return -1; } c->range = endcic - c->cic; for (i = 0; (i + c->cic) <= endcic; i++) { c->status[i] = state[i]; } res = isup_send_message(ss7, c, ISUP_CGBA, cicgroup_params); if (res == -1) { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send CGBA to DPC: %d\n", c->dpc); } return res; } int isup_cgua(struct ss7 *ss7, struct isup_call *c, int endcic, unsigned char state[]) { int i, res; if (!ss7 || !c) { return -1; } if (endcic - c->cic > 31) { return -1; } c->range = endcic - c->cic; for (i = 0; (i + c->cic) <= endcic; i++) { c->status[i] = state[i]; } res = isup_send_message(ss7, c, ISUP_CGUA, cicgroup_params); if (res == -1) { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send CGUA to DPC: %d\n", c->dpc); } return res; } int isup_iam(struct ss7 *ss7, struct isup_call *c) { int res; if (!ss7 || !c) { return -1; } if (ss7->switchtype == SS7_ITU) { res = isup_send_message(ss7, c, ISUP_IAM, iam_params); } else { res = isup_send_message(ss7, c, ISUP_IAM, ansi_iam_params); } if (res > -1) { isup_start_timer(ss7, c, ISUP_TIMER_T7); c->got_sent_msg |= ISUP_SENT_IAM; c->got_sent_msg &= ~ISUP_PENDING_IAM; } else { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send IAM to DPC: %d\n", c->dpc); } return res; } int isup_acm(struct ss7 *ss7, struct isup_call *c) { int res; if (!ss7 || !c) { return -1; } res = isup_send_message(ss7, c, ISUP_ACM, acm_params); if (res > -1) { c->got_sent_msg |= ISUP_SENT_ACM; isup_stop_timer(ss7, c, ISUP_TIMER_T35); isup_stop_timer(ss7, c, ISUP_TIMER_T10); } else { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send ACM to DPC: %d\n", c->dpc); } return res; } int isup_frj(struct ss7 *ss7, struct isup_call *c) { int res; if (!ss7 || !c) { return -1; } res = isup_send_message(ss7, c, ISUP_FRJ, frj_params); if (res == -1) { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send FRJ to DPC: %d\n", c->dpc); } return res; } int isup_faa(struct ss7 *ss7, struct isup_call *c) { int res; if (!ss7 || !c) { return -1; } res = isup_send_message(ss7, c, ISUP_FAA, faa_params); if (res == -1) { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send FAA to DPC: %d\n", c->dpc); } return res; } int isup_far(struct ss7 *ss7, struct isup_call *c) { int res = -1; 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; res = isup_send_message(ss7, c, ISUP_FAR, far_params); if (res > -1) { c->got_sent_msg |= ISUP_SENT_FAR; } else { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send FAR to DPC: %d\n", c->dpc); } } return res; } int isup_anm(struct ss7 *ss7, struct isup_call *c) { int res; if (!ss7 || !c) { return -1; } res = isup_send_message(ss7, c, ISUP_ANM, anm_params); if (res > -1) { c->got_sent_msg |= ISUP_SENT_ANM; isup_stop_timer(ss7, c, ISUP_TIMER_T35); isup_stop_timer(ss7, c, ISUP_TIMER_T10); } else { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send ANM to DPC: %d\n", c->dpc); } return res; } int isup_con(struct ss7 *ss7, struct isup_call *c) { int res; if (!ss7 || !c) { return -1; } c->got_sent_msg |= ISUP_SENT_CON; isup_stop_timer(ss7, c, ISUP_TIMER_T35); isup_stop_timer(ss7, c, ISUP_TIMER_T10); res = isup_send_message(ss7, c, ISUP_CON, con_params); if (res < 0) { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send CON to DPC: %d\n", c->dpc); } return res; } int isup_rel(struct ss7 *ss7, struct isup_call *c, int cause) { int res; if (!ss7 || !c) { return -1; } if (cause < 0) { cause = 16; } c->cause = cause; c->causecode = CODE_CCITT; c->causeloc = ss7->cause_location; res = isup_send_message(ss7, c, ISUP_REL, rel_params); if (res > -1) { isup_stop_timer(ss7, c, ISUP_TIMER_T7); isup_stop_timer(ss7, c, ISUP_TIMER_T8); isup_stop_timer(ss7, c, ISUP_TIMER_T27); isup_stop_timer(ss7, c, ISUP_TIMER_T2); isup_stop_timer(ss7, c, ISUP_TIMER_T6); isup_stop_timer(ss7, c, ISUP_TIMER_T35); isup_stop_timer(ss7, c, ISUP_TIMER_T10); isup_start_timer(ss7, c, ISUP_TIMER_T1); isup_start_timer(ss7, c, ISUP_TIMER_T5); c->got_sent_msg |= ISUP_SENT_REL; c->got_sent_msg &= ~(ISUP_CALL_PENDING | ISUP_CALL_CONNECTED); } else { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send REL to DPC: %d\n", c->dpc); } return res; } 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); if (res == -1) { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send RLC to DPC: %d\n", c->dpc); } return res; } int isup_inr(struct ss7 *ss7, struct isup_call *c, unsigned char ind0, unsigned char ind1) { int res; if (!ss7 || !c) { return -1; } c->inr_ind[0] = ind0; c->inr_ind[1] = ind1; res = isup_send_message(ss7, c, ISUP_INR, inr_params); if (res > -1) { c->got_sent_msg |= ISUP_SENT_INR; isup_start_timer(ss7, c, ISUP_TIMER_T33); } else { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send INR to DPC: %d\n", c->dpc); } return res; } int isup_inf(struct ss7 *ss7, struct isup_call *c, unsigned char ind0, unsigned char ind1) { int res; if (!ss7 || !c) { return -1; } c->inf_ind[0] = ind0; c->inf_ind[1] = ind1; res = isup_send_message(ss7, c, ISUP_INF, inf_params); if (res == -1) { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send INF to DPC: %d\n", c->dpc); } return res; } int isup_sus(struct ss7 *ss7, struct isup_call *c, unsigned char indicator) { int res; if (!ss7 || !c) { return -1; } c->network_isdn_indicator = indicator; res = isup_send_message(ss7, c, ISUP_SUS, sus_res_params); if (res == -1) { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send SUS to DPC: %d\n", c->dpc); } return res; } int isup_res(struct ss7 *ss7, struct isup_call *c, unsigned char indicator) { int res; if (!ss7 || !c) { return -1; } c->network_isdn_indicator = indicator; res = isup_send_message(ss7, c, ISUP_RES, sus_res_params); if (res == -1) { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send RES to DPC: %d\n", c->dpc); } return res; } static int isup_send_message_ciconly(struct ss7 *ss7, int messagetype, int cic, unsigned int dpc) { int res; struct isup_call c = {{0},}; 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) { int res; if (!ss7 || !c) { return -1; } c->event_info = event; res = isup_send_message(ss7, c, ISUP_CPG, cpg_params); if (res > -1) { isup_stop_timer(ss7, c, ISUP_TIMER_T35); isup_stop_timer(ss7, c, ISUP_TIMER_T10); } else { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send CPG to DPC: %d\n", c->dpc); } return res; } int isup_rsc(struct ss7 *ss7, struct isup_call *c) { int res; if (!ss7 || !c) { return -1; } res = isup_send_message(ss7, c, ISUP_RSC, empty_params); if (res > -1) { isup_stop_all_timers(ss7, c); isup_start_timer(ss7, c, ISUP_TIMER_T17); c->got_sent_msg |= ISUP_SENT_RSC; } else { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send RSC to DPC: %d\n", c->dpc); } return res; } int isup_blo(struct ss7 *ss7, struct isup_call *c) { int res; if (!ss7 || !c) { return -1; } res = isup_send_message(ss7, c, ISUP_BLO, empty_params); if (res > -1) { isup_start_timer(ss7, c, ISUP_TIMER_T12); isup_start_timer(ss7, c, ISUP_TIMER_T13); c->got_sent_msg |= ISUP_SENT_BLO; } else { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send BLO to DPC: %d\n", c->dpc); } return res; } int isup_ubl(struct ss7 *ss7, struct isup_call *c) { int res; if (!ss7 || !c) { return -1; } res = isup_send_message(ss7, c, ISUP_UBL, empty_params); if (res > -1) { isup_start_timer(ss7, c, ISUP_TIMER_T14); isup_start_timer(ss7, c, ISUP_TIMER_T15); c->got_sent_msg |= ISUP_SENT_UBL; } else { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send UBL to DPC: %d\n", c->dpc); } return res; } int isup_bla(struct ss7 *ss7, struct isup_call *c) { int res; if (!ss7 || !c) { return -1; } res = isup_send_message(ss7, c, ISUP_BLA, empty_params); if (res == -1) { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send BLA to DPC: %d\n", c->dpc); } return res; } int isup_lpa(struct ss7 *ss7, int cic, unsigned int dpc) { int res; if (!ss7) { return -1; } res = isup_send_message_ciconly(ss7, ISUP_LPA, cic, dpc); if (res == -1) { ss7_error(ss7, "Unable to send LPA to DPC: %d\n", dpc); } return res; } int isup_ucic(struct ss7 *ss7, int cic, unsigned int dpc) { int res; if (!ss7) { return -1; } res = isup_send_message_ciconly(ss7, ISUP_UCIC, cic, dpc); if (res == -1) { ss7_error(ss7, "Unable to send UCIC to DPC: %d\n", dpc); } return res; } int isup_uba(struct ss7 *ss7, struct isup_call *c) { int res; if (!ss7 || !c) { return -1; } res = isup_send_message(ss7, c, ISUP_UBA, empty_params); if (res == -1) { ss7_call_null(ss7, c, 0); isup_free_call(ss7, c); ss7_error(ss7, "Unable to send UBA to DPC: %d\n", c->dpc); } return res; } int isup_cvr(struct ss7 *ss7, int cic, unsigned int dpc) { int res; if (!ss7) { return -1; } res = isup_send_message_ciconly(ss7, ISUP_CVR, cic, dpc); if (res == -1) { ss7_error(ss7, "Unable to send CVR to DPC: %d\n", dpc); } return res; } /*! * \internal * \brief Append snprintf output to the given buffer. * * \param buf Buffer currently filling. * \param buf_used Offset into buffer where to put new stuff. * \param buf_size Actual buffer size of buf. * \param format printf format string. * * \return Total buffer space used. */ static size_t ss7_snprintf(char *buf, size_t buf_used, size_t buf_size, const char *format, ...) __attribute__((format(printf, 4, 5))); static size_t ss7_snprintf(char *buf, size_t buf_used, size_t buf_size, const char *format, ...) { va_list args; if (buf_used < buf_size) { va_start(args, format); buf_used += vsnprintf(buf + buf_used, buf_size - buf_used, format, args); va_end(args); } if (buf_size < buf_used) { buf_used = buf_size + 1; } return buf_used; } void isup_show_calls(struct ss7 *ss7, ss7_printf_cb cust_printf, int fd) { int x; char *buf, *tmp_buf; size_t tmp_used, buf_used; size_t buf_size = 4096; /* This should be bigger than we will ever need. */ struct isup_call *c = ss7->calls; buf = malloc(buf_size); if (!buf) { return; } tmp_buf = malloc(buf_size); if (!tmp_buf) { free(buf); return; } cust_printf(fd, "%5s %5s %3s %-24s %-16s %s\n", " CIC", " DPC", "SLS", "Sent", "Got", "TIMERS (time left s)"); while (c) { buf_used = 0; tmp_used = 0; tmp_buf[0] = '\0'; if (c->got_sent_msg & ISUP_SENT_RSC) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "RSC "); } if (c->got_sent_msg & ISUP_SENT_IAM) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "IAM "); } if (c->got_sent_msg & ISUP_SENT_ACM) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "ACM "); } if (c->got_sent_msg & ISUP_SENT_REL) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "REL "); } if (c->got_sent_msg & ISUP_SENT_BLO) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "BLO "); } if (c->got_sent_msg & ISUP_SENT_UBL) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "UBL "); } if (c->got_sent_msg & ISUP_SENT_GRS) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "GRS "); } if (c->got_sent_msg & ISUP_SENT_GRS2) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "GRS2 "); } if (c->got_sent_msg & ISUP_SENT_CGB) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "CGB "); } if (c->got_sent_msg & ISUP_SENT_CGU) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "CGU "); } if (c->got_sent_msg & ISUP_SENT_CON) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "CON "); } if (c->got_sent_msg & ISUP_SENT_ANM) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "ANM "); } if (c->got_sent_msg & ISUP_SENT_INR) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "INR "); } if (c->got_sent_msg & ISUP_SENT_FAR) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "FAR "); } buf_used = ss7_snprintf(buf, buf_used, buf_size, "%5i %5i %3i %-24s", c->cic, c->dpc, c->sls, tmp_buf); tmp_used = 0; if (c->got_sent_msg & ISUP_GOT_CCR) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "CCR "); } if (c->got_sent_msg & ISUP_PENDING_IAM) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "-IAM "); } if (c->got_sent_msg & ISUP_GOT_IAM) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "IAM "); } if (c->got_sent_msg & ISUP_GOT_ACM) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "ACM "); } if (c->got_sent_msg & ISUP_GOT_ANM) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "ANM "); } if (c->got_sent_msg & ISUP_GOT_CON) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "CON "); } if (c->got_sent_msg & ISUP_GOT_CGB) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "CGB "); } if (c->got_sent_msg & ISUP_GOT_CGU) { tmp_used = ss7_snprintf(tmp_buf, tmp_used, buf_size, "CGU "); } buf_used = ss7_snprintf(buf, buf_used, buf_size, " %-16s ", tmp_buf); for (x = 0; x < ISUP_MAX_TIMERS; x++) { if (c->timer[x] > -1) { buf_used = ss7_snprintf(buf, buf_used, buf_size, "%s(%li) ", isup_timer2str(x), ss7->ss7_sched[c->timer[x]].when.tv_sec - time(NULL)); } } cust_printf(fd, "%s\n", buf); c = c->next; } free(buf); free(tmp_buf); } int ss7_set_isup_timer(struct ss7 *ss7, char *name, int ms) { if (!strcasecmp(name, "t1")) { ss7->isup_timers[ISUP_TIMER_T1] = ms; } else if (!strcasecmp(name, "t2")) { ss7->isup_timers[ISUP_TIMER_T2] = ms; } else if (!strcasecmp(name, "t5")) { ss7->isup_timers[ISUP_TIMER_T5] = ms; } else if (!strcasecmp(name, "t6")) { ss7->isup_timers[ISUP_TIMER_T6] = ms; } else if (!strcasecmp(name, "t7")) { ss7->isup_timers[ISUP_TIMER_T7] = ms; } else if (!strcasecmp(name, "t8")) { ss7->isup_timers[ISUP_TIMER_T8] = ms; } else if (!strcasecmp(name, "t10")) { ss7->isup_timers[ISUP_TIMER_T10] = ms; } else if (!strcasecmp(name, "t12")) { ss7->isup_timers[ISUP_TIMER_T12] = ms; } else if (!strcasecmp(name, "t13")) { ss7->isup_timers[ISUP_TIMER_T13] = ms; } else if (!strcasecmp(name, "t14")) { ss7->isup_timers[ISUP_TIMER_T14] = ms; } else if (!strcasecmp(name, "t15")) { ss7->isup_timers[ISUP_TIMER_T15] = ms; } else if (!strcasecmp(name, "t16")) { ss7->isup_timers[ISUP_TIMER_T16] = ms; } else if (!strcasecmp(name, "t17")) { ss7->isup_timers[ISUP_TIMER_T17] = ms; } else if (!strcasecmp(name, "t18")) { ss7->isup_timers[ISUP_TIMER_T18] = ms; } else if (!strcasecmp(name, "t19")) { ss7->isup_timers[ISUP_TIMER_T19] = ms; } else if (!strcasecmp(name, "t20")) { ss7->isup_timers[ISUP_TIMER_T20] = ms; } else if (!strcasecmp(name, "t21")) { ss7->isup_timers[ISUP_TIMER_T21] = ms; } else if (!strcasecmp(name, "t22")) { ss7->isup_timers[ISUP_TIMER_T22] = ms; } else if (!strcasecmp(name, "t23")) { ss7->isup_timers[ISUP_TIMER_T23] = ms; } else if (!strcasecmp(name, "t27")) { ss7->isup_timers[ISUP_TIMER_T27] = ms; } else if (!strcasecmp(name, "t33")) { ss7->isup_timers[ISUP_TIMER_T33] = ms; } else if (!strcasecmp(name, "t35")) { ss7->isup_timers[ISUP_TIMER_T35] = ms; } else { ss7_message(ss7, "Unknown ISUP timer: %s\n", name); return 0; } ss7_message(ss7, "ISUP timer %s = %ims\n", name, ms); return 1; } static void isup_timer_expiry(void *data) { struct isup_timer_param *param = data; int x; ss7_event *e; if (param->timer == ISUP_TIMER_T5 || param->timer == ISUP_TIMER_T13 || param->timer == ISUP_TIMER_T15 || param->timer == ISUP_TIMER_T17 || param->timer == ISUP_TIMER_T19 || param->timer == ISUP_TIMER_T21 || param->timer == ISUP_TIMER_T22) { ss7_error(param->ss7, "ISUP timer %s expired on CIC %i DPC %i\n", isup_timer2str(param->timer), param->c->cic, param->c->dpc); } else { ss7_debug_msg(param->ss7, SS7_DEBUG_ISUP, "ISUP timer %s expired on CIC %i DPC %i\n", isup_timer2str(param->timer), param->c->cic, param->c->dpc); } param->c->timer[param->timer] = -1; switch (param->timer) { case ISUP_TIMER_T1: isup_send_message(param->ss7, param->c, ISUP_REL, rel_params); isup_start_timer(param->ss7, param->c, ISUP_TIMER_T1); break; case ISUP_TIMER_T16: param->c->got_sent_msg |= ISUP_SENT_RSC; isup_send_message(param->ss7, param->c, ISUP_RSC, empty_params); isup_start_timer(param->ss7, param->c, ISUP_TIMER_T16); break; case ISUP_TIMER_T2: case ISUP_TIMER_T6: ss7_hangup(param->ss7, param->c->cic, param->c->dpc, 16, SS7_HANGUP_SEND_REL); break; case ISUP_TIMER_T7: ss7_hangup(param->ss7, param->c->cic, param->c->dpc, 31, SS7_HANGUP_SEND_REL); break; case ISUP_TIMER_T8: isup_rel(param->ss7, param->c, 41); /* Q.764 2.1.8 */ break; case ISUP_TIMER_T5: ss7_notinservice(param->ss7, param->c->cic, param->c->dpc); /* no break here */ case ISUP_TIMER_T17: isup_stop_all_timers(param->ss7, param->c); param->c->got_sent_msg |= ISUP_SENT_RSC; isup_send_message(param->ss7, param->c, ISUP_RSC, empty_params); isup_start_timer(param->ss7, param->c, ISUP_TIMER_T17); break; case ISUP_TIMER_T10: e = ss7_next_empty_event(param->ss7); if (!e) { ss7_call_null(param->ss7, param->c, 1); isup_free_call(param->ss7, param->c); break; } e->e = ISUP_EVENT_DIGITTIMEOUT; e->digittimeout.cic = param->c->cic; e->digittimeout.call = param->c; e->digittimeout.opc = param->c->dpc; e->digittimeout.cot_check_required = param->c->cot_check_required; e->digittimeout.cot_performed_on_previous_cic = param->c->cot_performed_on_previous_cic; e->digittimeout.cot_check_passed = param->c->cot_check_passed; break; case ISUP_TIMER_T12: isup_send_message(param->ss7, param->c, ISUP_BLO, empty_params); isup_start_timer(param->ss7, param->c, ISUP_TIMER_T12); break; case ISUP_TIMER_T13: isup_stop_timer(param->ss7, param->c, ISUP_TIMER_T12); isup_send_message(param->ss7, param->c, ISUP_BLO, empty_params); isup_start_timer(param->ss7, param->c, ISUP_TIMER_T13); break; case ISUP_TIMER_T14: isup_send_message(param->ss7, param->c, ISUP_UBL, empty_params); isup_start_timer(param->ss7, param->c, ISUP_TIMER_T14); break; case ISUP_TIMER_T15: isup_stop_timer(param->ss7, param->c, ISUP_TIMER_T14); isup_send_message(param->ss7, param->c, ISUP_UBL, empty_params); isup_start_timer(param->ss7, param->c, ISUP_TIMER_T15); break; case ISUP_TIMER_T19: isup_stop_timer(param->ss7, param->c, ISUP_TIMER_T18); isup_start_timer(param->ss7, param->c, ISUP_TIMER_T19); /* no break here */ case ISUP_TIMER_T18: if (param->timer != ISUP_TIMER_T19) { isup_start_timer(param->ss7, param->c, ISUP_TIMER_T18); } param->c->range = param->c->sent_cgb_endcic - param->c->cic; param->c->cicgroupsupervisiontype = param->c->sent_cgb_type; for (x = 0; (x + param->c->cic) <= param->c->sent_cgb_endcic; x++) { param->c->status[x] = param->c->sent_cgb_status[x]; } isup_send_message(param->ss7, param->c, ISUP_CGB, cicgroup_params); break; case ISUP_TIMER_T21: isup_stop_timer(param->ss7, param->c, ISUP_TIMER_T20); isup_start_timer(param->ss7, param->c, ISUP_TIMER_T21); /* no break here */ case ISUP_TIMER_T20: if (param->timer != ISUP_TIMER_T21) { isup_start_timer(param->ss7, param->c, ISUP_TIMER_T20); } param->c->range = param->c->sent_cgu_endcic - param->c->cic; param->c->cicgroupsupervisiontype = param->c->sent_cgu_type; for (x = 0; (x + param->c->cic) <= param->c->sent_cgu_endcic; x++) { param->c->status[x] = param->c->sent_cgu_status[x]; } isup_send_message(param->ss7, param->c, ISUP_CGU, cicgroup_params); case ISUP_TIMER_T23: isup_stop_timer(param->ss7, param->c, ISUP_TIMER_T22); isup_start_timer(param->ss7, param->c, ISUP_TIMER_T23); /* no break here */ case ISUP_TIMER_T22: if (param->timer != ISUP_TIMER_T23) { isup_start_timer(param->ss7, param->c, ISUP_TIMER_T22); } param->c->range = param->c->sent_grs_endcic - param->c->cic; isup_send_message(param->ss7, param->c, ISUP_GRS, greset_params); break; case ISUP_TIMER_T27: isup_rsc(param->ss7, param->c); break; case ISUP_TIMER_T33: param->c->got_sent_msg &= ~ISUP_SENT_INR; isup_rel(param->ss7, param->c, 16); break; case ISUP_TIMER_T35: isup_rel(param->ss7, param->c, 28); break; default: ss7_message (param->ss7, "timer expired, doing nothing\n"); } free(param); } static void isup_stop_timer(struct ss7 *ss7, struct isup_call *c, int timer) { struct isup_timer_param *param; if (!ss7 || !c) { return; } if (c->timer[timer] > -1) { param = ss7->ss7_sched[c->timer[timer]].data; ss7_schedule_del(ss7, &c->timer[timer]); free(param); c->timer[timer] = -1; ss7_debug_msg(ss7, SS7_DEBUG_ISUP, "ISUP timer %s stopped on CIC %i DPC: %i\n", isup_timer2str(timer), c->cic, c->dpc); } } static void isup_stop_all_timers(struct ss7 *ss7, struct isup_call *c) { int x; if (!ss7 || !c) { return; } for (x = 0; x < ISUP_MAX_TIMERS; x++) { if (c->timer[x] > -1) { isup_stop_timer(ss7, c, x); } } } static int isup_start_timer(struct ss7 *ss7, struct isup_call *c, int timer) { struct isup_timer_param *data; if (!ss7 || !c) { return -1; } if (!ss7->isup_timers[timer]) { return -1; } data = calloc(1, sizeof(struct isup_timer_param)); data->ss7 = ss7; data->c = c; data->timer = timer; if (c->timer[timer] > -1) { isup_stop_timer(ss7, c, timer); } c->timer[timer] = ss7_schedule_event(ss7, ss7->isup_timers[timer], &isup_timer_expiry, data); if (c->timer[timer] > -1) { ss7_debug_msg(ss7, SS7_DEBUG_ISUP, "ISUP timer %s (%ims) started on CIC %i DPC %i\n", isup_timer2str(timer), ss7->isup_timers[timer], c->cic, c->dpc); return 0; } ss7_error(ss7, "Unable to start ISUP timer %s (%ims) on CIC %i DPC %i\n", isup_timer2str(timer), ss7->isup_timers[timer], c->cic, c->dpc); free(data); return -1; } struct isup_call * isup_free_call_if_clear(struct ss7 *ss7, struct isup_call *c) { int x; if (!ss7 || !c) { return NULL; } if (c->got_sent_msg) { return c; } for (x = 0; x < ISUP_MAX_TIMERS; x++) { if (c->timer[x] > -1) { return c; } } isup_free_call(ss7, c); return NULL; } void isup_free_all_calls(struct ss7 *ss7) { while (ss7->calls) { ss7_call_null(ss7, ss7->calls, 1); isup_free_call(ss7, ss7->calls); } } void isup_clear_callflags(struct ss7 *ss7, struct isup_call *c, unsigned long flags) { if (!ss7 || !c) { return; } c->got_sent_msg &= ~flags; if (flags & ISUP_SENT_IAM) { isup_stop_timer(ss7, c, ISUP_TIMER_T7); } if (flags & ISUP_SENT_CGB) { isup_stop_timer(ss7, c, ISUP_TIMER_T18); isup_stop_timer(ss7, c, ISUP_TIMER_T19); } if (flags & ISUP_SENT_CGU) { isup_stop_timer(ss7, c, ISUP_TIMER_T20); isup_stop_timer(ss7, c, ISUP_TIMER_T21); } } int isup_start_digittimeout(struct ss7 *ss7, struct isup_call *c) { return isup_start_timer(ss7, c, ISUP_TIMER_T10); } libss7-2.0.0/libss7.h0000644000000000000000000005065712345407637013016 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 /*! * Bump this for each libss7 Application Binary Interface (ABI) * change that makes the ABI/API incompatible with previous * versions. This is expected to just be the major version of * the libss7 branches. */ #define LIBSS7_ABI_COMPATIBILITY 2 /* Internal -- MTP2 events */ #define SS7_EVENT_UP 1 /*!< SS7 link up */ #define SS7_EVENT_DOWN 2 /*!< SS7 link down */ #define MTP2_LINK_UP 3 /*!< MTP layer 2 up */ #define MTP2_LINK_DOWN 4 /*!< MTP layer 2 down */ #define ISUP_EVENT_IAM 5 /*!< Initial address */ #define ISUP_EVENT_ACM 6 /*!< Address complete */ #define ISUP_EVENT_ANM 7 /*!< Answer */ #define ISUP_EVENT_REL 8 /*!< Release */ #define ISUP_EVENT_RLC 9 /*!< Release complete */ #define ISUP_EVENT_GRS 10 /*!< Circuit group reset */ #define ISUP_EVENT_GRA 11 /*!< Circuit group reset acknowledgement */ #define ISUP_EVENT_CON 12 /*!< Connect */ #define ISUP_EVENT_COT 13 /*!< Continuity */ #define ISUP_EVENT_CCR 14 /*!< Continuity check request */ #define ISUP_EVENT_BLO 15 /*!< Blocking */ #define ISUP_EVENT_UBL 16 /*!< Unblocking */ #define ISUP_EVENT_BLA 17 /*!< Blocking acknowledgement */ #define ISUP_EVENT_UBA 18 /*!< Unblocking acknowledgement */ #define ISUP_EVENT_CGB 19 /*!< Circuit group blocking */ #define ISUP_EVENT_CGU 20 /*!< Circuit group unblocking */ #define ISUP_EVENT_RSC 21 /*!< Reset circuit */ #define ISUP_EVENT_CPG 22 /*!< Call progress */ #define ISUP_EVENT_UCIC 23 /*!< Unequipped CIC (national use) */ #define ISUP_EVENT_LPA 24 /*!< Loop back acknowledgement (national use) */ #define ISUP_EVENT_CQM 25 /*!< Circuit group query (national use) */ #define ISUP_EVENT_FAR 26 /*!< Facility request */ #define ISUP_EVENT_FAA 27 /*!< Facility accepted */ #define ISUP_EVENT_CVT 28 /*!< ???Used??? */ #define ISUP_EVENT_CVR 29 /*!< Not used */ #define ISUP_EVENT_SUS 30 /*!< Suspend */ #define ISUP_EVENT_RES 31 /*!< Resume */ #define ISUP_EVENT_CGBA 32 /*!< Circuit group blocking acknowledgement */ #define ISUP_EVENT_CGUA 33 /*!< Circuit group unblocking acknowledgement */ #define ISUP_EVENT_SAM 34 /*!< Subsequent address */ #define ISUP_EVENT_DIGITTIMEOUT 35 /*!< ISUP T10 expired */ #define ISUP_EVENT_FRJ 36 /*!< Facility rejected */ /* ISUP MSG Flags */ #define ISUP_SENT_GRS (1 << 0) #define ISUP_SENT_CGB (1 << 1) #define ISUP_SENT_CGU (1 << 2) #define ISUP_SENT_RSC (1 << 3) #define ISUP_SENT_REL (1 << 4) #define ISUP_SENT_BLO (1 << 5) #define ISUP_SENT_UBL (1 << 6) #define ISUP_SENT_IAM (1 << 7) #define ISUP_SENT_FAR (1 << 8) #define ISUP_GOT_CCR (1 << 9) #define ISUP_GOT_IAM (1 << 10) #define ISUP_GOT_ACM (1 << 11) #define ISUP_GOT_CON (1 << 12) #define ISUP_GOT_ANM (1 << 13) #define ISUP_SENT_ACM (1 << 14) #define ISUP_GOT_CGB (1 << 15) #define ISUP_GOT_CGU (1 << 16) #define ISUP_SENT_CON (1 << 17) #define ISUP_SENT_ANM (1 << 18) #define ISUP_SENT_INR (1 << 19) #define ISUP_SENT_GRS2 (1 << 20) #define ISUP_PENDING_IAM (1 << 21) #define ISUP_CALL_CONNECTED (ISUP_GOT_ACM | ISUP_GOT_ANM | ISUP_GOT_CON | ISUP_SENT_CON | ISUP_SENT_ACM | ISUP_SENT_ANM) #define ISUP_CALL_PENDING (ISUP_GOT_IAM | ISUP_SENT_IAM | ISUP_PENDING_IAM | ISUP_GOT_CCR | ISUP_SENT_INR | ISUP_SENT_FAR) /* 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 #define SS7_NAI_NETWORKROUTED 0x08 /* 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 /* Transmission Medium Requirement */ #define SS7_TMR_SPEECH 0x00 #define SS7_TMR_SPARE 0x01 #define SS7_TMR_64K_UNRESTRICTED 0x02 #define SS7_TMR_3K1_AUDIO 0x03 #define SS7_TMR_N64K_OR_SPARE 0x04 /* 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 /* What have to do after the hangup */ #define SS7_HANGUP_DO_NOTHING 0 #define SS7_HANGUP_SEND_REL 1 #define SS7_HANGUP_SEND_RSC 2 #define SS7_HANGUP_SEND_RLC 3 #define SS7_HANGUP_FREE_CALL 4 #define SS7_HANGUP_REEVENT_IAM 5 /* Special SS7 Hangupcause */ #define SS7_CAUSE_TRY_AGAIN 256 /* return values from ss7_hangup */ #define SS7_CIC_NOT_EXISTS 0 #define SS7_CIC_USED 1 #define SS7_CIC_IDLE 2 /* Closed user group indicator */ #define ISUP_CUG_NON 0 #define ISUP_CUG_OUTGOING_ALLOWED 2 #define ISUP_CUG_OUTGOING_NOT_ALLOWED 3 /* FLAGS */ #define SS7_INR_IF_NO_CALLING (1 << 0) /* request calling num, if the remote party didn't send */ #define SS7_ISDN_ACCESS_INDICATOR (1 << 1) /* originating/access indicator */ struct ss7; struct isup_call; typedef struct { int e; int cic; int transcap; int cot_check_required; int cot_performed_on_previous_cic; 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 redirect_counter; unsigned char redirect_info; unsigned char redirect_info_ind; unsigned char redirect_info_orig_reas; unsigned char redirect_info_reas; unsigned char redirect_info_counter; unsigned char generic_name_typeofname; unsigned char generic_name_avail; unsigned char generic_name_presentation; unsigned char echocontrol_ind; char generic_name[50]; int oli_ani2; unsigned char cug_indicator; char cug_interlock_ni[5]; unsigned short cug_interlock_code; unsigned int opc; unsigned long got_sent_msg; struct isup_call *call; } ss7_event_iam; typedef struct { int e; int cic; int cause; unsigned int opc; unsigned long got_sent_msg; struct isup_call *call; } ss7_event_rel; typedef struct { int e; int cic; unsigned int opc; unsigned long got_sent_msg; struct isup_call *call; } ss7_event_cic; typedef struct { int e; int cic; unsigned int opc; unsigned long got_sent_msg; struct isup_call *call; char connected_num[50]; unsigned char connected_nai; unsigned char connected_presentation_ind; unsigned char connected_screening_ind; unsigned char echocontrol_ind; } ss7_event_con; typedef struct { int e; int cic; unsigned int opc; unsigned long got_sent_msg; struct isup_call *call; } ss7_event_rsc; typedef struct { int e; int cic; unsigned int opc; char connected_num[50]; unsigned char connected_nai; unsigned char connected_presentation_ind; unsigned char connected_screening_ind; unsigned long got_sent_msg; unsigned char echocontrol_ind; 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; unsigned long got_sent_msg; struct isup_call *call; /* Backward call indicator */ unsigned char called_party_status_ind; unsigned char echocontrol_ind; } ss7_event_acm; typedef struct { int e; int startcic; int endcic; int sent_endcic; int type; int sent_type; unsigned int opc; unsigned char status[255]; unsigned int sent_status[255]; unsigned long got_sent_msg; struct isup_call *call; } ss7_event_cicrange; typedef struct { int e; int cic; int passed; int cot_performed_on_previous_cic; unsigned int opc; unsigned long got_sent_msg; struct isup_call *call; } ss7_event_cot; typedef struct { int e; int data; } ss7_event_generic; typedef struct { int e; struct mtp2 *link; } ss7_event_link; typedef struct { int e; int cic; unsigned int opc; unsigned char event; unsigned long got_sent_msg; unsigned char echocontrol_ind; unsigned char connected_nai; unsigned char connected_presentation_ind; unsigned char connected_screening_ind; char connected_num[50]; struct isup_call *call; } 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_frj; 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 struct { int e; int cic; int network_isdn_indicator; unsigned int opc; unsigned long got_sent_msg; struct isup_call *call; } ss7_event_sus_res; typedef struct { int e; int cic; unsigned int opc; char called_party_num[50]; unsigned char called_nai; int cot_check_required; int cot_check_passed; int cot_performed_on_previous_cic; unsigned long got_sent_msg; struct isup_call *call; } ss7_event_sam; typedef struct { int e; int cic; unsigned int opc; int cot_check_required; int cot_check_passed; int cot_performed_on_previous_cic; struct isup_call *call; } ss7_event_digittimeout; typedef union { int e; ss7_event_generic gen; ss7_event_link link; 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_cic rlc; ss7_event_anm anm; ss7_event_acm acm; ss7_event_frj frj; ss7_event_faa faa; ss7_event_far far; ss7_event_con con; ss7_event_cot cot; ss7_event_cic ccr; ss7_event_cic cvt; ss7_event_cic blo; ss7_event_cic ubl; ss7_event_cic bla; ss7_event_cic uba; ss7_event_cic ucic; ss7_event_rsc rsc; ss7_event_cpg cpg; ss7_event_sus_res sus; ss7_event_sus_res res; ss7_event_cic lpa; ss7_event_sam sam; ss7_event_digittimeout digittimeout; } 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); void ss7_set_notinservice(void (*func)(struct ss7 *ss7, int cic, unsigned int dpc)); void ss7_set_hangup(int (*func)(struct ss7 *ss7, int cic, unsigned int dpc, int cause, int do_hangup)); void ss7_set_call_null(void (*func)(struct ss7 *ss7, struct isup_call *c, int lock)); /* 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 slc, unsigned int adjpc); 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); void ss7_destroy(struct ss7 *ss7); void ss7_set_cause_location(struct ss7 *ss7, unsigned char location); void ss7_set_sls_shift(struct ss7 *ss7, unsigned char shift); void ss7_set_flags(struct ss7 *ss7, unsigned int flags); void ss7_clear_flags(struct ss7 *ss7, unsigned int flags); 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); int ss7_set_mtp3_timer(struct ss7 *ss7, char *name, int ms); /* ISUP call related message functions */ int ss7_set_isup_timer(struct ss7 *ss7, char *name, int ms); struct isup_call * isup_free_call_if_clear(struct ss7 *ss7, struct isup_call *c); int isup_start_digittimeout(struct ss7 *ss7, struct isup_call *c); /* Send an IAM */ int isup_iam(struct ss7 *ss7, struct isup_call *c); int isup_inr(struct ss7 *ss7, struct isup_call *c, unsigned char ind0, unsigned char ind1); int isup_inf(struct ss7 *ss7, struct isup_call *c, unsigned char ind0, unsigned char ind1); 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 cic, unsigned int dpc, int outgoing); int isup_acm(struct ss7 *ss7, struct isup_call *c); int isup_frj(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_sus(struct ss7 *ss7, struct isup_call *c, unsigned char indicator); int isup_res(struct ss7 *ss7, struct isup_call *c, unsigned char indicator); 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, struct isup_call *c, int endcic, unsigned char state[]); int isup_grs(struct ss7 *ss7, struct isup_call *c, int endcic); int isup_cgb(struct ss7 *ss7, struct isup_call *c, int endcic, unsigned char state[], int type); int isup_cgu(struct ss7 *ss7, struct isup_call *c, int endcic, unsigned char state[], int type); int isup_cgba(struct ss7 *ss7, struct isup_call *c, int endcic, unsigned char state[]); int isup_cgua(struct ss7 *ss7, struct isup_call *c, int endcic, unsigned char state[]); int isup_blo(struct ss7 *ss7, struct isup_call *c); int isup_ubl(struct ss7 *ss7, struct isup_call *c); /* int isup_ccr(struct ss7 *ss7, int cic, unsigned int dpc); FIXME Not Implemented ! */ int isup_bla(struct ss7 *ss7, struct isup_call *c); int isup_ucic(struct ss7 *ss7, int cic, unsigned int dpc); int isup_uba(struct ss7 *ss7, struct isup_call *c); int isup_rsc(struct ss7 *ss7, struct isup_call *c); 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[]); int isup_event_iam(struct ss7 *ss7, struct isup_call *c, int opc); void isup_clear_callflags(struct ss7 *ss7, struct isup_call *c, unsigned long flags); /* Various call related sets */ void isup_free_call(struct ss7 *ss7, struct isup_call *c); 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_connected(struct isup_call *c, const char *connected, unsigned char connected_nai, unsigned char connected_presentation_ind, unsigned char connected_screening_ind); void isup_set_redirecting_number(struct isup_call *c, const char *redirecting_number, unsigned char redirecting_num_nai, unsigned char redirecting_num_presentation_ind, unsigned char redirecting_num_screening_ind); void isup_set_redirection_info(struct isup_call *c, unsigned char redirect_info_ind, unsigned char redirect_info_orig_reas, unsigned char redirect_info_counter, unsigned char redirect_info_reas); void isup_set_redirect_counter(struct isup_call *c, unsigned char redirect_counter); void isup_set_orig_called_num(struct isup_call *c, const char *orig_called_num, unsigned char orig_called_nai, unsigned char orig_called_pres_ind, unsigned char orig_called_screening_ind); void isup_set_tmr(struct isup_call *c, int tmr); 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); void isup_set_col_req(struct isup_call *c); void isup_set_cug(struct isup_call *c, unsigned char cug_indicator, const char *cug_interlock_ni, unsigned short cug_interlock_code); void isup_set_interworking_indicator(struct isup_call *c, unsigned char interworking_indicator); void isup_set_forward_indicator_pmbits(struct isup_call *c, unsigned char pmbits); void isup_set_echocontrol(struct isup_call *c, unsigned char ec); 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); void isup_set_calling_party_category(struct isup_call *c, unsigned int category); /* End of call related sets */ typedef void (*ss7_printf_cb)(int fd, const char *fmt, ...) __attribute__((format(printf, 2, 3))); void isup_show_calls(struct ss7 *ss7, ss7_printf_cb cust_printf, int fd); void ss7_show_linkset(struct ss7 *ss7, ss7_printf_cb cust_printf, int fd); /* net mng */ const char * mtp3_net_mng(struct ss7 *ss7, unsigned int slc, const char *cmd, unsigned int param); void mtp3_init_restart(struct ss7 *ss7, int slc); int ss7_set_mtp3_timer(struct ss7 *ss7, char *name, int ms); void ss7_pc_to_str(int ss7type, unsigned int pc, char *str); #endif /* _LIBSS7_H */ libss7-2.0.0/build_tools/0000755000000000000000000000000012347606620013737 5ustar rootrootlibss7-2.0.0/build_tools/make_version_c0000755000000000000000000000055612010747414016651 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-2.0.0/build_tools/make_version0000755000000000000000000000262012010747414016341 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-2.0.0/libss7-2.0.0-summary.html0000644000000000000000000001632012347606614015644 0ustar rootroot Release Summary - libss7-2.0.0

Release Summary

libss7-2.0.0

Date: 2014-06-16

<asteriskteam@digium.com>


Table of Contents

  1. Summary
  2. Contributors
  3. Closed Issues
  4. Other Changes
  5. Diffstat

Summary

[Back to Top]

This release includes new features. For a list of new features that have been included with this release, please see the CHANGES file inside the source package. Since this is new major release, users are encouraged to do extended testing before upgrading to this version in a production environment.

The data in this summary reflects changes that have been made since the previous release, libss7-1.0.


Contributors

[Back to Top]

This table lists the people who have submitted code, those that have tested patches, as well as those that reported issues on the issue tracker that were resolved in this release. For coders, the number is how many of their patches (of any size) were committed into this release. For testers, the number is the number of times their name was listed as assisting with testing a patch. Finally, for reporters, the number is the number of issues that they reported that were closed by commits that went into this release.

Coders

Testers

Reporters

11 rmudgett
1 tzafrir

Closed Issues

[Back to Top]

This is a list of all issues from the issue tracker that were closed by changes that went into this release.

Category: General


SS7-54: libss7 and gcc 4.6: 'set but not used' variables
Revision: 322
Reporter: tzafrir
Coders: rmudgett


Commits Not Associated with an Issue

[Back to Top]

This is a list of all changes that went into this release that did not directly close an issue from the issue tracker. The commits may have been marked as being related to an issue. If that is the case, the issue numbers are listed here, as well.

RevisionAuthorSummaryIssues Referenced
309rmudgettRestore trunk for further use.
311rmudgettReset trunk to current v1.0 branch.
312rmudgettOmnibus libss7 update. SS7-27, SS7-7, SS7-21, SS7-28, SS7-33, SS7-36, SS7-38, SS7-39, SS7-40, SS7-42, SS7-43, SS7-45, SS7-46, SS7-47, SS7-48, SS7-49, SS7-51, SS7-52, SS7-53, SS7-54
314rmudgettAdded ABI compatibility define.
315rmudgettDon't kill the call if isup_far() chooses to not send the message.
316rmudgettFix ANSI double send of GRS causing message loop. SS7-27
317rmudgettChange isup_start_digittimeout() to return if the timer started.
319rmudgettAllow passing compiler flags (CFLAGS, LDFLAGS)
320rmudgettQuiet unconditional libss7 debug messages unless enabled.
323rmudgettlibss7: Dual seizure improvements.

Diffstat Results

[Back to Top]

This is a summary of the changes to the source code that went into this release that was generated using the diffstat utility.

Makefile       |  195 ++-
README         |    6
isup.c         | 3311 +++++++++++++++++++++++++++++++++++++++++++++++----------
isup.h         |  339 ++++-
libss7.h       |  404 +++++-
mtp2.c         |  235 ++--
mtp2.h         |   72 -
mtp3.c         | 1811 ++++++++++++++++++++++++++++---
mtp3.h         |  139 ++
parser_debug.c |   16
ss7.c          |  487 ++++++--
ss7_internal.h |   63 -
ss7linktest.c  |   66 -
ss7test.c      |   37
14 files changed, 6009 insertions(+), 1172 deletions(-)