From 6bd57e0720283b9099daf6861acce5df92291dcc Mon Sep 17 00:00:00 2001
From: Jeff Peeler <jpeeler@digium.com>
Date: Wed, 3 Mar 2010 17:37:30 +0000
Subject: [PATCH] Add new config option to control AMI alarm event reporting in
 chan_dahdi.

New config parameter "reportalarms" added in chan_dahdi.conf which supports the
following possible values:
"channels": report each channel alarms (current behavior, default for backward compatibility)
"spans": report an "SpanAlarm" event when the span of any configured channel is alarmed
"all": report channel and span alarms (aggregated behavior)
"none": do not report any alarms

(closes issue #16709)
Reported by: nahuelgreco
Patches:
      chan_dahdi.c.reportalarms.patch uploaded by nahuelgreco (license 162)



git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@250392 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 CHANGES                        |  2 +
 channels/chan_dahdi.c          | 97 ++++++++++++++++++++++++++++------
 configs/chan_dahdi.conf.sample |  8 +++
 3 files changed, 90 insertions(+), 17 deletions(-)

diff --git a/CHANGES b/CHANGES
index 69b0843286..9d1c8a9a66 100644
--- a/CHANGES
+++ b/CHANGES
@@ -421,6 +421,8 @@ Miscellaneous
    configuration directory (/etc/asterisk by default) during reloads.
  * The parkeddynamic option has been added to features.conf to enable the creation
    of dynamic parkinglots.
+ * chan_dahdi now supports reporting alarms over AMI either by channel or span via
+   the reportalarms config option.
 
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 1.6.1 to Asterisk 1.6.2  -------------
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index dacd234b37..a9f322769c 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -418,6 +418,10 @@ static int numbufs = 4;
 static int mwilevel = 512;
 static int dtmfcid_level = 256;
 
+#define REPORT_CHANNEL_ALARMS 1
+#define REPORT_SPAN_ALARMS    2 
+static int report_alarms = REPORT_CHANNEL_ALARMS;
+
 #ifdef HAVE_PRI
 static int pridebugfd = -1;
 static char pridebugfilename[1024] = "";
@@ -963,6 +967,12 @@ struct dahdi_pvt {
 	 * \note Applies to SS7 and MFCR2 channels.
 	 */
 	unsigned int remotelyblocked:1;
+	/*!
+	 * \brief TRUE if the channel alarms will be managed also as Span ones
+	 * \note Applies to all channels
+	 */
+	unsigned int manages_span_alarms:1;
+
 #if defined(HAVE_PRI)
 	struct sig_pri_pri *pri;
 	int prioffset;
@@ -3022,6 +3032,18 @@ static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f, void *da
 #endif
 }
 
+static void handle_clear_alarms(struct dahdi_pvt *p)
+{
+	if (report_alarms & REPORT_CHANNEL_ALARMS) {
+		ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
+		manager_event(EVENT_FLAG_SYSTEM, "AlarmClear", "Channel: %d\r\n", p->channel);
+	}
+	if (report_alarms & REPORT_SPAN_ALARMS && p->manages_span_alarms) {
+		ast_log(LOG_NOTICE, "Alarm cleared on span %d\n", p->span);
+		manager_event(EVENT_FLAG_SYSTEM, "SpanAlarmClear", "Span: %d\r\n", p->span);
+	}
+}
+
 #ifdef HAVE_OPENR2
 
 static int dahdi_r2_answer(struct dahdi_pvt *p)
@@ -3110,8 +3132,7 @@ static void dahdi_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
 		res = get_alarms(p);
 		handle_alarms(p, res);
 	} else {
-		ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
-		manager_event(EVENT_FLAG_SYSTEM, "AlarmClear", "Channel: %d\r\n", p->channel);
+		handle_clear_alarms(p);
 	}
 	ast_mutex_unlock(&p->lock);
 }
@@ -5040,10 +5061,28 @@ static void dahdi_unlink_pri_pvt(struct dahdi_pvt *pvt)
 }
 #endif	/* defined(HAVE_PRI) */
 
+static struct dahdi_pvt *find_next_iface_in_span(struct dahdi_pvt *cur)
+{
+	if (cur->next && cur->next->span == cur->span) {
+		return cur->next;
+	} else if (cur->prev && cur->prev->span == cur->span) {
+		return cur->prev;
+	}
+
+	return NULL;
+}
+
 static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
 {
 	struct dahdi_pvt *p = pvt;
 
+	if (p->manages_span_alarms) {
+		struct dahdi_pvt *next = find_next_iface_in_span(p);
+		if (next) {
+			next->manages_span_alarms = 1;
+		}
+	}
+
 	/* Remove channel from the list */
 #if defined(HAVE_PRI)
 	dahdi_unlink_pri_pvt(p);
@@ -6953,11 +6992,21 @@ static void handle_alarms(struct dahdi_pvt *p, int alms)
 {
 	const char *alarm_str = alarm2str(alms);
 
-	ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", p->channel, alarm_str);
-	manager_event(EVENT_FLAG_SYSTEM, "Alarm",
-		"Alarm: %s\r\n"
-		"Channel: %d\r\n",
-		alarm_str, p->channel);
+	if (report_alarms & REPORT_CHANNEL_ALARMS) {
+		ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", p->channel, alarm_str);
+		manager_event(EVENT_FLAG_SYSTEM, "Alarm",
+					  "Alarm: %s\r\n"
+					  "Channel: %d\r\n",
+					  alarm_str, p->channel);
+	}
+
+	if (report_alarms & REPORT_SPAN_ALARMS && p->manages_span_alarms) {
+		ast_log(LOG_WARNING, "Detected alarm on span %d: %s\n", p->span, alarm_str);
+		manager_event(EVENT_FLAG_SYSTEM, "SpanAlarm",
+					  "Alarm: %s\r\n"
+					  "Span: %d\r\n",
+					  alarm_str, p->span);
+	}
 }
 
 static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
@@ -7464,9 +7513,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
 		}
 #endif
 		p->inalarm = 0;
-		ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
-		manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
-							"Channel: %d\r\n", p->channel);
+		handle_clear_alarms(p);
 		break;
 	case DAHDI_EVENT_WINKFLASH:
 		if (p->inalarm) break;
@@ -9974,9 +10021,7 @@ static void *mwi_thread(void *data)
 				break;
 			case DAHDI_EVENT_NOALARM:
 				mtd->pvt->inalarm = 0;
-				ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", mtd->pvt->channel);
-				manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
-					"Channel: %d\r\n", mtd->pvt->channel);
+				handle_clear_alarms(mtd->pvt);
 				break;
 			case DAHDI_EVENT_ALARM:
 				mtd->pvt->inalarm = 1;
@@ -10390,9 +10435,7 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
 		break;
 	case DAHDI_EVENT_NOALARM:
 		i->inalarm = 0;
-		ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", i->channel);
-		manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
-			"Channel: %d\r\n", i->channel);
+		handle_clear_alarms(i);
 		break;
 	case DAHDI_EVENT_ALARM:
 		i->inalarm = 1;
@@ -16695,7 +16738,16 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 				mwilevel = atoi(v->value);
 			} else if (!strcasecmp(v->name, "dtmfcidlevel")) {
 				dtmfcid_level = atoi(v->value);
-			}
+			} else if (!strcasecmp(v->name, "reportalarms")) {
+				if (!strcasecmp(v->value, "all"))
+					report_alarms = REPORT_CHANNEL_ALARMS | REPORT_SPAN_ALARMS;
+				if (!strcasecmp(v->value, "none"))
+					report_alarms = 0;
+				else if (!strcasecmp(v->value, "channels"))
+					report_alarms = REPORT_CHANNEL_ALARMS;
+			   else if (!strcasecmp(v->value, "spans"))
+					report_alarms = REPORT_SPAN_ALARMS;
+			 }
 		} else if (!(options & PROC_DAHDI_OPT_NOWARN) )
 			ast_log(LOG_WARNING, "Ignoring any changes to '%s' (on reload) at line %d.\n", v->name, v->lineno);
 	}
@@ -16706,6 +16758,17 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 			return -1;
 		}
 	}
+
+	/* mark the first channels of each DAHDI span to watch for their span alarms */
+	for (tmp = iflist, y=-1; tmp; tmp = tmp->next) {
+		if (!tmp->destroy && tmp->span != y) {
+			tmp->manages_span_alarms = 1;
+			y = tmp->span; 
+		} else {
+			tmp->manages_span_alarms = 0;
+		}
+	}
+
 	/*< \todo why check for the pseudo in the per-channel section.
 	 * Any actual use for manual setup of the pseudo channel? */
 	if (!found_pseudo && reload != 1) {
diff --git a/configs/chan_dahdi.conf.sample b/configs/chan_dahdi.conf.sample
index 9423753410..fb0d06931c 100644
--- a/configs/chan_dahdi.conf.sample
+++ b/configs/chan_dahdi.conf.sample
@@ -964,6 +964,14 @@ pickupgroup=1
 ;context=default
 ;channel => 1
 
+; AMI alarm event reporting
+;reportalarms=channels
+;Possible values are:
+;channels - report each channel alarms (current behavior, default for backward compatibility)
+;spans - report an "SpanAlarm" event when the span of any configured channel is alarmed
+;all - report channel and span alarms (aggregated behavior)
+;none - do not report any alarms.
+
 ; ---------------- Options for use with signalling=ss7 -----------------
 ; None of them can be changed by a reload.
 ;
-- 
GitLab