[asterisk-commits] file: branch file/earlybridge r43433 - in /team/file/earlybridge: ./ apps/ bu...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Thu Sep 21 12:12:04 MST 2006


Author: file
Date: Thu Sep 21 14:12:03 2006
New Revision: 43433

URL: http://svn.digium.com/view/asterisk?rev=43433&view=rev
Log:
Merged revisions 43403,43406,43411-43412,43423,43427-43429 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/trunk

................
r43403 | kpfleming | 2006-09-21 12:00:51 -0400 (Thu, 21 Sep 2006) | 2 lines

remove extraneous property

................
r43406 | kpfleming | 2006-09-21 12:09:31 -0400 (Thu, 21 Sep 2006) | 10 lines

Merged revisions 43405 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/branches/1.4

........
r43405 | kpfleming | 2006-09-21 11:08:03 -0500 (Thu, 21 Sep 2006) | 2 lines

remove this change... it requires binutils 2.17

........

................
r43411 | tilghman | 2006-09-21 12:38:16 -0400 (Thu, 21 Sep 2006) | 18 lines

Merged revisions 43410 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/branches/1.4

................
r43410 | tilghman | 2006-09-21 11:31:59 -0500 (Thu, 21 Sep 2006) | 10 lines

Merged revisions 43409 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/branches/1.2

........
r43409 | tilghman | 2006-09-21 11:18:19 -0500 (Thu, 21 Sep 2006) | 2 lines

TDS 0.64 updates

........

................

................
r43412 | tilghman | 2006-09-21 12:43:27 -0400 (Thu, 21 Sep 2006) | 2 lines

Last merge should not have brought in the 1.2 props

................
r43423 | tilghman | 2006-09-21 13:06:43 -0400 (Thu, 21 Sep 2006) | 18 lines

Merged revisions 43422 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/branches/1.4

................
r43422 | tilghman | 2006-09-21 12:04:40 -0500 (Thu, 21 Sep 2006) | 10 lines

Merged revisions 43420 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/branches/1.2

........
r43420 | tilghman | 2006-09-21 12:01:48 -0500 (Thu, 21 Sep 2006) | 2 lines

Whitespace change... really just an excuse to test repotools

........

................

................
r43427 | mattf | 2006-09-21 14:41:33 -0400 (Thu, 21 Sep 2006) | 2 lines

Merge in SS7 changes.... need to still cleanup zapata.conf

................
r43428 | mattf | 2006-09-21 14:42:57 -0400 (Thu, 21 Sep 2006) | 2 lines

Update configure

................
r43429 | pcadach | 2006-09-21 14:48:53 -0400 (Thu, 21 Sep 2006) | 1 line

Introduce Cisco G.726-32 capability (g726aal2 form)
................

Modified:
    team/file/earlybridge/   (props changed)
    team/file/earlybridge/apps/app_rpt.c
    team/file/earlybridge/build_tools/menuselect-deps.in
    team/file/earlybridge/cdr/cdr_tds.c
    team/file/earlybridge/channels/chan_h323.c
    team/file/earlybridge/channels/chan_zap.c
    team/file/earlybridge/channels/h323/ast_h323.cxx
    team/file/earlybridge/channels/h323/caps_h323.cxx
    team/file/earlybridge/channels/h323/caps_h323.h
    team/file/earlybridge/configs/zapata.conf.sample
    team/file/earlybridge/configure
    team/file/earlybridge/configure.ac
    team/file/earlybridge/include/asterisk/autoconfig.h.in
    team/file/earlybridge/main/Makefile
    team/file/earlybridge/makeopts.in

Propchange: team/file/earlybridge/
------------------------------------------------------------------------------
--- branch-1.4-merged (original)
+++ branch-1.4-merged Thu Sep 21 14:12:03 2006
@@ -1,1 +1,1 @@
-/branches/1.4:1-43376,43383,43386,43388,43392,43396
+/branches/1.4:1-43376,43383,43386,43388,43392,43396,43405,43410,43422

Propchange: team/file/earlybridge/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Thu Sep 21 14:12:03 2006
@@ -1,1 +1,1 @@
-/trunk:1-43397
+/trunk:1-43431

Modified: team/file/earlybridge/apps/app_rpt.c
URL: http://svn.digium.com/view/asterisk/team/file/earlybridge/apps/app_rpt.c?rev=43433&r1=43432&r2=43433&view=diff
==============================================================================
--- team/file/earlybridge/apps/app_rpt.c (original)
+++ team/file/earlybridge/apps/app_rpt.c Thu Sep 21 14:12:03 2006
@@ -1882,55 +1882,54 @@
 
 static int get_wait_interval(struct rpt *myrpt, int type)
 {
-        int interval;
-        const char *wait_times;
-        char *wait_times_save;
-                                                                                                                  
-        wait_times_save = NULL;
-        wait_times = ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
-                                                                                                                  
-        if(wait_times){
-                wait_times_save = ast_strdupa(wait_times);
-                if(!wait_times_save){
-                        ast_log(LOG_WARNING, "Out of memory in wait_interval()\n");
-                        wait_times = NULL;
-                }
-        }
-                                                                                                                  
-        switch(type){
-                case DLY_TELEM:
-                        if(wait_times)
-                                interval = retrieve_astcfgint(myrpt,wait_times_save, "telemwait", 500, 5000, 1000);
-                        else
-                                interval = 1000;
-                        break;
-                                                                                                                  
-                case DLY_ID:
-                        if(wait_times)
-                                interval = retrieve_astcfgint(myrpt,wait_times_save, "idwait",250,5000,500);
-                        else
-                                interval = 500;
-                        break;
-                                                                                                                  
-                case DLY_UNKEY:
-                        if(wait_times)
-                                interval = retrieve_astcfgint(myrpt,wait_times_save, "unkeywait",500,5000,1000);
-                        else
-                                interval = 1000;
-                        break;
-                                                                                                                  
-                case DLY_CALLTERM:
-                        if(wait_times)
-                                interval = retrieve_astcfgint(myrpt,wait_times_save, "calltermwait",500,5000,1500);
-                        else
-                                interval = 1500;
-                        break;
-                                                                                                                  
-                default:
-                        return 0;
-        }
+	int interval;
+	const char *wait_times;
+	char *wait_times_save = NULL;
+
+	wait_times = ast_variable_retrieve(cfg, myrpt->name, "wait_times");
+
+	if (wait_times) {
+		wait_times_save = ast_strdupa(wait_times);
+		if (!wait_times_save) {
+			ast_log(LOG_WARNING, "Out of memory in wait_interval()\n");
+			wait_times = NULL;
+		}
+	}
+
+	switch (type) {
+	case DLY_TELEM:
+		if (wait_times)
+			interval = retrieve_astcfgint(wait_times_save, "telemwait", 500, 5000, 1000);
+		else
+			interval = 1000;
+		break;
+
+	case DLY_ID:
+		if (wait_times)
+			interval = retrieve_astcfgint(wait_times_save, "idwait", 250, 5000, 500);
+		else
+			interval = 500;
+		break;
+
+	case DLY_UNKEY:
+		if (wait_times)
+			interval = retrieve_astcfgint(wait_times_save, "unkeywait", 500, 5000, 1000);
+		else
+			interval = 1000;
+		break;
+
+	case DLY_CALLTERM:
+		if (wait_times)
+			interval = retrieve_astcfgint(wait_times_save, "calltermwait", 500, 5000, 1500);
+		else
+			interval = 1500;
+		break;
+
+	default:
+		return 0;
+	}
 	return interval;
-}                                                                                                                  
+}														  
 
 
 /*

Modified: team/file/earlybridge/build_tools/menuselect-deps.in
URL: http://svn.digium.com/view/asterisk/team/file/earlybridge/build_tools/menuselect-deps.in?rev=43433&r1=43432&r2=43433&view=diff
==============================================================================
--- team/file/earlybridge/build_tools/menuselect-deps.in (original)
+++ team/file/earlybridge/build_tools/menuselect-deps.in Thu Sep 21 14:12:03 2006
@@ -18,6 +18,7 @@
 PGSQL=@PBX_PGSQL@
 POPT=@PBX_POPT@
 PRI=@PBX_PRI@
+SS7=@PBX_SS7@
 QT=@PBX_QT@
 RADIUS=@PBX_RADIUS@
 SPEEX=@PBX_SPEEX@

Modified: team/file/earlybridge/cdr/cdr_tds.c
URL: http://svn.digium.com/view/asterisk/team/file/earlybridge/cdr/cdr_tds.c?rev=43433&r1=43432&r2=43433&view=diff
==============================================================================
--- team/file/earlybridge/cdr/cdr_tds.c (original)
+++ team/file/earlybridge/cdr/cdr_tds.c Thu Sep 21 14:12:03 2006
@@ -320,7 +320,7 @@
 
 static int mssql_connect(void)
 {
-#ifdef FREETDS_0_63
+#if (defined(FREETDS_0_63) || defined(FREETDS_0_64))
 	TDSCONNECTION *connection = NULL;
 #else
 	TDSCONNECTINFO *connection = NULL;
@@ -346,7 +346,11 @@
 	tds_set_packet(login, 512);
 	tds_set_version(login, 7, 0);
 
+#ifdef FREETDS_0_64
+	if (!(context = tds_alloc_context(NULL)))
+#else
 	if (!(context = tds_alloc_context()))
+#endif
 	{
 		ast_log(LOG_ERROR, "tds_alloc_context() failed.\n");
 		goto connect_fail;
@@ -369,7 +373,7 @@
 	{
 		ast_log(LOG_ERROR, "Failed to connect to MSSQL server.\n");
 		tds = NULL;	/* freed by tds_connect() on error */
-#ifdef FREETDS_0_63
+#if (defined(FREETDS_0_63) || defined(FREETDS_0_64))
 		tds_free_connection(connection);
 #else
 		tds_free_connect(connection);
@@ -377,7 +381,7 @@
 		connection = NULL;
 		goto connect_fail;
 	}
-#ifdef FREETDS_0_63
+#if (defined(FREETDS_0_63) || defined(FREETDS_0_64))
 	tds_free_connection(connection);
 #else
 	tds_free_connect(connection);

Modified: team/file/earlybridge/channels/chan_h323.c
URL: http://svn.digium.com/view/asterisk/team/file/earlybridge/channels/chan_h323.c?rev=43433&r1=43432&r2=43433&view=diff
==============================================================================
--- team/file/earlybridge/channels/chan_h323.c (original)
+++ team/file/earlybridge/channels/chan_h323.c Thu Sep 21 14:12:03 2006
@@ -137,7 +137,7 @@
 static char default_context[AST_MAX_CONTEXT] = "default";
 static struct sockaddr_in bindaddr;
 
-#define GLOBAL_CAPABILITY (AST_FORMAT_G723_1 | AST_FORMAT_GSM | AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_G729A | AST_FORMAT_H261)
+#define GLOBAL_CAPABILITY (AST_FORMAT_G723_1 | AST_FORMAT_GSM | AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_G729A | AST_FORMAT_G726_AAL2 | AST_FORMAT_H261)
 
 /** H.323 configuration values */
 static int h323_signalling_port = 1720;
@@ -1902,6 +1902,10 @@
 	if (!pvt->rtp)
 		__oh323_rtp_create(pvt);
 
+	if ((pt == 2) && (pvt->jointcapability & AST_FORMAT_G726_AAL2)) {
+		ast_rtp_set_rtpmap_type(pvt->rtp, pt, "audio", "G726-32", AST_RTP_OPT_G726_NONSTANDARD);
+	}
+
 	them.sin_family = AF_INET;
 	/* only works for IPv4 */
 	them.sin_addr.s_addr = inet_addr(remoteIp);

Modified: team/file/earlybridge/channels/chan_zap.c
URL: http://svn.digium.com/view/asterisk/team/file/earlybridge/channels/chan_zap.c?rev=43433&r1=43432&r2=43433&view=diff
==============================================================================
--- team/file/earlybridge/channels/chan_zap.c (original)
+++ team/file/earlybridge/channels/chan_zap.c Thu Sep 21 14:12:03 2006
@@ -41,6 +41,7 @@
 	<depend>zaptel</depend>
 	<depend>tonezone</depend>
 	<use>pri</use>
+	<use>ss7</use>
  ***/
 
 #include "asterisk.h"
@@ -69,6 +70,10 @@
 
 #ifdef HAVE_PRI
 #include <libpri.h>
+#endif
+
+#ifdef HAVE_SS7
+#include <libss7.h>
 #endif
 
 #include "asterisk/lock.h"
@@ -158,6 +163,9 @@
 #ifdef HAVE_PRI
                " w/PRI"
 #endif
+#ifdef HAVEL_LIBSS7
+	       "w/SS7"
+#endif
 ;
 
 static const char config[] = "zapata.conf";
@@ -178,6 +186,7 @@
 #define SIG_FXOGS	ZT_SIG_FXOGS
 #define SIG_FXOKS	ZT_SIG_FXOKS
 #define SIG_PRI		ZT_SIG_CLEAR
+#define SIG_SS7		(0x1000000 | ZT_SIG_CLEAR)
 #define	SIG_SF		ZT_SIG_SF
 #define SIG_SFWINK 	(0x0100000 | ZT_SIG_SF)
 #define SIG_SF_FEATD	(0x0200000 | ZT_SIG_SF)
@@ -401,6 +410,36 @@
 struct zt_pvt;
 
 static int ringt_base = DEFAULT_RINGT;
+
+#ifdef HAVE_SS7
+
+#define LINKSTATE_INALARM	(1 << 0)
+#define LINKSTATE_STARTING	(1 << 1)
+#define LINKSTATE_UP		(1 << 2)
+#define LINKSTATE_DOWN		(1 << 3)
+
+struct zt_ss7 {
+	pthread_t master;						/*!< Thread of master */
+	ast_mutex_t lock;
+	int fds[NUM_DCHANS];
+	int numsigchans;
+	int linkstate[NUM_DCHANS];
+	int numchans;
+	int type;
+	struct ss7 *ss7;
+	struct zt_pvt *pvts[MAX_CHANNELS];				/*!< Member channel pvt structs */
+};
+
+static struct zt_ss7 linksets[NUM_SPANS];
+
+static int cur_ss7type = -1;
+static int cur_linkset = -1;
+static int cur_pointcode = -1;
+static int cur_cicbeginswith = -1;
+static int cur_adjpointcode = -1;
+static int cur_networkindicator = -1;
+static int cur_defaultdpc = -1;
+#endif /* HAVE_SS7 */
 
 #ifdef HAVE_PRI
 
@@ -604,6 +643,9 @@
 	unsigned int progress:1;
 	unsigned int resetting:1;
 	unsigned int setup_ack:1;
+#endif
+#if defined(HAVE_SS7)
+	unsigned int blocked:1;
 #endif
 	unsigned int use_smdi:1;		/* Whether to use SMDI on this channel */
 	struct ast_smdi_interface *smdi_iface;	/* The serial port to listen for SMDI data on */
@@ -691,6 +733,12 @@
 #endif	
 	int polarity;
 	int dsp_features;
+#ifdef HAVE_SS7
+	struct zt_ss7 *ss7;
+	struct isup_call *ss7call;
+	int transcap;
+	int cic;							/*!< CIC associated with channel */
+#endif
 	char begindigit;
 } *iflist = NULL, *ifend = NULL;
 
@@ -758,6 +806,30 @@
 }
 #endif
 
+#ifdef HAVE_SS7
+static inline void ss7_rel(struct zt_ss7 *ss7)
+{
+	ast_mutex_unlock(&ss7->lock);
+}
+
+static inline int ss7_grab(struct zt_pvt *pvt, struct zt_ss7 *pri)
+{
+	int res;
+	/* Grab the lock first */
+	do {
+		res = ast_mutex_trylock(&pri->lock);
+		if (res) {
+			ast_mutex_unlock(&pvt->lock);
+			/* Release the lock and try again */
+			usleep(1);
+			ast_mutex_lock(&pvt->lock);
+		}
+	} while (res);
+	/* Then break the poll */
+	pthread_kill(pri->master, SIGURG);
+	return 0;
+}
+#endif
 #define NUM_CADENCE_MAX 25
 static int num_cadence = 4;
 static int user_has_defined_cadences = 0;
@@ -833,16 +905,32 @@
 #endif			
 }
 
+static void zap_queue_frame(struct zt_pvt *p, struct ast_frame *f, void *data)
+{
 #ifdef HAVE_PRI
-static void zap_queue_frame(struct zt_pvt *p, struct ast_frame *f, struct zt_pri *pri)
-#else
-static void zap_queue_frame(struct zt_pvt *p, struct ast_frame *f, void *pri)
-#endif
-{
+	struct zt_pri *pri = (struct zt_pri*) data;
+#endif
+#ifdef HAVE_SS7
+	struct zt_ss7 *ss7 = (struct zt_ss7*) data;
+#endif
 	/* We must unlock the PRI to avoid the possibility of a deadlock */
+#if defined(HAVE_PRI) || defined(HAVE_SS7)
+	if (data) {
+		switch (p->sig) {
 #ifdef HAVE_PRI
-	if (pri)
-		ast_mutex_unlock(&pri->lock);
+		case SIG_PRI:
+			ast_mutex_unlock(&pri->lock);
+			break;
+#endif
+#ifdef HAVE_SS7
+		case SIG_SS7:
+			ast_mutex_unlock(&ss7->lock);
+			break;
+#endif
+		default:
+			break;
+		}
+	}
 #endif		
 	for (;;) {
 		if (p->owner) {
@@ -858,9 +946,24 @@
 		} else
 			break;
 	}
+#if defined(HAVE_PRI) || defined(HAVE_SS7)
+	if (data) {
+		switch (p->sig) {
 #ifdef HAVE_PRI
-	if (pri)
-		ast_mutex_lock(&pri->lock);
+		case SIG_PRI:
+			ast_mutex_lock(&pri->lock);
+			break;
+#endif
+#ifdef HAVE_SS7
+		case SIG_SS7:
+			ast_mutex_lock(&ss7->lock);
+			break;
+#endif
+		default:
+			break;
+		}
+	}
+
 #endif		
 }
 
@@ -1220,6 +1323,8 @@
 		return "FXO Kewlstart";
 	case SIG_PRI:
 		return "PRI Signalling";
+	case SIG_SS7:
+		return "SS7 Signalling";
 	case SIG_SF:
 		return "SF (Tone) Signalling Immediate";
 	case SIG_SFWINK:
@@ -1443,7 +1548,7 @@
 		return;
 	}
 	if (p->echocancel) {
-		if (p->sig == SIG_PRI) {
+		if ((p->sig == SIG_PRI) || (p->sig == SIG_SS7)) {
 			x = 1;
 			res = ioctl(p->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &x);
 			if (res)
@@ -1645,7 +1750,7 @@
 {
 	int x, y, res;
 	x = muted;
-	if (p->sig == SIG_PRI) {
+	if ((p->sig == SIG_PRI) || (p->sig == SIG_SS7)) {
 		y = 1;
 		res = ioctl(p->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &y);
 		if (res)
@@ -2051,6 +2156,7 @@
 		ast_setstate(ast, AST_STATE_UP);
 		break;		
 	case SIG_PRI:
+	case SIG_SS7:
 		/* We'll get it in a moment -- but use dialdest to store pre-setup_ack digits */
 		p->dialdest[0] = '\0';
 		break;
@@ -2059,6 +2165,37 @@
 		ast_mutex_unlock(&p->lock);
 		return -1;
 	}
+#ifdef HAVE_SS7
+	if (p->ss7) {
+		c = strchr(dest, '/');
+		if (c)
+			c++;
+		else
+			c = dest;
+
+		if (!p->hidecallerid) {
+			l = ast->cid.cid_num;
+		} else {
+			l = NULL;
+		}
+
+		ss7_grab(p, p->ss7);
+		p->digital = IS_DIGITAL(ast->transfercapability);
+		p->ss7call = isup_new_call(p->ss7->ss7);
+
+		if (!p->ss7call) {
+			ss7_rel(p->ss7);
+			ast_mutex_unlock(&p->lock);
+			ast_log(LOG_ERROR, "Unable to allocate new SS7 call!\n");
+			return -1;
+		}
+
+		isup_init_call(p->ss7->ss7, p->ss7call, p->cic, c + p->stripmsd, l);
+
+		isup_iam(p->ss7->ss7, p->ss7call);
+		ss7_rel(p->ss7);
+	}
+#endif /* HAVE_SS7 */
 #ifdef HAVE_PRI
 	if (p->pri) {
 		struct pri_sr *sr;
@@ -2438,7 +2575,7 @@
 	
 	index = zt_get_index(ast, p, 1);
 
-	if (p->sig == SIG_PRI) {
+	if ((p->sig == SIG_PRI) || (p->sig == SIG_SS7)) {
 		x = 1;
 		ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
 	}
@@ -2592,6 +2729,23 @@
 		if (res < 0) 
 			ast_log(LOG_WARNING, "Unable to set law on channel %d to default\n", p->channel);
 		/* Perform low level hangup if no owner left */
+#ifdef HAVE_SS7
+		if (p->ss7) {
+			if (p->ss7call) {
+				if (!ss7_grab(p, p->ss7)) {
+					if (!p->alreadyhungup) {
+						isup_rel(p->ss7->ss7, p->ss7call, ast->hangupcause ? ast->hangupcause : -1);
+						ss7_rel(p->ss7);
+						p->alreadyhungup = 1;
+					} else
+						ast_log(LOG_WARNING, "Trying to hangup twice!\n");
+				} else {
+					ast_log(LOG_WARNING, "Unable to grab SS7 on CIC %d\n", p->cic);
+					res = -1;
+				}
+			}
+		}
+#endif
 #ifdef HAVE_PRI
 		if (p->pri) {
 #ifdef SUPPORT_USERUSER
@@ -2645,7 +2799,7 @@
 			}
 		}
 #endif
-		if (p->sig && (p->sig != SIG_PRI))
+		if (p->sig && ((p->sig != SIG_PRI) && (p->sig != SIG_SS7)))
 			res = zt_set_hook(p->subs[SUB_REAL].zfd, ZT_ONHOOK);
 		if (res < 0) {
 			ast_log(LOG_WARNING, "Unable to hangup line %s\n", ast->name);
@@ -2696,7 +2850,7 @@
 		update_conf(p);
 		reset_conf(p);
 		/* Restore data mode */
-		if (p->sig == SIG_PRI) {
+		if ((p->sig == SIG_PRI) || (p->sig == SIG_SS7)) {
 			x = 0;
 			ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
 		}
@@ -2815,6 +2969,18 @@
 			pri_rel(p->pri);
 		} else {
 			ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
+			res = -1;
+		}
+		break;
+#endif
+#ifdef HAVE_SS7
+	case SIG_SS7:
+		if (!ss7_grab(p, p->ss7)) {
+			p->proceeding = 1;
+			res = isup_anm(p->ss7->ss7, p->ss7call);
+			ss7_rel(p->ss7);
+		} else {
+			ast_log(LOG_WARNING, "Unable to grab SS7 on span %d\n", p->span);
 			res = -1;
 		}
 		break;
@@ -3746,7 +3912,7 @@
 								"Alarm: %s\r\n"
 								"Channel: %d\r\n",
 								alarm2str(res), p->channel);
-#ifdef HAVE_LIBPRI
+#ifdef HAVE_PRI
 			if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
 				/* fall through intentionally */
 			} else {
@@ -5028,7 +5194,19 @@
 				}
 				p->alerting = 1;
 			}
-#endif
+
+#endif
+#ifdef HAVE_SS7
+			if ((!p->alerting) && (p->sig == SIG_SS7) && p->ss7 && !p->outgoing && (chan->_state != AST_STATE_UP)) {
+				if (p->ss7->ss7) {
+					ss7_grab(p, p->ss7);
+					isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_ALERTING);
+					p->alerting = 1;
+					ss7_rel(p->ss7);
+				}
+			}
+#endif
+
 			res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_RINGTONE);
 			if (chan->_state != AST_STATE_UP) {
 				if ((chan->_state != AST_STATE_RING) ||
@@ -5051,6 +5229,17 @@
 						ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
 				}
 				p->proceeding = 1;
+			}
+#endif
+#ifdef HAVE_SS7
+			if (!p->proceeding && p->sig==SIG_SS7 && p->ss7 && !p->outgoing) {
+				if (p->ss7->ss7) {
+					ss7_grab(p, p->ss7);
+					isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_INBANDINFO);
+					p->proceeding = 1;
+					ss7_rel(p->ss7);
+
+				}
 			}
 #endif
 			/* don't continue in ast_indicate */
@@ -5243,7 +5432,7 @@
 				i->dsp_features = features & ~DSP_PROGRESS_TALK;
 #ifdef HAVE_PRI
 				/* We cannot do progress detection until receives PROGRESS message */
-				if (i->outgoing && (i->sig == SIG_PRI)) {
+				if (i->outgoing && ((i->sig == SIG_PRI) || (i->sig == SIG_SS7))) {
 					/* Remember requested DSP features, don't treat
 					   talking as ANSWER */
 					features = 0;
@@ -5306,7 +5495,7 @@
 #endif
 	tmp->cid.cid_pres = i->callingpres;
 	tmp->cid.cid_ton = i->cid_ton;
-#ifdef HAVE_PRI
+#if defined(HAVE_PRI) || defined(HAVE_SS7)
 	tmp->transfercapability = transfercapability;
 	pbx_builtin_setvar_helper(tmp, "TRANSFERCAPABILITY", ast_transfercapability2str(transfercapability));
 	if (transfercapability & PRI_TRANS_CAP_DIGITAL)
@@ -6664,6 +6853,7 @@
 			zt_set_hook(i->subs[SUB_REAL].zfd, ZT_ONHOOK);
 			break;
 		case SIG_PRI:
+		case SIG_SS7:
 			zt_disable_ec(i);
 			res = tone_zone_play_tone(i->subs[SUB_REAL].zfd, -1);
 			break;
@@ -7038,6 +7228,16 @@
 
 #endif
 
+#ifdef HAVE_SS7
+static struct zt_ss7 * ss7_resolve_linkset(int linkset)
+{
+	if ((linkset < 0) || (linkset >= NUM_SPANS))
+		return NULL;
+	else
+		return &linksets[linkset - 1];
+}
+#endif /* HAVE_SS7 */
+
 static struct zt_pvt *mkintf(int channel, int signalling, int outsignalling, int radio, struct zt_pri *pri, int reloading)
 {
 	/* Make a zt_pvt structure for this interface (or CRV if "pri" is specified) */
@@ -7131,6 +7331,35 @@
 					return NULL;
 				}
 			}
+#ifdef HAVE_SS7
+			if (signalling == SIG_SS7) {
+				struct zt_ss7 *ss7;
+				int clear = 0;
+				if (ioctl(tmp->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &clear)) {
+					ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
+					destroy_zt_pvt(&tmp);
+					return NULL;
+				}
+
+				ss7 = ss7_resolve_linkset(cur_linkset);
+				if (!ss7) {
+					ast_log(LOG_ERROR, "Unable to find linkset %d\n", cur_linkset);
+					destroy_zt_pvt(&tmp);
+					return NULL;
+				}
+				if (cur_cicbeginswith < 0) {
+					ast_log(LOG_ERROR, "Need to set cicbeginswith for the channels!\n");
+					destroy_zt_pvt(&tmp);
+					return NULL;
+				}
+
+				tmp->cic = cur_cicbeginswith++;
+
+				tmp->ss7 = ss7;
+				tmp->ss7call = NULL;
+				ss7->pvts[ss7->numchans++] = tmp;
+			}
+#endif
 #ifdef HAVE_PRI
 			if ((signalling == SIG_PRI) || (signalling == SIG_GR303FXOKS) || (signalling == SIG_GR303FXSKS)) {
 				int offset;
@@ -7419,7 +7648,7 @@
 				ast_dsp_digitmode(tmp->dsp, DSP_DIGITMODE_DTMF | tmp->dtmfrelax);
 			update_conf(tmp);
 			if (!here) {
-				if (signalling != SIG_PRI)
+				if ((signalling != SIG_PRI) && (signalling != SIG_SS7))
 					/* Hang it up to be sure it's good */
 					zt_set_hook(tmp->subs[SUB_REAL].zfd, ZT_ONHOOK);
 			}
@@ -7528,6 +7757,15 @@
 		/* Trust PRI */
 		if (p->pri) {
 			if (p->resetting || p->call)
+				return 0;
+			else
+				return 1;
+		}
+#endif
+#ifdef HAVE_SS7
+		/* Trust PRI */
+		if (p->ss7) {
+			if (p->ss7call || p->blocked)
 				return 0;
 			else
 				return 1;
@@ -7880,6 +8118,454 @@
 	return tmp;
 }
 
+#ifdef HAVE_SS7
+static int zt_setlaw(int zfd, int law);
+
+static int ss7_find_cic(struct zt_ss7 *linkset, int cic)
+{
+	int i;
+	int winner = -1;
+	for (i = 0; i < linkset->numchans; i++) {
+		if (linkset->pvts[i] && (linkset->pvts[i]->cic == cic)) {
+			winner = i;
+		}
+	}
+	return winner;
+}
+
+static inline void ss7_block_cics(struct zt_ss7 *linkset, int startcic, int endcic, unsigned char state[], int block)
+{
+	int i;
+
+	for (i = 0; i < linkset->numchans; i++) {
+		if (linkset->pvts[i] && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic))) {
+			if (state) {
+				if (state[i])
+					linkset->pvts[i]->blocked = block;
+			} else
+				linkset->pvts[i]->blocked = block;
+		}
+	}
+}
+
+static int ss7_reset_linkset(struct zt_ss7 *linkset)
+{
+	int i, startcic = -1, endcic;
+
+	if (linkset->numchans <= 0)
+		return 0;
+
+	startcic = linkset->pvts[0]->cic;
+
+	for (i = 0; i < linkset->numchans; i++) {
+		if (linkset->pvts[i+1] && (linkset->pvts[i+1]->cic - linkset->pvts[i]->cic) == 1) {
+			continue;
+		} else {
+			endcic = linkset->pvts[i]->cic;
+			ast_verbose(VERBOSE_PREFIX_3 "Resetting CICs %d to %d\n", startcic, endcic);
+			isup_grs(linkset->ss7, startcic, endcic);
+
+			if (linkset->pvts[i+1])
+				startcic = linkset->pvts[i+1]->cic;
+		}
+	}
+}
+
+static void zt_loopback(struct zt_pvt *p, int enable)
+{
+	if (ioctl(p->subs[SUB_REAL].zfd, ZT_LOOPBACK, &enable)) {
+		ast_log(LOG_WARNING, "Unable to set loopback on channel %d\n", p->channel);
+		return;
+	}
+}
+
+static void ss7_start_call(struct zt_pvt *p, struct zt_ss7 *linkset)
+{
+	struct ss7 *ss7 = linkset->ss7;
+	int res;
+	int law = 1;
+	struct ast_channel *c;
+
+	if (ioctl(p->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &law) == -1)
+		ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d\n", p->channel, law);
+	
+	if (linkset->type == SS7_ITU)
+		law = ZT_LAW_ALAW;
+	else
+		law = ZT_LAW_MULAW;
+
+	res = zt_setlaw(p->subs[SUB_REAL].zfd, law);
+	if (res < 0) 
+		ast_log(LOG_WARNING, "Unable to set law on channel %d\n", p->channel);
+	
+	isup_acm(ss7, p->ss7call);
+
+	ast_mutex_unlock(&linkset->lock);
+	c = zt_new(p, AST_STATE_RING, 1, SUB_REAL, law, 0);
+	ast_mutex_lock(&linkset->lock);
+	if (c)
+		ast_verbose(VERBOSE_PREFIX_3 "Accepting call to '%s' on CIC %d\n", p->exten, p->cic);
+	else
+		ast_log(LOG_WARNING, "Unable to start PBX on CIC %d\n", p->cic);
+}
+
+static void *ss7_linkset(void *data)
+{
+	int res, i;
+	struct timeval *next = NULL, tv;
+	struct zt_ss7 *linkset = (struct zt_ss7 *) data;
+	struct ss7 *ss7 = linkset->ss7;
+	ss7_event *e = NULL;
+	struct zt_pvt *p;
+	int chanpos;
+	pthread_attr_t attr;
+	struct pollfd pollers[NUM_DCHANS];
+	int cic;
+	int nextms = 0;
+
+	pthread_attr_init(&attr);
+	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+	ss7_start(ss7);
+
+	while(1) {
+		ast_mutex_lock(&linkset->lock);
+		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;
+		}
+		ast_mutex_unlock(&linkset->lock);
+
+		for (i = 0; i < linkset->numsigchans; i++) {
+			pollers[i].fd = linkset->fds[i];
+			pollers[i].events = POLLIN | POLLOUT | POLLPRI;
+			pollers[i].revents = 0;
+		}
+
+		res = poll(pollers, linkset->numsigchans, nextms);
+		if ((res < 0) && (errno != EINTR)) {
+			ast_log(LOG_ERROR, "poll(%s)\n", strerror(errno));
+		} else if (!res) {
+			ast_mutex_lock(&linkset->lock);
+			ss7_schedule_run(ss7);
+			ast_mutex_unlock(&linkset->lock);
+			continue;
+		}
+
+		ast_mutex_lock(&linkset->lock);
+		for (i = 0; i < linkset->numsigchans; i++) {
+			if (pollers[i].revents & POLLPRI) {
+				int x;
+				if (ioctl(pollers[i].fd, ZT_GETEVENT, &x)) {
+					ast_log(LOG_ERROR, "Error in exception retrieval!\n");
+				}
+				switch (x) {
+				case ZT_EVENT_OVERRUN:
+					ast_log(LOG_ERROR, "Overrun detected!\n");
+					break;
+				case ZT_EVENT_BADFCS:
+					ast_log(LOG_ERROR, "Bad FCS!\n");
+					break;
+				case ZT_EVENT_ABORT:
+					ast_log(LOG_ERROR, "HDLC Abort!\n");
+					break;
+				case ZT_EVENT_ALARM:
+					ast_log(LOG_ERROR, "Alarm on link!\n");
+					linkset->linkstate[i] |= (LINKSTATE_DOWN | LINKSTATE_INALARM);
+					linkset->linkstate[i] &= ~LINKSTATE_UP;
+					ss7_link_alarm(ss7, pollers[i].fd);
+					break;
+				case ZT_EVENT_NOALARM:
+					ast_log(LOG_ERROR, "Alarm cleared on link\n");
+					linkset->linkstate[i] &= ~(LINKSTATE_INALARM | LINKSTATE_DOWN);
+					linkset->linkstate[i] |= LINKSTATE_STARTING;
+					ss7_link_noalarm(ss7, pollers[i].fd);
+					break;
+				default:
+					ast_log(LOG_ERROR, "Got exception %d!\n", x);
+					break;
+				}
+			}
+
+			if (pollers[i].revents & POLLIN)
+				res = ss7_read(ss7, pollers[i].fd);
+			if (pollers[i].revents & POLLOUT) {
+				res = ss7_write(ss7, pollers[i].fd);
+				if (res < 0) {
+					ast_log(LOG_ERROR, "Error in write %s", strerror(errno));
+				}
+			}
+		}
+
+#if 0
+		if (res < 0)
+			exit(-1);
+#endif
+
+		while ((e = ss7_check_event(ss7))) {
+			switch (e->e) {
+			case SS7_EVENT_UP:
+				ast_verbose("--- SS7 Up ---\n");
+				ss7_reset_linkset(linkset);
+				break;
+			case MTP2_LINK_UP:
+				ast_log(LOG_DEBUG, "MTP2 link up\n");
+				break;
+			case ISUP_EVENT_CPG:
+				chanpos = ss7_find_cic(linkset, e->cpg.cic);
+				if (chanpos < 0) {
+					ast_log(LOG_WARNING, "CPG on unconfigured CIC %d\n", e->cpg.cic);
+					break;
+				}
+				p = linkset->pvts[chanpos];
+				ast_mutex_lock(&p->lock);
+				switch (e->cpg.event) {
+				case CPG_EVENT_ALERTING:
+					p->alerting = 1;
+					p->subs[SUB_REAL].needringing = 1;
+					break;
+				case CPG_EVENT_PROGRESS:
+				case CPG_EVENT_INBANDINFO:
+					{
+						struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, };
+						ast_log(LOG_DEBUG, "Queuing frame PROGRESS on CIC %d\n", p->cic);
+						zap_queue_frame(p, &f, ss7);
+						p->progress = 1;
+					}
+					break;
+				default:
+					ast_log(LOG_DEBUG, "Do not handle CPG with event type 0x%x\n", e->cpg.event);
+				}
+
+				ast_mutex_unlock(&p->lock);
+				break;
+			case ISUP_EVENT_RSC:
+				ast_verbose("Resetting CIC %d\n", e->rsc.cic);
+				chanpos = ss7_find_cic(linkset, e->rsc.cic);
+				if (chanpos < 0) {
+					ast_log(LOG_WARNING, "RSC on unconfigured CIC %d\n", e->rsc.cic);
+					break;
+				}
+				p = linkset->pvts[chanpos];
+				p->blocked = 0;
+				isup_rlc(ss7, e->rsc.call);
+				break;
+			case ISUP_EVENT_GRS:
+				ast_log(LOG_DEBUG, "Got Reset for CICs %d to %d: Acknowledging\n", e->grs.startcic, e->grs.endcic);
+				isup_gra(ss7, e->grs.startcic, e->grs.endcic);
+				ss7_block_cics(linkset, e->grs.startcic, e->grs.endcic, NULL, 0);
+				break;
+			case ISUP_EVENT_GRA:
+				ast_log(LOG_DEBUG, "Got GRA from CIC %d to %d.\n", e->gra.startcic, e->gra.endcic);
+				ss7_block_cics(linkset, e->gra.startcic, e->gra.endcic, e->gra.status, 1);
+				break;
+			case ISUP_EVENT_IAM:
+				ast_log(LOG_DEBUG, "Got IAM for CIC %d and number %s\n", e->iam.cic, e->iam.called_party_num);
+				chanpos = ss7_find_cic(linkset, e->iam.cic);
+				if (chanpos < 0) {
+					ast_log(LOG_WARNING, "IAM on unconfigured CIC %d\n", e->iam.cic);
+					isup_rel(ss7, e->iam.call, -1);
+					break;
+				}
+				p = linkset->pvts[chanpos];
+				ast_mutex_lock(&p->lock);
+				if (p->owner) {
+					if (p->ss7call == e->iam.call) {
+						ast_mutex_unlock(&p->lock);
+						ast_log(LOG_WARNING, "Duplicate IAM requested on CIC %d\n", e->iam.cic);
+						break;
+					} else {
+						ast_mutex_unlock(&p->lock);
+						ast_log(LOG_WARNING, "Ring requested on CIC %d already in use!\n", e->iam.cic);
+						break;
+					}
+				}
+
+				p->ss7call = e->iam.call;
+
+				if (p->use_callerid)
+					ast_copy_string(p->cid_num, e->iam.calling_party_num, sizeof(p->cid_num));
+				else
+					p->cid_num[0] = 0;
+
+				if (p->immediate) {
+					p->exten[0] = 's';
+					p->exten[1] = '\0';
+				} else if (!ast_strlen_zero(e->iam.called_party_num)) {
+					char *st;
+					ast_copy_string(p->exten, e->iam.called_party_num, sizeof(p->exten));
+					st = strchr(p->exten, '#');
+					if (st)
+						*st = '\0';
+				} else
+					p->exten[0] = '\0';
+
+				/* Need to fill these fields */
+				p->cid_ani[0] = '\0';
+				p->cid_name[0] = '\0';
+				p->cid_ton = 0;
+				/* Set DNID */
+				if (!ast_strlen_zero(e->iam.called_party_num))
+					ast_copy_string(p->dnid, e->iam.called_party_num, sizeof(p->exten));
+
+				if (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
+
+					if (e->iam.cot_check_required) {
+						zt_loopback(p, 1);
+					} else
+						ss7_start_call(p, linkset);
+				} else {
+					ast_log(LOG_DEBUG, "Call on CIC for unconfigured extension %s\n", p->exten);
+					isup_rel(ss7, e->iam.call, -1);
+				}
+				ast_mutex_unlock(&p->lock);
+				break;
+			case ISUP_EVENT_COT:
+				chanpos = ss7_find_cic(linkset, e->cot.cic);
+				if (chanpos < 0) {
+					ast_log(LOG_WARNING, "COT on unconfigured CIC %d\n", e->cot.cic);
+					isup_rel(ss7, e->cot.call, -1);
+					break;
+				}
+				p = linkset->pvts[chanpos];
+
+				zt_loopback(p, 0);
+				
+				isup_acm(ss7, p->ss7call);
+				ss7_start_call(p, linkset);
+				break;
+			case ISUP_EVENT_REL:
+				chanpos = ss7_find_cic(linkset, e->rel.cic);
+				if (chanpos < 0) {
+					ast_log(LOG_WARNING, "REL on unconfigured CIC %d\n", e->rel.cic);
+					break;
+				}
+				p = linkset->pvts[chanpos];
+				ast_mutex_lock(&p->lock);
+				if (p->owner)
+					ast_queue_hangup(p->owner);
+				else
+					ast_log(LOG_WARNING, "REL on channel (CIC %d) without owner!\n", p->cic);
+
+				isup_rlc(ss7, e->rel.call);
+				p->ss7call = NULL;
+
+				ast_mutex_unlock(&p->lock);
+				break;
+			case ISUP_EVENT_ACM:
+				chanpos = ss7_find_cic(linkset, e->acm.cic);
+				if (chanpos < 0) {
+					ast_log(LOG_WARNING, "ACM on unconfigured CIC %d\n", e->acm.cic);
+					isup_rel(ss7, e->acm.call, -1);
+					break;
+				} else {
+					struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROCEEDING, };
+
+					p = linkset->pvts[chanpos];
+
+					ast_log(LOG_DEBUG, "Queueing frame from SS7_EVENT_ACM on CIC %d\n", p->cic);
+
+					ast_mutex_lock(&p->lock);
+					zap_queue_frame(p, &f, linkset);
+					p->proceeding = 1;
+
+					ast_mutex_unlock(&p->lock);
+				}
+				break;
+			case ISUP_EVENT_CGB:
+				ss7_block_cics(linkset, e->cgb.startcic, e->cgb.endcic, e->cgb.status, 1);
+				isup_cgba(linkset->ss7, e->cgb.startcic, e->cgb.endcic, e->cgb.status);
+				break;
+			case ISUP_EVENT_CGU:
+				ss7_block_cics(linkset, e->cgu.startcic, e->cgu.endcic, e->cgb.status, 0);
+				isup_cgua(linkset->ss7, e->cgu.startcic, e->cgu.endcic, e->cgb.status);
+				break;
+			case ISUP_EVENT_BLO:
+				chanpos = ss7_find_cic(linkset, e->blo.cic);
+				if (chanpos < 0) {
+					ast_log(LOG_WARNING, "BLO on unconfigured CIC %d\n", e->blo.cic);
+					break;
+				}
+				p = linkset->pvts[chanpos];
+				ast_log(LOG_DEBUG, "Blocking CIC %d\n", e->blo.cic);
+				p->blocked = 1;
+				isup_bla(linkset->ss7, e->blo.cic);
+				break;
+			case ISUP_EVENT_UBL:
+				chanpos = ss7_find_cic(linkset, e->ubl.cic);
+				if (chanpos < 0) {
+					ast_log(LOG_WARNING, "UBL on unconfigured CIC %d\n", e->ubl.cic);
+					break;
+				}
+				p = linkset->pvts[chanpos];
+				ast_log(LOG_DEBUG, "Unblocking CIC %d\n", e->ubl.cic);
+				p->blocked = 0;
+				isup_uba(linkset->ss7, e->ubl.cic);
+				break;
+			case ISUP_EVENT_CON:
+			case ISUP_EVENT_ANM:
+				if (e->e == ISUP_EVENT_CON)
+					cic = e->con.cic;
+				else
+					cic = e->anm.cic;
+
+				chanpos = ss7_find_cic(linkset, cic);
+				if (chanpos < 0) {
+					ast_log(LOG_WARNING, "ANM/CON on unconfigured CIC %d\n", cic);
+					isup_rel(ss7, (e->e == ISUP_EVENT_ANM) ? e->anm.call : e->con.call, -1);
+					break;
+				} else {
+					p = linkset->pvts[chanpos];
+					ast_mutex_lock(&p->lock);
+					p->subs[SUB_REAL].needanswer = 1;
+					zt_enable_ec(p);
+					ast_mutex_unlock(&p->lock);
+				}
+				break;
+			case ISUP_EVENT_RLC:
+				chanpos = ss7_find_cic(linkset, e->rlc.cic);
+				if (chanpos < 0) {
+					ast_log(LOG_WARNING, "RLC on unconfigured CIC %d\n", e->rlc.cic);
+					break;
+				} else {
+					p = linkset->pvts[chanpos];
+					ast_mutex_lock(&p->lock);
+					p->ss7call = NULL;
+					ast_mutex_unlock(&p->lock);
+				}
+				break;
+			default:
+				ast_log(LOG_DEBUG, "Unknown event %s\n", ss7_event2str(e->e));
+				break;
+			}
+		}
+		ast_mutex_unlock(&linkset->lock);
+	}
+
+	return 0;
+}
+
+static void zt_ss7_message(struct ss7 *ss7, char *s)
+{
+	ast_log(LOG_DEBUG, "%s", s);
+}
+
+static void zt_ss7_error(struct ss7 *ss7, char *s)
+{
+	ast_log(LOG_ERROR, "%s", s);
+}
+#endif /* HAVE_SS7 */
 
 #ifdef HAVE_PRI
 static struct zt_pvt *pri_find_crv(struct zt_pri *pri, int crv)
@@ -9878,6 +10564,12 @@
 				if (tmp->slaves[x])
 					ast_cli(fd, "Slave Channel: %d\n", tmp->slaves[x]->channel);
 			}
+#ifdef HAVE_SS7
+			if (tmp->ss7) {
+				ast_cli(fd, "CIC: %d\n", tmp->cic);
+				ast_cli(fd, "Blocked: %s\n", tmp->blocked ? "yes" : "no");
+			}
+#endif
 #ifdef HAVE_PRI
 			if (tmp->pri) {
 				ast_cli(fd, "PRI Flags: ");
@@ -10309,16 +11001,242 @@
 		zt_close(pris[i].fds[i]);
 	}
 #endif
+#ifdef HAVE_SS7
+	for (i = 0; i < NUM_SPANS; i++) {
+		if (linksets[i].master && (linksets[i].master != AST_PTHREADT_NULL))
+			pthread_join(linksets[i].master, NULL);
+		zt_close(linksets[i].fds[i]);
+	}
+#endif /* HAVE_SS7 */
 	return 0;
 }
 
+#ifdef HAVE_SS7
+static int linkset_addsigchan(int sigchan)
+{
+	struct zt_ss7 *link;
+	int res;
+	int curfd;
+	ZT_PARAMS p;
+	ZT_BUFFERINFO bi;
+	struct zt_spaninfo si;
+
+
+	link = ss7_resolve_linkset(cur_linkset);
+	if (!link) {
+		ast_log(LOG_ERROR, "Invalid linkset number.  Must be between 1 and %d\n", NUM_SPANS + 1);
+		return -1;
+	}
+
+	if (cur_ss7type < 0) {
+		ast_log(LOG_ERROR, "Unspecified or invalid ss7type\n");
+		return -1;
+	}
+
+	if (!link->ss7)
+		link->ss7 = ss7_new(cur_ss7type);
+
+	if (!link->ss7) {
+		ast_log(LOG_ERROR, "Can't create new SS7!\n");
+		return -1;
+	}
+
+	link->type = cur_ss7type;
+
+	if (cur_pointcode < 0) {
+		ast_log(LOG_ERROR, "Unspecified pointcode!\n");
+		return -1;
+	} else
+		ss7_set_pc(link->ss7, cur_pointcode);
+
+	if (sigchan < 0) {
+		ast_log(LOG_ERROR, "Invalid sigchan!\n");
+		return -1;
+	} else {
+		if (link->numsigchans >= NUM_DCHANS) {
+			ast_log(LOG_ERROR, "Too many sigchans on linkset %d\n", cur_linkset);
+			return -1;
+		}
+		curfd = link->numsigchans;
+
+		link->fds[curfd] = open("/dev/zap/channel", O_RDWR, 0600);
+		if ((link->fds[curfd] < 0) || (ioctl(link->fds[curfd],ZT_SPECIFY,&sigchan) == -1)) {
+			ast_log(LOG_ERROR, "Unable to open SS7 sigchan %d (%s)\n", sigchan, strerror(errno));
+			return -1;
+		}
+		res = ioctl(link->fds[curfd], ZT_GET_PARAMS, &p);
+		if (res) {
+			zt_close(link->fds[curfd]);
+			link->fds[curfd] = -1;
+			ast_log(LOG_ERROR, "Unable to get parameters for sigchan %d (%s)\n", sigchan, strerror(errno));
+			return -1;
+		}
+		if ((p.sigtype != ZT_SIG_HDLCFCS) && (p.sigtype != ZT_SIG_HARDHDLC)) {
+			zt_close(link->fds[curfd]);
+			link->fds[curfd] = -1;
+			ast_log(LOG_ERROR, "sigchan %d is not in HDLC/FCS mode.  See /etc/zaptel.conf\n", sigchan);
+			return -1;
+		}
+
+		bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
+		bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
+		bi.numbufs = 32;
+		bi.bufsize = 512;
+
+		if (ioctl(link->fds[curfd], ZT_SET_BUFINFO, &bi)) {
+			ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d\n", sigchan);
+			zt_close(link->fds[curfd]);
+			link->fds[curfd] = -1;
+			return -1;
+		}
+
+		ss7_add_link(link->ss7, link->fds[curfd]);
+		link->numsigchans++;
+
+		memset(&si, 0, sizeof(si));
+		res = ioctl(link->fds[curfd], ZT_SPANSTAT, &si);
+		if (res) {
+			zt_close(link->fds[curfd]);
+			link->fds[curfd] = -1;
+			ast_log(LOG_ERROR, "Unable to get span state for sigchan %d (%s)\n", sigchan, strerror(errno));
+		}
+
+		if (!si.alarms) {
+			link->linkstate[curfd] = LINKSTATE_DOWN;
+			ss7_link_noalarm(link->ss7, link->fds[curfd]);
+		} else {
+			link->linkstate[curfd] = LINKSTATE_DOWN | LINKSTATE_INALARM;
+			ss7_link_alarm(link->ss7, link->fds[curfd]);
+		}
+	}
+
+	if (cur_adjpointcode < 0) {
+		ast_log(LOG_ERROR, "Unspecified adjpointcode!\n");
+		return -1;
+	} else {
+		ss7_set_adjpc(link->ss7, link->fds[curfd], cur_adjpointcode);
+	}
+
+	if (cur_defaultdpc < 0) {
+		ast_log(LOG_ERROR, "Unspecified defaultdpc!\n");
+		return -1;
+	} else {
+		ss7_set_default_dpc(link->ss7, cur_defaultdpc);
+	}
+

[... 1066 lines stripped ...]


More information about the asterisk-commits mailing list