[asterisk-commits] rmudgett: branch group/CCSS r243776 - in /team/group/CCSS: ./ channels/ configs/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Jan 27 16:56:18 CST 2010


Author: rmudgett
Date: Wed Jan 27 16:56:13 2010
New Revision: 243776

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=243776
Log:
Add chan_dahdi ISDN native CC support.

Modified:
    team/group/CCSS/channels/chan_dahdi.c
    team/group/CCSS/channels/sig_pri.c
    team/group/CCSS/channels/sig_pri.h
    team/group/CCSS/configs/chan_dahdi.conf.sample
    team/group/CCSS/configure.ac

Modified: team/group/CCSS/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/team/group/CCSS/channels/chan_dahdi.c?view=diff&rev=243776&r1=243775&r2=243776
==============================================================================
--- team/group/CCSS/channels/chan_dahdi.c (original)
+++ team/group/CCSS/channels/chan_dahdi.c Wed Jan 27 16:56:13 2010
@@ -607,6 +607,11 @@
 };
 
 static struct dahdi_pri pris[NUM_SPANS];
+
+#if defined(HAVE_PRI_CCSS)
+/*! DAHDI PRI CCSS agent and monitor type name. */
+static const char dahdi_pri_cc_type[] = "DAHDI/PRI";
+#endif	/* defined(HAVE_PRI_CCSS) */
 
 #else
 /*! Shut up the compiler */
@@ -1319,6 +1324,12 @@
 			.nodetype = PRI_CPE,
 			.qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL,
 
+#if defined(HAVE_PRI_CCSS)
+			.cc_ptmp_recall_mode = 1,/* specificRecall */
+			.cc_qsig_signaling_link_req = 1,/* retain */
+			.cc_qsig_signaling_link_rsp = 1,/* retain */
+#endif	/* defined(HAVE_PRI_CCSS) */
+
 			.minunused = 2,
 			.idleext = "",
 			.idledial = "",
@@ -2795,6 +2806,65 @@
 	ast_copy_string(p->rdnis, rdnis, sizeof(p->rdnis));
 }
 
+/*!
+ * \internal
+ * \brief Make a dialstring for native ISDN CC to recall properly.
+ * \since 1.8
+ *
+ * \param priv Channel private control structure.
+ * \param buf Where to put the modified dialstring.
+ * \param buf_size Size of modified dialstring buffer.
+ *
+ * \details
+ * original dialstring:
+ * DAHDI/[i<span>-]<channel#>[c|r<cadance#>|d][/extension[/options]]
+ * DAHDI/[i<span>-](g|G|r|R)<group#(0-63)>[c|r<cadance#>|d][/extension[/options]]
+ *
+ * The modified dialstring will have prefixed the channel-group section
+ * with the ISDN channel restriction.
+ *
+ * buf:
+ * DAHDI/i<span>-<channel#>[c|r<cadance#>|d][/extension[/options]]
+ * DAHDI/i<span>-(g|G|r|R)<group#(0-63)>[c|r<cadance#>|d][/extension[/options]]
+ *
+ * The routine will check to see if the ISDN channel restriction is already
+ * in the original dialstring.
+ *
+ * \return Nothing
+ */
+static void my_pri_make_cc_dialstring(void *priv, char *buf, size_t buf_size)
+{
+	char *dial;
+	struct dahdi_pvt *pvt;
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(tech);	/* channel technology token */
+		AST_APP_ARG(group);	/* channel/group token */
+		//AST_APP_ARG(ext);	/* extension token */
+		//AST_APP_ARG(opts);	/* options token */
+		//AST_APP_ARG(other);	/* Any remining unused arguments */
+	);
+
+	pvt = priv;
+	dial = ast_strdupa(pvt->dialstring);
+	AST_NONSTANDARD_APP_ARGS(args, dial, '/');
+	if (!args.tech) {
+		ast_copy_string(buf, pvt->dialstring, buf_size);
+		return;
+	}
+	if (!args.group) {
+		/* Append the ISDN span channel restriction to the dialstring. */
+		snprintf(buf, buf_size, "%s/i%d-", args.tech, pvt->pri->span);
+		return;
+	}
+	if (args.group[0] == 'i') {
+		/* The ISDN span channel restriction is already in the dialstring. */
+		ast_copy_string(buf, pvt->dialstring, buf_size);
+		return;
+	}
+	/* Insert the ISDN span channel restriction into the dialstring. */
+	snprintf(buf, buf_size, "%s/i%d-%s", args.tech, pvt->pri->span, args.group);
+}
+
 static int dahdi_new_pri_nobch_channel(struct sig_pri_pri *pri);
 
 static struct sig_pri_callback dahdi_pri_callbacks =
@@ -2813,6 +2883,8 @@
 	.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,
+	.make_cc_dialstring = my_pri_make_cc_dialstring,
 };
 #endif	/* defined(HAVE_PRI) */
 
@@ -5105,6 +5177,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);
@@ -5939,6 +6014,16 @@
 		*cp = (p->callprogress & CALLPROGRESS_FAX) ? 0 : 1;
 		ast_debug(1, "Reporting fax tone detection %sabled on %s\n", *cp ? "en" : "dis", chan->name);
 		break;
+	case AST_OPTION_CC_AGENT_TYPE:
+#if defined(HAVE_PRI)
+#if defined(HAVE_PRI_CCSS)
+		if (dahdi_sig_pri_lib_handles(p->sig)) {
+			ast_copy_string((char *) data, dahdi_pri_cc_type, *datalen);
+			break;
+		}
+#endif	/* defined(HAVE_PRI_CCSS) */
+#endif	/* defined(HAVE_PRI) */
+		return -1;
 	default:
 		return -1;
 	}
@@ -7964,23 +8049,30 @@
 
 static const char *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;
 
-	if (monitor_policy == AST_CC_MONITOR_GENERIC || monitor_policy == AST_CC_MONITOR_ALWAYS) {
-		monitor_type = "generic";
-	} else if (monitor_policy == AST_CC_MONITOR_NATIVE) {
-		monitor_type = "DAHDI";
-	} else {
-		return NULL;
-	}
-
-	if (ast_cc_monitor_count(device_name, monitor_type) >= ast_get_cc_max_monitors(cc_params)) {
-		return NULL;
-	}
-
-	return monitor_type;
+	monitor_type = NULL;
+	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 monitor_type;
+	}
+
+	return NULL;
 }
 
 static struct ast_frame *dahdi_read(struct ast_channel *ast)
@@ -8675,6 +8767,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;
@@ -11197,6 +11294,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++)
@@ -11440,6 +11542,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;
@@ -11462,6 +11574,14 @@
 						pris[span].pri.hold_disconnect_transfer =
 							conf->pri.pri.hold_disconnect_transfer;
 #endif	/* defined(HAVE_PRI_CALL_HOLD) */
+#if defined(HAVE_PRI_CCSS)
+						pris[span].pri.cc_ptmp_recall_mode =
+							conf->pri.pri.cc_ptmp_recall_mode;
+						pris[span].pri.cc_qsig_signaling_link_req =
+							conf->pri.pri.cc_qsig_signaling_link_req;
+						pris[span].pri.cc_qsig_signaling_link_rsp =
+							conf->pri.pri.cc_qsig_signaling_link_rsp;
+#endif	/* defined(HAVE_PRI_CCSS) */
 						pris[span].pri.facilityenable = conf->pri.pri.facilityenable;
 						ast_copy_string(pris[span].pri.msn_list, conf->pri.pri.msn_list, sizeof(pris[span].pri.msn_list));
 						ast_copy_string(pris[span].pri.idledial, conf->pri.pri.idledial, sizeof(pris[span].pri.idledial));
@@ -11766,7 +11886,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;
@@ -11888,9 +12008,17 @@
 	return tmp;
 }
 
-static int is_group_or_channel_match(struct dahdi_pvt *p, ast_group_t groupmatch, int *groupmatched, int channelmatch, int *channelmatched)
-{
-	/* First, check group matching */
+static int is_group_or_channel_match(struct dahdi_pvt *p, int span, ast_group_t groupmatch, int *groupmatched, int channelmatch, int *channelmatched)
+{
+#if defined(HAVE_PRI)
+	if (0 < span) {
+		/* The channel must be on the specified PRI span. */
+		if (!p->pri || p->pri->span != span) {
+			return 0;
+		}
+	}
+#endif	/* defined(HAVE_PRI) */
+	/* check group matching */
 	if (groupmatch) {
 		if ((p->group & groupmatch) != groupmatch)
 			/* Doesn't match the specified group, try the next one */
@@ -12002,6 +12130,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;
@@ -12103,13 +12236,29 @@
 	return p;
 }
 
-static struct dahdi_pvt *determine_starting_point(char *data, ast_group_t *groupmatch, int *channelmatch, int *backwards, int *roundrobin, int *rr_starting_point)
+struct dahdi_starting_point {
+	/*! Group matching mask.  Zero if not specified. */
+	ast_group_t groupmatch;
+	/*! DAHDI channel to match with.  -1 if not specified. */
+	int channelmatch;
+	/*! Round robin saved search location index. (Valid if roundrobin TRUE) */
+	int rr_starting_point;
+	/*! ISDN span where channels can be picked (Zero if not specified) */
+	int span;
+	/*! Analog channel distinctive ring cadance index. */
+	int cadance;
+	/*! Dialing option. c/r/d if present and valid. */
+	char opt;
+	/*! TRUE if to search the channel list backwards. */
+	char backwards;
+	/*! TRUE if search is done with round robin sequence. */
+	char roundrobin;
+};
+static struct dahdi_pvt *determine_starting_point(const char *data, struct dahdi_starting_point *param)
 {
 	char *dest;
 	char *s;
-	char opt = 0;
 	int x;
-	int y = 0;
 	int res = 0;
 	struct dahdi_pvt *p;
 	AST_DECLARE_APP_ARGS(args,
@@ -12122,8 +12271,11 @@
 	/*
 	 * data is ---v
 	 * Dial(DAHDI/pseudo[/extension[/options]])
-	 * Dial(DAHDI/<channel#>[c|r<cadance#>|d][/extension[/options]])
-	 * Dial(DAHDI/(g|G|r|R)<group#(0-63)>[c|r<cadance#>|d][/extension[/options]])
+	 * Dial(DAHDI/[i<span>-]<channel#>[c|r<cadance#>|d][/extension[/options]])
+	 * Dial(DAHDI/[i<span>-](g|G|r|R)<group#(0-63)>[c|r<cadance#>|d][/extension[/options]])
+	 *
+	 * i - ISDN span channel restriction.
+	 *     Used by CC to ensure that the CC recall goes out the same span.
 	 *
 	 * g - channel group allocation search forward
 	 * G - channel group allocation search backward
@@ -12136,7 +12288,7 @@
 	 */
 
 	if (data) {
-		dest = ast_strdupa((char *)data);
+		dest = ast_strdupa(data);
 	} else {
 		ast_log(LOG_WARNING, "Channel requested with no data\n");
 		return NULL;
@@ -12147,24 +12299,47 @@
 		return NULL;
 	}
 
+	/* Initialize the output parameters */
+	memset(param, 0, sizeof(*param));
+	param->channelmatch = -1;
+
+	if (args.group[0] == 'i') {
+		/* Extract the ISDN span channel restriction specifier. */
+		res = sscanf(args.group + 1, "%30d", &x);
+		if (res < 1) {
+			ast_log(LOG_WARNING, "Unable to determine ISDN span %s\n", data);
+			return NULL;
+		}
+		param->span = x;
+
+		/* Remove the ISDN span channel restriction specifier. */
+		s = strchr(args.group, '-');
+		if (!s) {
+			ast_log(LOG_WARNING, "Bad format for ISDN span %s\n", data);
+			return NULL;
+		}
+		args.group = s + 1;
+		res = 0;
+	}
 	if (toupper(args.group[0]) == 'G' || toupper(args.group[0])=='R') {
 		/* Retrieve the group number */
 		s = args.group + 1;
-		if ((res = sscanf(s, "%30d%1c%30d", &x, &opt, &y)) < 1) {
-			ast_log(LOG_WARNING, "Unable to determine group for data %s\n", (char *)data);
+		res = sscanf(s, "%30d%1c%30d", &x, &param->opt, &param->cadance);
+		if (res < 1) {
+			ast_log(LOG_WARNING, "Unable to determine group for data %s\n", data);
 			return NULL;
 		}
-		*groupmatch = ((ast_group_t) 1 << x);
+		param->groupmatch = ((ast_group_t) 1 << x);
 
 		if (toupper(args.group[0]) == 'G') {
 			if (args.group[0] == 'G') {
-				*backwards = 1;
+				param->backwards = 1;
 				p = ifend;
 			} else
 				p = iflist;
 		} else {
 			if (args.group[0] == 'R') {
-				*backwards = 1;
+				param->backwards = 1;
 				p = round_robin[x]?round_robin[x]->prev:ifend;
 				if (!p)
 					p = ifend;
@@ -12173,58 +12348,57 @@
 				if (!p)
 					p = iflist;
 			}
-			*roundrobin = 1;
+			param->roundrobin = 1;
+			param->rr_starting_point = x;
 		}
 	} else {
 		s = args.group;
 		if (!strcasecmp(s, "pseudo")) {
 			/* Special case for pseudo */
 			x = CHAN_PSEUDO;
-			*channelmatch = x;
-		} else if ((res = sscanf(s, "%30d%1c%30d", &x, &opt, &y)) < 1) {
-			ast_log(LOG_WARNING, "Unable to determine channel for data %s\n", (char *)data);
-			return NULL;
+			param->channelmatch = x;
 		} else {
-			*channelmatch = x;
+			res = sscanf(s, "%30d%1c%30d", &x, &param->opt, &param->cadance);
+			if (res < 1) {
+				ast_log(LOG_WARNING, "Unable to determine channel for data %s\n", data);
+				return NULL;
+			} else {
+				param->channelmatch = x;
+			}
 		}
 
 		p = iflist;
 	}
-	if (*roundrobin) {
-		*rr_starting_point = x;
-	}
+
+	if (param->opt == 'r' && res < 3) {
+		ast_log(LOG_WARNING, "Distinctive ring missing identifier in '%s'\n", data);
+		param->opt = '\0';
+	}
+
 	return p;
 }
 
 static struct ast_channel *dahdi_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
 {
-	ast_group_t groupmatch = 0;
-	int channelmatch = -1;
-	int roundrobin = 0;
 	int callwait = 0;
 	int unavailreason = 0;
 	struct dahdi_pvt *p;
 	struct ast_channel *tmp = NULL;
-	char opt=0;
-	int res=0, y=0;
-	int backwards = 0;
 	struct dahdi_pvt *exitpvt;
 	int channelmatched = 0;
 	int groupmatched = 0;
 	int transcapdigital = 0;
-	int rr_starting_point;
-
-	p = determine_starting_point(data, &groupmatch, &channelmatch, &backwards, &roundrobin, &rr_starting_point);
+	struct dahdi_starting_point start;
+
+	p = determine_starting_point(data, &start);
 	/* Search for an unowned channel */
 	exitpvt = p;
 	ast_mutex_lock(&iflock);
 	while (p && !tmp) {
-		if (roundrobin)
-			round_robin[rr_starting_point] = p;
-#if 0
-		ast_verbose("name = %s, %d, %d, %llu\n",p->owner ? p->owner->name : "<none>", p->channel, channelmatch, groupmatch);
-#endif
-		if (is_group_or_channel_match(p, groupmatch, &groupmatched, channelmatch, &channelmatched)
+		if (start.roundrobin)
+			round_robin[start.rr_starting_point] = p;
+
+		if (is_group_or_channel_match(p, start.span, start.groupmatch, &groupmatched, start.channelmatch, &channelmatched)
 			&& available(p, &unavailreason)) {
 			ast_debug(1, "Using channel %d\n", p->channel);
 
@@ -12249,22 +12423,25 @@
 			}
 
 			/* Make special notes */
-			if (res > 1) {
-				if (opt == 'c') {
-					/* Confirm answer */
-					p->confirmanswer = 1;
-				} else if (opt == 'r') {
-					/* Distinctive ring */
-					if (res < 3)
-						ast_log(LOG_WARNING, "Distinctive ring missing identifier in '%s'\n", (char *)data);
-					else
-						p->distinctivering = y;
-				} else if (opt == 'd') {
-					/* If this is an ISDN call, make it digital */
-					transcapdigital = AST_TRANS_CAP_DIGITAL;
-				} else {
-					ast_log(LOG_WARNING, "Unknown option '%c' in '%s'\n", opt, (char *)data);
-				}
+			switch (start.opt) {
+			case '\0':
+				/* No option present. */
+				break;
+			case 'c':
+				/* Confirm answer */
+				p->confirmanswer = 1;
+				break;
+			case 'r':
+				/* Distinctive ring */
+				p->distinctivering = start.cadance;
+				break;
+			case 'd':
+				/* If this is an ISDN call, make it digital */
+				transcapdigital = AST_TRANS_CAP_DIGITAL;
+				break;
+			default:
+				ast_log(LOG_WARNING, "Unknown option '%c' in '%s'\n", start.opt, (char *)data);
+				break;
 			}
 
 			p->outgoing = 1;
@@ -12292,7 +12469,7 @@
 #ifdef HAVE_OPENR2
 next:
 #endif
-		if (backwards) {
+		if (start.backwards) {
 			p = p->prev;
 			if (!p)
 				p = ifend;
@@ -12338,19 +12515,17 @@
  */
 static int dahdi_cc_callback(struct ast_channel *inbound, const char *dest, ast_cc_callback_fn callback)
 {
-	struct dahdi_pvt *p, *exitpvt;
-	ast_group_t groupmatch = 0;
+	struct dahdi_pvt *p;
+	struct dahdi_pvt *exitpvt;
+	struct dahdi_starting_point start;
 	int groupmatched = 0;
-	int channelmatch = -1;
 	int channelmatched = 0;
-	int backwards = 0;
-	int roundrobin = 0;
-	int rr_starting_point = 0;
-
-	p = determine_starting_point((char *)dest, &groupmatch, &channelmatch, &backwards, &roundrobin, &rr_starting_point);
+
+	p = determine_starting_point(dest, &start);
+	ast_mutex_lock(&iflock);
 	exitpvt = p;
 	for (;;) {
-		if (is_group_or_channel_match(p, groupmatch, &groupmatched, channelmatch, &channelmatched)) {
+		if (is_group_or_channel_match(p, start.span, start.groupmatch, &groupmatched, start.channelmatch, &channelmatched)) {
 			/* We found a potential match. call the callback */
 			struct ast_str *device_name;
 			char *dash;
@@ -12396,18 +12571,25 @@
 				 * monitor can be made to do this task.
 				 */
 				monitor_type = AST_CC_GENERIC_MONITOR_TYPE;
-				callback(inbound, p->cc_params, monitor_type, full_device_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) */
+					monitor_type, full_device_name, dialstring);
 				break;
 			}
 		}
-		p = backwards ? p->prev : p->next;
+		p = start.backwards ? p->prev : p->next;
 		if (!p) {
-			p = backwards ? ifend : iflist;
+			p = start.backwards ? ifend : iflist;
 		}
 		if (p == exitpvt) {
 			break;
 		}
 	}
+	ast_mutex_unlock(&iflock);
 	return 0;
 }
 
@@ -15738,6 +15920,168 @@
 };
 #endif	/* defined(HAVE_SS7) */
 
+#if defined(HAVE_PRI)
+#if defined(HAVE_PRI_CCSS)
+/*!
+ * \internal
+ * \brief CC agent initialization.
+ * \since 1.8
+ *
+ * \param agent CC core agent control.
+ * \param chan Original channel the agent will attempt to recall.
+ *
+ * \details
+ * This callback is called when the CC core is initialized.  Agents should allocate
+ * any private data necessary for the call and assign it to the private_data
+ * on the agent.  Additionally, if any ast_cc_agent_flags are pertinent to the
+ * specific agent type, they should be set in this function as well.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int dahdi_pri_cc_agent_init(struct ast_cc_agent *agent, struct ast_channel *chan)
+{
+	struct dahdi_pvt *pvt;
+	struct sig_pri_chan *pvt_chan;
+	int res;
+
+	ast_assert(!strcmp(chan->tech->type, "DAHDI"));
+
+	pvt = chan->tech_pvt;
+	if (dahdi_sig_pri_lib_handles(pvt->sig)) {
+		pvt_chan = pvt->sig_pvt;
+	} else {
+		pvt_chan = NULL;
+	}
+	if (!pvt_chan) {
+		return -1;
+	}
+
+	ast_module_ref(ast_module_info->self);
+
+	res = sig_pri_cc_agent_init(agent, pvt_chan);
+	if (res) {
+		ast_module_unref(ast_module_info->self);
+	}
+	return res;
+}
+#endif	/* defined(HAVE_PRI_CCSS) */
+#endif	/* defined(HAVE_PRI) */
+
+#if defined(HAVE_PRI)
+#if defined(HAVE_PRI_CCSS)
+/*!
+ * \internal
+ * \brief Destroy private data on the agent.
+ * \since 1.8
+ *
+ * \param agent CC core agent control.
+ *
+ * \details
+ * The core will call this function upon completion
+ * or failure of CC.
+ *
+ * \return Nothing
+ */
+static void dahdi_pri_cc_agent_destructor(struct ast_cc_agent *agent)
+{
+	sig_pri_cc_agent_destructor(agent);
+
+	ast_module_unref(ast_module_info->self);
+}
+#endif	/* defined(HAVE_PRI_CCSS) */
+#endif	/* defined(HAVE_PRI) */
+
+#if defined(HAVE_PRI)
+#if defined(HAVE_PRI_CCSS)
+static struct ast_cc_agent_callbacks dahdi_pri_cc_agent_callbacks = {
+	.type = dahdi_pri_cc_type,
+	.init = dahdi_pri_cc_agent_init,
+	.start_offer_timer = sig_pri_cc_agent_start_offer_timer,
+	.stop_offer_timer = sig_pri_cc_agent_stop_offer_timer,
+	.ack = sig_pri_cc_agent_req_ack,
+	.status_request = sig_pri_cc_agent_status_req,
+	.stop_ringing = sig_pri_cc_agent_stop_ringing,
+	.party_b_free = sig_pri_cc_agent_party_b_free,
+	.start_monitoring = sig_pri_cc_agent_start_monitoring,
+	.callee_available = sig_pri_cc_agent_callee_available,
+	.destructor = dahdi_pri_cc_agent_destructor,
+};
+#endif	/* defined(HAVE_PRI_CCSS) */
+#endif	/* defined(HAVE_PRI) */
+
+#if defined(HAVE_PRI)
+#if defined(HAVE_PRI_CCSS)
+/*!
+ * \internal
+ * \brief CC monitor initialization.
+ * \since 1.8
+ *
+ * \param monitor CC core monitor control.
+ * \param core_id core_id of the CC transaction.
+ *
+ * \details
+ * Implementers must allocate the monitor's private_data
+ * and initialize it to whatever may be necessary.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure.
+ */
+static int dahdi_pri_cc_monitor_init(struct ast_cc_monitor *monitor, const int core_id)
+{
+	int res;
+
+	ast_module_ref(ast_module_info->self);
+
+	res = sig_pri_cc_monitor_init(monitor, core_id);
+	if (res) {
+		ast_module_unref(ast_module_info->self);
+	}
+	return res;
+}
+
+#endif	/* defined(HAVE_PRI_CCSS) */
+#endif	/* defined(HAVE_PRI) */
+
+#if defined(HAVE_PRI)
+#if defined(HAVE_PRI_CCSS)
+/*!
+ * \internal
+ * \brief Destroy private data on the monitor.
+ * \since 1.8
+ *
+ * \param monitor CC core monitor control.
+ *
+ * \details
+ * Implementers of this callback are responsible for destroying
+ * all heap-allocated data in the monitor's private_data pointer, including
+ * the private_data itself.
+ */
+static void dahdi_pri_cc_monitor_destructor(struct ast_cc_monitor *monitor)
+{
+	sig_pri_cc_monitor_destructor(monitor);
+
+	ast_module_unref(ast_module_info->self);
+}
+#endif	/* defined(HAVE_PRI_CCSS) */
+#endif	/* defined(HAVE_PRI) */
+
+#if defined(HAVE_PRI)
+#if defined(HAVE_PRI_CCSS)
+static struct ast_cc_monitor_callbacks dahdi_pri_cc_monitor_callbacks = {
+	.type = dahdi_pri_cc_type,
+	.init = dahdi_pri_cc_monitor_init,
+	.request_cc = sig_pri_cc_monitor_req_cc,
+	.suspend = sig_pri_cc_monitor_suspend,
+	.unsuspend = sig_pri_cc_monitor_unsuspend,
+	.status_response = sig_pri_cc_monitor_status_rsp,
+	.cancel_available_timer = sig_pri_cc_monitor_cancel_available_timer,
+	.destructor = dahdi_pri_cc_monitor_destructor,
+	.instance_destructor = sig_pri_cc_monitor_instance_destructor,
+};
+#endif	/* defined(HAVE_PRI_CCSS) */
+#endif	/* defined(HAVE_PRI) */
+
 static int __unload_module(void)
 {
 	struct dahdi_pvt *p;
@@ -15806,6 +16150,11 @@
 			dahdi_close_pri_fd(&(pris[i]), j);
 		}
 	}
+#if defined(HAVE_PRI_CCSS)
+	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)
@@ -16606,6 +16955,34 @@
 			} 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)
+			} else if (!strcasecmp(v->name, "cc_ptmp_recall_mode")) {
+				if (!strcasecmp(v->value, "global")) {
+					confp->pri.pri.cc_ptmp_recall_mode = 0;/* globalRecall */
+				} else if (!strcasecmp(v->value, "specific")) {
+					confp->pri.pri.cc_ptmp_recall_mode = 1;/* specificRecall */
+				} else {
+					confp->pri.pri.cc_ptmp_recall_mode = 1;/* specificRecall */
+				}
+			} else if (!strcasecmp(v->name, "cc_qsig_signaling_link_req")) {
+				if (!strcasecmp(v->value, "release")) {
+					confp->pri.pri.cc_qsig_signaling_link_req = 0;/* release */
+				} else if (!strcasecmp(v->value, "retain")) {
+					confp->pri.pri.cc_qsig_signaling_link_req = 1;/* retain */
+				} else if (!strcasecmp(v->value, "do_not_care")) {
+					confp->pri.pri.cc_qsig_signaling_link_req = 2;/* do-not-care */
+				} else {
+					confp->pri.pri.cc_qsig_signaling_link_req = 1;/* retain */
+				}
+			} else if (!strcasecmp(v->name, "cc_qsig_signaling_link_rsp")) {
+				if (!strcasecmp(v->value, "release")) {
+					confp->pri.pri.cc_qsig_signaling_link_rsp = 0;/* release */
+				} else if (!strcasecmp(v->value, "retain")) {
+					confp->pri.pri.cc_qsig_signaling_link_rsp = 1;/* retain */
+				} else {
+					confp->pri.pri.cc_qsig_signaling_link_rsp = 1;/* retain */
+				}
+#endif	/* defined(HAVE_PRI_CCSS) */
 #endif /* HAVE_PRI */
 #ifdef HAVE_SS7
 			} else if (!strcasecmp(v->name, "ss7type")) {
@@ -16906,23 +17283,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;
@@ -17037,7 +17448,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) {
@@ -17058,9 +17469,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) {
@@ -17075,7 +17487,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")) {
@@ -17088,9 +17500,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;
@@ -17147,6 +17560,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;
@@ -17167,6 +17606,23 @@
 #ifdef HAVE_PRI_PROG_W_CAUSE
 	ast_register_application_xml(dahdi_send_callrerouting_facility_app, dahdi_send_callrerouting_facility_exec);
 #endif
+#if defined(HAVE_PRI_CCSS)
+	if (ast_cc_agent_register(&dahdi_pri_cc_agent_callbacks)
+		|| ast_cc_monitor_register(&dahdi_pri_cc_monitor_callbacks)) {
+		__unload_module();
+		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/group/CCSS/channels/sig_pri.c
URL: http://svnview.digium.com/svn/asterisk/team/group/CCSS/channels/sig_pri.c?view=diff&rev=243776&r1=243775&r2=243776
==============================================================================
--- team/group/CCSS/channels/sig_pri.c (original)
+++ team/group/CCSS/channels/sig_pri.c Wed Jan 27 16:56:13 2010
@@ -61,6 +61,39 @@
 #define DEFAULT_PRI_DEBUG 0
 #endif
 
+#if defined(HAVE_PRI_CCSS)
+struct sig_pri_cc_agent_prv {
+	/*! Asterisk span D channel control structure. */
+	struct sig_pri_pri *pri;
+	/*! CC id value to use with libpri. -1 if invalid. */
+	long cc_id;
+	/*! 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 {
+	/*!
+	 * \brief CC core monitor structure associted with this monitor instance.
+	 * \note NULL if no association established.
+	 * \note Holds a reference to the CC core monitor if not NULL.
+	 */
+	struct ast_cc_monitor *monitor;
+	/*! \brief Asterisk span D channel control structure. */
+	struct sig_pri_pri *pri;
+	/*! CC id value to use with libpri. (-1 if already canceled). */
+	long cc_id;
+	/*! CC core id value. */
+	int core_id;
+	/*! Device name(Channel name less sequence number) */
+	char name[1];
+};
+
+/*! Upper level agent/monitor type name. */
+static const char *sig_pri_cc_type_name;
+/*! Container of sig_pri monitor instances. */
+static struct ao2_container *sig_pri_cc_monitors;
+#endif	/* defined(HAVE_PRI_CCSS) */
+
 static int pri_matchdigittimeout = 3000;
 
 static int pri_gendigittimeout = 8000;
@@ -119,6 +152,27 @@
 	if (p->calls->set_digital)
 		p->calls->set_digital(p->chan_pvt, flag);
 }
+
+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);
+	}
+	ast_log(LOG_ERROR, "get_orig_dialstring callback not defined\n");
+	return "";
+}
+
+#if defined(HAVE_PRI_CCSS)
+static void sig_pri_make_cc_dialstring(struct sig_pri_chan *p, char *buf, size_t buf_size)
+{
+	if (p->calls->make_cc_dialstring) {
+		p->calls->make_cc_dialstring(p->chan_pvt, buf, buf_size);
+	} else {
+		ast_log(LOG_ERROR, "make_cc_dialstring callback not defined\n");
+		buf[0] = '\0';
+	}
+}
+#endif	/* defined(HAVE_PRI_CCSS) */
 
 /*!
  * \internal
@@ -1476,6 +1530,644 @@
 	}
 }
 
+#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->cc_id != -1) {
+		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);
+	}
+
+	if (monitor_instance->monitor) {
+		ao2_ref(monitor_instance->monitor, -1);
+	}
+}
+#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 sig_pri_chan *pvt;
+	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];
+	char dialstring[AST_CHANNEL_NAME];
+
+	pvt = pri->pvts[chanpos];
+
+	core_id = ast_cc_get_current_core_id(pvt->owner);
+	if (core_id == -1) {
+		return -1;
+	}
+
+	cc_params = ast_channel_get_cc_config_params(pvt->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(pvt->owner, device_name, sizeof(device_name));
+		sig_pri_make_cc_dialstring(pvt, dialstring, sizeof(dialstring));
+		monitor = sig_pri_cc_monitor_instance_init(core_id, pri, cc_id, device_name);
+		res = ast_queue_cc_frame(pvt->owner, sig_pri_cc_type_name, dialstring, service);
+		if (res) {
+			ao2_unlink(sig_pri_cc_monitors, monitor);
+			monitor->cc_id = -1;
+		}
+		ao2_ref(monitor, -1);
+		break;
+	case AST_CC_MONITOR_GENERIC:
+		ast_queue_cc_frame(pvt->owner, AST_CC_GENERIC_MONITOR_TYPE,
+			sig_pri_get_orig_dialstring(pvt), service);
+		/* Say it failed to force caller to cancel native CC. */
+		break;
+	}
+	return res;
+}
+#endif	/* defined(HAVE_PRI_CCSS) */
+
+/*!
+ * \internal
+ * \brief Check if generic CC monitor is needed and request it.

[... 1596 lines stripped ...]



More information about the asterisk-commits mailing list