[asterisk-commits] rmudgett: branch rmudgett/dahdi_ccss r239796 - /team/rmudgett/dahdi_ccss/chan...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Jan 13 12:09:40 CST 2010


Author: rmudgett
Date: Wed Jan 13 12:09:38 2010
New Revision: 239796

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=239796
Log:
Add CCSS core option support for sig_pri.

*  Fix initialization memory leak created when CCSS core option support
added for sig_analog.
*  Fix dahdi_cc_is_possible() and make it also handle
ast_channel_get_cc_config_params() failure.
*  Add reference counted sig_pri monitor_instance and container.
*  Add libpri subcmd event handling for dummy channel and CIS calls.

Modified:
    team/rmudgett/dahdi_ccss/channels/chan_dahdi.c
    team/rmudgett/dahdi_ccss/channels/sig_pri.c
    team/rmudgett/dahdi_ccss/channels/sig_pri.h

Modified: team/rmudgett/dahdi_ccss/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/dahdi_ccss/channels/chan_dahdi.c?view=diff&rev=239796&r1=239795&r2=239796
==============================================================================
--- team/rmudgett/dahdi_ccss/channels/chan_dahdi.c (original)
+++ team/rmudgett/dahdi_ccss/channels/chan_dahdi.c Wed Jan 13 12:09:38 2010
@@ -2818,6 +2818,7 @@
 	.set_dnid = my_pri_set_dnid,
 	.set_rdnis = my_pri_set_rdnis,
 	.new_nobch_intf = dahdi_new_pri_nobch_channel,
+	.get_orig_dialstring = my_get_orig_dialstring,
 };
 #endif	/* defined(HAVE_PRI) */
 
@@ -5110,6 +5111,9 @@
 		ast_event_unsubscribe(p->mwi_event_sub);
 	if (p->vars) {
 		ast_variables_destroy(p->vars);
+	}
+	if (p->cc_params) {
+		ast_cc_config_params_destroy(p->cc_params);
 	}
 	ast_mutex_destroy(&p->lock);
 	dahdi_close_sub(p, SUB_REAL);
@@ -7969,28 +7973,30 @@
 
 static int dahdi_cc_is_possible(struct ast_channel *chan, const char * const device_name)
 {
-	struct ast_cc_config_params *cc_params = ast_channel_get_cc_config_params(chan);
-	enum ast_cc_monitor_policies monitor_policy = ast_get_cc_monitor_policy(cc_params);
+	struct ast_cc_config_params *cc_params;
 	const char *monitor_type;
 
 	monitor_type = NULL;
-	switch (monitor_policy) {
-	case AST_CC_MONITOR_NEVER:
-		break;
-	case AST_CC_MONITOR_NATIVE:
-	case AST_CC_MONITOR_GENERIC:
-	case AST_CC_MONITOR_ALWAYS:
-		monitor_type = AST_CC_GENERIC_MONITOR_TYPE;
-		break;
+	cc_params = ast_channel_get_cc_config_params(chan);
+	if (cc_params) {
+		switch (ast_get_cc_monitor_policy(cc_params)) {
+		case AST_CC_MONITOR_NEVER:
+			break;
+		case AST_CC_MONITOR_NATIVE:
+		case AST_CC_MONITOR_GENERIC:
+		case AST_CC_MONITOR_ALWAYS:
+			monitor_type = AST_CC_GENERIC_MONITOR_TYPE;
+			break;
+		}
 	}
 
 	if (monitor_type
 		&& ast_cc_monitor_count(device_name, monitor_type)
-		>= ast_get_cc_max_monitors(cc_params)) {
-		return 0;
-	}
-
-	return 1;
+		< ast_get_cc_max_monitors(cc_params)) {
+		return 1;
+	}
+
+	return 0;
 }
 
 static struct ast_frame *dahdi_read(struct ast_channel *ast)
@@ -8685,6 +8691,11 @@
 	if (!tmp)
 		return NULL;
 	tmp->tech = &dahdi_tech;
+#if defined(HAVE_PRI)
+	if (i->pri) {
+		ast_cc_copy_config_params(i->cc_params, i->pri->cc_params);
+	}
+#endif	/* defined(HAVE_PRI) */
 	ast_channel_cc_params_init(tmp, i->cc_params);
 	memset(&ps, 0, sizeof(ps));
 	ps.channo = i->channel;
@@ -11207,6 +11218,11 @@
 		if (!tmp) {
 			return NULL;
 		}
+		tmp->cc_params = ast_cc_config_params_init();
+		if (!tmp->cc_params) {
+			ast_free(tmp);
+			return NULL;
+		}
 		ast_mutex_init(&tmp->lock);
 		ifcount++;
 		for (x = 0; x < 3; x++)
@@ -11450,6 +11466,16 @@
 						tmp->sig_pvt = pchan;
 						tmp->pri = &pris[span].pri;
 
+						if (!tmp->pri->cc_params) {
+							tmp->pri->cc_params = ast_cc_config_params_init();
+							if (!tmp->pri->cc_params) {
+								destroy_dahdi_pvt(tmp);
+								return NULL;
+							}
+						}
+						ast_cc_copy_config_params(tmp->pri->cc_params,
+							conf->chan.cc_params);
+
 						pris[span].pri.sig = chan_sig;
 						pris[span].pri.nodetype = conf->pri.pri.nodetype;
 						pris[span].pri.switchtype = myswitchtype;
@@ -11776,7 +11802,7 @@
 		tmp->answeronpolarityswitch = conf->chan.answeronpolarityswitch;
 		tmp->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
 		tmp->sendcalleridafter = conf->chan.sendcalleridafter;
-		tmp->cc_params = conf->chan.cc_params;
+		ast_cc_copy_config_params(tmp->cc_params, conf->chan.cc_params);
 
 		if (!here) {
 			tmp->locallyblocked = tmp->remotelyblocked = 0;
@@ -12012,6 +12038,11 @@
 	if (!pvt) {
 		return -1;
 	}
+	pvt->cc_params = ast_cc_config_params_init();
+	if (!pvt->cc_params) {
+		ast_free(pvt);
+		return -1;
+	}
 	ast_mutex_init(&pvt->lock);
 	for (idx = 0; idx < ARRAY_LEN(pvt->subs); ++idx) {
 		pvt->subs[idx].dfd = -1;
@@ -12364,7 +12395,13 @@
 #endif	/* defined(HAVE_PRI) */
 			snprintf(full_interface_name, sizeof(full_interface_name), "DAHDI/%s", ast_str_buffer(interface_name));
 			snprintf(dialstring, sizeof(dialstring), "DAHDI/%s", dest);
-			callback(inbound, p->cc_params, full_interface_name, dialstring);
+			callback(inbound,
+#if defined(HAVE_PRI)
+				p->pri ? p->pri->cc_params : p->cc_params,
+#else
+				p->cc_params,
+#endif	/* defined(HAVE_PRI) */
+				full_interface_name, dialstring);
 			ast_free(interface_name);
 		}
 		p = backwards ? p->prev : p->next;
@@ -15939,6 +15976,7 @@
 	ast_cc_agent_unregister(&dahdi_pri_cc_agent_callbacks);
 	ast_cc_monitor_unregister(&dahdi_pri_cc_monitor_callbacks);
 #endif	/* defined(HAVE_PRI_CCSS) */
+	sig_pri_unload();
 #endif
 
 #if defined(HAVE_SS7)
@@ -16739,6 +16777,13 @@
 			} else if (!strcasecmp(v->name, "hold_disconnect_transfer")) {
 				confp->pri.pri.hold_disconnect_transfer = ast_true(v->value);
 #endif	/* defined(HAVE_PRI_CALL_HOLD) */
+#if defined(HAVE_PRI_CCSS)
+/*
+ * BUGBUG need to add CCSS DAHDI/PRI specific options:
+ * Q.SIG retain CC signaling link options.
+ * ETSI PTMP recall mode
+ */
+#endif	/* defined(HAVE_PRI_CCSS) */
 #endif /* HAVE_PRI */
 #ifdef HAVE_SS7
 			} else if (!strcasecmp(v->name, "ss7type")) {
@@ -17039,23 +17084,57 @@
 		*/
 		struct dahdi_chan_conf conf = dahdi_chan_conf_default();
 
-		tmp = mkintf(CHAN_PSEUDO, &conf, reload);
-
+		if (conf.chan.cc_params) {
+			tmp = mkintf(CHAN_PSEUDO, &conf, reload);
+		} else {
+			tmp = NULL;
+		}
 		if (tmp) {
 			ast_verb(3, "Automatically generated pseudo channel\n");
 		} else {
 			ast_log(LOG_WARNING, "Unable to register pseudo channel!\n");
 		}
+		ast_cc_config_params_destroy(conf.chan.cc_params);
 	}
 	return 0;
 }
 
-static int setup_dahdi(int reload)
-{
-	struct ast_config *cfg, *ucfg;
+/*!
+ * \internal
+ * \brief Deep copy struct dahdi_chan_conf.
+ * \since 1.8
+ *
+ * \param dest Destination.
+ * \param src Source.
+ *
+ * \return Nothing
+ */
+static void deep_copy_dahdi_chan_conf(struct dahdi_chan_conf *dest, const struct dahdi_chan_conf *src)
+{
+	struct ast_cc_config_params *cc_params;
+
+	cc_params = dest->chan.cc_params;
+	memcpy(dest, src, sizeof(dest));
+	dest->chan.cc_params = cc_params;
+	ast_cc_copy_config_params(dest->chan.cc_params, src->chan.cc_params);
+}
+
+/*!
+ * \internal
+ * \brief Setup DAHDI channel driver.
+ *
+ * \param reload enum: load_module(0), reload(1), restart(2).
+ * \param base_conf Default config parameters.  So cc_params can be properly destroyed.
+ * \param conf Local config parameters.  So cc_params can be properly destroyed.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int setup_dahdi_int(int reload, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf)
+{
+	struct ast_config *cfg;
+	struct ast_config *ucfg;
 	struct ast_variable *v;
- 	struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
- 	struct dahdi_chan_conf conf;
 	struct ast_flags config_flags = { reload == 1 ? CONFIG_FLAG_FILEUNCHANGED : 0 };
 	const char *cat;
 	int res;
@@ -17170,7 +17249,7 @@
 	mwimonitornotify[0] = '\0';
 
 	v = ast_variable_browse(cfg, "channels");
-	if ((res = process_dahdi(&base_conf, "", v, reload, 0))) {
+	if ((res = process_dahdi(base_conf, "", v, reload, 0))) {
 		ast_mutex_unlock(&iflock);
 		ast_config_destroy(cfg);
 		if (ucfg) {
@@ -17191,9 +17270,10 @@
 			continue;
 		}
 
-		memcpy(&conf, &base_conf, sizeof(conf));
-
-		if ((res = process_dahdi(&conf, cat, ast_variable_browse(cfg, cat), reload, PROC_DAHDI_OPT_NOCHAN))) {
+		/* Copy base_conf to conf. */
+		deep_copy_dahdi_chan_conf(conf, base_conf);
+
+		if ((res = process_dahdi(conf, cat, ast_variable_browse(cfg, cat), reload, PROC_DAHDI_OPT_NOCHAN))) {
 			ast_mutex_unlock(&iflock);
 			ast_config_destroy(cfg);
 			if (ucfg) {
@@ -17208,7 +17288,7 @@
 	if (ucfg) {
 		const char *chans;
 
-		process_dahdi(&base_conf, "", ast_variable_browse(ucfg, "general"), 1, 0);
+		process_dahdi(base_conf, "", ast_variable_browse(ucfg, "general"), 1, 0);
 
 		for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
 			if (!strcasecmp(cat, "general")) {
@@ -17221,9 +17301,10 @@
 				continue;
 			}
 
-			memcpy(&conf, &base_conf, sizeof(conf));
-
-			if ((res = process_dahdi(&conf, cat, ast_variable_browse(ucfg, cat), reload, PROC_DAHDI_OPT_NOCHAN | PROC_DAHDI_OPT_NOWARN))) {
+			/* Copy base_conf to conf. */
+			deep_copy_dahdi_chan_conf(conf, base_conf);
+
+			if ((res = process_dahdi(conf, cat, ast_variable_browse(ucfg, cat), reload, PROC_DAHDI_OPT_NOCHAN | PROC_DAHDI_OPT_NOWARN))) {
 				ast_config_destroy(ucfg);
 				ast_mutex_unlock(&iflock);
 				return res;
@@ -17280,6 +17361,32 @@
 	return 0;
 }
 
+/*!
+ * \internal
+ * \brief Setup DAHDI channel driver.
+ *
+ * \param reload enum: load_module(0), reload(1), restart(2).
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int setup_dahdi(int reload)
+{
+	int res;
+ 	struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
+ 	struct dahdi_chan_conf conf = dahdi_chan_conf_default();
+
+	if (base_conf.chan.cc_params && conf.chan.cc_params) {
+		res = setup_dahdi_int(reload, &base_conf, &conf);
+	} else {
+		res = -1;
+	}
+	ast_cc_config_params_destroy(base_conf.chan.cc_params);
+	ast_cc_config_params_destroy(conf.chan.cc_params);
+
+	return res;
+}
+
 static int load_module(void)
 {
 	int res;
@@ -17307,6 +17414,16 @@
 		return AST_MODULE_LOAD_FAILURE;
 	}
 #endif	/* defined(HAVE_PRI_CCSS) */
+	if (sig_pri_load(
+#if defined(HAVE_PRI_CCSS)
+		dahdi_pri_cc_type
+#else
+		NULL
+#endif	/* defined(HAVE_PRI_CCSS) */
+		)) {
+		__unload_module();
+		return AST_MODULE_LOAD_FAILURE;
+	}
 #endif
 #ifdef HAVE_SS7
 	memset(linksets, 0, sizeof(linksets));

Modified: team/rmudgett/dahdi_ccss/channels/sig_pri.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/dahdi_ccss/channels/sig_pri.c?view=diff&rev=239796&r1=239795&r2=239796
==============================================================================
--- team/rmudgett/dahdi_ccss/channels/sig_pri.c (original)
+++ team/rmudgett/dahdi_ccss/channels/sig_pri.c Wed Jan 13 12:09:38 2010
@@ -70,6 +70,25 @@
 	/*! TRUE if CC has been requested and we are waiting for the response. */
 	unsigned char cc_request_response_pending;
 };
+
+struct sig_pri_cc_monitor_instance {
+	/*!
+	 * CC core monitor structure associted with this monitor instance.
+	 * NULL if no association established.
+	 */
+	struct ast_cc_monitor *monitor;
+	/*! Asterisk span D channel control structure. */
+	struct sig_pri_pri *pri;
+	/*! CC id value to use with libpri. -1 if invalid. */
+	long cc_id;
+	/*! CC core id value. */
+	int core_id;
+	/*! Device name(Channel name less sequence number) */
+	char name[1];
+};
+
+static const char *sig_pri_cc_type_name;
+static struct ao2_container *sig_pri_cc_monitors;
 #endif	/* defined(HAVE_PRI_CCSS) */
 
 static int pri_matchdigittimeout = 3000;
@@ -130,6 +149,16 @@
 	if (p->calls->set_digital)
 		p->calls->set_digital(p->chan_pvt, flag);
 }
+
+#if defined(HAVE_PRI_CCSS)
+static const char *sig_pri_get_orig_dialstring(struct sig_pri_chan *p)
+{
+	if (p->calls->get_orig_dialstring) {
+		return p->calls->get_orig_dialstring(p->chan_pvt);
+	}
+	return "";
+}
+#endif	/* defined(HAVE_PRI_CCSS) */
 
 /*!
  * \internal
@@ -1487,6 +1516,523 @@
 	}
 }
 
+#if defined(HAVE_PRI_CCSS)
+/*!
+ * \internal
+ * \brief Compare the CC agent private data by libpri cc_id.
+ * \since 1.8
+ *
+ * \param obj pointer to the (user-defined part) of an object.
+ * \param arg callback argument from ao2_callback()
+ * \param flags flags from ao2_callback()
+ *
+ * \return values are a combination of enum _cb_results.
+ */
+static int sig_pri_cc_agent_cmp_cc_id(void *obj, void *arg, int flags)
+{
+	struct ast_cc_agent *agent_1 = obj;
+	struct sig_pri_cc_agent_prv *agent_prv_1 = agent_1->private_data;
+	struct sig_pri_cc_agent_prv *agent_prv_2 = arg;
+
+	return (agent_prv_1 && agent_prv_1->pri == agent_prv_2->pri
+		&& agent_prv_1->cc_id == agent_prv_2->cc_id) ? CMP_MATCH | CMP_STOP : 0;
+}
+#endif	/* defined(HAVE_PRI_CCSS) */
+
+#if defined(HAVE_PRI_CCSS)
+/*!
+ * \internal
+ * \brief Find the CC agent by libpri cc_id.
+ * \since 1.8
+ *
+ * \param pri sig_pri PRI control structure.
+ * \param cc_id CC record ID to find.
+ *
+ * \note
+ * Since agents are refcounted, and this function returns
+ * a reference to the agent, it is imperative that you decrement
+ * the refcount of the agent once you have finished using it.
+ *
+ * \retval agent on success.
+ * \retval NULL not found.
+ */
+static struct ast_cc_agent *sig_pri_find_cc_agent_by_cc_id(struct sig_pri_pri *pri, long cc_id)
+{
+	struct sig_pri_cc_agent_prv finder = {
+		.pri = pri,
+		.cc_id = cc_id,
+	};
+
+	return ast_cc_agent_callback(0, sig_pri_cc_agent_cmp_cc_id, &finder,
+		sig_pri_cc_type_name);
+}
+#endif	/* defined(HAVE_PRI_CCSS) */
+
+#if defined(HAVE_PRI_CCSS)
+/*!
+ * \internal
+ * \brief Compare the CC monitor instance by libpri cc_id.
+ * \since 1.8
+ *
+ * \param obj pointer to the (user-defined part) of an object.
+ * \param arg callback argument from ao2_callback()
+ * \param flags flags from ao2_callback()
+ *
+ * \return values are a combination of enum _cb_results.
+ */
+static int sig_pri_cc_monitor_cmp_cc_id(void *obj, void *arg, int flags)
+{
+	struct sig_pri_cc_monitor_instance *monitor_1 = obj;
+	struct sig_pri_cc_monitor_instance *monitor_2 = arg;
+
+	return (monitor_1->pri == monitor_2->pri
+		&& monitor_1->cc_id == monitor_2->cc_id) ? CMP_MATCH | CMP_STOP : 0;
+}
+#endif	/* defined(HAVE_PRI_CCSS) */
+
+#if defined(HAVE_PRI_CCSS)
+/*!
+ * \internal
+ * \brief Find the CC monitor instance by libpri cc_id.
+ * \since 1.8
+ *
+ * \param pri sig_pri PRI control structure.
+ * \param cc_id CC record ID to find.
+ *
+ * \note
+ * Since monitor_instances are refcounted, and this function returns
+ * a reference to the instance, it is imperative that you decrement
+ * the refcount of the instance once you have finished using it.
+ *
+ * \retval monitor_instance on success.
+ * \retval NULL not found.
+ */
+static struct sig_pri_cc_monitor_instance *sig_pri_find_cc_monitor_by_cc_id(struct sig_pri_pri *pri, long cc_id)
+{
+	struct sig_pri_cc_monitor_instance finder = {
+		.pri = pri,
+		.cc_id = cc_id,
+	};
+
+	return ao2_callback(sig_pri_cc_monitors, 0, sig_pri_cc_monitor_cmp_cc_id, &finder);
+}
+#endif	/* defined(HAVE_PRI_CCSS) */
+
+#if defined(HAVE_PRI_CCSS)
+/*!
+ * \internal
+ * \brief Find the CC monitor instance by CC core_id.
+ * \since 1.8
+ *
+ * \param core_id CC core ID.
+ *
+ * \note
+ * Since monitor_instances are refcounted, and this function returns
+ * a reference to the instance, it is imperative that you decrement
+ * the refcount of the instance once you have finished using it.
+ *
+ * \retval monitor_instance on success.
+ * \retval NULL not found.
+ */
+static struct sig_pri_cc_monitor_instance *sig_pri_find_cc_monitor_by_core_id(int core_id)
+{
+	struct sig_pri_cc_monitor_instance finder = {
+		.core_id = core_id,
+	};
+
+	return ao2_find(sig_pri_cc_monitors, &finder, OBJ_POINTER);
+}
+#endif	/* defined(HAVE_PRI_CCSS) */
+
+#if defined(HAVE_PRI_CCSS)
+/*!
+ * \internal
+ * \brief Destroy the given monitor instance.
+ * \since 1.8
+ *
+ * \param data Monitor instance to destroy.
+ *
+ * \return Nothing
+ */
+static void sig_pri_cc_monitor_instance_destroy(void *data)
+{
+	struct sig_pri_cc_monitor_instance *monitor_instance = data;
+
+	if (monitor_instance->pri) {
+		ast_mutex_lock(&monitor_instance->pri->lock);
+		pri_cc_cancel(monitor_instance->pri->pri, monitor_instance->cc_id);
+		ast_mutex_unlock(&monitor_instance->pri->lock);
+		monitor_instance->pri = NULL;
+	}
+
+	if (monitor_instance->monitor) {
+		ao2_ref(monitor_instance->monitor, -1);
+		monitor_instance->monitor = NULL;
+	}
+}
+#endif	/* defined(HAVE_PRI_CCSS) */
+
+#if defined(HAVE_PRI_CCSS)
+/*!
+ * \internal
+ * \brief Construct a new monitor instance.
+ * \since 1.8
+ *
+ * \param core_id CC core ID.
+ * \param pri sig_pri PRI control structure.
+ * \param cc_id CC record ID.
+ * \param device_name Name of device (Asterisk channel name less sequence number).
+ *
+ * \note
+ * Since monitor_instances are refcounted, and this function returns
+ * a reference to the instance, it is imperative that you decrement
+ * the refcount of the instance once you have finished using it.
+ *
+ * \retval monitor_instance on success.
+ * \retval NULL on error.
+ */
+static struct sig_pri_cc_monitor_instance *sig_pri_cc_monitor_instance_init(int core_id, struct sig_pri_pri *pri, long cc_id, const char *device_name)
+{
+	struct sig_pri_cc_monitor_instance *monitor_instance;
+
+	monitor_instance = ao2_alloc(sizeof(*monitor_instance) + strlen(device_name),
+		sig_pri_cc_monitor_instance_destroy);
+	if (!monitor_instance) {
+		return NULL;
+	}
+
+	monitor_instance->cc_id = cc_id;
+	monitor_instance->pri = pri;
+	monitor_instance->core_id = core_id;
+	strcpy(monitor_instance->name, device_name);
+
+	ao2_link(sig_pri_cc_monitors, monitor_instance);
+	return monitor_instance;
+}
+#endif	/* defined(HAVE_PRI_CCSS) */
+
+#if defined(HAVE_PRI_CCSS)
+/*!
+ * \internal
+ * \brief Announce to the CC core that protocol CC monitor is available for this call.
+ * \since 1.8
+ *
+ * \param pri sig_pri PRI control structure.
+ * \param chanpos Channel position in the span.
+ * \param cc_id CC record ID.
+ * \param service CCBS/CCNR indication.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
+ * \note Assumes the sig_pri_lock_owner(pri, chanpos) is already obtained.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int sig_pri_cc_available(struct sig_pri_pri *pri, int chanpos, long cc_id, enum ast_cc_service_type service)
+{
+	struct ast_channel *owner;
+	struct ast_cc_config_params *cc_params;
+	struct sig_pri_cc_monitor_instance *monitor;
+	enum ast_cc_monitor_policies monitor_policy;
+	int core_id;
+	int res;
+	char device_name[AST_CHANNEL_NAME];
+
+	owner = pri->pvts[chanpos]->owner;
+
+	core_id = ast_cc_get_current_core_id(owner);
+	if (core_id == -1) {
+		return -1;
+	}
+
+	cc_params = ast_channel_get_cc_config_params(owner);
+	if (!cc_params) {
+		return -1;
+	}
+
+	res = -1;
+	monitor_policy = ast_get_cc_monitor_policy(cc_params);
+	switch (monitor_policy) {
+	case AST_CC_MONITOR_NEVER:
+		/* CCSS is not enabled. */
+		break;
+	case AST_CC_MONITOR_NATIVE:
+	case AST_CC_MONITOR_ALWAYS:
+		/*
+		 * If it is AST_CC_MONITOR_ALWAYS and native fails we will attempt the fallback
+		 * later in the call to sig_pri_cc_generic_check().
+		 */
+		ast_channel_get_device_name(owner, device_name, sizeof(device_name));
+		monitor = sig_pri_cc_monitor_instance_init(core_id, pri, cc_id, device_name);
+		res = ast_queue_cc_frame(owner, sig_pri_cc_type_name,
+			sig_pri_get_orig_dialstring(pri->pvts[chanpos]), service);
+		if (res) {
+			monitor->pri = NULL;
+			ao2_unlink(sig_pri_cc_monitors, monitor);
+		}
+		ao2_ref(monitor, -1);
+		break;
+	case AST_CC_MONITOR_GENERIC:
+		ast_queue_cc_frame(owner, AST_CC_GENERIC_MONITOR_TYPE,
+			sig_pri_get_orig_dialstring(pri->pvts[chanpos]), service);
+		/* Say it failed to force caller to cancel native CC. */
+		break;
+	}
+	return res;
+}
+#endif	/* defined(HAVE_PRI_CCSS) */
+
+#if defined(HAVE_PRI_CCSS)
+/*!
+ * \internal
+ * \brief Check if generic CC monitor is needed and request it.
+ * \since 1.8
+ *
+ * \param pri sig_pri PRI control structure.
+ * \param chanpos Channel position in the span.
+ * \param service CCBS/CCNR indication.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ * \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_cc_generic_check(struct sig_pri_pri *pri, int chanpos, enum ast_cc_service_type service)
+{
+	struct ast_channel *owner;
+	struct ast_cc_config_params *cc_params;
+	struct sig_pri_cc_monitor_instance *monitor;
+	enum ast_cc_monitor_policies monitor_policy;
+	int core_id;
+
+	if (!pri->pvts[chanpos]->outgoing) {
+		/* This is not an outgoing call so it cannot be CC monitor. */
+		return;
+	}
+
+	sig_pri_lock_owner(pri, chanpos);
+	owner = pri->pvts[chanpos]->owner;
+	if (!owner) {
+		return;
+	}
+	core_id = ast_cc_get_current_core_id(owner);
+	if (core_id == -1) {
+		/* No CC core setup */
+		goto done;
+	}
+
+	cc_params = ast_channel_get_cc_config_params(owner);
+	if (!cc_params) {
+		/* Could not get CC config parameters. */
+		goto done;
+	}
+
+	monitor = sig_pri_find_cc_monitor_by_core_id(core_id);
+	if (monitor) {
+		/* CC monitor is already present so no need for generic CC. */
+		ao2_ref(monitor, -1);
+		goto done;
+	}
+
+	monitor_policy = ast_get_cc_monitor_policy(cc_params);
+	switch (monitor_policy) {
+	case AST_CC_MONITOR_NEVER:
+		/* CCSS is not enabled. */
+		break;
+	case AST_CC_MONITOR_NATIVE:
+		if (pri->sig == SIG_BRI_PTMP && pri->nodetype == PRI_NETWORK) {
+			/* Request generic CC monitor. */
+			ast_queue_cc_frame(owner, AST_CC_GENERIC_MONITOR_TYPE,
+				sig_pri_get_orig_dialstring(pri->pvts[chanpos]), service);
+		}
+		break;
+	case AST_CC_MONITOR_ALWAYS:
+		if (pri->sig == SIG_BRI_PTMP && pri->nodetype != PRI_NETWORK) {
+			/* Cannot monitor PTMP TE side since this is not defined. */
+			break;
+		}
+		/*
+		 * We are either falling back or this is a PTMP NT span.
+		 * Request generic CC monitor.
+		 */
+		ast_queue_cc_frame(owner, AST_CC_GENERIC_MONITOR_TYPE,
+			sig_pri_get_orig_dialstring(pri->pvts[chanpos]), service);
+		break;
+	case AST_CC_MONITOR_GENERIC:
+		if (pri->sig == SIG_BRI_PTMP && pri->nodetype == PRI_NETWORK) {
+			/* Request generic CC monitor. */
+			ast_queue_cc_frame(owner, AST_CC_GENERIC_MONITOR_TYPE,
+				sig_pri_get_orig_dialstring(pri->pvts[chanpos]), service);
+		}
+		break;
+	}
+
+done:
+	ast_channel_unlock(owner);
+}
+#endif	/* defined(HAVE_PRI_CCSS) */
+
+/*!
+ * \internal
+ * \brief TRUE if PRI event came in on a CIS call.
+ * \since 1.8
+ *
+ * \param channel PRI encoded span/channel
+ *
+ * \retval non-zero if CIS call.
+ */
+static int sig_pri_is_cis_call(int channel)
+{
+	return channel != -1 && (channel & PRI_CIS_CALL);
+}
+
+/*!
+ * \internal
+ * \brief Handle the CIS associated PRI subcommand events.
+ * \since 1.8
+ *
+ * \param pri sig_pri PRI control structure.
+ * \param event_id PRI event id
+ * \param subcmds Subcommands to process if any. (Could be NULL).
+ * \param call_rsp libpri opaque call structure to send any responses toward.
+ * Could be NULL either because it is not available or the call is for the
+ * dummy call reference.  However, this should not be NULL in the cases that
+ * need to use the pointer to send a response message back.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_handle_cis_subcmds(struct sig_pri_pri *pri, int event_id,
+	const struct pri_subcommands *subcmds, q931_call *call_rsp)
+{
+	int index;
+#if defined(HAVE_PRI_CCSS)
+	struct ast_cc_agent *agent;
+	struct sig_pri_cc_agent_prv *agent_prv;
+	struct sig_pri_cc_monitor_instance *monitor;
+#endif	/* defined(HAVE_PRI_CCSS) */
+
+	if (!subcmds) {
+		return;
+	}
+	for (index = 0; index < subcmds->counter_subcmd; ++index) {
+		const struct pri_subcommand *subcmd = &subcmds->subcmd[index];
+
+		switch (subcmd->cmd) {
+#if defined(HAVE_PRI_CCSS)
+		case PRI_SUBCMD_CC_REQ:
+			agent = sig_pri_find_cc_agent_by_cc_id(pri, subcmd->u.cc_request.cc_id);
+			if (!agent) {
+				pri_cc_cancel(pri->pri, subcmd->u.cc_request.cc_id);
+				break;
+			}
+			if (!ast_cc_request_is_within_limits()) {
+				if (pri_cc_req_rsp(pri->pri, subcmd->u.cc_request.cc_id,
+					5/* queue_full */)) {
+					pri_cc_cancel(pri->pri, subcmd->u.cc_request.cc_id);
+				}
+				ast_cc_failed(agent->core_id, "System CC queue full");
+				ao2_ref(agent, -1);
+				break;
+			}
+			agent_prv = agent->private_data;
+			agent_prv->cc_request_response_pending = 1;
+			if (!ast_cc_agent_accept_request(agent->core_id,
+				"Caller accepted CC offer.")) {
+				agent_prv->cc_request_response_pending = 0;
+				if (pri_cc_req_rsp(pri->pri, subcmd->u.cc_request.cc_id,
+					2/* short_term_denial */)) {
+					pri_cc_cancel(pri->pri, subcmd->u.cc_request.cc_id);
+				}
+				ast_cc_failed(agent->core_id, "CC core request accept failed");
+			}
+			ao2_ref(agent, -1);
+			break;
+#endif	/* defined(HAVE_PRI_CCSS) */
+#if defined(HAVE_PRI_CCSS)
+		case PRI_SUBCMD_CC_REQ_RSP:
+			monitor = sig_pri_find_cc_monitor_by_cc_id(pri,
+				subcmd->u.cc_request_rsp.cc_id);
+			if (!monitor) {
+				pri_cc_cancel(pri->pri, subcmd->u.cc_request_rsp.cc_id);
+				break;
+			}
+			switch (subcmd->u.cc_request_rsp.status) {
+			case 0:/* success */
+				ast_cc_monitor_request_acked(monitor->core_id,
+					"Far end accepted CC request");
+				break;
+			case 1:/* timeout */
+				ast_verb(2, "%s CC request timeout\n", sig_pri_cc_type_name);
+				ast_cc_monitor_failed(monitor->core_id, monitor->name,
+					sig_pri_cc_type_name);
+				break;
+			case 2:/* error */
+				ast_verb(2, "%s CC request error: %s\n", sig_pri_cc_type_name,
+					pri_facility_error2str(subcmd->u.cc_request_rsp.fail_code));
+				ast_cc_monitor_failed(monitor->core_id, monitor->name,
+					sig_pri_cc_type_name);
+				break;
+			case 3:/* reject */
+				ast_verb(2, "%s CC request reject: %s\n", sig_pri_cc_type_name,
+					pri_facility_reject2str(subcmd->u.cc_request_rsp.fail_code));
+				ast_cc_monitor_failed(monitor->core_id, monitor->name,
+					sig_pri_cc_type_name);
+				break;
+			default:
+				ast_cc_monitor_failed(monitor->core_id, monitor->name,
+					sig_pri_cc_type_name);
+				break;
+			}
+			ao2_ref(monitor, -1);
+			break;
+#endif	/* defined(HAVE_PRI_CCSS) */
+#if defined(HAVE_PRI_CCSS)
+		case PRI_SUBCMD_CC_REMOTE_USER_FREE:
+			/*! \todo BUGBUG sig_pri_handle_cis_subcmds() not written */
+			break;
+#endif	/* defined(HAVE_PRI_CCSS) */
+#if defined(HAVE_PRI_CCSS)
+		case PRI_SUBCMD_CC_B_FREE:
+			/*! \todo BUGBUG sig_pri_handle_cis_subcmds() not written */
+			break;
+#endif	/* defined(HAVE_PRI_CCSS) */
+#if defined(HAVE_PRI_CCSS)
+		case PRI_SUBCMD_CC_STATUS_REQ:
+			/*! \todo BUGBUG sig_pri_handle_cis_subcmds() not written */
+			break;
+#endif	/* defined(HAVE_PRI_CCSS) */
+#if defined(HAVE_PRI_CCSS)
+		case PRI_SUBCMD_CC_STATUS_REQ_RSP:
+			/*! \todo BUGBUG sig_pri_handle_cis_subcmds() not written */
+			break;
+#endif	/* defined(HAVE_PRI_CCSS) */
+#if defined(HAVE_PRI_CCSS)
+		case PRI_SUBCMD_CC_STATUS:
+			/*! \todo BUGBUG sig_pri_handle_cis_subcmds() not written */
+			break;
+#endif	/* defined(HAVE_PRI_CCSS) */
+#if defined(HAVE_PRI_CCSS)
+		case PRI_SUBCMD_CC_CANCEL:
+			/*! \todo BUGBUG sig_pri_handle_cis_subcmds() not written */
+			break;
+#endif	/* defined(HAVE_PRI_CCSS) */
+#if defined(HAVE_PRI_CCSS)
+		case PRI_SUBCMD_CC_STOP_ALERTING:
+			/*! \todo BUGBUG sig_pri_handle_cis_subcmds() not written */
+			break;
+#endif	/* defined(HAVE_PRI_CCSS) */
+		default:
+			ast_debug(2,
+				"Unknown CIS subcommand(%d) in %s event on span %d.\n",
+				subcmd->cmd, pri_event2str(event_id), pri->span);
+			break;
+		}
+	}
+}
+
 /*!
  * \internal
  * \brief Handle the call associated PRI subcommand events.
@@ -1658,6 +2204,47 @@
 			}
 			break;
 #endif	/* defined(HAVE_PRI_CALL_REROUTING) */
+#if defined(HAVE_PRI_CCSS)
+		case PRI_SUBCMD_CC_AVAILABLE:
+			sig_pri_lock_owner(pri, chanpos);
+			owner = pri->pvts[chanpos]->owner;
+			if (owner) {
+				enum ast_cc_service_type service;
+
+				switch (event_id) {
+				case PRI_EVENT_RINGING:
+					service = AST_CC_CCNR;
+					break;
+				case PRI_EVENT_HANGUP_REQ:
+					/* We will assume that the cause was busy/congestion. */
+					service = AST_CC_CCBS;
+					break;
+				default:
+					service = AST_CC_NONE;
+					break;
+				}
+				if (service == AST_CC_NONE
+					|| sig_pri_cc_available(pri, chanpos, subcmd->u.cc_available.cc_id,
+					service)) {
+					pri_cc_cancel(pri->pri, subcmd->u.cc_available.cc_id);
+				}
+				ast_channel_unlock(owner);
+			} else {
+				/* No asterisk channel. */
+				pri_cc_cancel(pri->pri, subcmd->u.cc_available.cc_id);
+			}
+			break;
+#endif	/* defined(HAVE_PRI_CCSS) */
+#if defined(HAVE_PRI_CCSS)
+		case PRI_SUBCMD_CC_CALL:
+			/*! \todo BUGBUG sig_pri_handle_subcmds() not written */
+			break;
+#endif	/* defined(HAVE_PRI_CCSS) */
+#if defined(HAVE_PRI_CCSS)
+		case PRI_SUBCMD_CC_CANCEL:
+			/*! \todo BUGBUG sig_pri_handle_subcmds() not written */
+			break;
+#endif	/* defined(HAVE_PRI_CCSS) */
 		default:
 			ast_debug(2,
 				"Unknown call subcommand(%d) in %s event on channel %d/%d on span %d.\n",
@@ -2198,6 +2785,11 @@
 				}
 				break;
 			case PRI_EVENT_KEYPAD_DIGIT:
+				if (sig_pri_is_cis_call(e->digit.channel)) {
+					sig_pri_handle_cis_subcmds(pri, e->e, e->digit.subcmds,
+						e->digit.call);
+					break;
+				}
 				chanpos = pri_find_principle(pri, e->digit.channel, e->digit.call);
 				if (chanpos < 0) {
 					ast_log(LOG_WARNING, "KEYPAD_DIGITs received on unconfigured channel %d/%d span %d\n",
@@ -2228,6 +2820,11 @@
 				break;
 
 			case PRI_EVENT_INFO_RECEIVED:
+				if (sig_pri_is_cis_call(e->ring.channel)) {
+					sig_pri_handle_cis_subcmds(pri, e->e, e->ring.subcmds,
+						e->ring.call);
+					break;
+				}
 				chanpos = pri_find_principle(pri, e->ring.channel, e->ring.call);
 				if (chanpos < 0) {
 					ast_log(LOG_WARNING, "INFO received on unconfigured channel %d/%d span %d\n",
@@ -2319,7 +2916,12 @@
 					pri_destroycall(pri->pri, e->ring.call);
 					break;
 				}
-				if (e->ring.channel == -1)
+				if (sig_pri_is_cis_call(e->ring.channel)) {
+					sig_pri_handle_cis_subcmds(pri, e->e, e->ring.subcmds,
+						e->ring.call);
+					break;
+				}
+				if (e->ring.channel == -1 || PRI_CHANNEL(e->ring.channel) == 0xFF)
 					chanpos = pri_find_empty_chan(pri, 1);
 				else
 					chanpos = pri_find_principle(pri, e->ring.channel, e->ring.call);
@@ -2660,6 +3262,11 @@
 				}
 				break;
 			case PRI_EVENT_RINGING:
+				if (sig_pri_is_cis_call(e->ringing.channel)) {
+					sig_pri_handle_cis_subcmds(pri, e->e, e->ringing.subcmds,
+						e->ringing.call);
+					break;
+				}
 				chanpos = pri_find_principle(pri, e->ringing.channel, e->ringing.call);
 				if (chanpos < 0) {
 					ast_log(LOG_WARNING, "Ringing requested on unconfigured channel %d/%d span %d\n",
@@ -2674,6 +3281,9 @@
 
 						sig_pri_handle_subcmds(pri, chanpos, e->e, e->ringing.channel,
 							e->ringing.subcmds, e->ringing.call);
+#if defined(HAVE_PRI_CCSS)
+						sig_pri_cc_generic_check(pri, chanpos, AST_CC_CCNR);
+#endif	/* defined(HAVE_PRI_CCSS) */
 						sig_pri_set_echocanceller(pri->pvts[chanpos], 1);
 						pri_queue_control(pri->pvts[chanpos], AST_CONTROL_RINGING, pri);
 						pri->pvts[chanpos]->alerting = 1;
@@ -2697,7 +3307,11 @@
 				}
 				break;
 			case PRI_EVENT_PROGRESS:
-				/* Get chan value if e->e is not PRI_EVNT_RINGING */
+				if (sig_pri_is_cis_call(e->proceeding.channel)) {
+					sig_pri_handle_cis_subcmds(pri, e->e, e->proceeding.subcmds,
+						e->proceeding.call);
+					break;
+				}
 				chanpos = pri_find_principle(pri, e->proceeding.channel, e->proceeding.call);
 				if (chanpos > -1) {
 					sig_pri_lock_private(pri->pvts[chanpos]);
@@ -2747,6 +3361,11 @@
 				}
 				break;
 			case PRI_EVENT_PROCEEDING:
+				if (sig_pri_is_cis_call(e->proceeding.channel)) {
+					sig_pri_handle_cis_subcmds(pri, e->e, e->proceeding.subcmds,
+						e->proceeding.call);
+					break;
+				}
 				chanpos = pri_find_principle(pri, e->proceeding.channel, e->proceeding.call);
 				if (chanpos > -1) {
 					sig_pri_lock_private(pri->pvts[chanpos]);
@@ -2776,6 +3395,17 @@
 				}
 				break;
 			case PRI_EVENT_FACILITY:
+				if (!e->facility.call || sig_pri_is_cis_call(e->facility.channel)) {
+					/* Event came in on the dummy channel or a CIS call. */
+#if defined(HAVE_PRI_CALL_REROUTING)
+					sig_pri_handle_cis_subcmds(pri, e->e, e->facility.subcmds,
+						e->facility.subcall);
+#else
+					sig_pri_handle_cis_subcmds(pri, e->e, e->facility.subcmds,
+						e->facility.call);
+#endif	/* !defined(HAVE_PRI_CALL_REROUTING) */
+					break;
+				}
 				chanpos = pri_find_principle(pri, e->facility.channel, e->facility.call);
 				if (chanpos < 0) {
 					ast_log(LOG_WARNING, "Facility requested on unconfigured channel %d/%d span %d\n",
@@ -2799,6 +3429,11 @@
 				}
 				break;
 			case PRI_EVENT_ANSWER:
+				if (sig_pri_is_cis_call(e->answer.channel)) {
+					sig_pri_handle_cis_subcmds(pri, e->e, e->answer.subcmds,
+						e->answer.call);
+					break;
+				}
 				chanpos = pri_find_principle(pri, e->answer.channel, e->answer.call);
 				if (chanpos < 0) {
 					ast_log(LOG_WARNING, "Answer on unconfigured channel %d/%d span %d\n",
@@ -2837,6 +3472,12 @@
 				}
 				break;
 			case PRI_EVENT_HANGUP:
+				if (sig_pri_is_cis_call(e->hangup.channel)) {
+					sig_pri_handle_cis_subcmds(pri, e->e, e->hangup.subcmds,
+						e->hangup.call);
+					pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
+					break;
+				}
 				chanpos = pri_find_principle(pri, e->hangup.channel, e->hangup.call);
 				if (chanpos < 0) {
 					ast_log(LOG_WARNING, "Hangup requested on unconfigured channel %d/%d span %d\n",
@@ -2916,6 +3557,12 @@
 				}
 				break;
 			case PRI_EVENT_HANGUP_REQ:
+				if (sig_pri_is_cis_call(e->hangup.channel)) {
+					sig_pri_handle_cis_subcmds(pri, e->e, e->hangup.subcmds,
+						e->hangup.call);
+					pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
+					break;
+				}
 				chanpos = pri_find_principle(pri, e->hangup.channel, e->hangup.call);
 				if (chanpos < 0) {
 					ast_log(LOG_WARNING, "Hangup REQ requested on unconfigured channel %d/%d span %d\n",
@@ -2938,6 +3585,16 @@
 							sig_pri_lock_private(pri->pvts[chanpos]);
 						}
 #endif	/* defined(HAVE_PRI_CALL_HOLD) */
+#if defined(HAVE_PRI_CCSS)
+						switch (e->hangup.cause) {
+						case PRI_CAUSE_USER_BUSY:
+						case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
+							sig_pri_cc_generic_check(pri, chanpos, AST_CC_CCBS);
+							break;
+						default:
+							break;
+						}
+#endif	/* defined(HAVE_PRI_CCSS) */
 						if (pri->pvts[chanpos]->owner) {
 							pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
 							switch (pri->pvts[chanpos]->owner->_state) {
@@ -3000,6 +3657,11 @@
 				}
 				break;
 			case PRI_EVENT_HANGUP_ACK:
+				if (sig_pri_is_cis_call(e->hangup.channel)) {
+					sig_pri_handle_cis_subcmds(pri, e->e, e->hangup.subcmds,
+						e->hangup.call);
+					break;
+				}
 				chanpos = pri_find_principle(pri, e->hangup.channel, e->hangup.call);
 				if (chanpos < 0) {
 					ast_log(LOG_WARNING, "Hangup ACK requested on unconfigured channel number %d/%d span %d\n",
@@ -3083,6 +3745,11 @@
 				}
 				break;
 			case PRI_EVENT_SETUP_ACK:
+				if (sig_pri_is_cis_call(e->setup_ack.channel)) {
+					sig_pri_handle_cis_subcmds(pri, e->e, e->setup_ack.subcmds,
+						e->setup_ack.call);
+					break;
+				}
 				chanpos = pri_find_principle(pri, e->setup_ack.channel, e->setup_ack.call);
 				if (chanpos < 0) {
 					ast_log(LOG_WARNING, "Received SETUP_ACKNOWLEDGE on unconfigured channel %d/%d span %d\n",
@@ -3106,6 +3773,15 @@
 				}
 				break;
 			case PRI_EVENT_NOTIFY:
+				if (sig_pri_is_cis_call(e->notify.channel)) {
+#if defined(HAVE_PRI_CALL_HOLD)
+					sig_pri_handle_cis_subcmds(pri, e->e, e->notify.subcmds,
+						e->notify.call);
+#else
+					sig_pri_handle_cis_subcmds(pri, e->e, e->notify.subcmds, NULL);
+#endif	/* !defined(HAVE_PRI_CALL_HOLD) */
+					break;
+				}
 #if defined(HAVE_PRI_CALL_HOLD)
 				chanpos = pri_find_principle(pri, e->notify.channel, e->notify.call);
 #else
@@ -3146,6 +3822,7 @@
 				break;
 #if defined(HAVE_PRI_CALL_HOLD)
 			case PRI_EVENT_HOLD:
+				/* We should not be getting any CIS calls with this message type. */
 				if (sig_pri_handle_hold(pri, e)) {
 					pri_hold_rej(pri->pri, e->hold.call,
 						PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED);
@@ -3166,6 +3843,7 @@
 #endif	/* defined(HAVE_PRI_CALL_HOLD) */
 #if defined(HAVE_PRI_CALL_HOLD)
 			case PRI_EVENT_RETRIEVE:
+				/* We should not be getting any CIS calls with this message type. */
 				sig_pri_handle_retrieve(pri, e);
 				break;
 #endif	/* defined(HAVE_PRI_CALL_HOLD) */
@@ -3969,6 +4647,14 @@
 #if defined(HAVE_PRI_CALL_REROUTING)
 		pri_reroute_enable(pri->dchans[i], 1);
 #endif	/* defined(HAVE_PRI_CALL_REROUTING) */
+#if defined(HAVE_PRI_CCSS)
+		pri_cc_enable(pri->dchans[i], 1);
+/*
+ * BUGBUG need to add CCSS DAHDI/PRI specific options:
+ * Q.SIG retain CC signaling link options.
+ * ETSI PTMP recall mode
+ */
+#endif	/* defined(HAVE_PRI_CCSS) */
 		/* Enslave to master if appropriate */
 		if (i)
 			pri_enslave(pri->dchans[0], pri->dchans[i]);
@@ -4302,6 +4988,7 @@
 	cc_pvt = agent->private_data;
 	ast_mutex_lock(&cc_pvt->pri->lock);
 	if (cc_pvt->cc_request_response_pending) {
+		cc_pvt->cc_request_response_pending = 0;
 		res = pri_cc_req_rsp(cc_pvt->pri->pri, cc_pvt->cc_id, 0/* success */);
 	} else {
 		res = 0;
@@ -4500,6 +5187,46 @@
 
 #if defined(HAVE_PRI_CCSS)
 /*!
+ * \internal
+ * \brief Return the hash value of the given CC monitor instance object.
+ * \since 1.8
+ *
+ * \param obj pointer to the (user-defined part) of an object.
+ * \param flags flags from ao2_callback().  Ignored at the moment.
+ *
+ * \retval core_id
+ */
+static int sig_pri_cc_monitor_instance_hash_fn(const void *obj, const int flags)
+{
+	const struct sig_pri_cc_monitor_instance *monitor_instance = obj;
+
+	return monitor_instance->core_id;
+}
+#endif	/* defined(HAVE_PRI_CCSS) */
+
+#if defined(HAVE_PRI_CCSS)
+/*!
+ * \internal
+ * \brief Compere the monitor instance core_id key value.
+ * \since 1.8
+ *
+ * \param obj pointer to the (user-defined part) of an object.
+ * \param arg callback argument from ao2_callback()
+ * \param flags flags from ao2_callback()
+ *
+ * \return values are a combination of enum _cb_results.
+ */
+static int sig_pri_cc_monitor_instance_cmp_fn(void *obj, void *arg, int flags)
+{
+	struct sig_pri_cc_monitor_instance *monitor_1 = obj;
+	struct sig_pri_cc_monitor_instance *monitor_2 = arg;
+
+	return monitor_1->core_id == monitor_2->core_id ? CMP_MATCH | CMP_STOP : 0;
+}
+#endif	/* defined(HAVE_PRI_CCSS) */
+
+#if defined(HAVE_PRI_CCSS)
+/*!
  * \brief PRI CC monitor initialization.
  * \since 1.8
  *
@@ -4684,4 +5411,42 @@
 }
 #endif	/* defined(HAVE_PRI_CCSS) */
 
+/*!
+ * \brief Load the sig_pri submodule.
+ * \since 1.8
+ *
+ * \param cc_type_name CC type name to use when looking up agent/monitor.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int sig_pri_load(const char *cc_type_name)
+{
+#if defined(HAVE_PRI_CCSS)
+	sig_pri_cc_type_name = cc_type_name;
+	sig_pri_cc_monitors = ao2_container_alloc(37, sig_pri_cc_monitor_instance_hash_fn,
+		sig_pri_cc_monitor_instance_cmp_fn);
+	if (!sig_pri_cc_monitors) {
+		return -1;
+	}
+#endif	/* defined(HAVE_PRI_CCSS) */
+	return 0;
+}
+
+/*!
+ * \brief Unload the sig_pri submodule.
+ * \since 1.8
+ *
+ * \return Nothing
+ */
+void sig_pri_unload(void)
+{
+#if defined(HAVE_PRI_CCSS)
+	if (sig_pri_cc_monitors) {
+		ao2_ref(sig_pri_cc_monitors, -1);
+		sig_pri_cc_monitors = NULL;
+	}
+#endif	/* defined(HAVE_PRI_CCSS) */
+}
+
 #endif /* HAVE_PRI */

Modified: team/rmudgett/dahdi_ccss/channels/sig_pri.h

[... 30 lines stripped ...]



More information about the asterisk-commits mailing list