1 /**
2  * isup.cpp
3  * This file is part of the YATE Project http://YATE.null.ro
4  *
5  * Yet Another Signalling Stack - implements the support for SS7, ISDN and PSTN
6  *
7  * Yet Another Telephony Engine - a fully featured software PBX and IVR
8  * Copyright (C) 2004-2014 Null Team
9  *
10  * This software is distributed under multiple licenses;
11  * see the COPYING file in the main directory for licensing
12  * information for this specific distribution.
13  *
14  * This use of this software may be subject to additional restrictions.
15  * See the LEGAL file in the main directory for details.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20  */
21 
22 #include "yatesig.h"
23 #include <yatephone.h>
24 #include <string.h>
25 
26 using namespace TelEngine;
27 
28 #ifdef DEBUG
29 #define ISUP_HANDLE_CIC_EVENT_CONTROL
30 #else
31 //#define ISUP_HANDLE_CIC_EVENT_CONTROL
32 #endif
33 
34 // Maximum number of mandatory parameters including two terminators
35 #define MAX_MANDATORY_PARAMS 16
36 
37 // Timer limits and default values
38 #define ISUP_T7_MINVAL  20000
39 #define ISUP_T7_DEFVAL  20000
40 #define ISUP_T7_MAXVAL  30000
41 #define ISUP_T9_MINVAL  90000
42 #define ISUP_T9_DEFVAL  0
43 #define ISUP_T9_MAXVAL  180000
44 #define ISUP_T27_MINVAL 30000
45 #define ISUP_T27_DEFVAL 240000
46 #define ISUP_T27_MAXVAL 300000
47 #define ISUP_T34_MINVAL 2000
48 #define ISUP_T34_DEFVAL 3000
49 #define ISUP_T34_MAXVAL 4000
50 
51 // Utility: check if 2 cic codes are in valid range, return range if valid, 0 otherwise
checkValidRange(int code,int extra)52 static inline int checkValidRange(int code, int extra)
53 {
54     int range = extra - code;
55     return (range > -256 && range < 256) ? range : 0;
56 }
57 
58 // Adjust range and status data when needed (a new range is used)
adjustRangeAndStatus(char * status,unsigned int & code,unsigned int & range,int newRange)59 static void adjustRangeAndStatus(char* status, unsigned int& code, unsigned int& range,
60     int newRange)
61 {
62     if (!(status && newRange))
63 	return;
64     if (newRange > 0) {
65 	range = (unsigned int)newRange;
66 	status[0] = '1';
67 	::memset(status + 1,'0',range);
68     }
69     else {
70 	range = (unsigned int)(-newRange);
71 	code -= range;
72 	::memset(status,'0',range);
73 	status[range] = '1';
74     }
75     range++;
76 }
77 
78 // Description of each ISUP parameter
79 struct IsupParam {
80     // numeric type of the parameter
81     SS7MsgISUP::Parameters type;
82     // size in octets, zero for variable
83     unsigned char size;
84     // SS7 name of the parameter
85     const char* name;
86     // decoder callback function
87     bool (*decoder)(const SS7ISUP*,NamedList&,const IsupParam*,
88 	const unsigned char*,unsigned int,const String&);
89     // encoder callback function
90     unsigned char (*encoder)(const SS7ISUP*,SS7MSU&,unsigned char*,
91 	const IsupParam*,const NamedString*,const NamedList*,const String&);
92     // table data to be used by the callback
93     const void* data;
94 };
95 
96 // This structure describes parameters of each ISUP message for each dialect
97 struct MsgParams {
98     // type of the message described
99     SS7MsgISUP::Type type;
100     // does the message support optional part?
101     bool optional;
102     // parameters, fixed then variable, separated/terminated by EndOfParameters
103     //  using an array is a (moderate) waste of space
104     const SS7MsgISUP::Parameters params[MAX_MANDATORY_PARAMS];
105 };
106 
107 
108 // Nature of Address Indicator
109 static const TokenDict s_dict_nai[] = {
110     { "subscriber",        1 },
111     { "unknown",           2 },
112     { "national",          3 },
113     { "international",     4 },
114     { "network-specific",  5 },
115     { "national-routing",  6 },
116     { "specific-routing",  7 },
117     { "routing-with-cdn",  8 },
118     { 0, 0 }
119 };
120 
121 // Numbering Plan Indicator
122 static const TokenDict s_dict_numPlan[] = {
123     { "unknown",  0 },
124     { "isdn",     1 },
125     { "data",     3 },
126     { "telex",    4 },
127     { "private",  5 },
128     { "national", 6 },
129     { 0, 0 }
130 };
131 
132 // Address Presentation
133 static const TokenDict s_dict_presentation[] = {
134     { "allowed",     0 },
135     { "restricted",  1 },
136     { "unavailable", 2 },
137     // aliases for restrict=...
138     { "no",    0 },
139     { "false", 0 },
140     { "yes",   1 },
141     { "true",  1 },
142     { 0, 0 }
143 };
144 
145 // Screening Indicator
146 static const TokenDict s_dict_screening[] = {
147     { "user-provided",        0 },
148     { "user-provided-passed", 1 },
149     { "user-provided-failed", 2 },
150     { "network-provided",     3 },
151     // aliases for screened=...
152     { "no",    0 },
153     { "false", 0 },
154     { "yes",   1 },
155     { "true",  1 },
156     { 0, 0 }
157 };
158 
159 // Generic number qualifier
160 static const TokenDict s_dict_qual[] = {
161     { "dialed-digits",        0 },
162     { "called-additional",    1 },
163     { "caller-failed",        2 },
164     { "caller-not-screened",  3 },
165     { "terminating",          4 },
166     { "connected-additional", 5 },
167     { "caller-additional",    6 },
168     { "called-original",      7 },
169     { "redirecting",          8 },
170     { "redirection",          9 },
171     { 0, 0 }
172 };
173 
174 // Generic name qualifier
175 static const TokenDict s_dict_qual_name[] = {
176     { "caller" ,           0x20 },
177     { "called" ,           0x40 },
178     { "redirecting" ,      0x60 },
179     { "connected" ,        0x80 },
180     { 0, 0 }
181 };
182 
183 // Redirection Information (Q,763 3.45) bits CBA
184 static const TokenDict s_dict_redir_main[] = {
185     { "none",                     0 },
186     { "rerouted",                 1 },
187     { "rerouted-restrict-all",    2 },
188     { "diverted",                 3 },
189     { "diverted-restrict-all",    4 },
190     { "rerouted-restrict-number", 5 },
191     { "diverted-restrict-number", 6 },
192     { 0, 0 }
193 };
194 
195 // Redirection Information (Q,763 3.45) bits HGFE or PONM
196 static const TokenDict s_dict_redir_reason[] = {
197     { "busy",      1 },
198     { "noanswer",  2 },
199     { "always",    3 },
200     { "deflected", 4 },
201     { "diverted",  5 },
202     { "offline",   6 },
203     { 0, 0 }
204 };
205 
206 // Message Compatibility Information (Q.763 3.33)
207 static const SignallingFlags s_flags_msgcompat[] = {
208     { 0x01, 0x00, "transit" },           // End node / transit exchange
209     { 0x01, 0x01, "end-node" },
210     { 0x02, 0x02, "release" },           // Release call indicator
211     { 0x04, 0x04, "cnf" },               // Pass on set but not possible: Send CNF / RLC
212     { 0x08, 0x08, "discard" },           // Discard / pass on message
213     { 0x10, 0x00, "nopass-release" },    // Pass on not possible: Release call
214     { 0x10, 0x10, "nopass-discard" },    // Pass on not possible: Discard message
215     { 0, 0, 0 }
216 };
217 
218 // Parameter Compatibility Information (Q.763 3.41)
219 static const SignallingFlags s_flags_paramcompat[] = {
220     { 0x01, 0x00, "transit" },           // End node / transit exchange
221     { 0x01, 0x01, "end-node" },
222     { 0x02, 0x02, "release" },           // Release call indicator
223     { 0x04, 0x04, "cnf" },               // Parameter pass on set but not possible: Send CNF / RLC
224     { 0x08, 0x08, "discard-msg" },       // Discard / pass on message
225     { 0x18, 0x10, "discard-param" },     // Discard / pass on parameter (if not discarding message)
226     { 0x60, 0x00, "nopass-release" },    // No pass on: release call
227     { 0x60, 0x20, "nopass-msg" },        // No pass on: discard message
228     { 0x60, 0x40, "nopass-param" },      // No pass on: discard parameter
229     { 0x60, 0x60, "nopass-release" },    // Reserved, interpreted as 00
230     { 0, 0, 0 }
231 };
232 
233 // Application Transport Parameter instruction indicators (Q.763 3.82)
234 static const SignallingFlags s_flags_apt_indicators[] = {
235     { 0x01, 0x01, "release" },           // Release call indicator
236     { 0x02, 0x02, "cnf" },               // Send CNF notification
237     { 0, 0, 0 }
238 };
239 
240 // SLS special values on outbound calls
241 static const TokenDict s_dict_callSls[] = {
242     { "auto", SS7ISUP::SlsAuto    }, // Let Layer3 deal with it
243     { "last", SS7ISUP::SlsLatest  }, // Last SLS used
244     { "cic",  SS7ISUP::SlsCircuit }, // Lower bits of CIC
245     { 0, 0 }
246 };
247 
248 // Control operations
249 static const TokenDict s_dict_control[] = {
250     { "validate", SS7MsgISUP::CVT },
251     { "query", SS7MsgISUP::CQM },
252     { "conttest", SS7MsgISUP::CCR },
253     { "reset", SS7MsgISUP::RSC },
254     { "block", SS7MsgISUP::BLK },
255     { "unblock", SS7MsgISUP::UBL },
256     { "release", SS7MsgISUP::RLC },
257     { "parttest", SS7MsgISUP::UPT },
258     { "available", SS7MsgISUP::UPA },
259     { "save", SS7MsgISUP::CtrlSave },
260 #ifdef ISUP_HANDLE_CIC_EVENT_CONTROL
261     { "circuitevent", SS7MsgISUP::CtrlCicEvent },
262 #endif
263     { 0, 0 }
264 };
265 
266 static const TokenDict s_dict_CRG_process[] = {
267     { "confusion", SS7ISUP::Confusion },
268     { "ignore",    SS7ISUP::Ignore },
269     { "raw",       SS7ISUP::Raw },
270     { "parsed",    SS7ISUP::Parsed },
271     { 0, 0 }
272 };
273 
274 // Build next available parameter name
buildName(const NamedList & list,const IsupParam * param,const String & prefix,String & name)275 static void buildName(const NamedList& list, const IsupParam* param, const String& prefix, String& name)
276 {
277     name = prefix + param->name;
278     if (!list.getParam(name))
279 	return;
280     // conflict - find a free index
281     for (unsigned int i = 1; ; i++) {
282 	String tmp(name);
283 	tmp << "." << i;
284 	if (!list.getParam(tmp)) {
285 	    name = tmp;
286 	    break;
287 	}
288     }
289 }
290 
291 // Default decoder, dumps raw octets
decodeRaw(const SS7ISUP * isup,NamedList & list,const IsupParam * param,const unsigned char * buf,unsigned int len,const String & prefix)292 static bool decodeRaw(const SS7ISUP* isup, NamedList& list, const IsupParam* param,
293     const unsigned char* buf, unsigned int len, const String& prefix)
294 {
295     if (len < 1)
296 	return false;
297     String raw;
298     raw.hexify((void*)buf,len,' ');
299     DDebug(isup,DebugInfo,"decodeRaw decoded %s=%s",param->name,raw.c_str());
300     String preName;
301     buildName(list,param,prefix,preName);
302     list.addParam(preName,raw);
303     return true;
304 }
305 
306 // Raw decoder for unknown/failed parameter, dumps raw octets
decodeRawParam(const SS7ISUP * isup,NamedList & list,unsigned char value,const unsigned char * buf,unsigned int len,const String & prefix)307 static bool decodeRawParam(const SS7ISUP* isup, NamedList& list, unsigned char value,
308     const unsigned char* buf, unsigned int len, const String& prefix)
309 {
310     String name("Param_");
311     name << value;
312     IsupParam p;
313     p.type = (SS7MsgISUP::Parameters)value;
314     p.size = len;
315     p.name = name;
316     p.decoder = 0;
317     p.encoder = 0;
318     p.data = 0;
319     return decodeRaw(isup,list,&p,buf,len,prefix);
320 };
321 
322 // Integer decoder, interprets data as big endian integer
decodeInt(const SS7ISUP * isup,NamedList & list,const IsupParam * param,const unsigned char * buf,unsigned int len,const String & prefix)323 static bool decodeInt(const SS7ISUP* isup, NamedList& list, const IsupParam* param,
324     const unsigned char* buf, unsigned int len, const String& prefix)
325 {
326     unsigned int val = 0;
327     while (len--)
328 	val = (val << 8) | (unsigned int)(*buf++);
329     DDebug(isup,DebugAll,"decodeInt decoded %s=%s (%u)",param->name,lookup(val,(const TokenDict*)param->data),val);
330     String preName;
331     buildName(list,param,prefix,preName);
332     SignallingUtils::addKeyword(list,preName,(const TokenDict*)param->data,val);
333     return true;
334 }
335 
336 // Decoder for ISUP indicators (flags)
decodeFlags(const SS7ISUP * isup,NamedList & list,const IsupParam * param,const unsigned char * buf,unsigned int len,const String & prefix)337 static bool decodeFlags(const SS7ISUP* isup, NamedList& list, const IsupParam* param,
338     const unsigned char* buf, unsigned int len, const String& prefix)
339 {
340     const SignallingFlags* flags = (const SignallingFlags*)param->data;
341     if (!flags)
342 	return false;
343     String preName;
344     buildName(list,param,prefix,preName);
345     return SignallingUtils::decodeFlags(isup,list,preName,flags,buf,len);
346 }
347 
348 // Utility function - extract just ISUP digits from a parameter
getDigits(String & num,unsigned char oddNum,const unsigned char * buf,unsigned int len,bool ignoreUnk)349 static void getDigits(String& num, unsigned char oddNum, const unsigned char* buf, unsigned int len,
350     bool ignoreUnk)
351 {
352     bool odd = (oddNum & 0x80) != 0;
353     static const char digits1[] = "0123456789\0BC\0\0.";
354     static const char digits2[] = "0123456789ABCDE.";
355     const char* digits = ignoreUnk ? digits1 : digits2;
356     for (unsigned int i = 0; i < len; i++) {
357 	num += digits[buf[i] & 0x0f];
358 	if (odd && ((i+1) == len))
359 	    break;
360 	num += digits[buf[i] >> 4];
361     }
362 }
363 
364 const char* getIsupParamName(unsigned char type);
365 
366 // Decoder for message or parameter compatibility
367 // Q.763 3.33/3.41
decodeCompat(const SS7ISUP * isup,NamedList & list,const IsupParam * param,const unsigned char * buf,unsigned int len,const String & prefix)368 static bool decodeCompat(const SS7ISUP* isup, NamedList& list, const IsupParam* param,
369     const unsigned char* buf, unsigned int len, const String& prefix)
370 {
371     if (!len)
372 	return false;
373     String preName;
374     buildName(list,param,prefix,preName);
375     switch (param->type) {
376 	case SS7MsgISUP::MessageCompatInformation:
377 	    SignallingUtils::decodeFlags(isup,list,preName,s_flags_msgcompat,buf,1);
378 	    if (buf[0] & 0x80) {
379 		if (len == 1)
380 		    return true;
381 		DDebug(isup,DebugMild,
382 		    "decodeCompat invalid len=%u for %s with first byte having ext bit set",len,param->name);
383 		break;
384 	    }
385 	    return 0 != SignallingUtils::dumpDataExt(isup,list,preName+".more",buf+1,len-1);
386 	case SS7MsgISUP::ParameterCompatInformation:
387 	    for (unsigned int i = 0; i < len;) {
388 		unsigned char val = buf[i++];
389 		if (i == len) {
390 		    Debug(isup,DebugMild,"decodeCompat unexpected end of data (len=%u) for %s",len,param->name);
391 		    return false;
392 		}
393 		const char* paramName = getIsupParamName(val);
394 		String name = preName;
395 		if (paramName)
396 		    name << "." << paramName;
397 		else {
398 		    Debug(isup,DebugNote,"decodeCompat found unknown parameter %u for %s",val,param->name);
399 		    name << ".Param_" << (unsigned int)val;
400 		}
401 		SignallingUtils::decodeFlags(isup,list,name,s_flags_paramcompat,buf+i,1);
402 		if (buf[i++] & 0x80)
403 		    continue;
404 		unsigned int count = SignallingUtils::dumpDataExt(isup,list,name+".more",buf+i,len-i);
405 		if (!count)
406 		    return false;
407 		i += count;
408 	    }
409 	    decodeRaw(isup,list,param,buf,len,prefix);
410 	    return true;
411 	default:
412 	    Debug(isup,DebugStub,"decodeCompat not implemented for %s",param->name);
413     }
414     return false;
415 }
416 
417 // Decoder for various ISUP digit sequences (phone numbers)
decodeDigits(const SS7ISUP * isup,NamedList & list,const IsupParam * param,const unsigned char * buf,unsigned int len,const String & prefix)418 static bool decodeDigits(const SS7ISUP* isup, NamedList& list, const IsupParam* param,
419     const unsigned char* buf, unsigned int len, const String& prefix)
420 {
421     if (len < 2)
422 	return false;
423     unsigned char qualifier = 0;
424     if (SS7MsgISUP::GenericNumber == param->type) {
425 	if (--len < 2)
426 	    return false;
427 	qualifier = buf[0];
428 	buf++;
429     }
430     unsigned char nai = buf[0] & 0x7f;
431     unsigned char plan = (buf[1] >> 4) & 7;
432     unsigned char pres = (buf[1] >> 2) & 3;
433     unsigned char scrn = buf[1] & 3;
434     String tmp;
435     getDigits(tmp,buf[0],buf+2,len-2,isup && isup->ignoreUnknownAddrSignals());
436     DDebug(isup,DebugAll,"decodeDigits decoded %s='%s' inn/ni=%u nai=%u plan=%u pres=%u scrn=%u",
437 	param->name,tmp.c_str(),buf[1] >> 7,nai,plan,pres,scrn);
438     String preName;
439     buildName(list,param,prefix,preName);
440     list.addParam(preName,tmp);
441     if (SS7MsgISUP::GenericNumber == param->type)
442 	SignallingUtils::addKeyword(list,preName+".qualifier",s_dict_qual,qualifier);
443     SignallingUtils::addKeyword(list,preName+".nature",s_dict_nai,nai);
444     SignallingUtils::addKeyword(list,preName+".plan",s_dict_numPlan,plan);
445     switch (param->type) {
446 	case SS7MsgISUP::CalledPartyNumber:
447 	case SS7MsgISUP::RedirectionNumber:
448 	case SS7MsgISUP::LocationNumber:
449 	    tmp = ((buf[1] & 0x80) == 0);
450 	    list.addParam(preName+".inn",tmp);
451 	    break;
452 	case SS7MsgISUP::CallingPartyNumber:
453 	case SS7MsgISUP::GenericNumber:
454 	    tmp = ((buf[1] & 0x80) == 0);
455 	    list.addParam(preName+".complete",tmp);
456 	    break;
457 	case SS7MsgISUP::LastDivertingLineIdentity:
458 	case SS7MsgISUP::PresentationNumber:
459 	    tmp = ((buf[1] & 0x80) != 0);
460 	    list.addParam(preName+".pnp",tmp);
461 	    break;
462 	default:
463 	    break;
464     }
465     switch (param->type) {
466 	case SS7MsgISUP::CallingPartyNumber:
467 	case SS7MsgISUP::RedirectingNumber:
468 	case SS7MsgISUP::OriginalCalledNumber:
469 	case SS7MsgISUP::LocationNumber:
470 	case SS7MsgISUP::ConnectedNumber:
471 	case SS7MsgISUP::GenericNumber:
472 	case SS7MsgISUP::LastDivertingLineIdentity:
473 	case SS7MsgISUP::PresentationNumber:
474 	case SS7MsgISUP::CalledINNumber:
475 	case SS7MsgISUP::OriginalCalledINNumber:
476 	    SignallingUtils::addKeyword(list,preName+".restrict",s_dict_presentation,pres);
477 	default:
478 	    break;
479     }
480     switch (param->type) {
481 	case SS7MsgISUP::CallingPartyNumber:
482 	case SS7MsgISUP::LocationNumber:
483 	case SS7MsgISUP::ConnectedNumber:
484 	case SS7MsgISUP::GenericNumber:
485 	case SS7MsgISUP::LastDivertingLineIdentity:
486 	case SS7MsgISUP::PresentationNumber:
487 	    SignallingUtils::addKeyword(list,preName+".screened",s_dict_screening,scrn);
488 	default:
489 	    break;
490     }
491     return true;
492 }
493 
494 // Special decoder for subsequent number
decodeSubseq(const SS7ISUP * isup,NamedList & list,const IsupParam * param,const unsigned char * buf,unsigned int len,const String & prefix)495 static bool decodeSubseq(const SS7ISUP* isup, NamedList& list, const IsupParam* param,
496     const unsigned char* buf, unsigned int len, const String& prefix)
497 {
498     if (len < 1)
499 	return false;
500     String tmp;
501     getDigits(tmp,buf[0],buf+1,len-1,isup && isup->ignoreUnknownAddrSignals());
502     DDebug(isup,DebugAll,"decodeSubseq decoded %s='%s'",param->name,tmp.c_str());
503     String preName;
504     buildName(list,param,prefix,preName);
505     list.addParam(preName,tmp);
506     return true;
507 }
508 
509 // Decoder for circuit group range and status (Q.763 3.43)
decodeRangeSt(const SS7ISUP * isup,NamedList & list,const IsupParam * param,const unsigned char * buf,unsigned int len,const String & prefix)510 static bool decodeRangeSt(const SS7ISUP* isup, NamedList& list, const IsupParam* param,
511     const unsigned char* buf, unsigned int len, const String& prefix)
512 {
513     if (len < 1)
514 	return false;
515     String preName;
516     buildName(list,param,prefix,preName);
517     // 1st octet is the range code (range - 1)
518     len--;
519     unsigned int range = 1 + *buf++;
520     unsigned int octets = (range + 7) / 8;
521     if (octets > len) {
522 	if (len)
523 	    Debug(isup,DebugMild,"decodeRangeSt truncating range of %u bits to %u octets!",range,len);
524 	octets = len;
525     }
526     list.addParam(preName,String(range));
527 
528     String map;
529     if (len) {
530 	unsigned char mask = 1;
531 	unsigned int r = range;
532 	while (r--) {
533 	    map += (buf[0] & mask) ? "1" : "0";
534 	    mask <<= 1;
535 	    if (!mask) {
536 		++buf;
537 		if (!--octets)
538 		    break;
539 		mask = 1;
540 	    }
541 	}
542 	list.addParam(preName+".map",map);
543     }
544 
545     DDebug(isup,DebugAll,"decodeRangeSt decoded %s=%u '%s'",param->name,range,map.c_str());
546     return true;
547 }
548 
549 // Decoder for generic notification indicators (Q.763 3.25)
decodeNotif(const SS7ISUP * isup,NamedList & list,const IsupParam * param,const unsigned char * buf,unsigned int len,const String & prefix)550 static bool decodeNotif(const SS7ISUP* isup, NamedList& list, const IsupParam* param,
551     const unsigned char* buf, unsigned int len, const String& prefix)
552 {
553     if (len < 1)
554 	return false;
555     String flg;
556     for (; len; len--) {
557 	unsigned char val = *buf++;
558 	const char* keyword = lookup(val & 0x7f,(const TokenDict*)param->data);
559 	if (keyword)
560 	    flg.append(keyword,",");
561 	else {
562 	    String tmp(0x7f & (int)val);
563 	    flg.append(tmp,",");
564 	}
565 	if (val & 0x80)
566 	    break;
567     }
568     DDebug(isup,DebugAll,"decodeNotif decoded %s='%s'",param->name,flg.c_str());
569     String preName;
570     buildName(list,param,prefix,preName);
571     list.addParam(preName,flg);
572     return true;
573 }
574 
575 // Decoder for User Service Information
decodeUSI(const SS7ISUP * isup,NamedList & list,const IsupParam * param,const unsigned char * buf,unsigned int len,const String & prefix)576 static bool decodeUSI(const SS7ISUP* isup, NamedList& list, const IsupParam* param,
577     const unsigned char* buf, unsigned int len, const String& prefix)
578 {
579     String preName;
580     buildName(list,param,prefix,preName);
581     return SignallingUtils::decodeCaps(isup,list,buf,len,preName,true);
582 }
583 
584 // Decoder for cause indicators
decodeCause(const SS7ISUP * isup,NamedList & list,const IsupParam * param,const unsigned char * buf,unsigned int len,const String & prefix)585 static bool decodeCause(const SS7ISUP* isup, NamedList& list, const IsupParam* param,
586     const unsigned char* buf, unsigned int len, const String& prefix)
587 {
588     String preName;
589     buildName(list,param,prefix,preName);
590     return SignallingUtils::decodeCause(isup,list,buf,len,preName,true);
591 }
592 
593 // Decoder for application transport parameter
decodeAPT(const SS7ISUP * isup,NamedList & list,const IsupParam * param,const unsigned char * buf,unsigned int len,const String & prefix)594 static bool decodeAPT(const SS7ISUP* isup, NamedList& list, const IsupParam* param,
595     const unsigned char* buf, unsigned int len, const String& prefix)
596 {
597     if (len < 4) {
598 	if (len == 3)
599 	    Debug(isup,DebugNote,"Received '%s' with no data",param->name);
600 	return false;
601     }
602     // Field extension on more then 1 octet is not supported
603     if (0 == (buf[0] & buf[1] & buf[2] & 0x80)) {
604 	Debug(isup,DebugNote,"Received %s with unsupported extension bits set to 0",
605 	    param->name);
606 	return false;
607     }
608     // Segmentation is not supported
609     unsigned char si = (buf[2] & 0x40);
610     unsigned char segments = (buf[2] & 0x3f);
611     if (!si || segments) {
612 	Debug(isup,DebugNote,"Received unsupported segmented %s (si=%u segments=%u)",
613 	    param->name,si,segments);
614 	return false;
615     }
616     len -= 3;
617     // WARNING: HACK - ApplicationTransport does not follow naming convention
618     String preName(prefix + param->name);
619     String context((int)(buf[0] & 0x7f));
620     list.addParam(preName,context);
621     preName << "." << context;
622     // Application context identifier
623     SignallingUtils::dumpData(isup,list,preName,buf + 3,len);
624     // Instruction indicators
625     unsigned char inds = (buf[1] & 0x7f);
626     SignallingUtils::decodeFlags(isup,list,preName + ".indicators",s_flags_apt_indicators,&inds,1);
627     return true;
628 }
629 
630 // Decoder for generic name
decodeName(const SS7ISUP * isup,NamedList & list,const IsupParam * param,const unsigned char * buf,unsigned int len,const String & prefix)631 static bool decodeName(const SS7ISUP* isup, NamedList& list, const IsupParam* param,
632     const unsigned char* buf, unsigned int len, const String& prefix)
633 {
634     if (len < 1)
635 	return false;
636     String val((const char*)buf+1,len-1);
637     String preName;
638     buildName(list,param,prefix,preName);
639     list.addParam(preName,val);
640     list.addParam(preName+".available",String::boolText((buf[0] & 0x10) == 0));
641     SignallingUtils::addKeyword(list,preName+".qualifier",s_dict_qual_name,buf[0] & 0xe0);
642     SignallingUtils::addKeyword(list,preName+".restrict",s_dict_presentation,buf[0] & 0x03);
643     DDebug(isup,DebugAll,"decodeName decoded %s='%s'",param->name,val.c_str());
644     return true;
645 }
646 
647 // Decoder for Redirection information (Q.763 3.45)
decodeRedir(const SS7ISUP * isup,NamedList & list,const IsupParam * param,const unsigned char * buf,unsigned int len,const String & prefix)648 static bool decodeRedir(const SS7ISUP* isup, NamedList& list, const IsupParam* param,
649     const unsigned char* buf, unsigned int len, const String& prefix)
650 {
651     if (len < 1)
652 	return false;
653     String preName;
654     buildName(list,param,prefix,preName);
655     SignallingUtils::addKeyword(list,preName,s_dict_redir_main,buf[0] & 0x07);
656     unsigned int reason = buf[0] >> 4;
657     if (reason)
658 	SignallingUtils::addKeyword(list,preName+".reason_original",s_dict_redir_reason,reason);
659     if (len > 1) {
660 	int cnt = buf[1] & 0x07;
661 	if (cnt)
662 	    list.addParam(preName+".counter",String(cnt));
663 	reason = buf[1] >> 4;
664 	if (reason)
665 	    SignallingUtils::addKeyword(list,preName+".reason",s_dict_redir_reason,reason);
666     }
667     return true;
668 }
669 
670 // Default encoder, get hexified octets
encodeRaw(const SS7ISUP * isup,SS7MSU & msu,unsigned char * buf,const IsupParam * param,const NamedString * val,const NamedList *,const String &)671 static unsigned char encodeRaw(const SS7ISUP* isup, SS7MSU& msu,
672     unsigned char* buf, const IsupParam* param, const NamedString* val,
673     const NamedList*, const String&)
674 {
675     if (!(param && val))
676 	return 0;
677     DDebug(isup,DebugInfo,"encodeRaw encoding %s=%s",param->name,val->c_str());
678     DataBlock raw;
679     if (!raw.unHexify(val->c_str(),val->length(),' ')) {
680 	DDebug(isup,DebugMild,"encodeRaw failed: invalid string");
681 	return 0;
682     }
683     if (!raw.length() || raw.length() > 254 ||
684 	(param->size && param->size != raw.length())) {
685 	DDebug(isup,DebugMild,"encodeRaw failed: param size=%u data length=%u",
686 	    param->size,raw.length());
687 	return 0;
688     }
689     if (buf) {
690 	::memcpy(buf,raw.data(),raw.length());
691 	return raw.length();
692     }
693     unsigned char size = (unsigned char)raw.length();
694     msu.append(&size,1);
695     msu += raw;
696     return size;
697 }
698 
699 // Encoder for fixed length ISUP indicators (flags)
encodeFlags(const SS7ISUP * isup,SS7MSU & msu,unsigned char * buf,const IsupParam * param,const NamedString * val,const NamedList *,const String &)700 static unsigned char encodeFlags(const SS7ISUP* isup, SS7MSU& msu, unsigned char* buf,
701     const IsupParam* param, const NamedString* val, const NamedList*, const String&)
702 {
703     if (!param)
704 	return 0;
705     unsigned int n = param->size;
706     if (!(n && param->data))
707 	return 0;
708     unsigned int v = 0;
709     if (val)
710 	v = SignallingUtils::encodeFlags(isup,*val,(const SignallingFlags*)param->data,param->name);
711     else {
712 	// locate the defaults
713 	const SignallingFlags* flags = (const SignallingFlags*)param->data;
714 	while (flags->mask)
715 	    flags++;
716 	v = flags->value;
717     }
718     DDebug(isup,DebugAll,"encodeFlags encoding %s=0x%x on %u octets",param->name,v,n);
719     if (!buf) {
720 	unsigned int l = msu.length();
721 	DataBlock dummy(0,n+1);
722 	msu += dummy;
723 	buf = (unsigned char*)msu.getData(l,n+1);
724 	*buf++ = n & 0xff;
725     }
726     while (n--) {
727 	*buf++ = v & 0xff;
728 	v >>= 8;
729     }
730     return param->size;
731 }
732 
733 // Encoder for fixed length big-endian integer values
encodeInt(const SS7ISUP * isup,SS7MSU & msu,unsigned char * buf,const IsupParam * param,const NamedString * val,const NamedList *,const String &)734 static unsigned char encodeInt(const SS7ISUP* isup, SS7MSU& msu, unsigned char* buf,
735     const IsupParam* param, const NamedString* val, const NamedList*, const String&)
736 {
737     if (!param)
738 	return 0;
739     unsigned int n = param->size;
740     if (!n)
741 	return 0;
742     unsigned int v = 0;
743     if (val)
744 	v = val->toInteger((const TokenDict*)param->data);
745     DDebug(isup,DebugAll,"encodeInt encoding %s=%u on %u octets",param->name,v,n);
746     if (!buf) {
747 	unsigned int l = msu.length();
748 	DataBlock dummy(0,n+1);
749 	msu += dummy;
750 	buf = (unsigned char*)msu.getData(l,n+1);
751 	*buf++ = n & 0xff;
752     }
753     buf += n;
754     while (n--) {
755 	*(--buf) = v & 0xff;
756 	v >>= 8;
757     }
758     return param->size;
759 }
760 
761 // Utility function - write digit sequences
setDigits(SS7MSU & msu,const char * val,unsigned char nai,int b2=-1,int b3=-1,int b0=-1)762 static unsigned char setDigits(SS7MSU& msu, const char* val, unsigned char nai, int b2 = -1, int b3 = -1, int b0 = -1)
763 {
764     unsigned char buf[32];
765     unsigned int len = 1;
766     if (b0 >= 0)
767 	buf[len++] = b0 & 0xff;
768     unsigned int naiPos = len++;
769     buf[naiPos] = nai & 0x7f;
770     if (b2 >= 0) {
771 	buf[len++] = b2 & 0xff;
772 	if (b3 >= 0)
773 	    buf[len++] = b3 & 0xff;
774     }
775     bool odd = false;
776     while (val && (len < sizeof(buf))) {
777 	char c = *val++;
778 	if (!c)
779 	    break;
780 	unsigned char n = 0;
781 	if (('0' <= c) && (c <= '9'))
782 	    n = c - '0';
783 	else switch (c) {
784 	    case 'A':
785 	    case 'a':
786 		n = 10;
787 		break;
788 	    case 'B':
789 	    case 'b':
790 	    case '*':
791 		n = 11;
792 		break;
793 	    case 'C':
794 	    case 'c':
795 	    case '#':
796 		n = 12;
797 		break;
798 	    case 'D':
799 	    case 'd':
800 		n = 13;
801 		break;
802 	    case 'E':
803 	    case 'e':
804 		n = 14;
805 		break;
806 	    case 'F':
807 	    case 'f':
808 	    case '.':
809 		n = 15;
810 		break;
811 	    default:
812 		continue;
813 	}
814 	odd = !odd;
815 	if (odd)
816 	    buf[len] = n;
817 	else
818 	    buf[len++] |= (n << 4);
819     }
820     if (odd) {
821 	buf[naiPos] |= 0x80;
822 	len++;
823     }
824     buf[0] = (len-1) & 0xff;
825     DDebug(DebugAll,"setDigits encoding %u octets (%s)",len,odd ? "odd" : "even");
826     DataBlock tmp(buf,len,false);
827     msu += tmp;
828     tmp.clear(false);
829     return buf[0];
830 }
831 
832 // Encoder for variable length digit sequences
encodeDigits(const SS7ISUP * isup,SS7MSU & msu,unsigned char * buf,const IsupParam * param,const NamedString * val,const NamedList * extra,const String & prefix)833 static unsigned char encodeDigits(const SS7ISUP* isup, SS7MSU& msu,
834     unsigned char* buf, const IsupParam* param, const NamedString* val,
835     const NamedList* extra, const String& prefix)
836 {
837     if (!param || buf || param->size)
838 	return 0;
839     unsigned char nai = 2;
840     unsigned char plan = 1;
841     String preName;
842     if (val)
843 	preName = val->name();
844     else
845 	preName = prefix + param->name;
846     int b0 = -1;
847     if (SS7MsgISUP::GenericNumber == param->type) {
848 	b0 = 0;
849 	if (val && extra)
850 	    b0 = 0xff & extra->getIntValue(preName+".qualifier",s_dict_qual,0);
851     }
852     if (val && extra) {
853 	nai = extra->getIntValue(preName+".nature",s_dict_nai,nai);
854 	plan = extra->getIntValue(preName+".plan",s_dict_numPlan,plan);
855     }
856     unsigned char b2 = (plan & 7) << 4;
857     switch (param->type) {
858 	case SS7MsgISUP::CalledPartyNumber:
859 	case SS7MsgISUP::RedirectionNumber:
860 	case SS7MsgISUP::LocationNumber:
861 	    if (val && extra && !extra->getBoolValue(preName+".inn",true))
862 		b2 |= 0x80;
863 	    break;
864 	case SS7MsgISUP::CallingPartyNumber:
865 	case SS7MsgISUP::GenericNumber:
866 	    if (val && extra && !extra->getBoolValue(preName+".complete",true))
867 		b2 |= 0x80;
868 	    break;
869 	case SS7MsgISUP::LastDivertingLineIdentity:
870 	case SS7MsgISUP::PresentationNumber:
871 	    if (!val || !extra || extra->getBoolValue(preName+".pnp",true))
872 		b2 |= 0x80;
873 	    break;
874 	default:
875 	    break;
876     }
877     switch (param->type) {
878 	case SS7MsgISUP::CallingPartyNumber:
879 	case SS7MsgISUP::RedirectingNumber:
880 	case SS7MsgISUP::OriginalCalledNumber:
881 	case SS7MsgISUP::LocationNumber:
882 	case SS7MsgISUP::ConnectedNumber:
883 	case SS7MsgISUP::GenericNumber:
884 	case SS7MsgISUP::LastDivertingLineIdentity:
885 	case SS7MsgISUP::PresentationNumber:
886 	case SS7MsgISUP::CalledINNumber:
887 	case SS7MsgISUP::OriginalCalledINNumber:
888 	    if (val && extra)
889 		b2 |= (extra->getIntValue(preName+".restrict",s_dict_presentation) & 3) << 2;
890 	default:
891 	    break;
892     }
893     switch (param->type) {
894 	case SS7MsgISUP::CallingPartyNumber:
895 	case SS7MsgISUP::LocationNumber:
896 	case SS7MsgISUP::ConnectedNumber:
897 	case SS7MsgISUP::GenericNumber:
898 	case SS7MsgISUP::LastDivertingLineIdentity:
899 	case SS7MsgISUP::PresentationNumber:
900 	    if (val && extra)
901 		b2 |= extra->getIntValue(preName+".screened",s_dict_screening) & 3;
902 	default:
903 	    break;
904     }
905     return setDigits(msu,val ? val->c_str() : 0,nai,b2,-1,b0);
906 }
907 
908 // Special encoder for subsequent number
encodeSubseq(const SS7ISUP * isup,SS7MSU & msu,unsigned char * buf,const IsupParam * param,const NamedString * val,const NamedList *,const String &)909 static unsigned char encodeSubseq(const SS7ISUP* isup, SS7MSU& msu,
910     unsigned char* buf, const IsupParam* param, const NamedString* val,
911     const NamedList*, const String&)
912 {
913     return setDigits(msu,val ? val->c_str() : 0,0);
914 }
915 
916 // Encoder for circuit group range and status (Q.763 3.43)
encodeRangeSt(const SS7ISUP * isup,SS7MSU & msu,unsigned char * buf,const IsupParam * param,const NamedString * val,const NamedList * extra,const String & prefix)917 static unsigned char encodeRangeSt(const SS7ISUP* isup, SS7MSU& msu,
918     unsigned char* buf, const IsupParam* param, const NamedString* val,
919     const NamedList* extra, const String& prefix)
920 {
921     if (!(param && val))
922 	return 0;
923     unsigned char data[34] = {1};
924     // 1st octet is the range code (range - 1)
925     // Q.763 3.43 Sent range value must be in interval 1..256
926     unsigned int range = val->toInteger(0);
927     if (range < 1 || range > 256) {
928 	Debug(isup,DebugNote,"encodeRangeSt invalid range %s=%s",val->name().c_str(),val->safe());
929 	return 0;
930     }
931     data[1] = range - 1;
932     // Next octets: status bits for the circuits given by range
933     NamedString* map = extra->getParam(prefix+param->name+".map");
934     if (map && map->length()) {
935 	// Max status bits is 256. Relevant status bits: range
936 	unsigned int nBits = map->length();
937 	if (nBits > 256) {
938 	    Debug(isup,DebugNote,"encodeRangeSt truncating status bits %u to 256",map->length());
939 	    nBits = 256;
940 	}
941 	unsigned char* src = (unsigned char*)map->c_str();
942 	unsigned char* dest = data + 1;
943 	for (unsigned char crtBit = 0; nBits; nBits--, src++) {
944 	    if (!crtBit) {
945 		data[0]++;
946 		*++dest = 0;
947 	    }
948 	    if (*src != '0')
949 		*dest |= (1 << crtBit);
950 	    crtBit = (crtBit < 7 ? crtBit + 1 : 0);
951 	}
952     }
953     // Copy to msu
954     DDebug(isup,DebugAll,"encodeRangeSt encoding %s on %u octets",param->name,data[0]);
955     DataBlock tmp(data,data[0] + 1,false);
956     msu += tmp;
957     tmp.clear(false);
958     return data[0];
959 }
960 
961 // Encoder for generic notification indicators (Q.763 3.25)
encodeNotif(const SS7ISUP * isup,SS7MSU & msu,unsigned char * buf,const IsupParam * param,const NamedString * val,const NamedList *,const String &)962 static unsigned char encodeNotif(const SS7ISUP* isup, SS7MSU& msu,
963     unsigned char* buf, const IsupParam* param, const NamedString* val,
964     const NamedList*, const String&)
965 {
966     if (!(param && val) || buf || param->size)
967 	return 0;
968     unsigned char notif[32];
969     unsigned int len = 0;
970     ObjList* lst = val->split(',',false);
971     ObjList* p = lst->skipNull();
972     for (; p; p = p->skipNext()) {
973 	const String* s = static_cast<const String*>(p->get());
974 	int v = s->toInteger((const TokenDict*)param->data,-1);
975 	if (v < 0)
976 	    continue;
977 	notif[++len] = v & 0x7f;
978 	if (len >= sizeof(notif)-1)
979 	    break;
980     }
981     TelEngine::destruct(lst);
982     DDebug(isup,DebugAll,"encodeNotif encoding %s on %u octets",param->name,len);
983     if (!len)
984 	return 0;
985     notif[len] |= 0x80;
986     notif[0] = len & 0xff;
987     DataBlock tmp(notif,len+1,false);
988     msu += tmp;
989     tmp.clear(false);
990     return notif[0];
991 }
992 
993 // Encoder for User Service Information (Q.763 3.57, Q.931)
encodeUSI(const SS7ISUP * isup,SS7MSU & msu,unsigned char * buf,const IsupParam * param,const NamedString * val,const NamedList * extra,const String & prefix)994 static unsigned char encodeUSI(const SS7ISUP* isup, SS7MSU& msu,
995     unsigned char* buf, const IsupParam* param, const NamedString* val,
996     const NamedList* extra, const String& prefix)
997 {
998     if (!param)
999 	return 0;
1000     String preName;
1001     if (val)
1002 	preName = val->name();
1003     else
1004 	preName = prefix + param->name;
1005     DataBlock tmp;
1006     SignallingUtils::encodeCaps(isup,tmp,*extra,preName,true);
1007     DDebug(isup,DebugAll,"encodeUSI encoding %s on %u octets",param->name,tmp.length());
1008     if (tmp.length() < 1)
1009 	return 0;
1010     msu += tmp;
1011     return tmp.length() - 1;
1012 }
1013 
1014 // Encoder for cause indicators
encodeCause(const SS7ISUP * isup,SS7MSU & msu,unsigned char * buf,const IsupParam * param,const NamedString * val,const NamedList * extra,const String & prefix)1015 static unsigned char encodeCause(const SS7ISUP* isup, SS7MSU& msu,
1016     unsigned char* buf, const IsupParam* param, const NamedString* val,
1017     const NamedList* extra, const String& prefix)
1018 {
1019     if (!param)
1020 	return 0;
1021     String preName;
1022     if (val)
1023 	preName = val->name();
1024     else
1025 	preName = prefix + param->name;
1026     DataBlock tmp;
1027     SignallingUtils::encodeCause(isup,tmp,*extra,preName,true);
1028     DDebug(isup,DebugAll,"encodeCause encoding %s on %u octets",param->name,tmp.length());
1029     if (tmp.length() < 1)
1030 	return 0;
1031     msu += tmp;
1032     return tmp.length() - 1;
1033 }
1034 
1035 // Encoder for application transport parameter
encodeAPT(const SS7ISUP * isup,SS7MSU & msu,unsigned char * buf,const IsupParam * param,const NamedString * val,const NamedList * extra,const String & prefix)1036 static unsigned char encodeAPT(const SS7ISUP* isup, SS7MSU& msu,
1037     unsigned char* buf, const IsupParam* param, const NamedString* val,
1038     const NamedList* extra, const String& prefix)
1039 {
1040     if (!param)
1041 	return 0;
1042     if (TelEngine::null(val)) {
1043 	if (val)
1044 	    Debug(isup,DebugNote,"Failed to encode empty %s",val->name().c_str());
1045 	return 0;
1046     }
1047     int context = val->toInteger(-1);
1048     if (context < 0 || context > 127) {
1049 	// Assume binary parameter representation
1050 	DataBlock data;
1051 	if (!(data.unHexify(val->c_str(),val->length(),' ') && data.length()) ||
1052 	    data.length() < 4 || data.length() > 254) {
1053 	    Debug(isup,DebugNote,"Failed to encode invalid %s=%s",
1054 		param->name,val->c_str());
1055 	    return 0;
1056 	}
1057 	unsigned char len = data.length();
1058 	msu.append(&len,1);
1059 	msu += data;
1060 	return 1 + data.length();
1061     }
1062     // WARNING: HACK - ApplicationTransport does not follow naming convention
1063     String preName(prefix + param->name);
1064     preName << "." << context;
1065     unsigned char hdr[4] = {0,(unsigned char)(0x80 | context),0x80,0xc0};  // c0: extension bit set, new sequence bit set
1066     // Retrieve data. Make sure all bytes are correct and final length don't
1067     // overflow our return value
1068     DataBlock data;
1069     const String& tmp = extra ? (*extra)[preName] : String::empty();
1070     if (!(data.unHexify(tmp.c_str(),tmp.length(),' ') && data.length()) ||
1071 	data.length() > (255 - sizeof(hdr))) {
1072 	Debug(isup,DebugNote,"Failed to encode invalid %s=%s",
1073 	    param->name,tmp.c_str());
1074 	return 0;
1075     }
1076     String indName(preName + ".indicators");
1077     const String* inds = extra ? extra->getParam(indName) : 0;
1078     if (inds) {
1079 	unsigned int v = SignallingUtils::encodeFlags(isup,*inds,s_flags_apt_indicators,indName);
1080 	hdr[2] |= (v & 0x7f);
1081     }
1082     else {
1083 	// Set default indicators value: send CNF, no call release
1084 	hdr[2] |= 0x02;
1085     }
1086     hdr[0] = data.length() + 3;
1087     msu.append(hdr,sizeof(hdr));
1088     msu += data;
1089     return hdr[0];
1090 }
1091 
1092 // Encoder for Generic Name
encodeName(const SS7ISUP * isup,SS7MSU & msu,unsigned char * buf,const IsupParam * param,const NamedString * val,const NamedList * extra,const String & prefix)1093 static unsigned char encodeName(const SS7ISUP* isup, SS7MSU& msu,
1094     unsigned char* buf, const IsupParam* param, const NamedString* val,
1095     const NamedList* extra, const String& prefix)
1096 {
1097     if (!(param && val) || buf || param->size)
1098 	return 0;
1099     unsigned int len = val->length() + 1;
1100     if (len >= 127)
1101 	return 0;
1102     unsigned char gn[2] = { (unsigned char)len, 3 };
1103     if (extra) {
1104 	String preName;
1105 	if (val)
1106 	    preName = val->name();
1107 	else
1108 	    preName = prefix + param->name;
1109 	if (!extra->getBoolValue(preName+".available",true))
1110 	    gn[1] |= 0x10;
1111 	gn[1] = (gn[1] & 0x1f) |
1112 	    (extra->getIntValue(preName+".qualifier",s_dict_qual_name,gn[1] & 0xe0) & 0xe0);
1113 	gn[1] = (gn[1] & 0xfc) |
1114 	    (extra->getIntValue(preName+".restrict",s_dict_presentation,gn[1] & 0x03) & 0x03);
1115     }
1116     DataBlock tmp(gn,2);
1117     tmp += *val;
1118     DDebug(isup,DebugAll,"encodeName encoding %s on %u octets",param->name,tmp.length());
1119     msu += tmp;
1120     return len;
1121 }
1122 
1123 // Encoder for Redirection information (Q.763 3.45)
encodeRedir(const SS7ISUP * isup,SS7MSU & msu,unsigned char * buf,const IsupParam * param,const NamedString * val,const NamedList * extra,const String & prefix)1124 static unsigned char encodeRedir(const SS7ISUP* isup, SS7MSU& msu,
1125     unsigned char* buf, const IsupParam* param, const NamedString* val,
1126     const NamedList* extra, const String& prefix)
1127 {
1128     if (!(param && val) || buf || param->size)
1129 	return 0;
1130     unsigned char ri[3] = { 2, 0, 0 };
1131     if (extra) {
1132 	String preName;
1133 	if (val)
1134 	    preName = val->name();
1135 	else
1136 	    preName = prefix + param->name;
1137 	ri[1] = (extra->getIntValue(preName,s_dict_redir_main,0) & 0x07) |
1138 	    ((extra->getIntValue(preName+".reason_original",s_dict_redir_reason,0) & 0x0f) << 4);
1139 	ri[2] = (extra->getIntValue(preName+".counter") & 0x07) |
1140 	    ((extra->getIntValue(preName+".reason",s_dict_redir_reason,0) & 0x0f) << 4);
1141     }
1142     DataBlock tmp(ri,3,false);
1143     msu += tmp;
1144     tmp.clear(false);
1145     return ri[0];
1146 }
1147 
1148 // Nature of Connection Indicators (Q.763 3.35)
1149 static const SignallingFlags s_flags_naci[] = {
1150     // TODO: add more flags
1151     { 0x03, 0x00, "0sat" },
1152     { 0x03, 0x01, "1sat" },
1153     { 0x03, 0x02, "2sat" },
1154     { 0x0c, 0x00, "cont-check-none" },      // Continuity check not required
1155     { 0x0c, 0x04, "cont-check-this" },      // Continuity check required on this circuit
1156     { 0x0c, 0x08, "cont-check-prev" },      // Continuity check performed on a previous circuit
1157     { 0x10, 0x10, "echodev" },              // Outgoing half echo control device included
1158     { 0, 0, 0 }
1159 };
1160 
1161 // Forward Call Indicators (Q.763 3.23)
1162 static const SignallingFlags s_flags_fwcallind[] = {
1163     { 0x0001, 0x0000, "national" },         // National/international call indicator
1164     { 0x0001, 0x0001, "international" },
1165     { 0x0006, 0x0000, "e2e-none" },         // End-to-end method indicator (none available: only link-by-link)
1166     { 0x0006, 0x0002, "e2e-pass" },         //   Pass along method available
1167     { 0x0006, 0x0004, "e2e-sccp" },         //   SCCP along method available
1168     { 0x0006, 0x0006, "e2e-pass-sccp" },    //   Pass along and SCCP method available
1169     { 0x0008, 0x0008, "interworking" },     // Interworking indicator (0: SS7 all the way)
1170     { 0x0010, 0x0010, "e2e-info" },         // End-to-end information available
1171     { 0x0020, 0x0020, "isup-path" },        // ISUP indicator (ISUP used all the way)
1172     { 0x00c0, 0x0000, "isup-pref" },        // ISUP preference indicator: preferred all the way
1173     { 0x00c0, 0x0040, "isup-notreq" },      //   not required all the way
1174     { 0x00c0, 0x0080, "isup-req" },         //   required all the way
1175     { 0x0100, 0x0100, "isdn-orig" },        // Originating from ISDN
1176     { 0x0600, 0x0000, "sccp-none" },        // SCCP method indicator: no indication
1177     { 0x0600, 0x0200, "sccp-less" },        //   connectionless method available
1178     { 0x0600, 0x0400, "sccp-conn" },        //   connection oriented method available
1179     { 0x0600, 0x0600, "sccp-less-conn" },   //   connectionless and connection oriented methods available
1180     { 0x1000, 0x1000, "translated" },       // Number Translated (for portability)
1181     { 0x2000, 0x2000, "qor-routing" },      // QoR routing attempt in progress
1182     { 0, 0, 0 }
1183 };
1184 
1185 // Backward Call Indicators (Q.763 3.5)
1186 static const SignallingFlags s_flags_bkcallind[] = {
1187     { 0x0003, 0x0001, "no-charge" },        // Charge indicator
1188     { 0x0003, 0x0002, "charge" },
1189     { 0x000c, 0x0004, "called-free" },      // Called party's status indicator: subscriber free
1190     { 0x000c, 0x0008, "called-conn" },      // Called party's status indicator: connect when free
1191     { 0x0030, 0x0010, "called-ordinary" },  // Called party's category indicator: ordinary subscriber
1192     { 0x0030, 0x0020, "called-payphone" },  // Called party's category indicator: payphone
1193     { 0x00c0, 0x0000, "e2e-none" },         // End-to-end method indicator (none available: only link-by-link)
1194     { 0x00c0, 0x0040, "e2e-pass" },         //   Pass along method available
1195     { 0x00c0, 0x0080, "e2e-sccp" },         //   SCCP along method available
1196     { 0x00c0, 0x00c0, "e2e-pass-sccp" },    //   Pass along and SCCP method available
1197     { 0x0100, 0x0100, "interworking" },     // Interworking indicator (0: SS7 all the way)
1198     { 0x0200, 0x0200, "e2e-info" },         // End-to-end information available
1199     { 0x0400, 0x0400, "isup-path" },        // ISUP indicator (ISUP used all the way)
1200     { 0x0800, 0x0800, "hold-req" },         // Holding indicator: holding requested
1201     { 0x1000, 0x1000, "isdn-end" },         // Terminating in ISDN
1202     { 0x2000, 0x2000, "echodev" },          // Incoming half echo control device included
1203     { 0xc000, 0x0000, "sccp-none" },        // SCCP method indicator: no indication
1204     { 0xc000, 0x4000, "sccp-less" },        //   connectionless method available
1205     { 0xc000, 0x8000, "sccp-conn" },        //   connection oriented method available
1206     { 0xc000, 0xc000, "sccp-less-conn" },   //   connectionless and connection oriented methods available
1207     { 0, 0, 0 }
1208 };
1209 
1210 // Call Diversion Information (Q.763 3.6)
1211 static const SignallingFlags s_flags_calldivinfo[] = {
1212     { 0x07, 0x01, "presentation-not-allowed" },
1213     { 0x07, 0x02, "presentation-with-number" },
1214     { 0x07, 0x03, "presentation-without-number" },
1215     { 0x78, 0x08, "busy" },
1216     { 0x78, 0x10, "noanswer" },
1217     { 0x78, 0x18, "always" },
1218     { 0x78, 0x20, "deflected-alerting" },
1219     { 0x78, 0x28, "deflected-immediate" },
1220     { 0x78, 0x30, "offline" },
1221     { 0, 0, 0 }
1222 };
1223 
1224 // Optional Forward Call Indicators (Q.763 3.38)
1225 static const SignallingFlags s_flags_optfwcallind[] = {
1226     { 0x03, 0x00, "non-CUG" },
1227     { 0x03, 0x02, "CUG+out" },
1228     { 0x03, 0x03, "CUG" },
1229     { 0x04, 0x04, "segmentation" },         // Additional info will be sent in a segmentation message
1230     { 0x80, 0x80, "CLIR-requested" },
1231     { 0, 0, 0 }
1232 };
1233 
1234 // Optional Backward Call Indicators (Q.763 3.37)
1235 static const SignallingFlags s_flags_optbkcallind[] = {
1236     { 0x01, 0x01, "inband" },
1237     { 0x02, 0x02, "diversion-possible" },
1238     { 0x04, 0x04, "segmentation" },         // Additional info will be sent in a segmentation message
1239     { 0x08, 0x08, "MLPP-user" },
1240     { 0, 0, 0 }
1241 };
1242 
1243 // Event Information (Q.763 3.21)
1244 static const SignallingFlags s_flags_eventinfo[] = {
1245     { 0x7f, 0x01, "ringing" },
1246     { 0x7f, 0x02, "progress" },
1247     { 0x7f, 0x03, "inband" },
1248     { 0x7f, 0x04, "forward-busy" },
1249     { 0x7f, 0x05, "forward-noanswer" },
1250     { 0x7f, 0x06, "forward-always" },
1251     { 0x80, 0x80, "restricted" },
1252     { 0, 0, 0 }
1253 };
1254 
1255 // Continuity Indicators (Q.763 3.18)
1256 static const SignallingFlags s_flags_continuity[] = {
1257     { 0x01, 0x00, "failed" },
1258     { 0x01, 0x01, "success" },
1259     { 0, 0, 0 }
1260 };
1261 
1262 // Group Supervision Type Indicator (Q.763 3.13)
1263 static const SignallingFlags s_flags_grptypeind[] = {
1264     { 0x03, 0x00, "maintenance" },
1265     { 0x03, 0x01, "hw-failure" },
1266     { 0x03, 0x02, "national" },
1267     { 0, 0, 0 }
1268 };
1269 
1270 // Access Delivery Information (Q.763 3.2)
1271 static const SignallingFlags s_flags_accdelinfo[] = {
1272     { 0x01, 0x00, "setup-generated" },   // A Setup message was generated
1273     { 0x01, 0x01, "no-setup" },          // No Setup message generated
1274     { 0, 0, 0 }
1275 };
1276 
1277 // MCID Request or Response Indicators (Q.763 3.31 and 3.32)
1278 static const SignallingFlags s_flags_mcid[] = {
1279     { 0x01, 0x01, "MCID" },
1280     { 0x02, 0x02, "holding" },
1281     { 0, 0, 0 }
1282 };
1283 
1284 // ANSI Circuit Validation Response Indicator
1285 static const SignallingFlags s_flags_ansi_cvri[] = {
1286     { 0x03, 0x00, "failed" },
1287     { 0x03, 0x01, "success" },
1288     { 0, 0, 0 }
1289 };
1290 
1291 // ANSI Circuit Group Characteristics Indicator
1292 static const SignallingFlags s_flags_ansi_cgci[] = {
1293     { 0x03, 0x00, "carrier-unknown" },
1294     { 0x03, 0x01, "carrier-analog" },
1295     { 0x03, 0x02, "carrier-digital" },
1296     { 0x03, 0x03, "carrier-mixed" },
1297     { 0x0c, 0x00, "seize-none" },
1298     { 0x0c, 0x04, "seize-odd" },
1299     { 0x0c, 0x08, "seize-even" },
1300     { 0x0c, 0x0c, "seize-all" },
1301     { 0x30, 0x00, "alarm-default" },
1302     { 0x30, 0x10, "alarm-software" },
1303     { 0x30, 0x20, "alarm-hardware" },
1304     { 0xc0, 0x00, "continuity-unknown" },
1305     { 0xc0, 0x40, "continuity-none" },
1306     { 0xc0, 0x80, "continuity-statistical" },
1307     { 0xc0, 0xc0, "continuity-call" },
1308     { 0, 0, 0 }
1309 };
1310 
1311 // National Forward Call Indicators (NICC ND 1007 2001 3.2.1)
1312 static const SignallingFlags s_flags_nfci[] = {
1313     { 0x0001, 0x0000, "cli-blocked" },      // CLI Blocking Indicator (CBI)
1314     { 0x0001, 0x0001, "cli-allowed" },
1315     { 0x0002, 0x0002, "translated" },       // Network translated address indicator
1316     { 0x0004, 0x0004, "iup-priority" },     // Priority access indicator (IUP)
1317     { 0x0008, 0x0008, "iup-protected" },    // Protection indicator (IUP)
1318     { 0, 0, 0 }
1319 };
1320 
1321 // Calling Party Category (Q.763 3.11)
1322 static const TokenDict s_dict_callerCat[] = {
1323     { "unknown",     0 },                // calling party's category is unknown
1324     { "operator-FR", 1 },                // operator, language French
1325     { "operator-EN", 2 },                // operator, language English
1326     { "operator-DE", 3 },                // operator, language German
1327     { "operator-RU", 4 },                // operator, language Russian
1328     { "operator-ES", 5 },                // operator, language Spanish
1329     { "ordinary",   10 },                // ordinary calling subscriber
1330     { "priority",   11 },                // calling subscriber with priority
1331     { "data",       12 },                // data call (voice band data)
1332     { "test",       13 },                // test call
1333     { "payphone",   15 },                // payphone
1334     { 0, 0 }
1335 };
1336 
1337 // Transmission Medium Requirement (Q.763 3.54)
1338 static const TokenDict s_dict_mediumReq[] = {
1339     { "speech",          0 },
1340     { "64kbit",          2 },
1341     { "3.1khz-audio",    3 },
1342     { "64kb-preferred",  6 },
1343     { "2x64kbit",        7 },
1344     { "384kbit",         8 },
1345     { "1536kbit",        9 },
1346     { "1920kbit",       10 },
1347     { 0, 0 }
1348 };
1349 
1350 // Generic Notification Indicator (Q.763 3.25)
1351 static const TokenDict s_dict_notifications[] = {
1352     { "user-suspended",         0x00 },
1353     { "user-resumed",           0x01 },
1354     { "bearer-service-change",  0x02 },
1355     { "call-completion-delay",  0x04 },
1356     { "conf-established",       0x42 },
1357     { "conf-disconnected",      0x43 },
1358     { "party-added",            0x44 },
1359     { "isolated",               0x45 },
1360     { "reattached",             0x46 },
1361     { "party-isolated",         0x47 },
1362     { "party-reattached",       0x48 },
1363     { "party-split",            0x49 },
1364     { "party-disconnected",     0x4a },
1365     { "conf-floating",          0x4b },
1366     { "call-waiting",           0x60 },
1367     { "call-diversion",         0x68 },
1368     { "call-transfer-alerting", 0x69 },
1369     { "call-transfer-active",   0x6a },
1370     { "remote-hold",            0x79 },
1371     { "remote-retrieval",       0x7a },
1372     { "call-diverting",         0x7b },
1373     { 0, 0 }
1374 };
1375 
1376 // Number Portability Forward Information (Q.763 3.101)
1377 static const TokenDict s_dict_portability[] = {
1378     { "not-queried",       1 },
1379     { "called-not-ported", 2 },
1380     { "called-ported",     3 },
1381     { 0, 0 }
1382 };
1383 
1384 // ANSI Originating Line Info
1385 static const TokenDict s_dict_oli[] = {
1386     { "normal",            0 },
1387     { "multiparty",        1 },
1388     { "ani-failure",       2 },
1389     { "hotel-room-id",     6 },
1390     { "coinless",          7 },
1391     { "restricted",        8 },
1392     { "test-call-1",      10 },
1393     { "aiod-listed-dn",   20 },
1394     { "identified-line",  23 },
1395     { "800-call",         24 },
1396     { "coin-line",        27 },
1397     { "restricted-hotel", 68 },
1398     { "test-call-2",      95 },
1399     { 0, 0 }
1400 };
1401 
1402 #define MAKE_PARAM(p,s,a,d,t) { SS7MsgISUP::p,s,#p,a,d,t }
1403 static const IsupParam s_paramDefs[] = {
1404 //             name                          len decoder        encoder        table                  References
1405 
1406     // Standard parameters, references to ITU Q.763
1407     MAKE_PARAM(AccessDeliveryInformation,      1,decodeFlags,   encodeFlags,   s_flags_accdelinfo),   // 3.2
1408     MAKE_PARAM(AccessTransport,                0,0,             0,             0),                    // 3.3
1409     MAKE_PARAM(AutomaticCongestionLevel,       1,decodeInt,     encodeInt,     0),                    // 3.4
1410     MAKE_PARAM(BackwardCallIndicators,         2,decodeFlags,   encodeFlags,   s_flags_bkcallind),    // 3.5
1411     MAKE_PARAM(CallDiversionInformation,       1,decodeFlags,   encodeFlags,   s_flags_calldivinfo),  // 3.6
1412     MAKE_PARAM(CallHistoryInformation,         2,decodeInt,     encodeInt,     0),                    // 3.7
1413     MAKE_PARAM(CallReference,                  0,0,             0,             0),                    // 3.8
1414     MAKE_PARAM(CalledPartyNumber,              0,decodeDigits,  encodeDigits,  0),                    // 3.9
1415     MAKE_PARAM(CallingPartyNumber,             0,decodeDigits,  encodeDigits,  0),                    // 3.10
1416     MAKE_PARAM(CallingPartyCategory,           1,decodeInt,     encodeInt,     s_dict_callerCat),     // 3.11
1417     MAKE_PARAM(CauseIndicators,                0,decodeCause,   encodeCause,   0),                    // 3.12  Q.850-2.1
1418     MAKE_PARAM(GroupSupervisionTypeIndicator,  1,decodeFlags,   encodeFlags,   s_flags_grptypeind),   // 3.13
1419     MAKE_PARAM(CircuitStateIndicator,          0,0,             0,             0),                    // 3.14
1420     MAKE_PARAM(CUG_InterlockCode,              0,0,             0,             0),                    // 3.15
1421     MAKE_PARAM(ConnectedNumber,                0,decodeDigits,  encodeDigits,  0),                    // 3.16
1422     MAKE_PARAM(ConnectionRequest,              0,0,             0,             0),                    // 3.17
1423     MAKE_PARAM(ContinuityIndicators,           1,decodeFlags,   encodeFlags,   s_flags_continuity),   // 3.18
1424     MAKE_PARAM(EchoControlInformation,         0,0,             0,             0),                    // 3.19
1425     MAKE_PARAM(EventInformation,               1,decodeFlags,   encodeFlags,   s_flags_eventinfo),    // 3.21
1426     MAKE_PARAM(FacilityIndicator,              1,0,             0,             0),                    // 3.22
1427     MAKE_PARAM(ForwardCallIndicators,          2,decodeFlags,   encodeFlags,   s_flags_fwcallind),    // 3.23
1428     MAKE_PARAM(GenericDigits,                  0,0,             0,             0),                    // 3.24
1429     MAKE_PARAM(GenericNotification,            0,decodeNotif,   encodeNotif,   s_dict_notifications), // 3.25
1430     MAKE_PARAM(GenericNumber,                  0,decodeDigits,  encodeDigits,  0),                    // 3.26
1431     MAKE_PARAM(GenericReference,               0,0,             0,             0),                    // 3.27
1432     MAKE_PARAM(InformationIndicators,          2,0,             0,             0),                    // 3.28
1433     MAKE_PARAM(InformationRequestIndicators,   2,0,             0,             0),                    // 3.29
1434     MAKE_PARAM(LocationNumber,                 0,decodeDigits,  encodeDigits,  0),                    // 3.30
1435     MAKE_PARAM(MCID_RequestIndicator,          1,decodeFlags,   encodeFlags,   s_flags_mcid),         // 3.31
1436     MAKE_PARAM(MCID_ResponseIndicator,         1,decodeFlags,   encodeFlags,   s_flags_mcid),         // 3.32
1437     MAKE_PARAM(MessageCompatInformation,       0,decodeCompat,  0,             0),                    // 3.33
1438     MAKE_PARAM(NatureOfConnectionIndicators,   1,decodeFlags,   encodeFlags,   s_flags_naci),         // 3.35
1439     MAKE_PARAM(NetworkSpecificFacilities,      0,0,             0,             0),                    // 3.36
1440     MAKE_PARAM(OptionalBackwardCallIndicators, 1,decodeFlags,   encodeFlags,   s_flags_optbkcallind), // 3.37
1441     MAKE_PARAM(OptionalForwardCallIndicators,  1,decodeFlags,   encodeFlags,   s_flags_optfwcallind), // 3.38
1442     MAKE_PARAM(OriginalCalledNumber,           0,decodeDigits,  encodeDigits,  0),                    // 3.39
1443     MAKE_PARAM(OriginationISCPointCode,        0,0,             0,             0),                    // 3.40
1444     MAKE_PARAM(ParameterCompatInformation,     0,decodeCompat,  0,             0),                    // 3.41
1445     MAKE_PARAM(PropagationDelayCounter,        2,decodeInt,     encodeInt,     0),                    // 3.42
1446     MAKE_PARAM(RangeAndStatus,                 0,decodeRangeSt, encodeRangeSt, 0),                    // 3.43
1447     MAKE_PARAM(RedirectingNumber,              0,decodeDigits,  encodeDigits,  0),                    // 3.44
1448     MAKE_PARAM(RedirectionInformation,         0,decodeRedir,   encodeRedir,   0),                    // 3.45
1449     MAKE_PARAM(RedirectionNumber,              0,decodeDigits,  encodeDigits,  0),                    // 3.46
1450     MAKE_PARAM(RedirectionNumberRestriction,   0,0,             0,             0),                    // 3.47
1451     MAKE_PARAM(RemoteOperations,               0,0,             0,             0),                    // 3.48
1452     MAKE_PARAM(ServiceActivation,              0,0,             0,             0),                    // 3.49
1453     MAKE_PARAM(SignallingPointCode,            0,0,             0,             0),                    // 3.50
1454     MAKE_PARAM(SubsequentNumber,               0,decodeSubseq,  encodeSubseq,  0),                    // 3.51
1455     MAKE_PARAM(SuspendResumeIndicators,        1,0,             0,             0),                    // 3.52
1456     MAKE_PARAM(TransitNetworkSelection,        0,0,             0,             0),                    // 3.53
1457     MAKE_PARAM(TransmissionMediumRequirement,  1,decodeInt,     encodeInt,     s_dict_mediumReq),     // 3.54
1458     MAKE_PARAM(TransMediumRequirementPrime,    1,decodeInt,     encodeInt,     s_dict_mediumReq),     // 3.55
1459     MAKE_PARAM(TransmissionMediumUsed,         1,decodeInt,     encodeInt,     s_dict_mediumReq),     // 3.56
1460     MAKE_PARAM(UserServiceInformation,         0,decodeUSI,     encodeUSI,     0),                    // 3.57  Q.931-4.5.5
1461     MAKE_PARAM(UserServiceInformationPrime,    0,0,             0,             0),                    // 3.58
1462     MAKE_PARAM(UserTeleserviceInformation,     0,0,             0,             0),                    // 3.59
1463     MAKE_PARAM(UserToUserIndicators,           0,0,             0,             0),                    // 3.60
1464     MAKE_PARAM(UserToUserInformation,          0,0,             0,             0),                    // 3.61
1465     MAKE_PARAM(CCSScallIndication,             1,0,             0,             0),                    // 3.63
1466     MAKE_PARAM(ForwardGVNS,                    0,0,             0,             0),                    // 3.66
1467     MAKE_PARAM(BackwardGVNS,                   0,0,             0,             0),                    // 3.62
1468     MAKE_PARAM(CalledINNumber,                 0,decodeDigits,  encodeDigits,  0),                    // 3.73
1469     MAKE_PARAM(UID_ActionIndicators,           0,0,             0,             0),                    // 3.78
1470     MAKE_PARAM(UID_CapabilityIndicators,       0,0,             0,             0),                    // 3.79
1471     MAKE_PARAM(RedirectCapability,             0,0,             0,             0),                    // 3.96
1472     MAKE_PARAM(RedirectCounter,                0,0,             0,             0),                    // 3.97
1473     MAKE_PARAM(CCNRpossibleIndicator,          0,0,             0,             0),                    // 3.83
1474     MAKE_PARAM(PivotRoutingIndicators,         0,0,             0,             0),                    // 3.85
1475     MAKE_PARAM(CalledDirectoryNumber,          0,0,             0,             0),                    // 3.86
1476     MAKE_PARAM(OriginalCalledINNumber,         0,0,             0,             0),                    // 3.87
1477     MAKE_PARAM(CallingGeodeticLocation,        0,0,             0,             0),                    // 3.88
1478     MAKE_PARAM(HTR_Information,                0,0,             0,             0),                    // 3.89
1479     MAKE_PARAM(NetworkRoutingNumber,           0,0,             0,             0),                    // 3.90
1480     MAKE_PARAM(QueryOnReleaseCapability,       0,0,             0,             0),                    // 3.91
1481     MAKE_PARAM(PivotStatus,                    0,0,             0,             0),                    // 3.92
1482     MAKE_PARAM(PivotCounter,                   0,0,             0,             0),                    // 3.93
1483     MAKE_PARAM(PivotRoutingForwardInformation, 0,0,             0,             0),                    // 3.94
1484     MAKE_PARAM(PivotRoutingBackInformation,    0,0,             0,             0),                    // 3.95
1485     MAKE_PARAM(RedirectStatus,                 0,0,             0,             0),                    // 3.98
1486     MAKE_PARAM(RedirectForwardInformation,     0,0,             0,             0),                    // 3.99
1487     MAKE_PARAM(RedirectBackwardInformation,    0,0,             0,             0),                    // 3.100
1488     MAKE_PARAM(NumberPortabilityInformation,   0,decodeNotif,   encodeNotif,   s_dict_portability),   // 3.101
1489     // No references
1490     MAKE_PARAM(ApplicationTransport,           0,decodeAPT,     encodeAPT,     0),                    // 3.82
1491     MAKE_PARAM(BusinessGroup,                  0,0,             0,             0),                    //
1492     MAKE_PARAM(CallModificationIndicators,     0,0,             0,             0),                    //
1493     MAKE_PARAM(CarrierIdentification,          0,0,             0,             0),                    //
1494     MAKE_PARAM(CircuitIdentificationName,      0,0,             0,             0),                    //
1495     MAKE_PARAM(CarrierSelectionInformation,    0,0,             0,             0),                    //
1496     MAKE_PARAM(ChargeNumber,                   0,0,             0,             0),                    //
1497     MAKE_PARAM(CircuitAssignmentMap,           0,0,             0,             0),                    //
1498     MAKE_PARAM(CircuitGroupCharactIndicator,   1,decodeFlags,   encodeFlags,   s_flags_ansi_cgci),    // T1.113 ??
1499     MAKE_PARAM(CircuitValidationRespIndicator, 1,decodeFlags,   encodeFlags,   s_flags_ansi_cvri),    // T1.113 ??
1500     MAKE_PARAM(CommonLanguage,                 0,0,             0,             0),                    //
1501     MAKE_PARAM(CUG_CheckResponseIndicators,    0,0,             0,             0),                    //
1502     MAKE_PARAM(Egress,                         0,0,             0,             0),                    //
1503     MAKE_PARAM(FacilityInformationIndicators,  0,0,             0,             0),                    //
1504     MAKE_PARAM(FreephoneIndicators,            0,0,             0,             0),                    //
1505     MAKE_PARAM(GenericName,                    0,decodeName,    encodeName,    0),                    //
1506     MAKE_PARAM(HopCounter,                     1,decodeInt,     encodeInt,     0),                    // 3.80
1507     MAKE_PARAM(Index,                          0,0,             0,             0),                    //
1508     MAKE_PARAM(Jurisdiction,                   0,0,             0,             0),                    //
1509     MAKE_PARAM(MLPP_Precedence,                0,0,             0,             0),                    //
1510     MAKE_PARAM(NetworkTransport,               0,0,             0,             0),                    //
1511     MAKE_PARAM(NotificationIndicator,          0,0,             0,             0),                    //
1512     MAKE_PARAM(OperatorServicesInformation,    0,0,             0,             0),                    //
1513     MAKE_PARAM(OriginatingLineInformation,     1,decodeInt,     encodeInt,     s_dict_oli),           //
1514     MAKE_PARAM(OutgoingTrunkGroupNumber,       0,0,             0,             0),                    //
1515     MAKE_PARAM(Precedence,                     0,0,             0,             0),                    //
1516     MAKE_PARAM(ServiceCodeIndicator,           0,0,             0,             0),                    //
1517     MAKE_PARAM(SpecialProcessingRequest,       0,0,             0,             0),                    //
1518     MAKE_PARAM(TransactionRequest,             0,0,             0,             0),                    //
1519     // National use (UK-ISUP), references to NICC ND 1007 2001/07
1520     MAKE_PARAM(NationalForwardCallIndicators,          2,decodeFlags,   encodeFlags,   s_flags_nfci), // 3.2.1
1521     MAKE_PARAM(NationalForwardCallIndicatorsLinkByLink,0,0,             0,             0),            // 3.2.2
1522     MAKE_PARAM(PresentationNumber,                     0,decodeDigits,  encodeDigits,  0),            // 3.2.3
1523     MAKE_PARAM(LastDivertingLineIdentity,              0,decodeDigits,  encodeDigits,  0),            // 3.2.4
1524     MAKE_PARAM(PartialCLI,                             0,0,             0,             0),            // 3.2.5
1525     MAKE_PARAM(CalledSubscribersBasicServiceMarks,     0,0,             0,             0),            // 3.2.6
1526     MAKE_PARAM(CallingSubscribersBasicServiceMarks,    0,0,             0,             0),            // 3.2.7
1527     MAKE_PARAM(CallingSubscribersOriginatingFacilMarks,0,0,             0,             0),            // 3.2.8
1528     MAKE_PARAM(CalledSubscribersTerminatingFacilMarks, 0,0,             0,             0),            // 3.2.9
1529     MAKE_PARAM(NationalInformationRequestIndicators,   0,0,             0,             0),            // 3.2.10
1530     MAKE_PARAM(NationalInformationIndicators,          0,0,             0,             0),            // 3.2.11
1531     { SS7MsgISUP::EndOfParameters, 0, 0, 0, 0, 0 }
1532 };
1533 #undef MAKE_PARAM
1534 
getIsupParamName(unsigned char type)1535 const char* getIsupParamName(unsigned char type)
1536 {
1537    for (unsigned int i = 0; s_paramDefs[i].type; i++)
1538 	if (type == s_paramDefs[i].type)
1539 	    return s_paramDefs[i].name;
1540    return 0;
1541 }
1542 
1543 // Descriptor of ISUP message common across standards
1544 static const MsgParams s_common_params[] = {
1545     // call progress and release messages
1546     { SS7MsgISUP::ACM, true,
1547 	{
1548 	    SS7MsgISUP::BackwardCallIndicators,
1549 	SS7MsgISUP::EndOfParameters,
1550 	SS7MsgISUP::EndOfParameters
1551 	}
1552     },
1553     { SS7MsgISUP::CON, true,
1554 	{
1555 	    SS7MsgISUP::BackwardCallIndicators,
1556 	SS7MsgISUP::EndOfParameters,
1557 	SS7MsgISUP::EndOfParameters
1558 	}
1559     },
1560     { SS7MsgISUP::ANM, true,
1561 	{
1562 	SS7MsgISUP::EndOfParameters,
1563 	SS7MsgISUP::EndOfParameters
1564 	}
1565     },
1566     { SS7MsgISUP::REL, true,
1567 	{
1568 	SS7MsgISUP::EndOfParameters,
1569 	    SS7MsgISUP::CauseIndicators,
1570 	SS7MsgISUP::EndOfParameters
1571 	}
1572     },
1573     { SS7MsgISUP::RLC, true,
1574 	{
1575 	SS7MsgISUP::EndOfParameters,
1576 	SS7MsgISUP::EndOfParameters
1577 	}
1578     },
1579     { SS7MsgISUP::SAM, true,
1580 	{
1581 	SS7MsgISUP::EndOfParameters,
1582 	    SS7MsgISUP::SubsequentNumber,
1583 	SS7MsgISUP::EndOfParameters
1584 	}
1585     },
1586     { SS7MsgISUP::CPR, true,
1587 	{
1588 	    SS7MsgISUP::EventInformation,
1589 	SS7MsgISUP::EndOfParameters,
1590 	SS7MsgISUP::EndOfParameters
1591 	}
1592     },
1593     { SS7MsgISUP::CNF, true,
1594 	{
1595 	SS7MsgISUP::EndOfParameters,
1596 	    SS7MsgISUP::CauseIndicators,
1597 	SS7MsgISUP::EndOfParameters
1598 	}
1599     },
1600     { SS7MsgISUP::SUS, true,
1601 	{
1602 	    SS7MsgISUP::SuspendResumeIndicators,
1603 	SS7MsgISUP::EndOfParameters,
1604 	SS7MsgISUP::EndOfParameters
1605 	}
1606     },
1607     { SS7MsgISUP::RES, true,
1608 	{
1609 	    SS7MsgISUP::SuspendResumeIndicators,
1610 	SS7MsgISUP::EndOfParameters,
1611 	SS7MsgISUP::EndOfParameters
1612 	}
1613     },
1614     { SS7MsgISUP::INR, true,
1615 	{
1616 	    SS7MsgISUP::InformationRequestIndicators,
1617 	SS7MsgISUP::EndOfParameters,
1618 	SS7MsgISUP::EndOfParameters
1619 	}
1620     },
1621     { SS7MsgISUP::INF, true,
1622 	{
1623 	    SS7MsgISUP::InformationIndicators,
1624 	SS7MsgISUP::EndOfParameters,
1625 	SS7MsgISUP::EndOfParameters
1626 	}
1627     },
1628     // circuit group reset and acknowledgement
1629     { SS7MsgISUP::GRS, false,
1630 	{
1631 	SS7MsgISUP::EndOfParameters,
1632 	    SS7MsgISUP::RangeAndStatus,
1633 	SS7MsgISUP::EndOfParameters
1634 	}
1635     },
1636     { SS7MsgISUP::GRA, false,
1637 	{
1638 	SS7MsgISUP::EndOfParameters,
1639 	    SS7MsgISUP::RangeAndStatus,
1640 	SS7MsgISUP::EndOfParameters
1641 	}
1642     },
1643     // circuit group query
1644     { SS7MsgISUP::CQM, false,
1645 	{
1646 	SS7MsgISUP::EndOfParameters,
1647 	    SS7MsgISUP::RangeAndStatus,
1648 	SS7MsgISUP::EndOfParameters
1649 	}
1650     },
1651     { SS7MsgISUP::CQR, false,
1652 	{
1653 	SS7MsgISUP::EndOfParameters,
1654 	    SS7MsgISUP::RangeAndStatus,
1655 	    SS7MsgISUP::CircuitStateIndicator,
1656 	SS7MsgISUP::EndOfParameters
1657 	}
1658     },
1659     // circuit group blocking, unblocking and acknowledgement
1660     { SS7MsgISUP::CGB, false,
1661 	{
1662 	    SS7MsgISUP::GroupSupervisionTypeIndicator,
1663 	SS7MsgISUP::EndOfParameters,
1664 	    SS7MsgISUP::RangeAndStatus,
1665 	SS7MsgISUP::EndOfParameters
1666 	}
1667     },
1668     { SS7MsgISUP::CGA, false,
1669 	{
1670 	    SS7MsgISUP::GroupSupervisionTypeIndicator,
1671 	SS7MsgISUP::EndOfParameters,
1672 	    SS7MsgISUP::RangeAndStatus,
1673 	SS7MsgISUP::EndOfParameters
1674 	}
1675     },
1676     { SS7MsgISUP::CGU, false,
1677 	{
1678 	    SS7MsgISUP::GroupSupervisionTypeIndicator,
1679 	SS7MsgISUP::EndOfParameters,
1680 	    SS7MsgISUP::RangeAndStatus,
1681 	SS7MsgISUP::EndOfParameters
1682 	}
1683     },
1684     { SS7MsgISUP::CUA, false,
1685 	{
1686 	    SS7MsgISUP::GroupSupervisionTypeIndicator,
1687 	SS7MsgISUP::EndOfParameters,
1688 	    SS7MsgISUP::RangeAndStatus,
1689 	SS7MsgISUP::EndOfParameters
1690 	}
1691     },
1692     // circuit related messages - most without parameters, only CIC
1693     { SS7MsgISUP::BLK, false,
1694 	{
1695 	SS7MsgISUP::EndOfParameters,
1696 	SS7MsgISUP::EndOfParameters
1697 	}
1698     },
1699     { SS7MsgISUP::BLA, false,
1700 	{
1701 	SS7MsgISUP::EndOfParameters,
1702 	SS7MsgISUP::EndOfParameters
1703 	}
1704     },
1705     { SS7MsgISUP::UBL, false,
1706 	{
1707 	SS7MsgISUP::EndOfParameters,
1708 	SS7MsgISUP::EndOfParameters
1709 	}
1710     },
1711     { SS7MsgISUP::UBA, false,
1712 	{
1713 	SS7MsgISUP::EndOfParameters,
1714 	SS7MsgISUP::EndOfParameters
1715 	}
1716     },
1717     { SS7MsgISUP::CCR, false,
1718 	{
1719 	SS7MsgISUP::EndOfParameters,
1720 	SS7MsgISUP::EndOfParameters
1721 	}
1722     },
1723     { SS7MsgISUP::LPA, false,
1724 	{
1725 	SS7MsgISUP::EndOfParameters,
1726 	SS7MsgISUP::EndOfParameters
1727 	}
1728     },
1729     { SS7MsgISUP::OLM, false,
1730 	{
1731 	SS7MsgISUP::EndOfParameters,
1732 	SS7MsgISUP::EndOfParameters
1733 	}
1734     },
1735     { SS7MsgISUP::RSC, false,
1736 	{
1737 	SS7MsgISUP::EndOfParameters,
1738 	SS7MsgISUP::EndOfParameters
1739 	}
1740     },
1741     { SS7MsgISUP::UEC, false,
1742 	{
1743 	SS7MsgISUP::EndOfParameters,
1744 	SS7MsgISUP::EndOfParameters
1745 	}
1746     },
1747     { SS7MsgISUP::COT, false,
1748 	{
1749 	    SS7MsgISUP::ContinuityIndicators,
1750 	SS7MsgISUP::EndOfParameters,
1751 	SS7MsgISUP::EndOfParameters
1752 	}
1753     },
1754     // user part test and response
1755     { SS7MsgISUP::UPT, true,
1756 	{
1757 	SS7MsgISUP::EndOfParameters,
1758 	SS7MsgISUP::EndOfParameters
1759 	}
1760     },
1761     { SS7MsgISUP::UPA, true,
1762 	{
1763 	SS7MsgISUP::EndOfParameters,
1764 	SS7MsgISUP::EndOfParameters
1765 	}
1766     },
1767     // application transport
1768     { SS7MsgISUP::APM, true,
1769 	{
1770 	SS7MsgISUP::EndOfParameters,
1771 	SS7MsgISUP::EndOfParameters
1772 	}
1773     },
1774     // facility
1775     { SS7MsgISUP::FACR, true,
1776 	{
1777 	    SS7MsgISUP::FacilityIndicator,
1778 	SS7MsgISUP::EndOfParameters,
1779 	SS7MsgISUP::EndOfParameters
1780 	}
1781     },
1782     { SS7MsgISUP::FAA, true,
1783 	{
1784 	    SS7MsgISUP::FacilityIndicator,
1785 	SS7MsgISUP::EndOfParameters,
1786 	SS7MsgISUP::EndOfParameters
1787 	}
1788     },
1789     { SS7MsgISUP::FRJ, true,
1790 	{
1791 	    SS7MsgISUP::FacilityIndicator,
1792 	SS7MsgISUP::EndOfParameters,
1793 	    SS7MsgISUP::CauseIndicators,
1794 	SS7MsgISUP::EndOfParameters
1795 	}
1796     },
1797     // miscellaneous
1798     { SS7MsgISUP::USR, true,
1799 	{
1800 	SS7MsgISUP::EndOfParameters,
1801 	    SS7MsgISUP::UserToUserInformation,
1802 	SS7MsgISUP::EndOfParameters
1803 	}
1804     },
1805     { SS7MsgISUP::Unknown, false, { SS7MsgISUP::EndOfParameters } }
1806 };
1807 
1808 // Descriptor of ITU-T version of ISUP messages
1809 static const MsgParams s_itu_params[] = {
1810     { SS7MsgISUP::IAM, true,
1811 	{
1812 	    SS7MsgISUP::NatureOfConnectionIndicators,
1813 	    SS7MsgISUP::ForwardCallIndicators,
1814 	    SS7MsgISUP::CallingPartyCategory,
1815 	    SS7MsgISUP::TransmissionMediumRequirement,
1816 	SS7MsgISUP::EndOfParameters,
1817 	    SS7MsgISUP::CalledPartyNumber,
1818 	SS7MsgISUP::EndOfParameters
1819 	}
1820     },
1821     { SS7MsgISUP::Unknown, false, { SS7MsgISUP::EndOfParameters } }
1822 };
1823 
1824 // Descriptor of ANSI version of ISUP messages
1825 static const MsgParams s_ansi_params[] = {
1826     { SS7MsgISUP::IAM, true,
1827 	{
1828 	    SS7MsgISUP::NatureOfConnectionIndicators,
1829 	    SS7MsgISUP::ForwardCallIndicators,
1830 	    SS7MsgISUP::CallingPartyCategory,
1831 		SS7MsgISUP::EndOfParameters,
1832 	    SS7MsgISUP::UserServiceInformation,
1833 	    SS7MsgISUP::CalledPartyNumber,
1834 		SS7MsgISUP::EndOfParameters
1835 	}
1836     },
1837     { SS7MsgISUP::RLC, false,
1838 	{
1839 	SS7MsgISUP::EndOfParameters,
1840 	SS7MsgISUP::EndOfParameters
1841 	}
1842     },
1843     { SS7MsgISUP::EXM, true,
1844 	{
1845 	SS7MsgISUP::EndOfParameters,
1846 	SS7MsgISUP::EndOfParameters
1847 	}
1848     },
1849     { SS7MsgISUP::CVT, false,
1850 	{
1851 	SS7MsgISUP::EndOfParameters,
1852 	SS7MsgISUP::EndOfParameters
1853 	}
1854     },
1855     { SS7MsgISUP::CVR, true,
1856 	{
1857 	    SS7MsgISUP::CircuitValidationRespIndicator,
1858 	    SS7MsgISUP::CircuitGroupCharactIndicator,
1859 	SS7MsgISUP::EndOfParameters,
1860 	SS7MsgISUP::EndOfParameters
1861 	}
1862     },
1863     { SS7MsgISUP::Unknown, false, { SS7MsgISUP::EndOfParameters } }
1864 };
1865 
1866 // Descriptor for decoding of compatibility parameters of unsupported messages
1867 //  with only optional parameters (all new messages should be like this)
1868 static const MsgParams s_compatibility = {
1869     SS7MsgISUP::Unknown, true,
1870     {
1871     SS7MsgISUP::EndOfParameters,
1872     SS7MsgISUP::EndOfParameters
1873     }
1874 };
1875 
1876 // Generic decode helper function for a single parameter
decodeParam(const SS7ISUP * isup,NamedList & list,const IsupParam * param,const unsigned char * buf,unsigned int len,const String & prefix)1877 static bool decodeParam(const SS7ISUP* isup, NamedList& list, const IsupParam* param,
1878     const unsigned char* buf, unsigned int len, const String& prefix)
1879 {
1880     DDebug(isup,DebugAll,"decodeParam(%p,%p,%p,%u) type=0x%02x, size=%u, name='%s'",
1881 	&list,param,buf,len,param->type,param->size,param->name);
1882     if (param->size && (param->size != len))
1883 	return false;
1884     if (param->decoder)
1885 	return param->decoder(isup,list,param,buf,len,prefix);
1886     return decodeRaw(isup,list,param,buf,len,prefix);
1887 }
1888 
1889 // Generic encode helper function for a single mandatory parameter
encodeParam(const SS7ISUP * isup,SS7MSU & msu,const IsupParam * param,const NamedList * params,ObjList & exclude,const String & prefix,unsigned char * buf=0)1890 static unsigned char encodeParam(const SS7ISUP* isup, SS7MSU& msu,
1891     const IsupParam* param, const NamedList* params, ObjList& exclude,
1892     const String& prefix, unsigned char* buf = 0)
1893 {
1894     DDebug(isup,DebugAll,"encodeParam (mand) (%p,%p,%p,%p) type=0x%02x, size=%u, name='%s'",
1895 	&msu,param,params,buf,param->type,param->size,param->name);
1896     // variable length must not receive fixed buffer
1897     if (buf && !param->size)
1898 	return 0;
1899     NamedString* val = params ? params->getParam(prefix+param->name) : 0;
1900     if (val)
1901 	exclude.append(val)->setDelete(false);
1902     if (param->encoder)
1903 	return param->encoder(isup,msu,buf,param,val,params,prefix);
1904     return encodeRaw(isup,msu,buf,param,val,params,prefix);
1905 }
1906 
1907 // Generic encode helper for a single optional parameter
encodeParam(const SS7ISUP * isup,SS7MSU & msu,const IsupParam * param,const NamedString * val,const NamedList * extra,const String & prefix)1908 static unsigned char encodeParam(const SS7ISUP* isup, SS7MSU& msu,
1909     const IsupParam* param, const NamedString* val,
1910     const NamedList* extra, const String& prefix)
1911 {
1912     DDebug(isup,DebugAll,"encodeParam (opt) (%p,%p,%p,%p) type=0x%02x, size=%u, name='%s'",
1913 	&msu,param,val,extra,param->type,param->size,param->name);
1914     // add the parameter type now but remember the old length
1915     unsigned int len = msu.length();
1916     unsigned char tmp = param->type;
1917     msu.append(&tmp,1);
1918 
1919     unsigned char size = 0;
1920     if (param->encoder)
1921 	size = param->encoder(isup,msu,0,param,val,extra,prefix);
1922     else
1923 	size = encodeRaw(isup,msu,0,param,val,extra,prefix);
1924     if (!size) {
1925 	Debug(isup,DebugMild,"Unwinding type storage for failed parameter %s",param->name);
1926 	msu.truncate(len);
1927     }
1928     return size;
1929 }
1930 
1931 // Locate the description for a parameter by type
getParamDesc(SS7MsgISUP::Parameters type)1932 static const IsupParam* getParamDesc(SS7MsgISUP::Parameters type)
1933 {
1934     const IsupParam* param = s_paramDefs;
1935     for (; param->type != SS7MsgISUP::EndOfParameters; param++) {
1936 	if (param->type == type)
1937 	    return param;
1938     }
1939     return 0;
1940 }
1941 
1942 // Locate the description for a parameter by name
getParamDesc(const String & name)1943 static const IsupParam* getParamDesc(const String& name)
1944 {
1945     const IsupParam* param = s_paramDefs;
1946     for (; param->type != SS7MsgISUP::EndOfParameters; param++) {
1947 	if (name == param->name)
1948 	    return param;
1949     }
1950     return 0;
1951 }
1952 
1953 // Locate the description table for a message according to protocol type
getIsupParams(SS7PointCode::Type type,SS7MsgISUP::Type msg)1954 static const MsgParams* getIsupParams(SS7PointCode::Type type, SS7MsgISUP::Type msg)
1955 {
1956     const MsgParams* params = 0;
1957     switch (type) {
1958 	case SS7PointCode::ITU:
1959 	case SS7PointCode::China:
1960 	case SS7PointCode::Japan:
1961 	case SS7PointCode::Japan5:
1962 	    params = s_itu_params;
1963 	    break;
1964 	case SS7PointCode::ANSI:
1965 	case SS7PointCode::ANSI8:
1966 	    params = s_ansi_params;
1967 	    break;
1968 	default:
1969 	    return 0;
1970     }
1971     // search first in specific table
1972     for (; params->type != SS7MsgISUP::Unknown; params++) {
1973 	if (params->type == msg)
1974 	    return params;
1975     }
1976     // then search in common table
1977     for (params = s_common_params; params->type != SS7MsgISUP::Unknown; params++) {
1978 	if (params->type == msg)
1979 	    return params;
1980     }
1981     return 0;
1982 }
1983 
1984 // Hexify a list of isup parameter values/names
hexifyIsupParams(String & s,const String & list)1985 static void hexifyIsupParams(String& s, const String& list)
1986 {
1987     if (!list)
1988 	return;
1989     ObjList* l = list.split(',',false);
1990     unsigned int len = l->count();
1991     if (len) {
1992 	unsigned char* buf = new unsigned char[len];
1993 	len = 0;
1994 	for (ObjList* o = l->skipNull(); o; o = o->skipNext()) {
1995 	    String* str = static_cast<String*>(o->get());
1996 	    int val = str->toInteger(-1);
1997 	    if (val < 0) {
1998 		const IsupParam* p = getParamDesc(*str);
1999 		if (p)
2000 		    val = p->type;
2001 	    }
2002 	    if (val >= 0 && val < 256) {
2003 		// avoid duplicates
2004 		for (unsigned int i = 0; i < len; i++) {
2005 		    if ((unsigned char)val == buf[i]) {
2006 			val = -1;
2007 			break;
2008 		    }
2009 		}
2010 		if (val >= 0)
2011 		    buf[len++] = (unsigned char)val;
2012 	    }
2013 	}
2014 	if (len)
2015 	    s.hexify(buf,len,' ');
2016 	delete[] buf;
2017     }
2018     TelEngine::destruct(l);
2019 }
2020 
2021 // Check if an unhandled messages has only optional parameters
2022 #define MAKE_CASE(x) case SS7MsgISUP::x:
hasOptionalOnly(SS7MsgISUP::Type msg)2023 static bool hasOptionalOnly(SS7MsgISUP::Type msg)
2024 {
2025     switch (msg) {
2026 	MAKE_CASE(IAM)
2027 	MAKE_CASE(SAM)
2028 	MAKE_CASE(INR)
2029 	MAKE_CASE(INF)
2030 	MAKE_CASE(COT)
2031 	MAKE_CASE(ACM)
2032 	MAKE_CASE(CON)
2033 	MAKE_CASE(REL)
2034 	MAKE_CASE(SUS)
2035 	MAKE_CASE(RES)
2036 	MAKE_CASE(CCR)
2037 	MAKE_CASE(RSC)
2038 	MAKE_CASE(BLK)
2039 	MAKE_CASE(UBL)
2040 	MAKE_CASE(BLA)
2041 	MAKE_CASE(UBA)
2042 	MAKE_CASE(GRS)
2043 	MAKE_CASE(CGB)
2044 	MAKE_CASE(CGU)
2045 	MAKE_CASE(CGA)
2046 	MAKE_CASE(CUA)
2047 	MAKE_CASE(FACR)
2048 	MAKE_CASE(FAA)
2049 	MAKE_CASE(FRJ)
2050 	MAKE_CASE(LPA)
2051 	MAKE_CASE(PAM)
2052 	MAKE_CASE(GRA)
2053 	MAKE_CASE(CQM)
2054 	MAKE_CASE(CQR)
2055 	MAKE_CASE(CPR)
2056 	MAKE_CASE(USR)
2057 	MAKE_CASE(UEC)
2058 	MAKE_CASE(CNF)
2059 	MAKE_CASE(OLM)
2060 	    return false;
2061 	default:
2062 	    return true;
2063     }
2064 }
2065 #undef MAKE_CASE
2066 
2067 #define MAKE_NAME(x) { #x, SS7MsgISUP::x }
2068 static const TokenDict s_names[] = {
2069     // this list must be kept in synch with the header
2070     MAKE_NAME(IAM),
2071     MAKE_NAME(SAM),
2072     MAKE_NAME(INR),
2073     MAKE_NAME(INF),
2074     MAKE_NAME(COT),
2075     MAKE_NAME(ACM),
2076     MAKE_NAME(CON),
2077     MAKE_NAME(FOT),
2078     MAKE_NAME(ANM),
2079     MAKE_NAME(REL),
2080     MAKE_NAME(SUS),
2081     MAKE_NAME(RES),
2082     MAKE_NAME(RLC),
2083     MAKE_NAME(CCR),
2084     MAKE_NAME(RSC),
2085     MAKE_NAME(BLK),
2086     MAKE_NAME(UBL),
2087     MAKE_NAME(BLA),
2088     MAKE_NAME(UBA),
2089     MAKE_NAME(GRS),
2090     MAKE_NAME(CGB),
2091     MAKE_NAME(CGU),
2092     MAKE_NAME(CGA),
2093     MAKE_NAME(CGBA), // alias
2094     MAKE_NAME(CUA),
2095     MAKE_NAME(CMR),
2096     MAKE_NAME(CMC),
2097     MAKE_NAME(CMRJ),
2098     MAKE_NAME(FACR),
2099     MAKE_NAME(FAA),
2100     MAKE_NAME(FRJ),
2101     MAKE_NAME(FAD),
2102     MAKE_NAME(FAI),
2103     MAKE_NAME(LPA),
2104     MAKE_NAME(CSVR),
2105     MAKE_NAME(CSVS),
2106     MAKE_NAME(DRS),
2107     MAKE_NAME(PAM),
2108     MAKE_NAME(GRA),
2109     MAKE_NAME(CQM),
2110     MAKE_NAME(CQR),
2111     MAKE_NAME(CPR),
2112     MAKE_NAME(CPG),  // alias
2113     MAKE_NAME(USR),
2114     MAKE_NAME(UEC),
2115     MAKE_NAME(UCIC), // alias
2116     MAKE_NAME(CNF),
2117     MAKE_NAME(OLM),
2118     MAKE_NAME(CRG),
2119     MAKE_NAME(NRM),
2120     MAKE_NAME(FAC),
2121     MAKE_NAME(UPT),
2122     MAKE_NAME(UPA),
2123     MAKE_NAME(IDR),
2124     MAKE_NAME(IRS),
2125     MAKE_NAME(SGM),
2126     MAKE_NAME(LOP),
2127     MAKE_NAME(APM),
2128     MAKE_NAME(PRI),
2129     MAKE_NAME(SDN),
2130     MAKE_NAME(CRA),
2131     MAKE_NAME(CRM),
2132     MAKE_NAME(CVR),
2133     MAKE_NAME(CVT),
2134     MAKE_NAME(EXM),
2135     { 0, 0 }
2136 };
2137 #undef MAKE_NAME
2138 
names()2139 const TokenDict* SS7MsgISUP::names()
2140 {
2141     return s_names;
2142 }
2143 
toString(String & dest,const SS7Label & label,bool params,const void * raw,unsigned int rawLen) const2144 void SS7MsgISUP::toString(String& dest, const SS7Label& label, bool params,
2145 	const void* raw, unsigned int rawLen) const
2146 {
2147     const char* enclose = "\r\n-----";
2148     dest = enclose;
2149     dest << "\r\n" << name() << " [cic=" << m_cic << " label=" << label << ']';
2150     if (raw && rawLen) {
2151 	String tmp;
2152 	tmp.hexify((void*)raw,rawLen,' ');
2153 	dest << "  " << tmp;
2154     }
2155     if (params) {
2156 	unsigned int n = m_params.length();
2157 	for (unsigned int i = 0; i < n; i++) {
2158 	    NamedString* s = m_params.getParam(i);
2159 	    if (s)
2160 		dest << "\r\n  " << s->name() << "='" << *s << "'";
2161 	}
2162     }
2163     dest << enclose;
2164 }
2165 
2166 
2167 /**
2168  * Helper functions used to transmit responses
2169  */
2170 
2171 // Push down the protocol stack a RLC (Release Complete) message
2172 // @param msg Optional received message to copy release parameters. Ignored if reason is valid
transmitRLC(SS7ISUP * isup,unsigned int cic,const SS7Label & label,bool recvLbl,const char * reason=0,const char * diagnostic=0,const char * location=0)2173 static int transmitRLC(SS7ISUP* isup, unsigned int cic, const SS7Label& label, bool recvLbl,
2174     const char* reason = 0, const char* diagnostic = 0, const char* location = 0)
2175 {
2176     SS7MsgISUP* m = new SS7MsgISUP(SS7MsgISUP::RLC,cic);
2177     if (!TelEngine::null(reason)) {
2178 	m->params().addParam("CauseIndicators",reason);
2179 	m->params().addParam("CauseIndicators.location",location,false);
2180 	m->params().addParam("CauseIndicators.diagnostic",diagnostic,false);
2181     }
2182     return isup->transmitMessage(m,label,recvLbl);
2183 }
2184 
2185 // Push down the protocol stack a CNF (Confusion) message
transmitCNF(SS7ISUP * isup,unsigned int cic,const SS7Label & label,bool recvLbl,const char * reason,const char * diagnostic=0,const char * location=0)2186 static int transmitCNF(SS7ISUP* isup, unsigned int cic, const SS7Label& label, bool recvLbl,
2187     const char* reason, const char* diagnostic = 0, const char* location = 0)
2188 {
2189     SS7MsgISUP* m = new SS7MsgISUP(SS7MsgISUP::CNF,cic);
2190     if (reason)
2191 	m->params().addParam("CauseIndicators",reason);
2192     if (!location)
2193 	location = isup->location();
2194     m->params().addParam("CauseIndicators.location",location,false);
2195     m->params().addParam("CauseIndicators.diagnostic",diagnostic,false);
2196     return isup->transmitMessage(m,label,recvLbl);
2197 }
2198 
2199 
2200 // Utility used to check for called number completion
isCalledIncomplete(const NamedList & l,const String & p="CalledPartyNumber")2201 static inline bool isCalledIncomplete(const NamedList& l, const String& p = "CalledPartyNumber")
2202 {
2203     return !l[p].endsWith(".");
2204 }
2205 
2206 // Fill call release or cnf flags from message compatibility info
getMsgCompat(SS7MsgISUP * msg,bool & release,bool & cnf)2207 static void getMsgCompat(SS7MsgISUP* msg, bool& release, bool& cnf)
2208 {
2209     if (!msg)
2210 	return;
2211     String* msgCompat = msg->params().getParam(YSTRING("MessageCompatInformation"));
2212     if (msgCompat) {
2213 	ObjList* l = msgCompat->split(',',false);
2214 	// Use a while() to make sure the list is destroyed
2215 	do {
2216 	    release = (0 != l->find("release"));
2217 	    if (release)
2218 		break;
2219 	    // Discard the message (no pass on). Check if CNF should be sent
2220 	    if (l->find("discard")) {
2221 		cnf = (0 != l->find("cnf"));
2222 		break;
2223 	    }
2224 	    // Pass on set: we didn't passed on the message. Check REL/CNF
2225 	    release = (0 != l->find("nopass-release"));
2226 	    cnf = !release && l->find("cnf");
2227 	} while(false);
2228 	TelEngine::destruct(l);
2229     }
2230     else
2231 	cnf = true;
2232 }
2233 
setCallsTerminate(ObjList & lst,bool gracefully,const char * reason=0,const char * diagnostic=0,const char * location=0)2234 static void setCallsTerminate(ObjList& lst, bool gracefully, const char* reason = 0,
2235     const char* diagnostic = 0, const char* location = 0)
2236 {
2237     for (ObjList* o = lst.skipNull(); o; o = o->skipNext()) {
2238 	SS7ISUPCall* call = static_cast<SS7ISUPCall*>(o->get());
2239 	call->setTerminate(gracefully,reason,diagnostic,location);
2240     }
2241 }
2242 
2243 
2244 /**
2245  * SS7ISUPCall
2246  */
SS7ISUPCall(SS7ISUP * controller,SignallingCircuit * cic,const SS7PointCode & local,const SS7PointCode & remote,bool outgoing,int sls,const char * range,bool testCall)2247 SS7ISUPCall::SS7ISUPCall(SS7ISUP* controller, SignallingCircuit* cic,
2248 	const SS7PointCode& local, const SS7PointCode& remote, bool outgoing,
2249 	int sls, const char* range, bool testCall)
2250     : SignallingCall(controller,outgoing),
2251     m_state(Null),
2252     m_testCall(testCall),
2253     m_circuit(cic),
2254     m_cicRange(range),
2255     m_terminate(false),
2256     m_gracefully(true),
2257     m_circuitChanged(false),
2258     m_circuitTesting(false),
2259     m_inbandAvailable(false),
2260     m_replaceCounter(3),
2261     m_iamMsg(0),
2262     m_sgmMsg(0),
2263     m_relMsg(0),
2264     m_sentSamDigits(0),
2265     m_relTimer(300000),                  // Q.764: T5  - 5..15 minutes
2266     m_iamTimer(ISUP_T7_DEFVAL),          // Setup, Testing: Q.764: T7  - 20..30 seconds
2267                                          // Releasing: Q.764: T1: 15..60 seconds
2268     m_sgmRecvTimer(ISUP_T34_DEFVAL),     // Q.764: T34 - 2..4 seconds
2269     m_contTimer(ISUP_T27_DEFVAL),        // Q.764: T27 - 4 minutes
2270     m_anmTimer(0)                        // Q.764 T9 Q.118: 1.5 - 3 minutes, not always used
2271 {
2272     if (!(controller && m_circuit)) {
2273 	Debug(isup(),DebugWarn,
2274 	    "SS7ISUPCall(%u). No call controller or circuit. Terminate [%p]",
2275 	    id(),this);
2276 	setTerminate(true,m_circuit ? "temporary-failure" : "congestion");
2277 	return;
2278     }
2279     isup()->setLabel(m_label,local,remote,sls);
2280     if (isup()->m_t7Interval)
2281 	m_iamTimer.interval(isup()->m_t7Interval);
2282     if (isup()->m_t9Interval)
2283 	m_anmTimer.interval(isup()->m_t9Interval);
2284     if (isup()->m_t27Interval)
2285 	m_contTimer.interval(isup()->m_t27Interval);
2286     if (isup()->m_t34Interval)
2287 	m_sgmRecvTimer.interval(isup()->m_t34Interval);
2288     m_replaceCounter = isup()->m_replaceCounter;
2289     if (isup()->debugAt(DebugAll)) {
2290 	String tmp;
2291 	tmp << m_label;
2292 	Debug(isup(),DebugAll,"Call(%u) direction=%s routing-label=%s range=%s [%p]",
2293 	    id(),(outgoing ? "outgoing" : "incoming"),tmp.c_str(),m_cicRange.safe(),this);
2294     }
2295 }
2296 
~SS7ISUPCall()2297 SS7ISUPCall::~SS7ISUPCall()
2298 {
2299     TelEngine::destruct(m_iamMsg);
2300     TelEngine::destruct(m_sgmMsg);
2301     const char* timeout = 0;
2302     if (m_relTimer.started())
2303 	timeout = " (release timed out)";
2304     else if (m_contTimer.started())
2305 	timeout = " (T27 timed out)";
2306     releaseComplete(true,0,0,0 != timeout);
2307     Debug(isup(),!timeout ? DebugAll : DebugNote,
2308 	"Call(%u) destroyed with reason='%s'%s [%p]",
2309 	id(),m_reason.safe(),TelEngine::c_safe(timeout),this);
2310     TelEngine::destruct(m_relMsg);
2311     if (controller()) {
2312 	if (!timeout)
2313 	    controller()->releaseCircuit(m_circuit);
2314 	else
2315 	    isup()->startCircuitReset(m_circuit,m_relTimer.started() ? "T5" : "T16");
2316     }
2317     else
2318 	TelEngine::destruct(m_circuit);
2319 }
2320 
2321 // Stop waiting for a SGM (Segmentation) message when another message is
2322 //  received by the controller
stopWaitSegment(bool discard)2323 void SS7ISUPCall::stopWaitSegment(bool discard)
2324 {
2325     Lock mylock(this);
2326     if (!m_sgmMsg)
2327 	return;
2328     m_sgmRecvTimer.stop();
2329     if (discard)
2330 	TelEngine::destruct(m_sgmMsg);
2331 }
2332 
2333 // Helper functions called in getEvent
timeout(SS7ISUP * isup,SS7ISUPCall * call,SignallingTimer & timer,const Time & when,const char * req,bool stop=true)2334 inline static bool timeout(SS7ISUP* isup, SS7ISUPCall* call, SignallingTimer& timer,
2335 	const Time& when, const char* req, bool stop = true)
2336 {
2337     if (!timer.timeout(when.msec()))
2338 	return false;
2339     if (stop)
2340 	timer.stop();
2341     Debug(isup,DebugNote,"Call(%u). %s timed out [%p]",call->id(),req,call);
2342     return true;
2343 }
2344 
2345 // Get an event from this call
getEvent(const Time & when)2346 SignallingEvent* SS7ISUPCall::getEvent(const Time& when)
2347 {
2348     Lock mylock(this,SignallingEngine::maxLockWait());
2349     if (m_lastEvent || m_state == Released || !mylock.locked())
2350 	return 0;
2351     SS7MsgISUP* msg = 0;
2352     while (true) {
2353 	if (m_terminate) {
2354 	    if (m_state < Releasing && m_state > Null)
2355 		if (m_gracefully)
2356 		    m_lastEvent = release();
2357 		else
2358 		    m_lastEvent = releaseComplete(false,0);
2359 	    else if (m_state == Null || m_state == Released) {
2360 		m_gracefully = false;
2361 		m_lastEvent = releaseComplete(false,0);
2362 	    }
2363 	    m_terminate = false;
2364 	    break;
2365 	}
2366 	// Check if waiting for SGM
2367 	// Stop if: timeout, the controller stopped the timer or received a message other then SGM
2368 	if (m_sgmMsg) {
2369 	    msg = static_cast<SS7MsgISUP*>(dequeue(false));
2370 	    if (!msg && !m_sgmRecvTimer.timeout(when.msec()) && m_sgmRecvTimer.started())
2371 		return 0;
2372 	    msg = ((msg && msg->type() == SS7MsgISUP::SGM) ? static_cast<SS7MsgISUP*>(dequeue()) : 0);
2373 	    processSegmented(msg,m_sgmRecvTimer.timeout(when.msec()));
2374 	    break;
2375 	}
2376 	// Process received messages
2377 	msg = static_cast<SS7MsgISUP*>(dequeue());
2378 	if (msg && validMsgState(false,msg->type(),(msg->params().getParam(YSTRING("BackwardCallIndicators")) != 0)))
2379 	    switch (msg->type()) {
2380 		case SS7MsgISUP::IAM:
2381 		case SS7MsgISUP::CCR:
2382 		case SS7MsgISUP::COT:
2383 		case SS7MsgISUP::ACM:
2384 		case SS7MsgISUP::EXM:
2385 		case SS7MsgISUP::CPR:
2386 		case SS7MsgISUP::ANM:
2387 		case SS7MsgISUP::CON:
2388 		case SS7MsgISUP::CRG:
2389 		    m_sgmMsg = msg;
2390 		    {
2391 			const char* sgmParam = "OptionalBackwardCallIndicators";
2392 			if (msg->type() == SS7MsgISUP::IAM) {
2393 			    copyParamIAM(msg);
2394 			    setOverlapped(isCalledIncomplete(msg->params()));
2395 			    sgmParam = "OptionalForwardCallIndicators";
2396 			}
2397 			// Check segmentation. Keep the message and start timer if segmented
2398 			if (SignallingUtils::hasFlag(msg->params(),sgmParam,"segmentation")) {
2399 			    m_sgmRecvTimer.start(when.msec());
2400 			    return 0;
2401 			}
2402 		    }
2403 		    msg = 0;
2404 		    processSegmented(0,false);
2405 		    break;
2406 		case SS7MsgISUP::SAM:
2407 		    setOverlapped(isCalledIncomplete(msg->params(),"SubsequentNumber"));
2408 		    msg->params().addParam("tone",msg->params().getValue(YSTRING("SubsequentNumber")));
2409 		    msg->params().addParam("dialing",String::boolText(true));
2410 		    m_lastEvent = new SignallingEvent(SignallingEvent::Info,msg,this);
2411 		    break;
2412 		case SS7MsgISUP::RLC:
2413 		    m_gracefully = false;
2414 		    if (m_state < Releasing) {
2415 			setReason(0,msg);
2416 			m_location = isup()->location();
2417 			m_lastEvent = release(0,msg);
2418 		    }
2419 		    else {
2420 		        m_relTimer.stop();
2421 			m_lastEvent = releaseComplete(false,msg);
2422 		    }
2423 		    break;
2424 		case SS7MsgISUP::REL:
2425 		    if (m_state < Releasing) {
2426 		        m_relTimer.stop();
2427 			m_lastEvent = releaseComplete(false,msg);
2428 		    }
2429 		    else
2430 			transmitRLC(isup(),msg->cic(),m_label,false);
2431 		    break;
2432 		case SS7MsgISUP::SGM:
2433 		    DDebug(isup(),DebugInfo,"Call(%u). Received late 'SGM' [%p]",id(),this);
2434 		    break;
2435 		case SS7MsgISUP::SUS:
2436 		    m_lastEvent = new SignallingEvent(SignallingEvent::Suspend,msg,this);
2437 		    break;
2438 		case SS7MsgISUP::RES:
2439 		    m_lastEvent = new SignallingEvent(SignallingEvent::Resume,msg,this);
2440 		    break;
2441 		case SS7MsgISUP::APM:
2442 		    m_lastEvent = new SignallingEvent(SignallingEvent::Generic,msg,this);
2443 		    break;
2444 		default: ;
2445 		    Debug(isup(),DebugStub,"Call(%u). Unhandled '%s' message in getEvent() [%p]",
2446 			id(),msg->name(),this);
2447 	    }
2448 	break;
2449     }
2450     if (msg)
2451 	msg->deref();
2452     // No events: check timeouts
2453     if (!m_lastEvent) {
2454 	switch (m_state) {
2455 	    case Testing:
2456 	    case Setup:
2457 		if (timeout(isup(),this,m_iamTimer,when,"IAM")) {
2458 		    m_contTimer.stop();
2459 		    if (m_circuitTesting) {
2460 			if (m_iamMsg)
2461 			    setReason("bearer-cap-not-available",0);
2462 			else {
2463 			    setTerminate(true,"bearer-cap-not-available");
2464 			    break;
2465 			}
2466 		    }
2467 		    else
2468 			setReason("timeout",0);
2469 		    m_lastEvent = release();
2470 		    break;
2471 		}
2472 		if (timeout(isup(),this,m_contTimer,when,"T27",false)) {
2473 		    m_gracefully = false;
2474 		    m_lastEvent = releaseComplete(false,0,0,true);
2475 		}
2476 		break;
2477 	    case Releasing:
2478 		if (timeout(isup(),this,m_relTimer,when,"REL",false))
2479 		    m_lastEvent = releaseComplete(false,0,"noresponse",true);
2480 		else if (timeout(isup(),this,m_iamTimer,when,"T1")) {
2481 		    m_iamTimer.stop();
2482 		    m_iamTimer.start(when.msec());
2483 		    transmitREL();
2484 		}
2485 		break;
2486 	    default:
2487 		if (outgoing() && m_anmTimer.started() && m_state >= Accepted &&
2488 		    m_state < Answered && timeout(isup(),this,m_anmTimer,when,"T9")) {
2489 		    setReason("noresponse",0,0,isup()->location());
2490 		    m_lastEvent = release();
2491 		}
2492 	}
2493     }
2494     // Reset overlapped if our state is greater then Setup
2495     if (m_state > Setup)
2496 	setOverlapped(false,false);
2497     // Check circuit event
2498     if (!m_lastEvent && m_circuit) {
2499 	SignallingCircuitEvent* cicEvent = m_circuit->getEvent(when);
2500 	if (cicEvent) {
2501 	    if (isup())
2502 		m_lastEvent = isup()->processCircuitEvent(cicEvent,this);
2503 	    TelEngine::destruct(cicEvent);
2504 	}
2505     }
2506     if (m_lastEvent)
2507 	XDebug(isup(),DebugNote,"Call(%u). Raising event (%p,'%s') [%p]",
2508 	    id(),m_lastEvent,m_lastEvent->name(),this);
2509 
2510     return m_lastEvent;
2511 }
2512 
2513 // Helper that copies all parameters starting with a capital letter
copyUpper(NamedList & dest,const NamedList & src)2514 static void copyUpper(NamedList& dest, const NamedList& src)
2515 {
2516     static const Regexp r("^[A-Z][A-Za-z0-9_.]\\+$");
2517     unsigned int n = src.length();
2518     for (unsigned int i = 0; i < n; i++) {
2519 	const NamedString* p = src.getParam(i);
2520 	if (!p || !r.matches(p->name()))
2521 	    continue;
2522 	dest.setParam(p->name(),*p);
2523     }
2524 }
2525 
2526 // Send an event to this call
sendEvent(SignallingEvent * event)2527 bool SS7ISUPCall::sendEvent(SignallingEvent* event)
2528 {
2529     Lock mylock(this);
2530     if (!event)
2531 	return false;
2532     if (m_terminate || m_state == Released) {
2533 	mylock.drop();
2534 	delete event;
2535 	return false;
2536     }
2537     bool result = false;
2538     switch (event->type()) {
2539 	case SignallingEvent::NewCall:
2540 	    if (validMsgState(true,SS7MsgISUP::IAM)) {
2541 		if (!event->message()) {
2542 		    DDebug(isup(),DebugNote,
2543 			"Call(%u). No parameters for outgoing call [%p]",id(),this);
2544 		    setTerminate(true,"temporary-failure");
2545 		    break;
2546 		}
2547 		m_iamMsg = new SS7MsgISUP(SS7MsgISUP::IAM,id());
2548 		copyParamIAM(m_iamMsg,true,event->message());
2549 		// Update overlap
2550 		String* called = m_iamMsg->params().getParam(YSTRING("CalledPartyNumber"));
2551 		if (called && (called->length() > isup()->m_maxCalledDigits)) {
2552 		    // Longer than maximum digits allowed - send remainder with SAM
2553 		    m_samDigits = called->substr(isup()->m_maxCalledDigits);
2554 		    *called = called->substr(0,isup()->m_maxCalledDigits);
2555 		    setOverlapped(true);
2556 		}
2557 		else
2558 		    setOverlapped(isCalledIncomplete(m_iamMsg->params()));
2559 		result = transmitIAM();
2560 	    }
2561 	    break;
2562 	case SignallingEvent::Progress:
2563 	case SignallingEvent::Ringing:
2564 	    if (validMsgState(true,SS7MsgISUP::CPR)) {
2565 		SS7MsgISUP* m = new SS7MsgISUP(SS7MsgISUP::CPR,id());
2566 		m->params().addParam("EventInformation",
2567 		    event->type() == SignallingEvent::Ringing ? "ringing": "progress");
2568 		bool inband = m_inbandAvailable;
2569 		if (event->message()) {
2570 		    copyUpper(m->params(),event->message()->params());
2571 		    m_inbandAvailable = m_inbandAvailable ||
2572 			event->message()->params().getBoolValue(YSTRING("earlymedia"));
2573 		    inband = event->message()->params().getBoolValue(YSTRING("send-inband"),m_inbandAvailable);
2574 		}
2575 		if (inband && !outgoing())
2576 		    SignallingUtils::appendFlag(m->params(),"OptionalBackwardCallIndicators","inband");
2577 		m_state = Ringing;
2578 		mylock.drop();
2579 		result = transmitMessage(m);
2580 	    }
2581 	    break;
2582 	case SignallingEvent::Accept:
2583 	    if (validMsgState(true,SS7MsgISUP::ACM)) {
2584 		SS7MsgISUP* m = new SS7MsgISUP(SS7MsgISUP::ACM,id());
2585 		bool inband = m_inbandAvailable;
2586 		if (event->message()) {
2587 		    copyUpper(m->params(),event->message()->params());
2588 		    m_inbandAvailable = m_inbandAvailable ||
2589 			event->message()->params().getBoolValue(YSTRING("earlymedia"));
2590 		    inband = event->message()->params().getBoolValue(YSTRING("send-inband"),m_inbandAvailable);
2591 		}
2592 		if (inband && !outgoing())
2593 		    SignallingUtils::appendFlag(m->params(),"OptionalBackwardCallIndicators","inband");
2594 		m_state = Accepted;
2595 		mylock.drop();
2596 		result = transmitMessage(m);
2597 	    }
2598 	    break;
2599 	case SignallingEvent::Answer:
2600 	    if (validMsgState(true,SS7MsgISUP::ANM)) {
2601 		SS7MsgISUP* m = new SS7MsgISUP(SS7MsgISUP::ANM,id());
2602 		if (event->message())
2603 		    copyUpper(m->params(),event->message()->params());
2604 		m_state = Answered;
2605 		mylock.drop();
2606 		result = transmitMessage(m);
2607 	    }
2608 	    break;
2609 	case SignallingEvent::Release:
2610 	    if (validMsgState(true,SS7MsgISUP::REL)) {
2611 		release(event);
2612 		result = true;
2613 	    }
2614 	    break;
2615 	case SignallingEvent::Generic:
2616 	    if (event->message()) {
2617 		const String& oper = event->message()->params()[YSTRING("operation")];
2618 		if (oper == "charge") {
2619 		    if (!validMsgState(true,SS7MsgISUP::CRG))
2620 			break;
2621 		    SS7MsgISUP* m = new SS7MsgISUP(SS7MsgISUP::CRG,id());
2622 		    copyUpper(m->params(),event->message()->params());
2623 		    mylock.drop();
2624 		    result = transmitMessage(m);
2625 		    break;
2626 		}
2627 		if (oper != "transport")
2628 		    break;
2629 		if (!validMsgState(true,SS7MsgISUP::APM))
2630 		    break;
2631 		SS7MsgISUP* m = new SS7MsgISUP(SS7MsgISUP::APM,id());
2632 		copyUpper(m->params(),event->message()->params());
2633 		mylock.drop();
2634 		result = transmitMessage(m);
2635 	    }
2636 	    break;
2637 	case SignallingEvent::Suspend:
2638 	    if (event->message()) {
2639 		if (!validMsgState(true,SS7MsgISUP::SUS))
2640 		    break;
2641 		SS7MsgISUP* m = new SS7MsgISUP(SS7MsgISUP::SUS,id());
2642 		copyUpper(m->params(),event->message()->params());
2643 		mylock.drop();
2644 		result = transmitMessage(m);
2645 	    }
2646 	    break;
2647 	case SignallingEvent::Resume:
2648 	    if (event->message()) {
2649 		if (!validMsgState(true,SS7MsgISUP::RES))
2650 		    break;
2651 		SS7MsgISUP* m = new SS7MsgISUP(SS7MsgISUP::RES,id());
2652 		copyUpper(m->params(),event->message()->params());
2653 		mylock.drop();
2654 		result = transmitMessage(m);
2655 	    }
2656 	    break;
2657 	case SignallingEvent::Info:
2658 	    if (validMsgState(true,SS7MsgISUP::SAM)) {
2659 		mylock.drop();
2660 		transmitSAM(event->message()->params().getValue(YSTRING("tone")));
2661 		result = true;
2662 		break;
2663 	    }
2664 	//case SignallingEvent::Message:
2665 	//case SignallingEvent::Transfer:
2666 	case SignallingEvent::Charge:
2667 	    if (event->message()) {
2668 		if (!validMsgState(true,SS7MsgISUP::CRG))
2669 		    break;
2670 		SS7MsgISUP* m = new SS7MsgISUP(SS7MsgISUP::CRG,id());
2671 		copyUpper(m->params(),event->message()->params());
2672 		mylock.drop();
2673 		result = transmitMessage(m);
2674 	    }
2675 	    break;
2676 	default:
2677 	    DDebug(isup(),DebugStub,
2678 		"Call(%u). sendEvent not implemented for '%s' [%p]",
2679 		id(),event->name(),this);
2680     }
2681     // Reset overlapped if our state is greater then Setup
2682     if (m_state > Setup)
2683 	setOverlapped(false,false);
2684     XDebug(isup(),DebugAll,"Call(%u). Event (%p,'%s') sent. Result: %s [%p]",
2685 	id(),event,event->name(),String::boolText(result),this);
2686     mylock.drop();
2687     delete event;
2688     return result;
2689 }
2690 
2691 // Get reserved circuit or this object
getObject(const String & name) const2692 void* SS7ISUPCall::getObject(const String& name) const
2693 {
2694     if (name == YSTRING("SignallingCircuit"))
2695 	return m_circuit;
2696     if (name == YSTRING("SS7ISUPCall"))
2697 	return (void*)this;
2698     return SignallingCall::getObject(name);
2699 }
2700 
2701 // Check if the circuit can be replaced
2702 // Returns true unless the counter is already zero
canReplaceCircuit()2703 bool SS7ISUPCall::canReplaceCircuit()
2704 {
2705     if (m_replaceCounter <= 0)
2706 	return false;
2707     m_replaceCounter--;
2708     return true;
2709 }
2710 
2711 // Replace the circuit reserved for this call. Release the already reserved circuit.
2712 // Retransmit the initial IAM request on success.
2713 // On failure set the termination flag and release the new circuit if valid
replaceCircuit(SignallingCircuit * circuit,SS7MsgISUP * msg)2714 bool SS7ISUPCall::replaceCircuit(SignallingCircuit* circuit, SS7MsgISUP* msg)
2715 {
2716     Lock mylock(this);
2717     clearQueue();
2718     if (m_state > Setup || !circuit || !outgoing()) {
2719         Debug(isup(),DebugNote,"Call(%u). Failed to replace circuit [%p]",id(),this);
2720 	m_iamTimer.stop();
2721 	if (controller()) {
2722 	    controller()->releaseCircuit(m_circuit);
2723 	    controller()->releaseCircuit(circuit);
2724 	}
2725 	setTerminate(false,"congestion");
2726 	TelEngine::destruct(msg);
2727 	return false;
2728     }
2729     transmitMessage(msg);
2730     unsigned int oldId = id();
2731     if (controller())
2732 	controller()->releaseCircuit(m_circuit);
2733     m_circuit = circuit;
2734     Debug(isup(),DebugNote,"Call(%u). Circuit replaced by %u [%p]",oldId,id(),this);
2735     m_circuitChanged = true;
2736     return transmitIAM();
2737 }
2738 
2739 // Stop timers. Send a RLC (Release Complete) message if it should terminate gracefully
2740 // Decrease the object's refence count and generate a Release event if not final
2741 // @param final True if called from destructor
2742 // @param msg Received message with parameters if any
2743 // @param reason Optional release reason
releaseComplete(bool final,SS7MsgISUP * msg,const char * reason,bool timeout)2744 SignallingEvent* SS7ISUPCall::releaseComplete(bool final, SS7MsgISUP* msg, const char* reason,
2745     bool timeout)
2746 {
2747     if (timeout)
2748 	m_gracefully = false;
2749     m_iamTimer.stop();
2750     setReason(reason,msg);
2751     stopWaitSegment(true);
2752     if (m_state == Released)
2753 	return 0;
2754     if (isup() && m_gracefully) {
2755 	int sls = transmitRLC(isup(),id(),m_label,false);
2756 	if (sls != -1 && m_label.sls() == 255)
2757 	    m_label.setSls(sls);
2758     }
2759     m_state = Released;
2760     if (final)
2761 	return 0;
2762     // Return event and decrease reference counter
2763     bool create = (msg == 0);
2764     if (create)
2765 	msg = new SS7MsgISUP(SS7MsgISUP::RLC,id());
2766     if (m_circuit)
2767 	m_circuit->disconnect();
2768     msg->params().setParam("reason",m_reason);
2769     SignallingEvent* event = new SignallingEvent(SignallingEvent::Release,msg,this);
2770     // deref() msg if created here. If received, it will be deref()'d in getEvent()
2771     if (create)
2772 	msg->deref();
2773     deref();
2774     DDebug(isup(),DebugInfo,"Call(%u). Released with reason '%s' [%p]",
2775 	id(),m_reason.safe(),this);
2776     return event;
2777 }
2778 
2779 // Helper function to copy parameters
param(NamedList & dest,NamedList & src,const String & destParam,const String & srcParam,const char * defVal)2780 inline void param(NamedList& dest, NamedList& src, const String& destParam,
2781 	const String& srcParam, const char* defVal)
2782 {
2783     const char* val = src.getValue(srcParam,src.getValue(destParam,defVal));
2784     if ((val != defVal) || !dest.getParam(destParam))
2785 	dest.setParam(destParam,val);
2786 }
2787 
2788 // Initialize/set IAM message parameters
2789 // @param msg Valid ISUP message
2790 // @param outgoing Message direction: true for outgoing
2791 // @param sigMsg Valid signalling message with parameters if outgoing
copyParamIAM(SS7MsgISUP * msg,bool outgoing,SignallingMessage * sigMsg)2792 bool SS7ISUPCall::copyParamIAM(SS7MsgISUP* msg, bool outgoing, SignallingMessage* sigMsg)
2793 {
2794     NamedList& dest = msg->params();
2795     if (outgoing) {
2796 	NamedList& src = sigMsg->params();
2797 	copyUpper(dest,src);
2798 	param(dest,src,"CalledPartyNumber","called","");
2799 	param(dest,src,"CalledPartyNumber.inn","inn",String::boolText(isup()->m_inn));
2800 	param(dest,src,"CalledPartyNumber.nature","callednumtype",isup()->m_numType);
2801 	param(dest,src,"CalledPartyNumber.plan","callednumplan",isup()->m_numPlan);
2802 	param(dest,src,"CallingPartyCategory","callercategory",isup()->m_callerCat);
2803 	param(dest,src,"CallingPartyNumber","caller","");
2804 	param(dest,src,"CallingPartyNumber.nature","callernumtype",isup()->m_numType);
2805 	param(dest,src,"CallingPartyNumber.plan","callernumplan",isup()->m_numPlan);
2806 	param(dest,src,"CallingPartyNumber.restrict","callerpres",isup()->m_numPresentation);
2807 	param(dest,src,"CallingPartyNumber.screened","callerscreening",isup()->m_numScreening);
2808 	param(dest,src,"CallingPartyNumber.complete","complete","true");
2809 	m_format = src.getValue(YSTRING("format"),isup()->format());
2810 	dest.setParam("UserServiceInformation",m_format);
2811 	return true;
2812     }
2813     // Incoming call
2814     m_format = dest.getValue(YSTRING("UserServiceInformation"),isup()->format());
2815     dest.setParam("format",m_format);
2816     dest.setParam("caller",dest.getValue(YSTRING("CallingPartyNumber")));
2817     //dest.setParam("callername",dest.getValue(""));
2818     dest.setParam("callernumtype",dest.getValue(YSTRING("CallingPartyNumber.nature")));
2819     dest.setParam("callernumplan",dest.getValue(YSTRING("CallingPartyNumber.plan")));
2820     dest.setParam("callerpres",dest.getValue(YSTRING("CallingPartyNumber.restrict")));
2821     dest.setParam("callerscreening",dest.getValue(YSTRING("CallingPartyNumber.screened")));
2822     dest.setParam("called",dest.getValue(YSTRING("CalledPartyNumber")));
2823     dest.setParam("callednumtype",dest.getValue(YSTRING("CalledPartyNumber.nature")));
2824     dest.setParam("callednumplan",dest.getValue(YSTRING("CalledPartyNumber.plan")));
2825     dest.setParam("inn",dest.getValue(YSTRING("CalledPartyNumber.inn")));
2826     if (m_label.sls() != 0xff)
2827 	dest.setParam("sls",String((unsigned int)m_label.sls()));
2828     return true;
2829 }
2830 
2831 // If already releasing, set termination flag. Otherwise, send REL (Release) message
2832 // @param event Event with the parameters. 0 if release is started on unspecified interworking
release(SignallingEvent * event,SS7MsgISUP * msg)2833 SignallingEvent* SS7ISUPCall::release(SignallingEvent* event, SS7MsgISUP* msg)
2834 {
2835     m_iamTimer.stop();
2836     if (event)
2837 	setReason(0,event->message());
2838     else
2839 	setReason("interworking",0);
2840     stopWaitSegment(true);
2841     XDebug(isup(),DebugAll,"Call(%u). Releasing call with reason '%s' [%p]",
2842 	id(),m_reason.safe(),this);
2843     if (!isup() || m_state >= Releasing) {
2844 	m_terminate = true;
2845 	return 0;
2846     }
2847     m_iamTimer.interval(isup() ? isup()->m_t1Interval : 1);
2848     m_relTimer.interval(isup() ? isup()->m_t5Interval : 1);
2849     m_iamTimer.start();
2850     m_relTimer.start();
2851     m_state = Releasing;
2852     transmitREL((event && event->message()) ? &(event->message()->params()) : 0);
2853     if (event)
2854 	return 0;
2855     bool create = (msg == 0);
2856     if (create)
2857 	msg = new SS7MsgISUP(SS7MsgISUP::REL,id());
2858     msg->params().setParam("reason",m_reason);
2859     SignallingEvent* ev = new SignallingEvent(SignallingEvent::Release,msg,this);
2860     // deref() msg if created here. If received, it will be deref()'d in getEvent()
2861     if (create)
2862         TelEngine::destruct(msg);
2863     return ev;
2864 }
2865 
2866 // Set termination reason from received text or message
setReason(const char * reason,SignallingMessage * msg,const char * diagnostic,const char * location)2867 void SS7ISUPCall::setReason(const char* reason, SignallingMessage* msg,
2868     const char* diagnostic, const char* location)
2869 {
2870     if (!m_reason.null())
2871 	return;
2872     if (reason) {
2873 	m_reason = reason;
2874 	m_diagnostic = diagnostic;
2875 	m_location = location;
2876     }
2877     else if (msg) {
2878 	m_reason = msg->params().getValue(YSTRING("CauseIndicators"),msg->params().getValue(YSTRING("reason")));
2879 	m_diagnostic = msg->params().getValue(YSTRING("CauseIndicators.diagnostic"),diagnostic);
2880 	m_location = msg->params().getValue(YSTRING("CauseIndicators.location"),location);
2881     }
2882 }
2883 
2884 // Accept send/receive messages in current state based on call direction
validMsgState(bool send,SS7MsgISUP::Type type,bool hasBkwCallInd)2885 bool SS7ISUPCall::validMsgState(bool send, SS7MsgISUP::Type type, bool hasBkwCallInd)
2886 {
2887     bool handled = true;
2888     switch (type) {
2889 	case SS7MsgISUP::CCR:    // Continuity check
2890 	    if (m_state == Testing && send == outgoing())
2891 		return true;
2892 	    // fall through
2893 	case SS7MsgISUP::IAM:    // Initial address
2894 	    if (m_state != Null || send != outgoing())
2895 		break;
2896 	    return true;
2897 	case SS7MsgISUP::COT:    // Continuity
2898 	    if (m_state != Testing || send != outgoing())
2899 		break;
2900 	    return true;
2901 	case SS7MsgISUP::ACM:    // Address complete
2902 	case SS7MsgISUP::EXM:    // Exit Message (ANSI)
2903 	    if (m_state != Setup || send == outgoing())
2904 		break;
2905 	    return true;
2906 	case SS7MsgISUP::CPR:    // Call progress
2907 	    if (m_state < (hasBkwCallInd ? Setup : Accepted) || m_state >= Releasing)
2908 		break;
2909 	    return true;
2910 	case SS7MsgISUP::CON:    // Connect
2911 	    // CON can be sent/received on not accepted calls
2912 	    if (m_state == Setup && send != outgoing())
2913 		return true;
2914 	case SS7MsgISUP::ANM:    // Answer
2915 	    if (m_state < (hasBkwCallInd ? Setup : Accepted) || m_state >= Answered || send == outgoing())
2916 		break;
2917 	    return true;
2918 	case SS7MsgISUP::SAM:    // Subsequent address
2919 	    if (m_state != Setup || !m_overlap || send != outgoing())
2920 		break;
2921 	    return true;
2922 	case SS7MsgISUP::REL:    // Release
2923 	    if (send && m_state >= Releasing)
2924 		break;
2925 	    // fall through
2926 	case SS7MsgISUP::RLC:    // Release complete
2927 	case SS7MsgISUP::CRG:    // Charging
2928 	    if (m_state == Null || m_state == Released)
2929 		break;
2930 	    return true;
2931 	case SS7MsgISUP::SUS:    // Suspend
2932 	case SS7MsgISUP::RES:    // Resume
2933 	    if (m_state != Answered)
2934 		break;
2935 	    return true;
2936 	case SS7MsgISUP::SGM:    // Segmentation
2937 	case SS7MsgISUP::APM:    // Application Transport
2938 	    return true;
2939 	default:
2940 	    handled = false;
2941     }
2942     Debug(isup(),handled?DebugNote:DebugStub,
2943 	"Call(%u). Can't %s %smessage '%s' in state %u [%p]",
2944 	id(),send?"send":"accept",handled?"":"unhandled ",
2945 	SS7MsgISUP::lookup(type,""),m_state,this);
2946     return false;
2947 }
2948 
2949 // Connect or test the reserved circuit. Return false if it fails.
2950 // Return true if this call is a signalling only one
connectCircuit(const char * special)2951 bool SS7ISUPCall::connectCircuit(const char* special)
2952 {
2953     bool ok = signalOnly();
2954     if (TelEngine::null(special))
2955 	special = 0;
2956     if (m_circuit && !ok) {
2957 	u_int64_t t = Time::msecNow();
2958 	if (special) {
2959 	    m_circuit->updateFormat(m_format,0);
2960 	    ok = m_circuit->setParam("special_mode",special) &&
2961 		m_circuit->status(SignallingCircuit::Special);
2962 	}
2963 	else
2964 	    ok = m_circuit->connected() || m_circuit->connect(m_format);
2965 	t = Time::msecNow() - t;
2966 	if (t > 100) {
2967 	    int level = DebugInfo;
2968 	    if (t > 300)
2969 		level = DebugMild;
2970 	    else if (t > 200)
2971 		level = DebugNote;
2972 	    Debug(isup(),level,"Call(%u). Spent %u ms connecting circuit [%p]",
2973 		id(),(unsigned int)t,this);
2974 	}
2975 #ifdef DEBUG
2976 	else
2977 	    Debug(isup(),DebugAll,"Call(%u). Spent %u ms connecting circuit [%p]",
2978 		id(),(unsigned int)t,this);
2979 #endif
2980     }
2981     if (!ok)
2982 	Debug(isup(),DebugMild,"Call(%u). Circuit %s failed (format='%s')%s [%p]",
2983 	    id(),(special ? special : "connect"),
2984 	    m_format.safe(),(m_circuit ? "" : ". No circuit"),this);
2985 
2986     if (m_sgmMsg) {
2987 	if (m_circuitChanged) {
2988 	    m_sgmMsg->params().setParam("circuit-change","true");
2989 	    m_circuitChanged = false;
2990 	}
2991 	m_sgmMsg->params().setParam("format",m_format);
2992     }
2993     return ok;
2994 }
2995 
2996 // Transmit the IAM message. Start IAM timer if not started
transmitIAM()2997 bool SS7ISUPCall::transmitIAM()
2998 {
2999     if (!m_iamTimer.started())
3000 	m_iamTimer.start();
3001     if (!m_iamMsg)
3002 	return false;
3003     if (needsTesting(m_iamMsg)) {
3004 	if (m_circuitTesting && !(isup() && isup()->m_continuity)) {
3005 	    Debug(isup(),DebugWarn,"Call(%u). Continuity check requested but not configured [%p]",
3006 		id(),this);
3007 	    return false;
3008 	}
3009 	m_state = Testing;
3010 	if (m_circuitTesting && !connectCircuit("test:" + isup()->m_continuity))
3011 	    return false;
3012 	Debug(isup(),DebugNote,"Call(%u). %s continuity check [%p]",
3013 	    id(),(m_circuitTesting ? "Executing" : "Forwarding"),this);
3014     }
3015     else
3016 	m_state = Setup;
3017     m_iamMsg->m_cic = id();
3018     m_iamMsg->ref();
3019     // Reset SAM digits: this might be a re-send
3020     m_sentSamDigits = 0;
3021     bool ok = transmitMessage(m_iamMsg);
3022     if (ok && m_overlap)
3023 	transmitSAM();
3024     return ok;
3025 }
3026 
3027 // Transmit SAM digits
transmitSAM(const char * extra)3028 bool SS7ISUPCall::transmitSAM(const char* extra)
3029 {
3030     if (!m_overlap)
3031 	return false;
3032     m_samDigits << extra;
3033     while (m_samDigits.length() > m_sentSamDigits) {
3034 	unsigned int send = m_samDigits.length() - m_sentSamDigits;
3035 	if (send > isup()->m_maxCalledDigits)
3036 	    send = isup()->m_maxCalledDigits;
3037 	SS7MsgISUP* m = new SS7MsgISUP(SS7MsgISUP::SAM,id());
3038 	String number = m_samDigits.substr(m_sentSamDigits,send);
3039 	m->params().addParam("SubsequentNumber",number);
3040 	bool complete = !isCalledIncomplete(m->params(),"SubsequentNumber");
3041 	bool ok = transmitMessage(m);
3042 	if (ok) {
3043 	    m_sentSamDigits += send;
3044 	    if (complete) {
3045 		if (m_samDigits.length() > m_sentSamDigits)
3046 		    Debug(isup(),DebugNote,
3047 			"Call(%u). Completed number sending remaining='%s' [%p]",
3048 			id(),m_samDigits.substr(m_sentSamDigits).c_str(),this);
3049 		// Reset overlap sending
3050 		setOverlapped(false);
3051 		break;
3052 	    }
3053 	}
3054 	else {
3055 	    Debug(isup(),DebugNote,"Call(%u). Failed to send SAM with '%s' [%p]",
3056 		id(),number.c_str(),this);
3057 	    complete = false;
3058 	    break;
3059 	}
3060     }
3061     return true;
3062 }
3063 
3064 // (Re)transmit REL. Create and populate the message if needed
3065 // Remember sls
transmitREL(const NamedList * params)3066 bool SS7ISUPCall::transmitREL(const NamedList* params)
3067 {
3068     if (!isup())
3069 	return false;
3070     if (!m_relMsg) {
3071 	m_relMsg = new SS7MsgISUP(SS7MsgISUP::REL,id());
3072 	if (m_reason)
3073 	    m_relMsg->params().addParam("CauseIndicators",m_reason);
3074 	m_relMsg->params().addParam("CauseIndicators.diagnostic",m_diagnostic,false);
3075 	m_relMsg->params().addParam("CauseIndicators.location",m_location,false);
3076 	if (params)
3077 	    copyUpper(m_relMsg->params(),*params);
3078     }
3079     // transmitMessage will dereference message so make sure we preserve it
3080     m_relMsg->ref();
3081     int sls = isup()->transmitMessage(m_relMsg,m_label,false);
3082     if (sls != -1 && m_label.sls() == 255)
3083 	m_label.setSls(sls);
3084     return sls != -1;
3085 }
3086 
needsTesting(const SS7MsgISUP * msg)3087 bool SS7ISUPCall::needsTesting(const SS7MsgISUP* msg)
3088 {
3089     if ((m_state >= Testing) || !msg)
3090 	return false;
3091     const String* naci = msg->params().getParam(YSTRING("NatureOfConnectionIndicators"));
3092     if (!naci)
3093 	return false;
3094     ObjList* list = naci->split(',',false);
3095     m_circuitTesting = (0 != list->find("cont-check-this"));
3096     bool checkIt = m_circuitTesting || (0 != list->find("cont-check-prev"));
3097     TelEngine::destruct(list);
3098     return checkIt;
3099 }
3100 
3101 // Stop waiting for a SGM (Segmentation) message. Copy parameters to
3102 // the pending segmented message if sgm is valid.
3103 // Change call state and set m_lastEvent
processSegmented(SS7MsgISUP * sgm,bool timeout)3104 SignallingEvent* SS7ISUPCall::processSegmented(SS7MsgISUP* sgm, bool timeout)
3105 {
3106     if (sgm)
3107 	if (sgm->type() == SS7MsgISUP::SGM) {
3108 	    // Copy parameters from SGM as defined in Q.763 - Table 49
3109 	    // (Segmentation message) and Q.764 - 2.1.12 (re-assembly)
3110 	    #define COPY_PARAM(param) \
3111 		m_sgmMsg->params().copyParam(sgm->params(),param); \
3112 		m_sgmMsg->params().copyParam(sgm->params(),param,'.');
3113 	    COPY_PARAM(YSTRING("AccessTranport"))
3114 	    COPY_PARAM(YSTRING("UserToUserInformation"))
3115 	    COPY_PARAM(YSTRING("MessageCompatInformation"))
3116 	    COPY_PARAM(YSTRING("GenericDigits"))
3117 	    COPY_PARAM(YSTRING("GenericNotification"))
3118 	    COPY_PARAM(YSTRING("GenericNumber"))
3119 	    #undef COPY_PARAM
3120 	}
3121 	else
3122 	    Debug(isup(),DebugStub,"Call(%u). stopWaitSegment() called with non-SGM message !!! [%p]",
3123 		id(),this);
3124     else if (timeout)
3125 	Debug(isup(),DebugMild,"Call(%u). Segment waiting message '%s' timed out [%p]",
3126 	    id(),m_sgmMsg->name(),this);
3127     m_sgmRecvTimer.stop();
3128     // Raise event, connect the reserved circuit, change call state
3129     m_iamTimer.stop();
3130     switch (m_sgmMsg->type()) {
3131 	case SS7MsgISUP::COT:
3132 	    {
3133 		const String* cont = m_sgmMsg->params().getParam(YSTRING("ContinuityIndicators"));
3134 		bool ok = cont && (*cont == YSTRING("success"));
3135 		if (ok) {
3136 		    Debug(isup(),DebugNote,"Call(%u). Continuity check succeeded [%p]",
3137 			id(),this);
3138 		    m_circuitTesting = false;
3139 		}
3140 		else {
3141 		    Debug(isup(),DebugWarn,"Call(%u). Continuity check failed [%p]",
3142 			id(),this);
3143 		    m_contTimer.start();
3144 		    break;
3145 		}
3146 		if (!(ok && m_iamMsg)) {
3147 		    m_lastEvent = new SignallingEvent(SignallingEvent::Info,m_sgmMsg,this);
3148 		    break;
3149 		}
3150 	    }
3151 	    TelEngine::destruct(m_sgmMsg);
3152 	    m_sgmMsg = m_iamMsg;
3153 	    m_iamMsg = 0;
3154 	    // intentionally fall through
3155 	case SS7MsgISUP::IAM:
3156 	    if (needsTesting(m_sgmMsg)) {
3157 		m_state = Testing;
3158 		if (m_circuitTesting && !(isup() && isup()->m_continuity)) {
3159 		    Debug(isup(),DebugWarn,"Call(%u). Continuity check requested but not configured [%p]",
3160 			id(),this);
3161 		    setTerminate(true,"service-not-implemented",0,isup()->location());
3162 		    break;
3163 		}
3164 		if (m_circuitTesting && !connectCircuit(isup()->m_continuity)) {
3165 		    setTerminate(true,"bearer-cap-not-available",0,isup()->location());
3166 		    break;
3167 		}
3168 		Debug(isup(),DebugNote,"Call(%u). Waiting for continuity check [%p]",
3169 		    id(),this);
3170 		// Save message for later
3171 		m_iamMsg = m_sgmMsg;
3172 		m_sgmMsg = 0;
3173 		return 0;
3174 	    }
3175 	    m_state = Setup;
3176 	    if (!connectCircuit() && isup() &&
3177 		(isup()->mediaRequired() >= SignallingCallControl::MediaAlways)) {
3178 		setTerminate(true,"bearer-cap-not-available",0,isup()->location());
3179 		break;
3180 	    }
3181 	    m_sgmMsg->params().setParam("overlapped",String::boolText(m_overlap));
3182 	    m_lastEvent = new SignallingEvent(SignallingEvent::NewCall,m_sgmMsg,this);
3183 	    break;
3184 	case SS7MsgISUP::CCR:
3185 	    if (m_state < Testing) {
3186 		m_state = Testing;
3187 		if (!(isup() && isup()->m_continuity)) {
3188 		    Debug(isup(),DebugWarn,"Call(%u). Continuity check requested but not configured [%p]",
3189 			id(),this);
3190 		    setTerminate(true,"service-not-implemented",0,isup()->location());
3191 		    break;
3192 		}
3193 		m_circuitTesting = true;
3194 		if (!connectCircuit(isup()->m_continuity)) {
3195 		    setTerminate(true,"bearer-cap-not-available",0,isup()->location());
3196 		    break;
3197 		}
3198 		Debug(isup(),DebugNote,"Call(%u). Continuity test only [%p]",
3199 		    id(),this);
3200 	    }
3201 	    else if (!m_circuitTesting) {
3202 		setTerminate(true,"wrong-state-message",0,isup()->location());
3203 		break;
3204 	    }
3205 	    m_contTimer.stop();
3206 	    m_iamTimer.start();
3207 	    if (isup()->m_confirmCCR)
3208 		transmitMessage(new SS7MsgISUP(SS7MsgISUP::LPA,id()));
3209 	    break;
3210 	case SS7MsgISUP::ACM:
3211 	    m_state = Accepted;
3212 	    if (!connectCircuit() && isup() &&
3213 		(isup()->mediaRequired() >= SignallingCallControl::MediaAlways)) {
3214 		setReason("bearer-cap-not-available",0,0,isup()->location());
3215 		m_lastEvent = release();
3216 		break;
3217 	    }
3218 	    m_lastEvent = 0;
3219 	    m_inbandAvailable = m_inbandAvailable ||
3220 		SignallingUtils::hasFlag(m_sgmMsg->params(),"OptionalBackwardCallIndicators","inband");
3221 	    if (isup() && isup()->m_earlyAcm) {
3222 		// If the called party is known free report ringing
3223 		// If it may become free or there is inband audio report progress
3224 		bool ring = SignallingUtils::hasFlag(m_sgmMsg->params(),"BackwardCallIndicators","called-free");
3225 		if (m_inbandAvailable || ring || SignallingUtils::hasFlag(m_sgmMsg->params(),"BackwardCallIndicators","called-conn")) {
3226 		    m_sgmMsg->params().setParam("earlymedia",String::boolText(m_inbandAvailable));
3227 		    m_lastEvent = new SignallingEvent(ring ? SignallingEvent::Ringing : SignallingEvent::Progress,m_sgmMsg,this);
3228 		}
3229 	    }
3230 	    if (!m_lastEvent) {
3231 		m_sgmMsg->params().setParam("earlymedia",String::boolText(m_inbandAvailable));
3232 		m_lastEvent = new SignallingEvent(SignallingEvent::Accept,m_sgmMsg,this);
3233 	    }
3234 	    // intentionally fall through
3235 	case SS7MsgISUP::EXM:
3236 	    // Start T9 timer
3237 	    if (m_anmTimer.interval() && !m_anmTimer.started())
3238 		m_anmTimer.start();
3239 	    break;
3240 	case SS7MsgISUP::CPR:
3241 	    m_state = Ringing;
3242 	    if (!connectCircuit() && isup() &&
3243 		(isup()->mediaRequired() >= SignallingCallControl::MediaRinging)) {
3244 		setTerminate(true,"bearer-cap-not-available",0,isup()->location());
3245 		break;
3246 	    }
3247 	    m_inbandAvailable = m_inbandAvailable ||
3248 		SignallingUtils::hasFlag(m_sgmMsg->params(),"OptionalBackwardCallIndicators","inband") ||
3249 		SignallingUtils::hasFlag(m_sgmMsg->params(),"EventInformation","inband");
3250 	    m_sgmMsg->params().setParam("earlymedia",String::boolText(m_inbandAvailable));
3251 	    m_lastEvent = new SignallingEvent(
3252 		SignallingUtils::hasFlag(m_sgmMsg->params(),"EventInformation","ringing")
3253 	        ? SignallingEvent::Ringing : SignallingEvent::Progress,
3254 	        m_sgmMsg,this);
3255 	    break;
3256 	case SS7MsgISUP::ANM:
3257 	case SS7MsgISUP::CON:
3258 	    m_state = Answered;
3259 	    m_anmTimer.stop();
3260 	    if (!connectCircuit() && isup() &&
3261 		(isup()->mediaRequired() >= SignallingCallControl::MediaAnswered)) {
3262 		setTerminate(true,"bearer-cap-not-available",0,isup()->location());
3263 		break;
3264 	    }
3265 	    m_lastEvent = new SignallingEvent(SignallingEvent::Answer,m_sgmMsg,this);
3266 	    break;
3267 	case SS7MsgISUP::CRG:
3268 	    m_lastEvent = new SignallingEvent(SignallingEvent::Charge,m_sgmMsg,this);
3269 	    break;
3270 	default:
3271 	    Debug(isup(),DebugStub,"Call(%u). Segment waiting message is '%s' [%p]",
3272 		id(),m_sgmMsg->name(),this);
3273     }
3274     TelEngine::destruct(m_sgmMsg);
3275     return m_lastEvent;
3276 }
3277 
3278 // Transmit message. Set routing label's link if not already set
transmitMessage(SS7MsgISUP * msg)3279 bool SS7ISUPCall::transmitMessage(SS7MsgISUP* msg)
3280 {
3281     if (!msg || !isup()) {
3282 	TelEngine::destruct(msg);
3283 	return false;
3284     }
3285     DDebug(isup(),DebugAll,"Call(%u). Transmitting messsage (%s,%p) [%p]",
3286 	id(),msg->name(),msg,this);
3287     int sls = isup()->transmitMessage(msg,m_label,false);
3288     if (sls == -1)
3289 	return false;
3290     if (m_label.sls() == 255)
3291 	m_label.setSls(sls);
3292     return true;
3293 }
3294 
isup() const3295 SS7ISUP* SS7ISUPCall::isup() const
3296 {
3297     return static_cast<SS7ISUP*>(SignallingCall::controller());
3298 }
3299 
3300 // Set overlapped flag. Output a debug message
setOverlapped(bool on,bool numberComplete)3301 void SS7ISUPCall::setOverlapped(bool on, bool numberComplete)
3302 {
3303     if (m_overlap == on)
3304 	return;
3305     m_overlap = on;
3306     const char* reason = on ? "" : (numberComplete ? " (number complete)" : " (state changed)");
3307     Debug(isup(),DebugAll,"Call(%u). Overlapped dialing is %s%s [%p]",
3308 	id(),String::boolText(on),reason,this);
3309 }
3310 
3311 
3312 /**
3313  * SS7ISUP
3314  */
SS7ISUP(const NamedList & params,unsigned char sio)3315 SS7ISUP::SS7ISUP(const NamedList& params, unsigned char sio)
3316     : SignallingComponent(params.safe("SS7ISUP"),&params,"ss7-isup"),
3317       SignallingCallControl(params,"isup."),
3318       SS7Layer4(sio,&params),
3319       m_cicLen(2),
3320       m_type(SS7PointCode::Other),
3321       m_defPoint(0),
3322       m_remotePoint(0),
3323       m_sls(255),
3324       m_earlyAcm(true),
3325       m_inn(false),
3326       m_defaultSls(SlsLatest),
3327       m_maxCalledDigits(16),
3328       m_confirmCCR(true),
3329       m_dropOnUnknown(true),
3330       m_ignoreGRSSingle(false),
3331       m_ignoreCGBSingle(false),
3332       m_ignoreCGUSingle(false),
3333       m_duplicateCGB(false),
3334       m_ignoreUnkDigits(true),
3335       m_l3LinkUp(false),
3336       m_chargeProcessType(Confusion),
3337       m_t1Interval(15000),               // Q.764 T1 15..60 seconds
3338       m_t5Interval(300000),              // Q.764 T5 5..15 minutes
3339       m_t7Interval(ISUP_T7_DEFVAL),      // Q.764 T7 20..30 seconds
3340       m_t9Interval(0),                   // Q.764 T9 Q.118 1.5 - 3 minutes, not always used
3341       m_t12Interval(20000),              // Q.764 T12 (BLK) 15..60 seconds
3342       m_t13Interval(300000),             // Q.764 T13 (BLK global) 5..15 minutes
3343       m_t14Interval(20000),              // Q.764 T14 (UBL) 15..60 seconds
3344       m_t15Interval(300000),             // Q.764 T15 (UBL global) 5..15 minutes
3345       m_t16Interval(20000),              // Q.764 T16 (RSC) 15..60 seconds
3346       m_t17Interval(300000),             // Q.764 T17 5..15 minutes
3347       m_t18Interval(20000),              // Q.764 T18 (CGB) 15..60 seconds
3348       m_t19Interval(300000),             // Q.764 T19 (CGB global) 5..15 minutes
3349       m_t20Interval(20000),              // Q.764 T20 (CGU) 15..60 seconds
3350       m_t21Interval(300000),             // Q.764 T21 (CGU global) 5..15 minutes
3351       m_t27Interval(ISUP_T27_DEFVAL),    // Q.764 T27 4 minutes
3352       m_t34Interval(ISUP_T34_DEFVAL),    // Q.764 T34 2..4 seconds
3353       m_uptTimer(0),
3354       m_userPartAvail(true),
3355       m_uptMessage(SS7MsgISUP::UPT),
3356       m_uptCicCode(0),
3357       m_cicWarnLevel(DebugMild),
3358       m_replaceCounter(3),
3359       m_rscTimer(0),
3360       m_rscCic(0),
3361       m_rscSpeedup(0),
3362       m_lockTimer(2000),
3363       m_lockGroup(true),
3364       m_printMsg(false),
3365       m_extendedDebug(false)
3366 {
3367 #ifdef DEBUG
3368     if (debugAt(DebugAll)) {
3369 	String tmp;
3370 	params.dump(tmp,"\r\n  ",'\'',true);
3371 	Debug(this,DebugAll,"SS7ISUP::SS7ISUP(%p) [%p]%s",
3372 	    &params,this,tmp.c_str());
3373     }
3374 #endif
3375     const char* stype = params.getValue(YSTRING("pointcodetype"));
3376     m_type = SS7PointCode::lookup(stype);
3377     if (m_type == SS7PointCode::Other) {
3378 	Debug(this,DebugWarn,"Invalid point code type '%s'",c_safe(stype));
3379 	return;
3380     }
3381     if (m_type == SS7PointCode::ITU)
3382 	m_defaultSls = SlsCircuit;
3383 
3384     m_format = params.getValue(YSTRING("format"));
3385     if (-1 == lookup(m_format,SignallingUtils::dict(1,0),-1))
3386 	switch (m_type) {
3387 	    case SS7PointCode::ANSI:
3388 	    case SS7PointCode::ANSI8:
3389 	    case SS7PointCode::Japan:
3390 	    case SS7PointCode::Japan5:
3391 		m_format = "mulaw";
3392 		break;
3393 	    default:
3394 		m_format = "alaw";
3395 	}
3396 
3397     const char* rpc = params.getValue(YSTRING("remotepointcode"));
3398     m_remotePoint = new SS7PointCode(0,0,0);
3399     if (!(m_remotePoint->assign(rpc,m_type) && m_remotePoint->pack(m_type))) {
3400 	Debug(this,DebugMild,"Invalid remotepointcode='%s'",rpc);
3401 	TelEngine::destruct(m_remotePoint);
3402     }
3403 
3404     m_lockGroup = params.getBoolValue(YSTRING("lockgroup"),m_lockGroup);
3405     m_earlyAcm = params.getBoolValue(YSTRING("earlyacm"),m_earlyAcm);
3406     m_inn = params.getBoolValue(YSTRING("inn"),m_inn);
3407     m_numPlan = params.getValue(YSTRING("numplan"));
3408     if (-1 == lookup(m_numPlan,s_dict_numPlan,-1))
3409 	m_numPlan = "unknown";
3410     m_numType = params.getValue(YSTRING("numtype"));
3411     if (-1 == lookup(m_numType,s_dict_nai,-1))
3412 	m_numType = "unknown";
3413     m_numPresentation = params.getValue(YSTRING("presentation"));
3414     if (-1 == lookup(m_numPresentation,s_dict_presentation,-1))
3415 	m_numPresentation = "allowed";
3416     m_numScreening = params.getValue(YSTRING("screening"));
3417     if (-1 == lookup(m_numScreening,s_dict_screening,-1))
3418 	m_numScreening = "user-provided";
3419     m_callerCat = params.getValue(YSTRING("callercategory"));
3420     if (-1 == lookup(m_callerCat,s_dict_callerCat,-1))
3421 	m_callerCat = "ordinary";
3422 
3423     m_rscTimer.interval(params,"channelsync",60,300,true,true);
3424     m_rscInterval = m_rscTimer.interval();
3425 
3426     // Remote user part test
3427     m_uptTimer.interval(params,"userparttest",10,60,true,true);
3428     if (m_uptTimer.interval())
3429 	m_userPartAvail = false;
3430     else
3431 	m_lockTimer.start();
3432 
3433     // Timers
3434     m_t7Interval = SignallingTimer::getInterval(params,"t7",ISUP_T7_MINVAL,ISUP_T7_DEFVAL,ISUP_T7_MAXVAL,false);
3435     m_t9Interval = SignallingTimer::getInterval(params,"t9",ISUP_T9_MINVAL,ISUP_T9_DEFVAL,ISUP_T9_MAXVAL,true);
3436     m_t27Interval = SignallingTimer::getInterval(params,"t27",ISUP_T27_MINVAL,ISUP_T27_DEFVAL,ISUP_T27_MAXVAL,false);
3437     m_t34Interval = SignallingTimer::getInterval(params,"t34",ISUP_T34_MINVAL,ISUP_T34_DEFVAL,ISUP_T34_MAXVAL,false);
3438 
3439     m_continuity = params.getValue(YSTRING("continuity"));
3440     m_confirmCCR = params.getBoolValue(YSTRING("confirm_ccr"),true);
3441     m_dropOnUnknown = params.getBoolValue(YSTRING("drop_unknown"),true);
3442     m_ignoreGRSSingle = params.getBoolValue(YSTRING("ignore-grs-single"));
3443     m_ignoreCGBSingle = params.getBoolValue(YSTRING("ignore-cgb-single"));
3444     m_ignoreCGUSingle = params.getBoolValue(YSTRING("ignore-cgu-single"));
3445     m_duplicateCGB = params.getBoolValue(YSTRING("duplicate-cgb"),
3446 	(SS7PointCode::ANSI == m_type || SS7PointCode::ANSI8 == m_type));
3447     m_chargeProcessType = (ChargeProcess)params.getIntValue(YSTRING("charge-process"),s_dict_CRG_process,m_chargeProcessType);
3448     int testMsg = params.getIntValue(YSTRING("parttestmsg"),s_names,SS7MsgISUP::UPT);
3449     switch (testMsg) {
3450 	case SS7MsgISUP::CVT:
3451 	    if (SS7PointCode::ANSI != m_type && SS7PointCode::ANSI8 != m_type)
3452 		break;
3453 	    // fall through
3454 	case SS7MsgISUP::RSC:
3455 	case SS7MsgISUP::UBL:
3456 	case SS7MsgISUP::UPT:
3457 	    m_uptMessage = (SS7MsgISUP::Type)testMsg;
3458     }
3459     m_replaceCounter = params.getIntValue(YSTRING("max_replaces"),3,0,31);
3460     m_ignoreUnkDigits = params.getBoolValue(YSTRING("ignore-unknown-digits"),true);
3461     m_defaultSls = params.getIntValue(YSTRING("sls"),s_dict_callSls,m_defaultSls);
3462     m_maxCalledDigits = params.getIntValue(YSTRING("maxcalleddigits"),m_maxCalledDigits);
3463     if (m_maxCalledDigits < 1)
3464 	m_maxCalledDigits = 16;
3465 
3466     setDebug(params.getBoolValue(YSTRING("print-messages"),false),
3467 	params.getBoolValue(YSTRING("extended-debug"),false));
3468 
3469     if (debugAt(DebugInfo)) {
3470 	String s;
3471 	s << "pointcode-type=" << stype;
3472 	s << " format=" << m_format;
3473 	s << " plan/type/pres/screen=" << m_numPlan << "/" << m_numType << "/"
3474 	    << m_numPresentation << "/" << m_numScreening;
3475 	s << " caller-category=" << m_callerCat;
3476 	s << " remote-pointcode=";
3477 	if (m_remotePoint)
3478 	    s << *m_remotePoint;
3479 	else
3480 	    s << "missing";
3481 	s << " SIF/SSF=" << (unsigned int)sif() << "/" << (unsigned int)ssf();
3482 	s << " lockcircuits=" << params.getValue(YSTRING("lockcircuits"));
3483 	s << " userpartavail=" << String::boolText(m_userPartAvail);
3484 	s << " lockgroup=" << String::boolText(m_lockGroup);
3485 	s << " mediareq=" << lookup(m_mediaRequired,s_mediaRequired);
3486 	const char* sls = lookup(m_defaultSls,s_dict_callSls);
3487 	s << " outboundsls=";
3488 	if (sls)
3489 	    s << sls;
3490 	else
3491 	    s << m_defaultSls;
3492 	if (m_continuity)
3493 	    s << " continuity=" << m_continuity;
3494 	Debug(this,DebugInfo,"ISUP Call Controller %s [%p]",s.c_str(),this);
3495     }
3496 }
3497 
~SS7ISUP()3498 SS7ISUP::~SS7ISUP()
3499 {
3500     cleanup();
3501     if (m_remotePoint)
3502 	m_remotePoint->destruct();
3503     Debug(this,DebugInfo,"ISUP Call Controller destroyed [%p]",this);
3504 }
3505 
initialize(const NamedList * config)3506 bool SS7ISUP::initialize(const NamedList* config)
3507 {
3508 #ifdef DEBUG
3509     String tmp;
3510     if (config && debugAt(DebugAll))
3511 	config->dump(tmp,"\r\n  ",'\'',true);
3512     Debug(this,DebugInfo,"SS7ISUP::initialize(%p) [%p]%s",config,this,tmp.c_str());
3513 #endif
3514     if (config) {
3515 	debugLevel(config->getIntValue(YSTRING("debuglevel_isup"),
3516 	    config->getIntValue(YSTRING("debuglevel"),-1)));
3517 	setDebug(config->getBoolValue(YSTRING("print-messages"),false),
3518 	    config->getBoolValue(YSTRING("extended-debug"),false));
3519 	m_lockGroup = config->getBoolValue(YSTRING("lockgroup"),m_lockGroup);
3520 	m_earlyAcm = config->getBoolValue(YSTRING("earlyacm"),m_earlyAcm);
3521 	m_continuity = config->getValue(YSTRING("continuity"),m_continuity);
3522 	m_confirmCCR = config->getBoolValue(YSTRING("confirm_ccr"),true);
3523 	m_dropOnUnknown = config->getBoolValue(YSTRING("drop_unknown"),true);
3524 	m_ignoreGRSSingle = config->getBoolValue(YSTRING("ignore-grs-single"));
3525 	m_ignoreCGBSingle = config->getBoolValue(YSTRING("ignore-cgb-single"));
3526 	m_ignoreCGUSingle = config->getBoolValue(YSTRING("ignore-cgu-single"));
3527 	m_duplicateCGB = config->getBoolValue(YSTRING("duplicate-cgb"),
3528 	    (SS7PointCode::ANSI == m_type || SS7PointCode::ANSI8 == m_type));
3529 	int testMsg = config->getIntValue(YSTRING("parttestmsg"),s_names,SS7MsgISUP::UPT);
3530 	switch (testMsg) {
3531 	    case SS7MsgISUP::CVT:
3532 		if (SS7PointCode::ANSI != m_type && SS7PointCode::ANSI8 != m_type)
3533 		    break;
3534 		// fall through
3535 	    case SS7MsgISUP::RSC:
3536 	    case SS7MsgISUP::UBL:
3537 	    case SS7MsgISUP::UPT:
3538 		m_uptMessage = (SS7MsgISUP::Type)testMsg;
3539 	}
3540 	m_replaceCounter = config->getIntValue(YSTRING("max_replaces"),3,0,31);
3541         m_ignoreUnkDigits = config->getBoolValue(YSTRING("ignore-unknown-digits"),true);
3542 	m_defaultSls = config->getIntValue(YSTRING("sls"),s_dict_callSls,m_defaultSls);
3543 	m_chargeProcessType = (ChargeProcess)config->getIntValue(YSTRING("charge-process"),s_dict_CRG_process,m_chargeProcessType);
3544 	m_mediaRequired = (MediaRequired)config->getIntValue(YSTRING("needmedia"),
3545 	    s_mediaRequired,m_mediaRequired);
3546         // Timers
3547 	m_t7Interval = SignallingTimer::getInterval(*config,"t7",ISUP_T7_MINVAL,ISUP_T7_DEFVAL,ISUP_T7_MAXVAL,false);
3548 	m_t9Interval = SignallingTimer::getInterval(*config,"t9",ISUP_T9_MINVAL,ISUP_T9_DEFVAL,ISUP_T9_MAXVAL,true);
3549 	m_t27Interval = SignallingTimer::getInterval(*config,"t27",ISUP_T27_MINVAL,ISUP_T27_DEFVAL,ISUP_T27_MAXVAL,false);
3550 	m_t34Interval = SignallingTimer::getInterval(*config,"t34",ISUP_T34_MINVAL,ISUP_T34_DEFVAL,ISUP_T34_MAXVAL,false);
3551     }
3552     m_cicWarnLevel = DebugMild;
3553     return SS7Layer4::initialize(config);
3554 }
3555 
statusName() const3556 const char* SS7ISUP::statusName() const
3557 {
3558     if (exiting())
3559 	return "Exiting";
3560     if (!m_l3LinkUp)
3561 	return "Layer 3 down";
3562     if (!m_userPartAvail)
3563 	return "Remote unavailable";
3564     if (!m_defPoint)
3565 	return "No local PC set";
3566     if (!m_remotePoint)
3567 	return "No remote PC set";
3568     return "Operational";
3569 }
3570 
attach(SS7Layer3 * network)3571 void SS7ISUP::attach(SS7Layer3* network)
3572 {
3573     SS7Layer4::attach(network);
3574     m_l3LinkUp = network && network->operational();
3575 }
3576 
3577 // Append a point code to the list of point codes serviced by this controller
3578 // Set default point code
setPointCode(SS7PointCode * pc,bool def)3579 bool SS7ISUP::setPointCode(SS7PointCode* pc, bool def)
3580 {
3581     if (!(pc && pc->pack(m_type)))
3582 	return false;
3583     Lock mylock(this);
3584     // Force default if we are not having one or the list is empty
3585     def = def || !m_defPoint || !m_pointCodes.skipNull();
3586     // Force not default if the received point code is the same as the default one
3587     if (def && m_defPoint && *m_defPoint == *pc)
3588 	def = false;
3589     SS7PointCode* p = hasPointCode(*pc);
3590     if (def)
3591 	m_defPoint = p ? p : pc;
3592     String tmp;
3593     tmp << (def ? *m_defPoint : *pc);
3594     if (!p) {
3595 	m_pointCodes.append(pc);
3596 	DDebug(this,DebugAll,"Added new point code '%s'%s",tmp.safe(),def?". Set to default":"");
3597     }
3598     else {
3599 	TelEngine::destruct(pc);
3600 	if (def)
3601 	    Debug(this,DebugAll,"Set default point code '%s'",tmp.safe());
3602     }
3603     return true;
3604 }
3605 
3606 // Add all point codes described in a parameter list
setPointCode(const NamedList & params)3607 unsigned int SS7ISUP::setPointCode(const NamedList& params)
3608 {
3609     unsigned int count = 0;
3610     unsigned int n = params.length();
3611     bool hadDef = false;
3612     for (unsigned int i= 0; i < n; i++) {
3613 	NamedString* ns = params.getParam(i);
3614 	if (!ns)
3615 	    continue;
3616 	bool defPc = false;
3617 	if (ns->name() == YSTRING("defaultpointcode"))
3618 	    defPc = true;
3619 	else if (ns->name() != YSTRING("pointcode"))
3620 	    continue;
3621 	SS7PointCode* pc = new SS7PointCode(0,0,0);
3622 	if (pc->assign(*ns,m_type) && setPointCode(pc,defPc && !hadDef)) {
3623 	    count++;
3624 	    if (defPc) {
3625 		if (hadDef)
3626 		    Debug(this,DebugMild,"Added point code '%s' as non-default",ns->safe());
3627 		else
3628 		    hadDef = true;
3629 	    }
3630 	}
3631 	else {
3632 	    Debug(this,DebugWarn,"Invalid '%s'='%s' in parameters '%s'",
3633 		ns->name().c_str(),ns->safe(),params.safe());
3634 	    TelEngine::destruct(pc);
3635 	}
3636     }
3637     return count;
3638 }
3639 
3640 // Check if the given point code is serviced by this controller
hasPointCode(const SS7PointCode & pc)3641 SS7PointCode* SS7ISUP::hasPointCode(const SS7PointCode& pc)
3642 {
3643     Lock mylock(this);
3644     for (ObjList* o = m_pointCodes.skipNull(); o; o = o->skipNext()) {
3645 	SS7PointCode* p = static_cast<SS7PointCode*>(o->get());
3646 	if (*p == pc)
3647 	    return p;
3648     }
3649     return 0;
3650 }
3651 
createMSU(SS7MsgISUP::Type type,unsigned char ssf,const SS7Label & label,unsigned int cic,const NamedList * params) const3652 SS7MSU* SS7ISUP::createMSU(SS7MsgISUP::Type type, unsigned char ssf,
3653     const SS7Label& label, unsigned int cic, const NamedList* params) const
3654 {
3655     return buildMSU(type,sif() | (ssf & 0xf0),label,cic,params);
3656 }
3657 
3658 // Make an outgoing call
call(SignallingMessage * msg,String & reason)3659 SignallingCall* SS7ISUP::call(SignallingMessage* msg, String& reason)
3660 {
3661     if (!msg) {
3662 	reason = "noconn";
3663 	return 0;
3664     }
3665     if (exiting() || !m_l3LinkUp) {
3666 	Debug(this,DebugInfo,"Denying outgoing call request, reason: %s.",
3667 	    exiting() ? "exiting" : "L3 down");
3668 	TelEngine::destruct(msg);
3669 	reason = "net-out-of-order";
3670 	return 0;
3671     }
3672     if (!m_userPartAvail) {
3673 	Debug(this,DebugNote,"Remote User Part is unavailable");
3674 	TelEngine::destruct(msg);
3675 	reason = "noconn";
3676 	return 0;
3677     }
3678     SS7PointCode dest;
3679     SignallingCircuit* cic = 0;
3680     const char* range = msg->params().getValue(YSTRING("circuits"));
3681     reason.clear();
3682     Lock mylock(this);
3683     // Check
3684     while (true) {
3685 	if (!m_defPoint) {
3686  	    Debug(this,DebugNote,"Source point code is missing");
3687 	    reason = "noconn";
3688 	    break;
3689 	}
3690 	String pc = msg->params().getValue(YSTRING("calledpointcode"));
3691 	if (!(dest.assign(pc,m_type) && dest.pack(m_type))) {
3692 	    if (!m_remotePoint) {
3693 		Debug(this,DebugNote,
3694 		    "Destination point code is missing (calledpointcode=%s)",pc.safe());
3695 		reason = "noconn";
3696 		break;
3697 	    }
3698 	    dest = *m_remotePoint;
3699 	}
3700 	for (int attempts = 3; attempts; attempts--) {
3701 	    if (!reserveCircuit(cic,range,SignallingCircuit::LockLockedBusy)) {
3702 		Debug(this,DebugNote,"Can't reserve circuit");
3703 		break;
3704 	    }
3705 	    SS7ISUPCall* call2 = findCall(cic->code());
3706 	    if (!call2)
3707 		break;
3708 	    Debug(this,DebugWarn,"Circuit %u is already used by call %p",
3709 		cic->code(),call2);
3710 	    TelEngine::destruct(cic);
3711 	}
3712 	if (!cic)
3713 	    reason = "congestion";
3714 	break;
3715     }
3716     SS7ISUPCall* call = 0;
3717     if (reason.null()) {
3718 	String* cicParams = msg->params().getParam(YSTRING("circuit_parameters"));
3719 	if (cicParams) {
3720 	    NamedList* p = YOBJECT(NamedList,cicParams);
3721 	    if (p)
3722 		cic->setParams(*p);
3723 	}
3724 	int sls = msg->params().getIntValue(YSTRING("sls"),s_dict_callSls,m_defaultSls);
3725 	switch (sls) {
3726 	    case SlsCircuit:
3727 		if (cic) {
3728 		    sls = cic->code();
3729 		    break;
3730 		}
3731 		// fall through
3732 	    case SlsLatest:
3733 		sls = m_sls;
3734 		break;
3735 	}
3736 	call = new SS7ISUPCall(this,cic,*m_defPoint,dest,true,sls,range);
3737 	call->ref();
3738 	m_calls.append(call);
3739 	SignallingEvent* event = new SignallingEvent(SignallingEvent::NewCall,msg,call);
3740 	// (re)start RSC timer if not currently reseting
3741 	if (!m_rscCic && m_rscTimer.interval())
3742 	    m_rscTimer.start();
3743 	// Drop lock and send the event
3744 	mylock.drop();
3745 	if (!event->sendEvent()) {
3746 	    call->setTerminate(false,"failure");
3747 	    TelEngine::destruct(call);
3748 	    reason = "failure";
3749 	}
3750     }
3751     TelEngine::destruct(msg);
3752     return call;
3753 }
3754 
3755 // Converts an ISUP message to a Message Signal Unit and push it down the protocol stack
3756 // The given message is consumed
transmitMessage(SS7MsgISUP * msg,const SS7Label & label,bool recvLbl,int sls)3757 int SS7ISUP::transmitMessage(SS7MsgISUP* msg, const SS7Label& label, bool recvLbl, int sls)
3758 {
3759     if (!msg)
3760 	return -1;
3761     const SS7Label* p = &label;
3762     SS7Label tmp;
3763     if (recvLbl) {
3764 	switch (sls) {
3765 	    case SlsCircuit:
3766 		sls = msg->cic();
3767 		break;
3768 	    case SlsLatest:
3769 		sls = m_sls;
3770 		break;
3771 	    case SlsDefault:
3772 		sls = label.sls();
3773 		break;
3774 	}
3775 	tmp.assign(label.type(),label.opc(),label.dpc(),sls,label.spare());
3776 	p = &tmp;
3777     }
3778 
3779     lock();
3780     SS7MSU* msu = createMSU(msg->type(),ssf(),*p,msg->cic(),&msg->params());
3781 
3782     if (m_printMsg && debugAt(DebugInfo)) {
3783 	String tmp;
3784 	void* data = 0;
3785 	unsigned int len = 0;
3786 	if (m_extendedDebug && msu) {
3787 	    unsigned int offs = 2 + label.length() + m_cicLen;
3788 	    data = msu->getData(offs);
3789 	    len = data ? msu->length() - offs : 0;
3790 	}
3791 	msg->toString(tmp,*p,debugAt(DebugAll),data,len);
3792 	Debug(this,DebugInfo,"Sending message (%p)%s",msg,tmp.c_str());
3793     }
3794     else if (debugAt(DebugAll)) {
3795 	String tmp;
3796 	tmp << *p;
3797 	Debug(this,DebugAll,"Sending message '%s' cic=%u label=%s",
3798 	    msg->name(),msg->cic(),tmp.c_str());
3799     }
3800 
3801     sls = -1;
3802     if (msu && m_l3LinkUp) {
3803 	unlock();
3804 	sls = transmitMSU(*msu,*p,p->sls());
3805 	lock();
3806 	if ((m_sls == 255) && (sls != -1))
3807 	    m_sls = (unsigned char)sls;
3808     }
3809     unlock();
3810 #ifdef XDEBUG
3811     if (sls == -1)
3812 	Debug(this,DebugMild,"Failed to send message (%p): '%s'",msg,msg->name());
3813 #endif
3814     TelEngine::destruct(msu);
3815     TelEngine::destruct(msg);
3816     return sls;
3817 }
3818 
cleanup(const char * reason)3819 void SS7ISUP::cleanup(const char* reason)
3820 {
3821     ObjList terminate;
3822     lock();
3823     for (ObjList* o = m_calls.skipNull(); o; o = o->skipNext()) {
3824 	SS7ISUPCall* call = static_cast<SS7ISUPCall*>(o->get());
3825 	if (call->ref())
3826 	    terminate.append(call);
3827     }
3828     releaseCircuit(m_rscCic);
3829     m_rscTimer.stop();
3830     unlock();
3831     setCallsTerminate(terminate,true,reason);
3832     clearCalls();
3833 }
3834 
3835 // Remove all links with other layers. Disposes the memory
destroyed()3836 void SS7ISUP::destroyed()
3837 {
3838     lock();
3839     clearCalls();
3840     unlock();
3841     SignallingCallControl::attach(0);
3842     SS7Layer4::destroyed();
3843 }
3844 
3845 // Utility: find a pending (un)block message for a given circuit
findPendingMsgTimerLock(ObjList & list,unsigned int code)3846 static bool findPendingMsgTimerLock(ObjList& list, unsigned int code)
3847 {
3848     for (ObjList* o = list.skipNull(); o; o = o->skipNext()) {
3849 	SignallingMessageTimer* m = static_cast<SignallingMessageTimer*>(o->get());
3850 	SS7MsgISUP* msg = static_cast<SS7MsgISUP*>(m->message());
3851 	if (!msg || code < msg->cic())
3852 	    continue;
3853 	if (msg->type() == SS7MsgISUP::BLK || msg->type() == SS7MsgISUP::UBL) {
3854 	    if (msg->cic() == code)
3855 		return true;
3856 	    continue;
3857 	}
3858 	if (msg->type() != SS7MsgISUP::CGB && msg->type() != SS7MsgISUP::CGU)
3859 	    continue;
3860 	const String& map = msg->params()[YSTRING("RangeAndStatus.map")];
3861 	if (map[code - msg->cic()] == '1')
3862 	    return true;
3863     }
3864     return false;
3865 }
3866 
timerTick(const Time & when)3867 void SS7ISUP::timerTick(const Time& when)
3868 {
3869     Lock mylock(this,SignallingEngine::maxLockWait());
3870     if (!(mylock.locked() && m_l3LinkUp && circuits()))
3871 	return;
3872 
3873     // Test remote user part
3874     if (m_remotePoint && !m_userPartAvail && m_uptTimer.interval()) {
3875 	if (m_uptTimer.started()) {
3876 	    if (!m_uptTimer.timeout(when.msec()))
3877 		return;
3878 	    DDebug(this,DebugNote,"%s timed out. Retransmitting",lookup(m_uptMessage,s_names));
3879 	}
3880 	ObjList* o = circuits()->circuits().skipNull();
3881 	SignallingCircuit* cic = o ? static_cast<SignallingCircuit*>(o->get()) : 0;
3882 	m_uptCicCode = cic ? cic->code() : 1;
3883 	SS7MsgISUP* msg = new SS7MsgISUP(m_uptMessage,m_uptCicCode);
3884 	SS7Label label(m_type,*m_remotePoint,*m_defPoint,
3885 	    (m_defaultSls == SlsCircuit) ? m_uptCicCode : m_sls);
3886 	m_uptTimer.start(when.msec());
3887 	mylock.drop();
3888 	transmitMessage(msg,label,false);
3889 	return;
3890     }
3891 
3892     // Blocking/unblocking circuits
3893     if (m_lockTimer.timeout(when.msec())) {
3894 	DDebug(this,DebugAll,"Re-checking local lock sending");
3895 	m_lockTimer.stop();
3896 	mylock.drop();
3897 	sendLocalLock(when);
3898 	return;
3899     }
3900 
3901     // Pending messages
3902     ObjList reInsert;
3903     ObjList sendMsgs;
3904     ObjList rsc;
3905     while (true) {
3906 	SignallingMessageTimer* m = m_pending.timeout(when);
3907 	if (!m)
3908 	    break;
3909 	SS7MsgISUP* msg = static_cast<SS7MsgISUP*>(m->message());
3910 	if (!msg) {
3911 	    TelEngine::destruct(m);
3912 	    continue;
3913 	}
3914 	if (msg->type() != SS7MsgISUP::RSC &&
3915 	    msg->type() != SS7MsgISUP::REL &&
3916 	    msg->type() != SS7MsgISUP::CGB &&
3917 	    msg->type() != SS7MsgISUP::CGU &&
3918 	    msg->type() != SS7MsgISUP::BLK &&
3919 	    msg->type() != SS7MsgISUP::UBL) {
3920 	    Debug(this,DebugStub,"Unhandled pending message '%s'",msg->name());
3921 	    TelEngine::destruct(m);
3922 	    continue;
3923 	}
3924 	// Global timer timed out: set retransmission timer from it
3925 	if (m->global().timeout(when.msec())) {
3926 	    if (msg->type() != SS7MsgISUP::REL) {
3927 		m->interval(m->global().interval());
3928 		m->global().stop();
3929 		m->global().interval(0);
3930 		msg->params().setParam("isup_alert_maint",String::boolText(true));
3931 	    }
3932 	    else {
3933 		Debug(this,DebugNote,"Pending operation '%s' cic=%u timed out",
3934 		    msg->name(),msg->cic());
3935 		SignallingCircuit* c = circuits() ? circuits()->find(msg->cic()) : 0;
3936 		TelEngine::destruct(m);
3937 		if (c && c->ref())
3938 		    rsc.append(c)->setDelete(false);
3939 		continue;
3940 	    }
3941 	}
3942 	// Check if message is still in use
3943 	if (msg->type() == SS7MsgISUP::CGB || msg->type() == SS7MsgISUP::CGU) {
3944 	    String* map = msg->params().getParam(YSTRING("RangeAndStatus.map"));
3945 	    bool ok = !TelEngine::null(map);
3946 	    String removedCics;
3947 	    if (ok) {
3948 		unsigned int nCics = 0;
3949 		int flg = 0;
3950 		int flgReset = 0;
3951 		if ((msg->params()[YSTRING("GroupSupervisionTypeIndicator")] == YSTRING("hw-failure"))) {
3952 		    flg = SignallingCircuit::LockLocalHWFail;
3953 		    flgReset = SignallingCircuit::LockingHWFail;
3954 		}
3955 		else {
3956 		    flg = SignallingCircuit::LockLocalMaint;
3957 		    flgReset = SignallingCircuit::LockingMaint;
3958 		}
3959 		int on = (msg->type() == SS7MsgISUP::CGB) ? flg : 0;
3960 		char* s = (char*)map->c_str();
3961 		for (unsigned int i = 0; i < map->length(); i++) {
3962 		    if (s[i] == '0')
3963 			continue;
3964 		    unsigned int code = msg->cic() + i;
3965 		    SignallingCircuit* cic = circuits()->find(code);
3966 		    if (cic && (on == cic->locked(flg))) {
3967 			nCics++;
3968 			continue;
3969 		    }
3970 		    // Don't reset locking flag if there is another operation in progress
3971 		    if (cic && !(findPendingMsgTimerLock(m_pending,code) ||
3972 			findPendingMsgTimerLock(reInsert,code)) && cic->locked(flgReset)) {
3973 			cic->resetLock(flgReset);
3974 			Debug(this,DebugNote,"Pending %s reset flag=0x%x cic=%u current=0x%x",
3975 			    msg->name(),flgReset,code,cic->locked());;
3976 		    }
3977 		    s[i] = '0';
3978 		    removedCics.append(String(code),",");
3979 		}
3980 		if (nCics)
3981 		    msg->params().setParam("RangeAndStatus",String(nCics));
3982 		else
3983 		    ok = false;
3984 	    }
3985 	    if (!ok) {
3986 		Debug(this,DebugNote,"Removed empty pending operation '%s' cic=%u",
3987 		    msg->name(),msg->cic());
3988 		TelEngine::destruct(m);
3989 		continue;
3990 	    }
3991 	    if (removedCics)
3992 		Debug(this,DebugAll,"Removed cics=%s from pending operation '%s' map cic=%u",
3993 		    removedCics.c_str(),msg->name(),msg->cic());
3994 	}
3995 	else if (msg->type() == SS7MsgISUP::BLK || msg->type() == SS7MsgISUP::UBL) {
3996 	    // We set the following param when sending BLK/UBL for HW fail reason
3997 	    bool maint = !msg->params().getBoolValue(YSTRING("isup_pending_block_hwfail"));
3998 	    int flg = maint ? SignallingCircuit::LockLocalMaint : SignallingCircuit::LockLocalHWFail;
3999 	    int on = (msg->type() == SS7MsgISUP::BLK) ? flg : 0;
4000 	    SignallingCircuit* cic = circuits()->find(msg->cic());
4001 	    if (!cic || on != cic->locked(flg)) {
4002 		flg = maint ? SignallingCircuit::LockingMaint : SignallingCircuit::LockingHWFail;
4003 		// Don't reset locking flag if there is another operation in progress
4004 		if (cic && !(findPendingMsgTimerLock(m_pending,msg->cic()) ||
4005 		    findPendingMsgTimerLock(reInsert,msg->cic())) && cic->locked(flg)) {
4006 		    cic->resetLock(flg);
4007 		    Debug(this,DebugNote,"Pending %s reset flag=0x%x cic=%u current=0x%x",
4008 			msg->name(),flg,cic->code(),cic->locked());
4009 		}
4010 		Debug(this,DebugNote,"Removed empty pending operation '%s' cic=%u",
4011 		    msg->name(),msg->cic());
4012 		TelEngine::destruct(m);
4013 		continue;
4014 	    }
4015 	}
4016 	bool alert = msg->params().getBoolValue(YSTRING("isup_alert_maint"));
4017 	const char* reason = msg->params().getValue(YSTRING("isup_pending_reason"),"");
4018 	Debug(this,!alert ? DebugAll : DebugMild,
4019 	    "Pending operation '%s' cic=%u reason='%s' timed out",
4020 	    msg->name(),msg->cic(),reason);
4021 	if (alert) {
4022 	    // TODO: alert maintenance
4023 	}
4024 	msg->ref();
4025 	reInsert.append(m)->setDelete(false);
4026 	sendMsgs.append(msg)->setDelete(false);
4027     }
4028     // Re-insert
4029     ObjList* o = reInsert.skipNull();
4030     ObjList* oRsc = rsc.skipNull();
4031     if (o || oRsc) {
4032 	for (; o; o = o->skipNext())
4033 	    m_pending.add(static_cast<SignallingMessageTimer*>(o->get()),when);
4034 	mylock.drop();
4035 	transmitMessages(sendMsgs);
4036 	for (; oRsc; oRsc = oRsc->skipNext()) {
4037 	    SignallingCircuit* c = static_cast<SignallingCircuit*>(oRsc->get());
4038 	    c->resetLock(SignallingCircuit::Resetting);
4039 	    startCircuitReset(c,"T5");
4040 	}
4041 	return;
4042     }
4043 
4044     // Circuit reset disabled ?
4045     if (!m_rscTimer.interval())
4046 	return;
4047     if (m_rscTimer.started()) {
4048 	if (!m_rscTimer.timeout(when.msec()))
4049 	    return;
4050 	m_rscTimer.stop();
4051 	if (m_rscCic) {
4052 	    Debug(this,DebugMild,"Circuit reset timed out for cic=%u",m_rscCic->code());
4053 	    m_rscCic->resetLock(SignallingCircuit::Resetting);
4054 	    releaseCircuit(m_rscCic);
4055 	    return;
4056 	}
4057     }
4058     if (m_rscSpeedup && !--m_rscSpeedup) {
4059 	Debug(this,DebugNote,"Reset interval back to %u ms",m_rscInterval);
4060 	m_rscTimer.interval(m_rscInterval);
4061     }
4062     m_rscTimer.start(when.msec());
4063     // Pick the next circuit to reset. Ignore circuits locally locked or busy
4064     if (m_defPoint && m_remotePoint &&
4065 	reserveCircuit(m_rscCic,0,SignallingCircuit::LockLocal | SignallingCircuit::LockBusy)) {
4066 	// Avoid already resetting cic
4067 	if (!findPendingMessage(SS7MsgISUP::RSC,m_rscCic->code())) {
4068 	    m_rscCic->setLock(SignallingCircuit::Resetting);
4069 	    SS7MsgISUP* msg = new SS7MsgISUP(SS7MsgISUP::RSC,m_rscCic->code());
4070 	    SS7Label label(m_type,*m_remotePoint,*m_defPoint,
4071 		(m_defaultSls == SlsCircuit) ? m_rscCic->code() : m_sls);
4072 	    DDebug(this,DebugNote,"Periodic restart on cic=%u",m_rscCic->code());
4073 	    mylock.drop();
4074 	    transmitMessage(msg,label,false);
4075 	}
4076 	else
4077 	    releaseCircuit(m_rscCic);
4078     }
4079 }
4080 
4081 // Process a component control request
control(NamedList & params)4082 bool SS7ISUP::control(NamedList& params)
4083 {
4084     String* ret = params.getParam(YSTRING("completion"));
4085     const String* oper = params.getParam(YSTRING("operation"));
4086     const char* cmp = params.getValue(YSTRING("component"));
4087     int cmd = oper ? oper->toInteger(s_dict_control,-1) : -1;
4088 
4089     if (ret) {
4090 	if (oper && (cmd < 0))
4091 	    return false;
4092 	String part = params.getValue(YSTRING("partword"));
4093 	if (cmp) {
4094 	    if (toString() != cmp)
4095 		return false;
4096 	    for (const TokenDict* d = s_dict_control; d->token; d++)
4097 		Module::itemComplete(*ret,d->token,part);
4098 	    return true;
4099 	}
4100 	return Module::itemComplete(*ret,toString(),part);
4101     }
4102 
4103     if (!(cmp && toString() == cmp))
4104 	return false;
4105     Lock mylock(this);
4106     if (!m_remotePoint)
4107 	return TelEngine::controlReturn(&params,false);
4108     unsigned int code1 = 1;
4109     if (circuits()) {
4110 	ObjList* o = circuits()->circuits().skipNull();
4111 	if (o) {
4112 	    SignallingCircuit* cic = static_cast<SignallingCircuit*>(o->get());
4113 	    if (cic)
4114 		code1 = cic->code();
4115 	}
4116     }
4117     switch (cmd) {
4118 	case SS7MsgISUP::UPT:
4119 	case SS7MsgISUP::CVT:
4120 	    {
4121 		unsigned int code = params.getIntValue(YSTRING("circuit"),code1);
4122 		SS7MsgISUP* msg = new SS7MsgISUP((SS7MsgISUP::Type)cmd,code);
4123 		SS7Label label(m_type,*m_remotePoint,*m_defPoint,m_sls);
4124 		mylock.drop();
4125 		transmitMessage(msg,label,false);
4126 	    }
4127 	    return TelEngine::controlReturn(&params,true);
4128 	case SS7MsgISUP::CQM:
4129 	    {
4130 		unsigned int code = params.getIntValue(YSTRING("circuit"),code1);
4131 		unsigned int range = params.getIntValue(YSTRING("range"),1);
4132 		SS7MsgISUP* msg = new SS7MsgISUP(SS7MsgISUP::CQM,code);
4133 		msg->params().addParam("RangeAndStatus",String(range));
4134 		SS7Label label(m_type,*m_remotePoint,*m_defPoint,m_sls);
4135 		mylock.drop();
4136 		transmitMessage(msg,label,false);
4137 	    }
4138 	    return TelEngine::controlReturn(&params,true);
4139 	case SS7MsgISUP::CCR:
4140 	    {
4141 		unsigned int code = params.getIntValue(YSTRING("circuit"),code1);
4142 		// TODO: create a test call, not just send CCR
4143 		SS7MsgISUP* msg = 0;
4144 		const String& ok = params[YSTRING("success")];
4145 		if (ok.isBoolean()) {
4146 		    msg = new SS7MsgISUP(SS7MsgISUP::COT,code);
4147 		    msg->params().addParam("ContinuityIndicators",
4148 			ok.toBoolean() ? "success" : "failed");
4149 		}
4150 		else
4151 		    msg = new SS7MsgISUP(SS7MsgISUP::CCR,code);
4152 		SS7Label label(m_type,*m_remotePoint,*m_defPoint,m_sls);
4153 		mylock.drop();
4154 		transmitMessage(msg,label,false);
4155 	    }
4156 	    return TelEngine::controlReturn(&params,true);
4157 	case SS7MsgISUP::RSC:
4158 	    if (0 == (m_rscSpeedup = circuits() ? circuits()->count() : 0))
4159 		return TelEngine::controlReturn(&params,false);
4160 	    // Temporarily speed up reset interval to 10s or as provided
4161 	    m_rscTimer.interval(params,"interval",2,10,false,true);
4162 	    Debug(this,DebugNote,"Fast reset of %u circuits every %u ms",
4163 		m_rscSpeedup,(unsigned int)m_rscTimer.interval());
4164 	    if (m_rscTimer.started())
4165 		m_rscTimer.start(Time::msecNow());
4166 	    return TelEngine::controlReturn(&params,true);
4167 	case SS7MsgISUP::BLK:
4168 	case SS7MsgISUP::UBL:
4169 	    return TelEngine::controlReturn(&params,handleCicBlockCommand(params,cmd == SS7MsgISUP::BLK));
4170 	case SS7MsgISUP::RLC:
4171 	    {
4172 		int code = params.getIntValue(YSTRING("circuit"));
4173 		if (code <= 0)
4174 		    return TelEngine::controlReturn(&params,false);
4175 		SignallingMessageTimer* pending = findPendingMessage(SS7MsgISUP::RSC,code,true);
4176 		if (pending) {
4177 		    resetCircuit((unsigned int)code,false,false);
4178 		    TelEngine::destruct(pending);
4179 		    SS7Label label(m_type,*m_remotePoint,*m_defPoint,m_sls);
4180 		    mylock.drop();
4181 		    transmitRLC(this,code,label,false);
4182 		}
4183 		else {
4184 		    RefPointer<SS7ISUPCall> call;
4185 		    findCall(code,call);
4186 		    if (!call)
4187 			return TelEngine::controlReturn(&params,false);
4188 		    mylock.drop();
4189 		    call->setTerminate(true,params.getValue(YSTRING("reason"),"normal"));
4190 		}
4191 	    }
4192 	    return TelEngine::controlReturn(&params,true);
4193 	case SS7MsgISUP::UPA:
4194 	    if (!m_userPartAvail) {
4195 		const char* oldStat = statusName();
4196 		m_uptTimer.stop();
4197 		m_userPartAvail = true;
4198 		m_lockTimer.start();
4199 		if (statusName() != oldStat) {
4200 		    NamedList params("");
4201 		    params.addParam("from",toString());
4202 		    params.addParam("type","trunk");
4203 		    params.addParam("operational",String::boolText(m_l3LinkUp));
4204 		    params.addParam("available",String::boolText(m_userPartAvail));
4205 		    params.addParam("text",statusName());
4206 		    engine()->notify(this,params);
4207 		}
4208 	    }
4209 	    return TelEngine::controlReturn(&params,true);
4210 	case SS7MsgISUP::CtrlSave:
4211 	    setVerify(true,true);
4212 	    return TelEngine::controlReturn(&params,true);
4213 #ifdef ISUP_HANDLE_CIC_EVENT_CONTROL
4214 	case SS7MsgISUP::CtrlCicEvent:
4215 	    return TelEngine::controlReturn(&params,handleCicEventCommand(params));
4216 #endif
4217     }
4218     mylock.drop();
4219     return SignallingComponent::control(params);
4220 }
4221 
4222 // Process a notification generated by the attached network layer
notify(SS7Layer3 * link,int sls)4223 void SS7ISUP::notify(SS7Layer3* link, int sls)
4224 {
4225     if (!(link && network()))
4226 	return;
4227     Lock mylock(this);
4228     SS7Route::State state = m_remotePoint ?
4229 	network()->getRouteState(m_type,*m_remotePoint) : SS7Route::Unknown;
4230     bool linkTmp = m_l3LinkUp;
4231     bool partAvail = m_userPartAvail;
4232     const char* oldStat = statusName();
4233     // Copy linkset operational state
4234     m_l3LinkUp = network()->operational();
4235     // Reset remote user part's availability state if supported
4236     // Force UPT re-send
4237     if (m_uptTimer.interval() && (!m_l3LinkUp || (SS7Route::Prohibited == state))) {
4238 	m_uptTimer.stop();
4239 	m_userPartAvail = false;
4240     }
4241     Debug(this,DebugInfo,
4242 	"L3 '%s' sls=%d is %soperational.%s Route is %s. Remote User Part is %savailable",
4243 	link->toString().safe(),sls,
4244 	(link->operational() ? "" : "not "),
4245 	(network() == link ? "" : (m_l3LinkUp ? " L3 is up." : " L3 is down.")),
4246 	SS7Route::stateName(state),
4247 	(m_userPartAvail ? "" : "un"));
4248     if (linkTmp != m_l3LinkUp || partAvail != m_userPartAvail) {
4249 	NamedList params("");
4250 	params.addParam("from",toString());
4251 	params.addParam("type","trunk");
4252 	params.addParam("operational",String::boolText(m_l3LinkUp));
4253 	params.addParam("available",String::boolText(m_userPartAvail));
4254 	params.addParam("link",link->toString());
4255 	if (statusName() != oldStat)
4256 	    params.addParam("text",statusName());
4257 	engine()->notify(this,params);
4258     }
4259 }
4260 
buildMSU(SS7MsgISUP::Type type,unsigned char sio,const SS7Label & label,unsigned int cic,const NamedList * params) const4261 SS7MSU* SS7ISUP::buildMSU(SS7MsgISUP::Type type, unsigned char sio,
4262     const SS7Label& label, unsigned int cic, const NamedList* params) const
4263 {
4264     // Special treatment for charge message
4265     // Check if it is in raw format
4266     if (type == SS7MsgISUP::CRG && params && params->getParam(YSTRING("Charge")))
4267 	return encodeRawMessage(type,sio,label,cic,(*params)[YSTRING("Charge")]);
4268 
4269     if (type == SS7MsgISUP::PAM && params)
4270 	return encodeRawMessage(type,sio,label,cic,(*params)[YSTRING("PassAlong")]);
4271     // see what mandatory parameters we should put in this message
4272     const MsgParams* msgParams = getIsupParams(label.type(),type);
4273     if (!msgParams) {
4274 	if (!hasOptionalOnly(type)) {
4275 	    const char* name = SS7MsgISUP::lookup(type);
4276 	    if (name)
4277 		Debug(this,DebugWarn,"No parameter table for ISUP MSU type %s [%p]",name,this);
4278 	    else
4279 		Debug(this,DebugWarn,"Cannot create ISUP MSU type 0x%02x [%p]",type,this);
4280 	    return 0;
4281 	}
4282 	msgParams = &s_compatibility;
4283     }
4284     unsigned int len = m_cicLen + 1;
4285 
4286     const SS7MsgISUP::Parameters* plist = msgParams->params;
4287     SS7MsgISUP::Parameters ptype;
4288     // first add the length of mandatory fixed parameters
4289     while ((ptype = *plist++) != SS7MsgISUP::EndOfParameters) {
4290 	const IsupParam* param = getParamDesc(ptype);
4291 	if (!param) {
4292 	    // this is fatal as we don't know the length
4293 	    Debug(this,DebugCrit,"Missing description of fixed ISUP parameter 0x%02x [%p]",ptype,this);
4294 	    return 0;
4295 	}
4296 	if (!param->size) {
4297 	    Debug(this,DebugCrit,"Invalid (variable) description of fixed ISUP parameter 0x%02x [%p]",ptype,this);
4298 	    return 0;
4299 	}
4300 	len += param->size;
4301     }
4302     // initialize the pointer array offset just past the mandatory fixed part
4303     unsigned int ptr = label.length() + 1 + len;
4304     // then add one pointer octet to each mandatory variable parameter
4305     while ((ptype = *plist++) != SS7MsgISUP::EndOfParameters) {
4306 	const IsupParam* param = getParamDesc(ptype);
4307 	if (!param) {
4308 	    // this is fatal as we won't be able to populate later
4309 	    Debug(this,DebugCrit,"Missing description of variable ISUP parameter 0x%02x [%p]",ptype,this);
4310 	    return 0;
4311 	}
4312 	if (param->size)
4313 	    Debug(this,DebugMild,"Invalid (fixed) description of variable ISUP parameter 0x%02x [%p]",ptype,this);
4314 	len++;
4315     }
4316     // finally add a pointer to the optional part only if supported by type
4317     if (msgParams->optional)
4318 	len++;
4319     SS7MSU* msu = new SS7MSU(sio,label,0,len);
4320     unsigned char* d = msu->getData(label.length()+1,len);
4321     unsigned int i = m_cicLen;
4322     while (i--) {
4323 	*d++ = cic & 0xff;
4324 	cic >>= 8;
4325     }
4326     *d++ = type;
4327 #ifdef XDEBUG
4328     if (params && debugAt(DebugAll)) {
4329 	String tmp;
4330 	params->dump(tmp,"\r\n  ",'\'',true);
4331 	Debug(this,DebugAll,"SS7ISUP::buildMSU params:%s",
4332 	    tmp.c_str());
4333     }
4334 #endif
4335     ObjList exclude;
4336     plist = msgParams->params;
4337     String prefix = params->getValue(YSTRING("message-prefix"));
4338     // first populate with mandatory fixed parameters
4339     while ((ptype = *plist++) != SS7MsgISUP::EndOfParameters) {
4340 	const IsupParam* param = getParamDesc(ptype);
4341 	if (!param) {
4342 	    Debug(this,DebugFail,"Stage 2: no description of fixed ISUP parameter 0x%02x [%p]",ptype,this);
4343 	    continue;
4344 	}
4345 	if (!param->size) {
4346 	    Debug(this,DebugFail,"Stage 2: Invalid (variable) description of fixed ISUP parameter %s [%p]",param->name,this);
4347 	    continue;
4348 	}
4349 	if (!encodeParam(this,*msu,param,params,exclude,prefix,d))
4350 	    Debug(this,DebugCrit,"Could not encode fixed ISUP parameter %s [%p]",param->name,this);
4351 	d += param->size;
4352     }
4353     // now populate with mandatory variable parameters
4354     for (; (ptype = *plist++) != SS7MsgISUP::EndOfParameters; ptr++) {
4355 	const IsupParam* param = getParamDesc(ptype);
4356 	if (!param) {
4357 	    Debug(this,DebugFail,"Stage 2: no description of variable ISUP parameter 0x%02x [%p]",ptype,this);
4358 	    continue;
4359 	}
4360 	if (param->size) {
4361 	    Debug(this,DebugFail,"Stage 2: Invalid (fixed) description of variable ISUP parameter %s [%p]",param->name,this);
4362 	    continue;
4363 	}
4364 	// remember the offset this parameter will actually get stored
4365 	len = msu->length();
4366 	unsigned char size = encodeParam(this,*msu,param,params,exclude,prefix);
4367 	d = msu->getData(0,len+1);
4368 	if (!(size && d)) {
4369 	    Debug(this,DebugCrit,"Could not encode variable ISUP parameter %s [%p]",param->name,this);
4370 	    continue;
4371 	}
4372 	if ((d[len] != size) || (msu->length() != (len+1+size))) {
4373 	    Debug(this,DebugCrit,"Invalid encoding variable ISUP parameter %s (len=%u size=%u stor=%u) [%p]",
4374 		param->name,len,size,d[len],this);
4375 	    continue;
4376 	}
4377 	// store pointer to parameter
4378 	d[ptr] = len - ptr;
4379     }
4380     if (msgParams->optional && params) {
4381 	// remember the offset past last mandatory == first optional parameter
4382 	len = msu->length();
4383 	// optional parameters are possible - try to set anything left in the message
4384 	unsigned int n = params->length();
4385 	for (unsigned int i = 0; i < n; i++) {
4386 	    NamedString* ns = params->getParam(i);
4387 	    if (!ns || exclude.find(ns))
4388 		continue;
4389 	    if (prefix && !ns->name().startsWith(prefix))
4390 		continue;
4391 	    String tmp(ns->name());
4392 	    tmp >> prefix.c_str();
4393 	    static const Regexp s_suffix("\\.[0-9]\\+$");
4394 	    if (tmp.matches(s_suffix)) {
4395 		tmp.assign(tmp,tmp.matchOffset());
4396 		// WARNING: HACK - ApplicationTransport does not follow naming convention
4397 		if (tmp == YSTRING("ApplicationTransport"))
4398 		    continue;
4399 	    }
4400 	    const IsupParam* param = getParamDesc(tmp);
4401 	    unsigned char size = 0;
4402 	    if (param)
4403 		size = encodeParam(this,*msu,param,ns,params,prefix);
4404 	    else if (tmp.startSkip("Param_",false)) {
4405 		int val = tmp.toInteger(-1);
4406 		if (val >= 0 && val <= 255) {
4407 		    IsupParam p;
4408 		    p.name = tmp;
4409 		    p.type = (SS7MsgISUP::Parameters)val;
4410 		    p.size = 0;
4411 		    p.encoder = 0;
4412 		    size = encodeParam(this,*msu,&p,ns,params,prefix);
4413 		}
4414 	    }
4415 	    if (!size)
4416 		continue;
4417 	    if (len) {
4418 		d = msu->getData(0,len+1);
4419 		d[ptr] = len - ptr;
4420 		len = 0;
4421 	    }
4422 	}
4423 	if (!len) {
4424 	    // we stored some optional parameters so we need to put the terminator
4425 	    DataBlock tmp(0,1);
4426 	    *msu += tmp;
4427 	}
4428     }
4429     return msu;
4430 }
4431 
encodeRawMessage(SS7MsgISUP::Type type,unsigned char sio,const SS7Label & label,unsigned int cic,const String & param) const4432 SS7MSU* SS7ISUP::encodeRawMessage(SS7MsgISUP::Type type, unsigned char sio,
4433     const SS7Label& label, unsigned int cic, const String& param) const
4434 {
4435     DataBlock raw;
4436     if (!raw.unHexify(param.c_str(),param.length(),' ')) {
4437 	DDebug(this,DebugMild,"Encode raw charge failed: invalid string");
4438 	return 0;
4439     }
4440     if (raw.length() > 254) {
4441 	DDebug(this,DebugMild,"Encode raw charge failed: data length=%u",
4442 		raw.length());
4443 	return 0;
4444     }
4445     SS7MSU* msu = new SS7MSU(sio,label,0,m_cicLen + 1);
4446     unsigned char* d = msu->getData(label.length()+1,m_cicLen + 1);
4447     unsigned int i = m_cicLen;
4448     while (i--) {
4449 	*d++ = cic & 0xff;
4450 	cic >>= 8;
4451     }
4452     *d++ = type;
4453     *msu += raw;
4454     return msu;
4455 }
4456 
4457 
4458 
4459 // Decode a buffer to a list of parameters
decodeMessage(NamedList & msg,SS7MsgISUP::Type msgType,SS7PointCode::Type pcType,const unsigned char * paramPtr,unsigned int paramLen)4460 bool SS7ISUP::decodeMessage(NamedList& msg,
4461     SS7MsgISUP::Type msgType, SS7PointCode::Type pcType,
4462     const unsigned char* paramPtr, unsigned int paramLen)
4463 {
4464     String msgTypeName((int)msgType);
4465     const char* msgName = SS7MsgISUP::lookup(msgType,msgTypeName);
4466 #ifdef XDEBUG
4467     String tmp;
4468     tmp.hexify((void*)paramPtr,paramLen,' ');
4469     Debug(this,DebugAll,"Decoding msg=%s len=%u: %s [%p]",
4470 	msgName,paramLen,tmp.c_str(),this);
4471 #else
4472     DDebug(this,DebugAll,"Decoding msg=%s len=%u [%p]",
4473 	msgName,paramLen,this);
4474 #endif
4475 
4476     // see what parameters we expect for this message
4477     const MsgParams* params = getIsupParams(pcType,msgType);
4478     if (!params) {
4479 	if (hasOptionalOnly(msgType)) {
4480 	    Debug(this,DebugNote,"Unsupported message %s, decoding compatibility [%p]",msgName,this);
4481 	    params = &s_compatibility;
4482 	}
4483 	else if (msgType != SS7MsgISUP::PAM) {
4484 	    Debug(this,DebugWarn,"Unsupported message %s or point code type [%p]",msgName,this);
4485 	    return false;
4486 	}
4487 	else if (!paramLen) {
4488 	    // PAM message must have at least 1 byte for message type
4489 	    Debug(this,DebugNote,"Empty %s [%p]",msgName,this);
4490 	    return false;
4491 	}
4492     }
4493 
4494     // Get parameter prefix
4495     String prefix = msg.getValue(YSTRING("message-prefix"));
4496 
4497     // Add protocol and message type
4498     if (!msg.getValue(prefix+"protocol-type")) {
4499 	switch (pcType) {
4500 	    case SS7PointCode::ITU:
4501 		msg.setParam(prefix+"protocol-type","itu-t");
4502 		break;
4503 	    case SS7PointCode::ANSI:
4504 	    case SS7PointCode::ANSI8:
4505 		msg.setParam(prefix+"protocol-type","ansi");
4506 		break;
4507 	    case SS7PointCode::China:
4508 		msg.setParam(prefix+"protocol-type","chn");
4509 		msg.setParam(prefix+"protocol-basetype","chn");
4510 		break;
4511 	    case SS7PointCode::Japan:
4512 	    case SS7PointCode::Japan5:
4513 		msg.setParam(prefix+"protocol-type","ttc");
4514 		msg.setParam(prefix+"protocol-basetype","ttc93+");
4515 		break;
4516 	    default: ;
4517 	}
4518     }
4519     msg.addParam(prefix+"message-type",msgName);
4520 
4521     // Special decoder for PAM
4522     if (msgType == SS7MsgISUP::PAM) {
4523         String raw;
4524 	raw.hexify((void*)paramPtr,paramLen,' ');
4525         msg.addParam(prefix + "PassAlong",raw);
4526 	return true;
4527     }
4528 
4529     // Decode raw CRG if specified
4530     if (msgType == SS7MsgISUP::CRG && getChargeProcessType() != Parsed) {
4531 	String raw;
4532 	raw.hexify((void*)paramPtr,paramLen,' ');
4533 	msg.addParam(prefix + "Charge",raw);
4534 	return true;
4535     }
4536 
4537     String unsupported;
4538     const SS7MsgISUP::Parameters* plist = params->params;
4539     SS7MsgISUP::Parameters ptype;
4540     // first decode any mandatory fixed parameters the message should have
4541     while ((ptype = *plist++) != SS7MsgISUP::EndOfParameters) {
4542 	const IsupParam* param = getParamDesc(ptype);
4543 	if (!param) {
4544 	    // this is fatal as we don't know the length
4545 	    Debug(this,DebugCrit,"Missing description of fixed ISUP parameter 0x%02x [%p]",ptype,this);
4546 	    return false;
4547 	}
4548 	if (!param->size) {
4549 	    Debug(this,DebugCrit,"Invalid (variable) description of fixed ISUP parameter %s [%p]",param->name,this);
4550 	    return false;
4551 	}
4552 	if (paramLen < param->size) {
4553 	    Debug(this,DebugWarn,"Truncated ISUP message! [%p]",this);
4554 	    return false;
4555 	}
4556 	if (!decodeParam(this,msg,param,paramPtr,param->size,prefix)) {
4557 	    Debug(this,DebugWarn,"Could not decode fixed ISUP parameter %s [%p]",param->name,this);
4558 	    decodeRaw(this,msg,param,paramPtr,param->size,prefix);
4559 	    SignallingUtils::appendFlag(unsupported,param->name);
4560 	}
4561 	paramPtr += param->size;
4562 	paramLen -= param->size;
4563     } // while ((ptype = *plist++)...
4564     bool mustWarn = true;
4565     // next decode any mandatory variable parameters the message should have
4566     while ((ptype = *plist++) != SS7MsgISUP::EndOfParameters) {
4567 	mustWarn = false;
4568 	const IsupParam* param = getParamDesc(ptype);
4569 	if (!param) {
4570 	    // we could skip over unknown mandatory variable length but it's still bad
4571 	    Debug(this,DebugCrit,"Missing description of variable ISUP parameter 0x%02x [%p]",ptype,this);
4572 	    return false;
4573 	}
4574 	if (param->size)
4575 	    Debug(this,DebugMild,"Invalid (fixed) description of variable ISUP parameter %s [%p]",param->name,this);
4576 	unsigned int offs = paramPtr[0];
4577 	if ((offs < 1) || (offs >= paramLen)) {
4578 	    Debug(this,DebugWarn,"Invalid offset %u (len=%u) ISUP parameter %s [%p]",
4579 		offs,paramLen,param->name,this);
4580 	    return false;
4581 	}
4582 	unsigned int size = paramPtr[offs];
4583 	if ((size < 1) || (offs+size >= paramLen)) {
4584 	    Debug(this,DebugWarn,"Invalid size %u (ofs=%u, len=%u) ISUP parameter %s [%p]",
4585 		size,offs,paramLen,param->name,this);
4586 	    return false;
4587 	}
4588 	if (!decodeParam(this,msg,param,paramPtr+offs+1,size,prefix)) {
4589 	    Debug(this,DebugWarn,"Could not decode variable ISUP parameter %s (size=%u) [%p]",
4590 		param->name,size,this);
4591 	    decodeRaw(this,msg,param,paramPtr+offs+1,size,prefix);
4592 	    SignallingUtils::appendFlag(unsupported,param->name);
4593 	}
4594 	paramPtr++;
4595 	paramLen--;
4596     } // while ((ptype = *plist++)...
4597     // now decode the optional parameters if the message supports them
4598     if (params->optional) {
4599 	unsigned int offs = paramLen ? paramPtr[0] : 0;
4600 	if (offs >= paramLen) {
4601 	    if (paramLen) {
4602 		Debug(this,DebugWarn,"Invalid ISUP optional offset %u (len=%u) [%p]",
4603 		    offs,paramLen,this);
4604 		return false;
4605 	    }
4606 	    Debug(this,DebugMild,"ISUP message %s lacking optional parameters [%p]",
4607 		msgName,this);
4608 	}
4609 	else if (offs) {
4610 	    mustWarn = true;
4611 	    // advance pointer past mandatory parameters
4612 	    paramPtr += offs;
4613 	    paramLen -= offs;
4614 	    while (paramLen) {
4615 		ptype = (SS7MsgISUP::Parameters)(*paramPtr++);
4616 		paramLen--;
4617 		if (ptype == SS7MsgISUP::EndOfParameters)
4618 		    break;
4619 		if (paramLen < 2) {
4620 		    Debug(this,DebugWarn,"Only %u octets while decoding optional ISUP parameter 0x%02x [%p]",
4621 			paramLen,ptype,this);
4622 		    return false;
4623 		}
4624 		unsigned int size = *paramPtr++;
4625 		paramLen--;
4626 		if ((size < 1) || (size >= paramLen)) {
4627 		    Debug(this,DebugWarn,"Invalid size %u (len=%u) ISUP optional parameter 0x%02x [%p]",
4628 			size,paramLen,ptype,this);
4629 		    return false;
4630 		}
4631 		const IsupParam* param = getParamDesc(ptype);
4632 		if (!param) {
4633 		    Debug(this,DebugMild,"Unknown optional ISUP parameter 0x%02x (size=%u) [%p]",ptype,size,this);
4634 		    decodeRawParam(this,msg,ptype,paramPtr,size,prefix);
4635 		    SignallingUtils::appendFlag(unsupported,"Param_" + String((unsigned int)ptype));
4636 		}
4637 		else if (!decodeParam(this,msg,param,paramPtr,size,prefix)) {
4638 		    Debug(this,DebugWarn,"Could not decode optional ISUP parameter %s (size=%u) [%p]",param->name,size,this);
4639 		    decodeRaw(this,msg,param,paramPtr,size,prefix);
4640 		    SignallingUtils::appendFlag(unsupported,param->name);
4641 		}
4642 		paramPtr += size;
4643 		paramLen -= size;
4644 	    } // while (paramLen)
4645 	} // else if (offs)
4646 	else
4647 	    paramLen = 0;
4648     }
4649     if (unsupported)
4650 	msg.addParam(prefix + "parameters-unsupported",unsupported);
4651     String release,cnf,npRelease;
4652     String pCompat(prefix + "ParameterCompatInformation.");
4653     unsigned int n = msg.length();
4654     for (unsigned int i = 0; i < n; i++) {
4655 	NamedString* ns = msg.getParam(i);
4656 	if (!(ns && ns->name().startsWith(pCompat) && !ns->name().endsWith(".more")))
4657 	    continue;
4658 	ObjList* l = ns->split(',',false);
4659 	for (ObjList* ol = l->skipNull(); ol; ol = ol->skipNext()) {
4660 	    String* s = static_cast<String*>(ol->get());
4661 	    if (*s == YSTRING("release")) {
4662 		SignallingUtils::appendFlag(release,ns->name().substr(pCompat.length()));
4663 		break;
4664 	    }
4665 	    if (*s == YSTRING("cnf"))
4666 		SignallingUtils::appendFlag(cnf,ns->name().substr(pCompat.length()));
4667 	    if (*s == YSTRING("nopass-release"))
4668 		SignallingUtils::appendFlag(npRelease,ns->name().substr(pCompat.length()));
4669 	}
4670 	TelEngine::destruct(l);
4671     }
4672     if (release)
4673 	msg.setParam(prefix + "parameters-unhandled-release",release);
4674     if (cnf)
4675 	msg.setParam(prefix + "parameters-unhandled-cnf",cnf);
4676     if (npRelease)
4677 	msg.setParam(prefix + "parameters-nopass-release",npRelease);
4678     if (paramLen && mustWarn)
4679 	Debug(this,DebugWarn,"Got %u garbage octets after message type 0x%02x [%p]",
4680 	    paramLen,msgType,this);
4681     return true;
4682 }
4683 
4684 // Encode an ISUP list of parameters to a buffer
encodeMessage(DataBlock & buf,SS7MsgISUP::Type msgType,SS7PointCode::Type pcType,const NamedList & params,unsigned int * cic)4685 bool SS7ISUP::encodeMessage(DataBlock& buf, SS7MsgISUP::Type msgType, SS7PointCode::Type pcType,
4686     const NamedList& params, unsigned int* cic)
4687 {
4688     unsigned int circuit = cic ? *cic : 0;
4689     SS7Label label(pcType,1,1,1);
4690 
4691     SS7MSU* msu = buildMSU(msgType,1,label,circuit,&params);
4692     if (!msu)
4693 	return false;
4694     unsigned int start = 1 + label.length() + (cic ? 0 : m_cicLen);
4695     buf.assign(((char*)msu->data()) + start,msu->length() - start);
4696     TelEngine::destruct(msu);
4697     return true;
4698 }
4699 
4700 // Process parameter compatibility lists
4701 // Terminate an existing call or send CNF
4702 // Return true if any parameter compatibility was handled
processParamCompat(const NamedList & list,unsigned int cic,bool * callReleased)4703 bool SS7ISUP::processParamCompat(const NamedList& list, unsigned int cic, bool* callReleased)
4704 {
4705     if (!cic)
4706 	return true;
4707     const String& prefix = list[YSTRING("message-prefix")];
4708     // Release call params
4709     String relCall = list[prefix + "parameters-unhandled-release"];
4710     relCall.append(list[prefix + "parameters-nopass-release"],",");
4711     if (relCall) {
4712 	Lock lock(this);
4713 	SS7ISUPCall* call = findCall(cic);
4714 	Debug(this,DebugNote,
4715 	    "Terminating call (%p) on cic=%u: unknown/unhandled params='%s' [%p]",
4716 	    call,cic,relCall.c_str(),this);
4717 	String diagnostic;
4718 	hexifyIsupParams(diagnostic,relCall);
4719 	if (call) {
4720 	    lock.drop();
4721 	    call->setTerminate(true,"unknown-ie",diagnostic,m_location);
4722 	}
4723 	else if (m_remotePoint) {
4724 	    // No call: make sure the circuit is released at remote party
4725 	    SS7Label label(m_type,*m_remotePoint,*m_defPoint,
4726 		(m_defaultSls == SlsCircuit) ? cic : m_sls);
4727 	    lock.drop();
4728 	    transmitRLC(this,cic,label,false,"unknown-ie",diagnostic,m_location);
4729 	}
4730 	if (callReleased)
4731 	    *callReleased = true;
4732 	return true;
4733     }
4734     // Send CNF params
4735     const String& cnf = list[prefix + "parameters-unhandled-cnf"];
4736     if (!cnf)
4737 	return false;
4738     DDebug(this,DebugAll,"processParamCompat() cic=%u sending CNF for '%s' [%p]",
4739 	cic,cnf.c_str(),this);
4740     String diagnostic;
4741     hexifyIsupParams(diagnostic,cnf);
4742     if (diagnostic && m_remotePoint) {
4743 	SS7Label label(m_type,*m_remotePoint,*m_defPoint,
4744 	    (m_defaultSls == SlsCircuit) ? cic : m_sls);
4745 	transmitCNF(this,cic,label,false,"unknown-ie",diagnostic,m_location);
4746     }
4747     return !diagnostic.null();
4748 }
4749 
receivedMSU(const SS7MSU & msu,const SS7Label & label,SS7Layer3 * network,int sls)4750 HandledMSU SS7ISUP::receivedMSU(const SS7MSU& msu, const SS7Label& label, SS7Layer3* network, int sls)
4751 {
4752     if (msu.getSIF() != sif() || !hasPointCode(label.dpc()) || !handlesRemotePC(label.opc()))
4753 	return HandledMSU::Rejected;
4754     // we should have at least 2 bytes CIC and 1 byte message type
4755     const unsigned char* s = msu.getData(label.length()+1,3);
4756     if (!s) {
4757 	Debug(this,DebugNote,"Got short MSU");
4758 	return false;
4759     }
4760     unsigned int len = msu.length()-label.length()-1;
4761     unsigned int cic = s[0] | (s[1] << 8);
4762     SS7MsgISUP::Type type = (SS7MsgISUP::Type)s[2];
4763     String name = SS7MsgISUP::lookup(type);
4764     if (!name) {
4765         String tmp;
4766 	tmp.hexify((void*)s,len,' ');
4767 	Debug(this,DebugMild,"Received unknown ISUP type 0x%02x, cic=%u, length %u: %s",
4768 	    type,cic,len,tmp.c_str());
4769 	name = (int)type;
4770     }
4771     if (!(circuits() && circuits()->find(cic))) {
4772 	Debug(this,m_cicWarnLevel,"Received ISUP type 0x%02x (%s) for unknown cic=%u",
4773 	    type,name.c_str(),cic);
4774 	m_cicWarnLevel = DebugAll;
4775 	return HandledMSU::NoCircuit;
4776     }
4777     bool ok = processMSU(type,cic,s+3,len-3,label,network,sls);
4778     if (!ok && debugAt(DebugMild)) {
4779 	String tmp;
4780 	tmp.hexify((void*)s,len,' ');
4781 	Debug(this,DebugMild,"Unhandled ISUP type %s, cic=%u, length %u: %s",
4782 	    name.c_str(),cic,len,tmp.c_str());
4783     }
4784     return ok;
4785 }
4786 
processMSU(SS7MsgISUP::Type type,unsigned int cic,const unsigned char * paramPtr,unsigned int paramLen,const SS7Label & label,SS7Layer3 * network,int sls)4787 bool SS7ISUP::processMSU(SS7MsgISUP::Type type, unsigned int cic,
4788     const unsigned char* paramPtr, unsigned int paramLen,
4789     const SS7Label& label, SS7Layer3* network, int sls)
4790 {
4791     XDebug(this,DebugAll,"SS7ISUP::processMSU(%u,%u,%p,%u,%p,%p,%d) [%p]",
4792 	type,cic,paramPtr,paramLen,&label,network,sls,this);
4793 
4794     SS7MsgISUP* msg = new SS7MsgISUP(type,cic);
4795     if (!SS7MsgISUP::lookup(type)) {
4796 	String tmp;
4797 	tmp.hexify(&type,1);
4798 	msg->params().assign("Message_" + tmp);
4799     }
4800     if (!decodeMessage(msg->params(),type,label.type(),paramPtr,paramLen)) {
4801 	TelEngine::destruct(msg);
4802 	return false;
4803     }
4804 
4805     if (m_printMsg && debugAt(DebugInfo)) {
4806 	String tmp;
4807 	msg->toString(tmp,label,debugAt(DebugAll),
4808 	    m_extendedDebug ? paramPtr : 0,paramLen);
4809 	Debug(this,DebugInfo,"Received message (%p)%s",msg,tmp.c_str());
4810     }
4811     else if (debugAt(DebugAll)) {
4812 	String tmp;
4813 	tmp << label;
4814 	Debug(this,DebugAll,"Received message '%s' cic=%u label=%s",
4815 	    msg->name(),msg->cic(),tmp.c_str());
4816     }
4817 
4818     // TODO: check parameters-unsupported vs. ParameterCompatInformation
4819 
4820     // Check if we expected some response to UPT
4821     // Ignore
4822     if (!m_userPartAvail && m_uptTimer.started()) {
4823 	m_uptTimer.stop();
4824 	const char* oldStat = statusName();
4825 	m_userPartAvail = true;
4826 	m_lockTimer.start();
4827 	Debug(this,DebugInfo,"Remote user part is available");
4828 	if (statusName() != oldStat) {
4829 	    NamedList params("");
4830 	    params.addParam("from",toString());
4831 	    params.addParam("type","trunk");
4832 	    params.addParam("operational",String::boolText(m_l3LinkUp));
4833 	    params.addParam("available",String::boolText(m_userPartAvail));
4834 	    params.addParam("text",statusName());
4835 	    engine()->notify(this,params);
4836 	}
4837 	if (msg->cic() == m_uptCicCode &&
4838 	    (msg->type() == SS7MsgISUP::UPA ||
4839 	     msg->type() == SS7MsgISUP::CVR ||
4840 	     msg->type() == SS7MsgISUP::CNF ||
4841 	     msg->type() == SS7MsgISUP::UEC)) {
4842 	    m_uptCicCode = 0;
4843 	    TelEngine::destruct(msg);
4844 	    return true;
4845 	}
4846     }
4847 
4848     switch (msg->type()) {
4849 	case SS7MsgISUP::IAM:
4850 	case SS7MsgISUP::SAM:
4851 	case SS7MsgISUP::ACM:
4852 	case SS7MsgISUP::EXM:
4853 	case SS7MsgISUP::CPR:
4854 	case SS7MsgISUP::ANM:
4855 	case SS7MsgISUP::CON:
4856 	case SS7MsgISUP::REL:
4857 	case SS7MsgISUP::SGM:
4858 	case SS7MsgISUP::CCR:
4859 	case SS7MsgISUP::COT:
4860 	case SS7MsgISUP::APM:
4861 	case SS7MsgISUP::SUS:
4862 	case SS7MsgISUP::RES:
4863 	    processCallMsg(msg,label,sls);
4864 	    break;
4865 	case SS7MsgISUP::CRG:
4866 	    switch (getChargeProcessType()) {
4867 		case Confusion:
4868 		    processControllerMsg(msg,label,sls);
4869 		case Ignore:
4870 		    break;
4871 		default:
4872 		    processCallMsg(msg,label,sls);
4873 	    }
4874 	    break;
4875 	case SS7MsgISUP::RLC:
4876 	    if (m_rscCic && m_rscCic->code() == msg->cic())
4877 		processControllerMsg(msg,label,sls);
4878 	    else {
4879 		SignallingMessageTimer* m = findPendingMessage(SS7MsgISUP::RSC,msg->cic(),true);
4880 		if (m) {
4881 		    DDebug(this,DebugAll,"RSC confirmed for pending cic=%u",msg->cic());
4882 		    resetCircuit(msg->cic(),false,false);
4883 		    TelEngine::destruct(m);
4884 		}
4885 		else
4886 		    processCallMsg(msg,label,sls);
4887 	    }
4888 	    break;
4889 	default:
4890 	    processControllerMsg(msg,label,sls);
4891     }
4892 
4893     TelEngine::destruct(msg);
4894     return true;
4895 }
4896 
4897 // MTP notification that remote user part is unavailable
receivedUPU(SS7PointCode::Type type,const SS7PointCode node,SS7MSU::Services part,unsigned char cause,const SS7Label & label,int sls)4898 void SS7ISUP::receivedUPU(SS7PointCode::Type type, const SS7PointCode node,
4899     SS7MSU::Services part, unsigned char cause, const SS7Label& label, int sls)
4900 {
4901     if (part != sif() || !handlesRemotePC(node))
4902 	return;
4903     if (!(m_userPartAvail && m_uptTimer.interval()))
4904 	return;
4905     const char* oldStat = statusName();
4906     Debug(this,DebugNote,"Remote User Part is unavailable (received UPU)");
4907     m_userPartAvail = false;
4908     m_uptTimer.start();
4909     if (statusName() != oldStat) {
4910 	NamedList params("");
4911 	params.addParam("from",toString());
4912 	params.addParam("type","trunk");
4913 	params.addParam("operational",String::boolText(m_l3LinkUp));
4914 	params.addParam("available",String::boolText(m_userPartAvail));
4915 	params.addParam("text",statusName());
4916 	engine()->notify(this,params);
4917     }
4918 }
4919 
4920 // Process an event received from a non-reserved circuit
processCircuitEvent(SignallingCircuitEvent * & event,SignallingCall * call)4921 SignallingEvent* SS7ISUP::processCircuitEvent(SignallingCircuitEvent*& event,
4922     SignallingCall* call)
4923 {
4924     if (!event)
4925 	return 0;
4926     SignallingEvent* ev = 0;
4927     switch (event->type()) {
4928 	case SignallingCircuitEvent::Alarm:
4929 	case SignallingCircuitEvent::NoAlarm:
4930 	    if (event->circuit()) {
4931 		lock();
4932 		bool block = (event->type() == SignallingCircuitEvent::Alarm);
4933 		bool blocked = (0 != event->circuit()->locked(SignallingCircuit::LockLocalHWFail));
4934 		// Avoid notifying the same state
4935 		if (block != blocked) {
4936 		    event->circuit()->hwLock(block,false,true,true);
4937 		    if (!m_lockTimer.started())
4938 			m_lockTimer.start();
4939 		    if (block)
4940 			cicHwBlocked(event->circuit()->code(),String("1"));
4941 		}
4942 		unlock();
4943 		ev = new SignallingEvent(event,call);
4944 	    }
4945 	    break;
4946 	case SignallingCircuitEvent::Dtmf:
4947 	    if (event->getValue(YSTRING("tone"))) {
4948 		SignallingMessage* msg = new SignallingMessage(event->c_str());
4949 		msg->params().addParam("tone",event->getValue(YSTRING("tone")));
4950 		msg->params().addParam("inband",event->getValue(YSTRING("inband"),String::boolText(true)));
4951 		ev = new SignallingEvent(SignallingEvent::Info,msg,call);
4952 		TelEngine::destruct(msg);
4953 	    }
4954 	    break;
4955 	default:
4956 	    ev = new SignallingEvent(event,call);
4957     }
4958     TelEngine::destruct(event);
4959     return ev;
4960 }
4961 
4962 // Initiate a circuit reset
startCircuitReset(SignallingCircuit * & cic,const String & timer)4963 bool SS7ISUP::startCircuitReset(SignallingCircuit*& cic, const String& timer)
4964 {
4965     if (!cic)
4966 	return false;
4967     bool ok = false;
4968     do {
4969 	Lock lock(this);
4970 	// Check if the circuit can be reset
4971 	// Do nothing on locally locked circuit: this would clear our lock
4972 	// state at remote side. See Q.764 2.9.3.1
4973 	if (cic->locked(SignallingCircuit::LockLocal)) {
4974 	    Debug(this,DebugNote,
4975 		"Failed to start reset on locally locked circuit (cic=%u timer=%s) [%p]",
4976 		cic->code(),timer.c_str(),this);
4977 	    ok = SignallingCallControl::releaseCircuit(cic);
4978 	    break;
4979 	}
4980 	// Check if there is any management operation in progress on the cic
4981 	if (cic->locked(SignallingCircuit::LockBusy))
4982 	    break;
4983 	bool relTimeout = (timer == "T5");
4984 	Debug(this,!relTimeout ? DebugAll : DebugNote,
4985 	    "Starting circuit %u reset on timer %s [%p]",
4986 	    cic->code(),timer.c_str(),this);
4987 	// TODO: alert maintenance if T5 timer expired
4988 	SignallingMessageTimer* m = 0;
4989 	if (relTimeout)
4990 	    m = new SignallingMessageTimer(m_t17Interval);
4991 	else
4992 	    m = new SignallingMessageTimer(m_t16Interval,m_t17Interval);
4993 	m = m_pending.add(m);
4994 	if (m) {
4995 	    cic->setLock(SignallingCircuit::Resetting);
4996 	    SS7MsgISUP* msg = new SS7MsgISUP(SS7MsgISUP::RSC,cic->code());
4997 	    msg->params().addParam("isup_pending_reason",timer,false);
4998 	    if (relTimeout)
4999 		msg->params().addParam("isup_alert_maint",String::boolText(true));
5000 	    msg->ref();
5001 	    m->message(msg);
5002 	    lock.drop();
5003 	    ok = true;
5004 	    SS7Label label;
5005 	    if (setLabel(label,msg->cic()))
5006 		transmitMessage(msg,label,false);
5007 	}
5008 	else {
5009 	    Debug(this,DebugNote,
5010 		"Failed to add circuit %u reset to pending messages timer=%s [%p]",
5011 		cic->code(),timer.c_str(),this);
5012 	    ok = SignallingCallControl::releaseCircuit(cic);
5013 	}
5014     } while (false);
5015     TelEngine::destruct(cic);
5016     return ok;
5017 }
5018 
5019 // Process call related messages
processCallMsg(SS7MsgISUP * msg,const SS7Label & label,int sls)5020 void SS7ISUP::processCallMsg(SS7MsgISUP* msg, const SS7Label& label, int sls)
5021 {
5022     // Find a call for this message, create a new one or drop the message
5023     RefPointer<SS7ISUPCall> call;
5024     findCall(msg->cic(),call);
5025     const char* reason = 0;
5026     while (true) {
5027 	#define DROP_MSG(res) { reason = res; break; }
5028 	// Avoid cic == 0
5029 	if (!msg->cic())
5030 	    DROP_MSG("invalid CIC")
5031 	// non IAM message. Drop it if there is no call for it
5032 	if ((msg->type() != SS7MsgISUP::IAM) && (msg->type() != SS7MsgISUP::CCR)) {
5033 	    if (!call) {
5034 		if (msg->type() == SS7MsgISUP::REL)
5035 		    DROP_MSG("no call")
5036 		if (msg->type() != SS7MsgISUP::RLC) {
5037 		    // Initiate circuit reset
5038 		    SignallingCircuit* cic = 0;
5039 		    String s(msg->cic());
5040 		    if (reserveCircuit(cic,0,SignallingCircuit::LockLockedBusy,&s))
5041 			startCircuitReset(cic,"T16");
5042 		}
5043 		return;
5044 	    }
5045 	    break;
5046 	}
5047 	// IAM or CCR message
5048 	SignallingCircuit* circuit = 0;
5049 	// Check collision
5050 	if (call) {
5051 	    // If existing call is an incoming one, drop the message (retransmission ?)
5052 	    if (!call->outgoing()) {
5053 		if (msg->type() == SS7MsgISUP::CCR)
5054 		    break;
5055 		else
5056 		    DROP_MSG("retransmission")
5057 	    }
5058 	    Debug(this,DebugNote,"Incoming call %u collide with existing outgoing",msg->cic());
5059 	    // *** See Q.764 2.9.1.4
5060 	    // Drop the request if the outgoing call already received some response or
5061 	    // the destination point code is greater then the originating and the CIC is even
5062 	    if (call->state() > SS7ISUPCall::Setup)
5063 		DROP_MSG("collision - outgoing call responded")
5064 	    // The greater point code should have the even circuit
5065 	    unsigned int dpc = label.dpc().pack(label.type());
5066 	    unsigned int opc = label.opc().pack(label.type());
5067 	    bool controlling = (dpc > opc);
5068 	    bool even = (0 == (msg->cic() % 2));
5069 	    if (controlling == even)
5070 		DROP_MSG("collision - we control the CIC")
5071 	    // Accept the incoming request. Change the call's circuit
5072 	    reserveCircuit(circuit,call->cicRange(),SignallingCircuit::LockLockedBusy);
5073 	    call->replaceCircuit(circuit);
5074 	    circuit = 0;
5075 	    call = 0;
5076 	}
5077 	int flags = SignallingCircuit::LockLockedBusy;
5078 	// Q.764 2.8.2 - accept test calls even if the remote side is blocked
5079 	// Q.764 2.8.2.3 (xiv) - unblock remote side of the circuit for non-test calls
5080 	if ((msg->type() == SS7MsgISUP::CCR) ||
5081 	    (msg->params()[YSTRING("CallingPartyCategory")] == YSTRING("test"))) {
5082 	    Debug(this,DebugInfo,"Received test call on circuit %u",msg->cic());
5083 	    flags = 0;
5084 	}
5085 	else {
5086 	    circuit = circuits() ? circuits()->find(msg->cic()) : 0;
5087 	    if (circuit && circuit->locked(SignallingCircuit::LockRemote)) {
5088 		Debug(this,DebugNote,"Unblocking remote circuit %u on IAM request",msg->cic());
5089 		circuit->hwLock(false,true,0!=circuit->locked(SignallingCircuit::LockRemoteHWFail),false);
5090 		circuit->maintLock(false,true,0!=circuit->locked(SignallingCircuit::LockRemoteMaint),false);
5091 		m_verifyEvent = true;
5092 	    }
5093 	    circuit = 0;
5094 	}
5095 	String s(msg->cic());
5096 	if (reserveCircuit(circuit,0,flags,&s,true)) {
5097 	    call = new SS7ISUPCall(this,circuit,label.dpc(),label.opc(),false,label.sls(),
5098 		0,msg->type() == SS7MsgISUP::CCR);
5099 	    m_calls.append(call);
5100 	    break;
5101 	}
5102 	// Congestion: send REL
5103 	SS7MsgISUP* m = new SS7MsgISUP(SS7MsgISUP::REL,msg->cic());
5104 	m->params().addParam("CauseIndicators","congestion");
5105 	transmitMessage(m,label,true);
5106 	DROP_MSG("can't reserve circuit")
5107 	#undef DROP_MSG
5108     }
5109     if (!reason) {
5110 	msg->ref();
5111 	call->enqueue(msg);
5112     }
5113     else {
5114 	if (msg->type() != SS7MsgISUP::IAM && msg->type() != SS7MsgISUP::RLC)
5115 	    transmitRLC(this,msg->cic(),label,true);
5116 	if (msg->type() != SS7MsgISUP::RLC)
5117 	    Debug(this,DebugNote,"'%s' with cic=%u: %s",msg->name(),msg->cic(),reason);
5118     }
5119 }
5120 
getRangeAndStatus(NamedList & nl,unsigned int minRange,unsigned int maxRange,unsigned int maxMap=0,String ** map=0,unsigned int nCicsMax=0)5121 unsigned int getRangeAndStatus(NamedList& nl, unsigned int minRange, unsigned int maxRange,
5122     unsigned int maxMap = 0, String** map = 0, unsigned int nCicsMax = 0)
5123 {
5124     unsigned int range = nl.getIntValue(YSTRING("RangeAndStatus"));
5125     if (range < minRange || range > maxRange)
5126 	return 0;
5127     if (!maxMap)
5128 	return range;
5129     NamedString* ns = nl.getParam(YSTRING("RangeAndStatus.map"));
5130     if (!ns || ns->length() > maxMap || ns->length() < range)
5131 	return 0;
5132     if (map) {
5133 	if (nCicsMax) {
5134 	    // Check the number of bits set to 1 (circuits affected)
5135 	    for (unsigned int i = 0; i < ns->length(); i++) {
5136 		if ((*ns)[i] != '1')
5137 		    continue;
5138 		if (!nCicsMax)
5139                    return 0;
5140 		nCicsMax--;
5141            }
5142 	}
5143 	*map = ns;
5144     }
5145     return range;
5146 }
5147 
5148 // Retrieve maintenance/hwfail type indicator
5149 // Return false if invalid
getGrpTypeInd(SS7ISUP * isup,SS7MsgISUP * msg,bool & hwFail,NamedString ** ns=0)5150 static bool getGrpTypeInd(SS7ISUP* isup, SS7MsgISUP* msg, bool& hwFail, NamedString** ns = 0)
5151 {
5152     if (!msg)
5153 	return false;
5154     NamedString* s = msg->params().getParam(YSTRING("GroupSupervisionTypeIndicator"));
5155     if (s) {
5156 	if (ns)
5157 	    *ns = s;
5158 	hwFail = (*s == YSTRING("hw-failure"));
5159 	if (hwFail || (*s == YSTRING("maintenance")))
5160 	    return true;
5161     }
5162     Debug(isup,DebugNote,"%s with unknown/unsupported GroupSupervisionTypeIndicator=%s [%p]",
5163 	msg->name(),TelEngine::c_safe(s),isup);
5164     return false;
5165 }
5166 
5167 // Utility: set invalid-ie reason and diagnostic
setInvalidIE(unsigned char ie,const char * & reason,String & diagnostic)5168 static inline void setInvalidIE(unsigned char ie, const char*& reason, String& diagnostic)
5169 {
5170     reason = "invalid-ie";
5171     diagnostic.hexify(&ie,1);
5172 }
5173 
5174 // Process controller related messages
5175 // Q.764 2.1.12: stop waiting for SGM if message is not: COT,BLK,BLA,UBL,UBA,CGB,CGA,CGU,CUA,CQM,CQR
processControllerMsg(SS7MsgISUP * msg,const SS7Label & label,int sls)5176 void SS7ISUP::processControllerMsg(SS7MsgISUP* msg, const SS7Label& label, int sls)
5177 {
5178     const char* reason = 0;
5179     String diagnostic;
5180     bool impl = true;
5181     bool stopSGM = false;
5182 
5183     // TODO: Check if segmentation should stop for all affected circuits received withing range (CGB,GRS, ...)
5184 
5185     switch (msg->type()) {
5186 	case SS7MsgISUP::CNF: // Confusion
5187 	    // TODO: check if this message was received in response to RSC, UBL, UBK, CGB, CGU
5188 	    Debug(this,DebugNote,"%s with cic=%u cause='%s' diagnostic='%s'",
5189 		msg->name(),msg->cic(),
5190 		msg->params().getValue(YSTRING("CauseIndicators")),
5191 		msg->params().getValue(YSTRING("CauseIndicators.diagnostic")));
5192 	    stopSGM = true;
5193 	    break;
5194 	case SS7MsgISUP::RLC: // Release Complete
5195 	    // Response to RSC: reset local lock flags. Release m_rscCic
5196 	    resetCircuit(msg->cic(),false,false);
5197 	    break;
5198 	case SS7MsgISUP::RSC: // Reset Circuit
5199 	    if (resetCircuit(msg->cic(),true,true)) {
5200 		// Send BLK on previously blocked cic: Q.764 2.9.3.1 c)
5201 		lock();
5202 		SignallingCircuit* cic = circuits() ? circuits()->find(msg->cic()) : 0;
5203 		SS7MsgISUP* m = 0;
5204 		if (cic && cic->locked(SignallingCircuit::LockLocalMaint) &&
5205 		    !cic->locked(SignallingCircuit::LockingMaint))
5206 		    m = buildCicBlock(cic,true,true);
5207 		unlock();
5208 		if (m)
5209 		    transmitMessage(m,label,true);
5210 		transmitRLC(this,msg->cic(),label,true);
5211 	    }
5212 	    else
5213 		reason = "unknown-channel";
5214 	    stopSGM = true;
5215 	    break;
5216 	case SS7MsgISUP::GRS: // Circuit Group Reset
5217 	    stopSGM = true;
5218 	    {
5219 		// Q.763 3.43 min=1 max=31
5220 		unsigned int n = getRangeAndStatus(msg->params(),1,31);
5221 		if (!n) {
5222 		    Debug(this,DebugNote,"%s with invalid range %s",msg->name(),
5223 			msg->params().getValue(YSTRING("RangeAndStatus")));
5224 		    break;
5225 		}
5226 		else if (n == 1 && m_ignoreGRSSingle) {
5227 		    Debug(this,DebugAll,"Ignoring %s with range 1",msg->name());
5228 		    break;
5229 		}
5230 		String map('0',n);
5231 		char* d = (char*)map.c_str();
5232 		for (unsigned int i = 0; i < n; i++)
5233 		    if (!resetCircuit(msg->cic()+i,true,true))
5234 			d[i] = '1';
5235 		SS7MsgISUP* m = new SS7MsgISUP(SS7MsgISUP::GRA,msg->cic());
5236 		m->params().addParam("RangeAndStatus",String(n));
5237 		m->params().addParam("RangeAndStatus.map",map);
5238 		transmitMessage(m,label,true);
5239 	    }
5240 	    break;
5241 	case SS7MsgISUP::UBL: // Unblocking
5242 	    if (blockCircuit(msg->cic(),false,true,false,true,true))
5243 		transmitMessage(new SS7MsgISUP(SS7MsgISUP::UBA,msg->cic()),label,true);
5244 	    else
5245 		reason = "unknown-channel";
5246 	    break;
5247 	case SS7MsgISUP::BLK: // Blocking
5248 	    if (blockCircuit(msg->cic(),true,true,false,true,true)) {
5249 		transmitMessage(new SS7MsgISUP(SS7MsgISUP::BLA,msg->cic()),label,true);
5250 		// Replace circuit for outgoing call in initial state
5251 		replaceCircuit(msg->cic(),String('1'));
5252 	    }
5253 	    else
5254 		reason = "unknown-channel";
5255 	    break;
5256 	case SS7MsgISUP::UBA: // Unblocking Acknowledgement
5257 	case SS7MsgISUP::BLA: // Blocking Acknowledgement
5258 	    {
5259 		bool block = (msg->type() == SS7MsgISUP::BLA);
5260 		SS7MsgISUP::Type type = block ? SS7MsgISUP::BLK : SS7MsgISUP::UBL;
5261 		SignallingMessageTimer* t = findPendingMessage(type,msg->cic(),true);
5262 		if (t) {
5263 		    SS7MsgISUP* m = static_cast<SS7MsgISUP*>(t->message());
5264 		    bool hw = m && m->params().getBoolValue(YSTRING("isup_pending_block_hwfail"));
5265 		    DDebug(this,m ? DebugAll : DebugNote,"%s confirmed for pending cic=%u",
5266 			  block ? "BLK" : "UBL",msg->cic());
5267 		    TelEngine::destruct(t);
5268 		    blockCircuit(msg->cic(),block,false,hw,true,false,true);
5269 		    sendLocalLock();
5270 		}
5271 		else
5272 		    reason = "wrong-state-message";
5273 	    }
5274 	    break;
5275 	case SS7MsgISUP::CGA: // Circuit Group Blocking Acknowledgement
5276 	case SS7MsgISUP::CUA: // Circuit Group Unblocking Acknowledgement
5277 	    // Q.763 3.43 range can be 1..256. Max bits set to 1 should be 32
5278 	    // Bit: 0-no indication 1-block/unblock
5279 	    {
5280 		bool hwFail = false;
5281 		NamedString* grpSuperType = 0;
5282 		if (!getGrpTypeInd(this,msg,hwFail,&grpSuperType))
5283 		    break;
5284 		String* srcMap = 0;
5285 		unsigned int nCics = getRangeAndStatus(msg->params(),1,256,256,&srcMap,32);
5286 		if (!nCics) {
5287 		    Debug(this,DebugNote,"%s (%s) cic=%u with invalid range %s or map=%s",
5288 			msg->name(),grpSuperType->c_str(),msg->cic(),
5289 			msg->params().getValue(YSTRING("RangeAndStatus")),
5290 			msg->params().getValue(YSTRING("RangeAndStatus.map")));
5291 		    break;
5292 		}
5293 		bool block = (msg->type() == SS7MsgISUP::CGA);
5294 		lock();
5295 		// Check for correct response: same msg type, circuit code, type indicator, circuit map
5296 		SS7MsgISUP::Type type = block ? SS7MsgISUP::CGB : SS7MsgISUP::CGU;
5297 		SignallingMessageTimer* t = findPendingMessage(type,msg->cic(),
5298 		    grpSuperType->name(),*grpSuperType);
5299 		if (!t) {
5300 		    Debug(this,DebugNote,"%s (%s) cic=%u: no request for it in our queue",
5301 			msg->name(),grpSuperType->c_str(),msg->cic());
5302 		    unlock();
5303 		    break;
5304 		}
5305 		SS7MsgISUP* m = static_cast<SS7MsgISUP*>(t->message());
5306 		String map;
5307 		while (m) {
5308 		    // Check map
5309 		    map = m->params()[YSTRING("RangeAndStatus.map")];
5310 		    if (!map)
5311 			break;
5312 		    if (map.length() != nCics) {
5313 			map.clear();
5314 			break;
5315 		    }
5316 		    for (unsigned int i = 0; i < map.length(); i++)
5317 			if (map[i] == '0' && (*srcMap)[i] != '0') {
5318 			    map.clear();
5319 			    break;
5320 			}
5321 		    break;
5322 		}
5323 		if (map) {
5324 		    DDebug(this,DebugAll,"%s (%s) confirmed for pending cic=%u",
5325 			m->name(),grpSuperType->c_str(),msg->cic());
5326 		    m_pending.remove(t);
5327 		}
5328 		unlock();
5329 		if (!map) {
5330 		    Debug(this,DebugNote,"%s (%s) cic=%u with unnacceptable range %s or map=%s",
5331 			msg->name(),grpSuperType->c_str(),msg->cic(),
5332 			msg->params().getValue(YSTRING("RangeAndStatus")),
5333 			msg->params().getValue(YSTRING("RangeAndStatus.map")));
5334 		    break;
5335 		}
5336 		for (unsigned int i = 0; i < map.length(); i++)
5337 		    if (map[i] != '0')
5338 			blockCircuit(msg->cic()+i,block,false,hwFail,true,false,true);
5339 		sendLocalLock();
5340 	    }
5341 	    break;
5342 	case SS7MsgISUP::CGB: // Circuit Group Blocking
5343 	case SS7MsgISUP::CGU: // Circuit Group Unblocking
5344 	    // Q.763 3.43 range can be 1..256. Max bits set to 1 should be 32
5345 	    // Bit: 0-no indication 1-block/unblock
5346 	    {
5347 		bool hwFail = false;
5348 		if (!getGrpTypeInd(this,msg,hwFail))
5349 		    break;
5350 	        bool block = (msg->type() == SS7MsgISUP::CGB);
5351 		String* srcMap = 0;
5352 		unsigned int nCics = getRangeAndStatus(msg->params(),1,256,256,&srcMap,32);
5353 		if (!nCics) {
5354 		    Debug(this,DebugNote,"%s with invalid range %s or map=%s",msg->name(),
5355 			msg->params().getValue(YSTRING("RangeAndStatus")),
5356 			msg->params().getValue(YSTRING("RangeAndStatus.map")));
5357 		    break;
5358 		}
5359 		else if (nCics == 1 && ((block && m_ignoreCGBSingle) || (!block && m_ignoreCGUSingle))) {
5360 		    Debug(this,DebugAll,"Ignoring %s with range 1",msg->name());
5361 		    break;
5362 		}
5363 		String map('0',srcMap->length());
5364 		char* d = (char*)map.c_str();
5365 		for (unsigned int i = 0; i < srcMap->length(); i++)
5366 		    if (srcMap->at(i) != '0' && blockCircuit(msg->cic()+i,block,true,hwFail,true,true))
5367 			d[i] = '1';
5368 		SS7MsgISUP* m = new SS7MsgISUP(block?SS7MsgISUP::CGA:SS7MsgISUP::CUA,msg->cic());
5369 		m->params().copyParam(msg->params(),"GroupSupervisionTypeIndicator");
5370 		m->params().addParam("RangeAndStatus",String(nCics));
5371 		m->params().addParam("RangeAndStatus.map",map);
5372 		transmitMessage(m,label,true);
5373 		// Replace circuits for outgoing calls in initial state
5374 		// Terminate all others when blocking for hw failure
5375 		if (block) {
5376 		    if (hwFail)
5377 			cicHwBlocked(msg->cic(),map);
5378 		    else
5379 			replaceCircuit(msg->cic(),map);
5380 		}
5381 	    }
5382 	    break;
5383 	case SS7MsgISUP::UEC: // Unequipped CIC (national use)
5384 	    Debug(this,DebugWarn,"%s for cic=%u. Circuit is unequipped on remote side",
5385 		msg->name(),msg->cic());
5386 	    blockCircuit(msg->cic(),true,true,false,true,true);
5387 	    break;
5388 	case SS7MsgISUP::UPT: // User Part Test
5389 	    transmitMessage(new SS7MsgISUP(SS7MsgISUP::UPA,msg->cic()),label,true);
5390 	    break;
5391 	case SS7MsgISUP::UPA: // User Part Available
5392 	    if (m_uptCicCode && m_uptCicCode == msg->cic()) {
5393 		DDebug(this,DebugInfo,"Received valid %s",msg->name());
5394 		m_uptCicCode = 0;
5395 	    }
5396 #ifdef DEBUG
5397 	    else
5398 		Debug(this,DebugMild,"Received unexpected %s",msg->name());
5399 #endif
5400 	    break;
5401 	case SS7MsgISUP::GRA: // Circuit Group Reset Acknowledgement
5402 	    // TODO: stop receiving segments
5403 	    reason = "wrong-state-message";
5404 	    break;
5405 	case SS7MsgISUP::CVT: // Circuit Validation Test (ANSI)
5406 	    if (circuits() && circuits()->find(msg->cic())) {
5407 		SS7MsgISUP* m = new SS7MsgISUP(SS7MsgISUP::CVR,msg->cic());
5408 		m->params().addParam("CircuitValidationRespIndicator","success");
5409 		transmitMessage(m,label,true);
5410 	    }
5411 	    else
5412 		reason = "unknown-channel";
5413 	    break;
5414 	case SS7MsgISUP::CQM: // Circuit Group Query (national use)
5415 	    if (circuits()) {
5416 		// Q.763 3.43 min=1 max=31
5417 		unsigned int n = getRangeAndStatus(msg->params(),1,31);
5418 		if (!n) {
5419 		    reason = "invalid-ie";
5420 		    break;
5421 		}
5422 		DataBlock si(0,n);
5423 		for (unsigned int i = 0; i < n; i++) {
5424 		    unsigned char* state = si.data(i);
5425 		    if (!state)
5426 			break;
5427 		    SignallingCircuit* circuit = circuits()->find(msg->cic()+i);
5428 		    if (circuit && (circuit->status() != SignallingCircuit::Missing)) {
5429 			switch (circuit->locked(SignallingCircuit::LockLocalMaint | SignallingCircuit::LockRemoteMaint)) {
5430 			    case SignallingCircuit::LockLocalMaint:
5431 				*state = 0x01; // locally maint blocked
5432 				break;
5433 			    case SignallingCircuit::LockRemoteMaint:
5434 				*state = 0x02; // remote maint blocked
5435 				break;
5436 			    case SignallingCircuit::LockLocalMaint | SignallingCircuit::LockRemoteMaint:
5437 				*state = 0x03; // locally and remote maint blocked
5438 				break;
5439 			}
5440 			switch (circuit->locked(SignallingCircuit::LockLocalHWFail | SignallingCircuit::LockRemoteHWFail)) {
5441 			    case SignallingCircuit::LockLocalHWFail:
5442 				*state |= 0x1c; // locally hw blocked
5443 				continue;
5444 			    case SignallingCircuit::LockRemoteHWFail:
5445 				*state |= 0x2c; // locally hw blocked
5446 				continue;
5447 			    case SignallingCircuit::LockLocalHWFail | SignallingCircuit::LockRemoteHWFail:
5448 				*state |= 0x3c; // locally and remotely hw blocked
5449 				continue;
5450 			}
5451 			if (circuit->connected())
5452 			    *state |= 0x04; // incoming busy
5453 			else if (!circuit->available())
5454 			    *state |= 0x08; // outgoing busy
5455 			else
5456 			    *state |= 0x0c; // idle
5457 		    }
5458 		    else
5459 			*state = 0x03; // Unequipped
5460 		}
5461 		String tmp;
5462 		tmp.hexify(si.data(),si.length(),' ');
5463 		DDebug(this,DebugInfo,"Sending CQR (%u+%u): %s",msg->cic(),n,tmp.c_str());
5464 		SS7MsgISUP* m = new SS7MsgISUP(SS7MsgISUP::CQR,msg->cic());
5465 		m->params().addParam("RangeAndStatus",String(n));
5466 		m->params().addParam("CircuitStateIndicator",tmp);
5467 		transmitMessage(m,label,true);
5468 	    }
5469 	    else
5470 		reason = "unknown-channel";
5471 	    break;
5472 	case SS7MsgISUP::CQR: // Circuit Group Query Response (national use)
5473 	case SS7MsgISUP::CVR: // Circuit Validation Response (ANSI)
5474 	case SS7MsgISUP::LPA: // Loopback Acknowledge (national use)
5475 	    // Known but not implemented responses, just ignore them
5476 	    impl = false;
5477 	    break;
5478 	default:
5479 	    impl = false;
5480 	    // Q.764 2.9.5.1: call in Setup state:
5481 	    // incoming: drop it and reset cic
5482 	    // outgoing: repeat IAM and reset cic
5483 	    lock();
5484 	    SS7ISUPCall* call = findCall(msg->cic());
5485 	    if (call)
5486 		call->ref();
5487 	    unlock();
5488 	    if (m_dropOnUnknown && call && call->earlyState() && msg->type() != SS7MsgISUP::CRG) {
5489 		Debug(this,DebugNote,
5490 		    "Received unexpected message for call %u (%p) in initial state",
5491 		    msg->cic(),call);
5492 		if (call->outgoing())
5493 		    replaceCircuit(msg->cic(),String("1"),false);
5494 		else {
5495 		    call->setTerminate(false,"normal",0,m_location);
5496 		    SignallingCircuit* c = call->m_circuit;
5497 		    if (c && c->ref())
5498 			startCircuitReset(c,String::empty());
5499 		}
5500 	    }
5501 	    else {
5502 		bool cnf = false;
5503 		bool release = false;
5504 		getMsgCompat(msg,release,cnf);
5505 		if (cnf || release) {
5506 		    reason = "unknown-message";
5507 		    unsigned char type = msg->type();
5508 		    diagnostic.hexify(&type,1);
5509 		    if (release) {
5510 			if (call)
5511 			    call->setTerminate(true,reason,diagnostic,m_location);
5512 			else
5513 			    transmitRLC(this,msg->cic(),label,true,reason,diagnostic,m_location);
5514 			// Avoid sending CNF
5515 			reason = 0;
5516 		    }
5517 		}
5518 	    }
5519 	    TelEngine::destruct(call);
5520     }
5521     if (stopSGM) {
5522 	RefPointer<SS7ISUPCall> call;
5523 	findCall(msg->cic(),call);
5524 	if (call)
5525 	    call->stopWaitSegment(false);
5526 	call = 0;
5527     }
5528     if (reason || !impl) {
5529 	Debug(this,impl?DebugNote:DebugStub,"'%s' with cic=%u: %s",
5530 	    msg->name(),msg->cic(),(reason ? reason : "Not implemented, ignoring"));
5531 	if (reason)
5532 	    transmitCNF(this,msg->cic(),label,true,reason,diagnostic);
5533     }
5534 }
5535 
5536 // Replace a call's circuit if checkCall is true
5537 // Release currently reseting circuit if the code match
5538 // Clear lock flags
5539 // See Q.764 2.9.3.1
resetCircuit(unsigned int cic,bool remote,bool checkCall)5540 bool SS7ISUP::resetCircuit(unsigned int cic, bool remote, bool checkCall)
5541 {
5542     SignallingCircuit* circuit = circuits() ? circuits()->find(cic) : 0;
5543     if (!circuit)
5544 	return false;
5545     DDebug(this,DebugAll,"Reseting circuit %u",cic);
5546     if (checkCall) {
5547 	RefPointer<SS7ISUPCall> call;
5548 	findCall(cic,call);
5549 	if (call) {
5550 	    if (call->outgoing() && call->state() == SS7ISUPCall::Setup) {
5551 	        SignallingCircuit* newCircuit = 0;
5552 		reserveCircuit(newCircuit,call->cicRange(),SignallingCircuit::LockLockedBusy);
5553 		call->replaceCircuit(newCircuit);
5554 	    }
5555 	    else
5556 		call->setTerminate(false,"normal");
5557 	}
5558     }
5559     // Remove remote lock flags (Q.764 2.9.3.1)
5560     if (remote && circuit->locked(SignallingCircuit::LockRemote)) {
5561 	Debug(this,DebugNote,"Unblocking remote circuit %u on reset request",cic);
5562 	circuit->hwLock(false,true,0!=circuit->locked(SignallingCircuit::LockRemoteHWFail),false);
5563 	circuit->maintLock(false,true,0!=circuit->locked(SignallingCircuit::LockRemoteMaint),false);
5564 	m_verifyEvent = true;
5565     }
5566     // Remove pending RSC/REL. Reset 'Resetting' flag'
5567     SignallingMessageTimer* m = findPendingMessage(SS7MsgISUP::RSC,cic,true);
5568     if (!m)
5569 	m = findPendingMessage(SS7MsgISUP::REL,cic,true);
5570     if (m) {
5571 	Debug(this,DebugAll,"Pending %s`cic=%u removed",m->message()->name(),cic);
5572 	TelEngine::destruct(m);
5573     }
5574     circuit->resetLock(SignallingCircuit::Resetting);
5575     if (m_rscCic && m_rscCic->code() == cic)
5576 	releaseCircuit(m_rscCic);
5577     else
5578 	circuit->status(SignallingCircuit::Idle);
5579     return true;
5580 }
5581 
5582 // Block/unblock a circuit
5583 // See Q.764 2.8.2
blockCircuit(unsigned int cic,bool block,bool remote,bool hwFail,bool changed,bool changedState,bool resetLocking)5584 bool SS7ISUP::blockCircuit(unsigned int cic, bool block, bool remote, bool hwFail,
5585 	bool changed, bool changedState, bool resetLocking)
5586 {
5587     XDebug(this,DebugAll,"blockCircuit(%u,%u,%u,%u,%u,%u,%u)",
5588 	cic,block,remote,hwFail,changed,changedState,resetLocking);
5589     SignallingCircuit* circuit = circuits() ? circuits()->find(cic) : 0;
5590     if (!circuit)
5591 	return false;
5592 
5593     bool something = false;
5594     if (hwFail)
5595 	something = circuit->hwLock(block,remote,changed,changedState);
5596     else
5597 	something = circuit->maintLock(block,remote,changed,changedState);
5598     if (resetLocking && !remote)
5599 	circuit->resetLock(hwFail ? SignallingCircuit::LockingHWFail : SignallingCircuit::LockingMaint);
5600 
5601     if (something) {
5602 	Debug(this,DebugNote,"%s %s side of circuit %u. Current flags 0x%x",
5603 	    (block ? "Blocked" : "Unblocked"),
5604 	    (remote ? "remote" : "local"),
5605 	    cic,circuit->locked(-1));
5606 	m_verifyEvent = true;
5607     }
5608     return true;
5609 }
5610 
findCall(unsigned int cic)5611 SS7ISUPCall* SS7ISUP::findCall(unsigned int cic)
5612 {
5613     for (ObjList* o = m_calls.skipNull(); o; o = o->skipNext()) {
5614 	SS7ISUPCall* call = static_cast<SS7ISUPCall*>(o->get());
5615 	if (call->id() == cic)
5616 	    return call;
5617     }
5618     return 0;
5619 }
5620 
5621 // Utility used in sendLocalLock()
5622 // Check if a circuit has lock change flag set and can be locked (not busy)
canLock(SignallingCircuit * cic,bool hw)5623 static inline bool canLock(SignallingCircuit* cic, bool hw)
5624 {
5625     if (hw)
5626 	return cic->locked(SignallingCircuit::LockLocalHWFailChg) &&
5627             !cic->locked(SignallingCircuit::LockingHWFail | SignallingCircuit::Resetting);
5628     return cic->locked(SignallingCircuit::LockLocalMaintChg) &&
5629 	!cic->locked(SignallingCircuit::LockingMaint | SignallingCircuit::Resetting);
5630 }
5631 
5632 // Utility: check if a circuit needs lock and not currently locking
checkNeedLock(SignallingCircuit * cic,bool & needLock)5633 static inline void checkNeedLock(SignallingCircuit* cic, bool& needLock)
5634 {
5635     if (needLock)
5636 	return;
5637     needLock = cic->locked(SignallingCircuit::LockLocalChg) &&
5638         !cic->locked(SignallingCircuit::LockingHWFail | SignallingCircuit::LockingMaint);
5639 }
5640 
5641 // Send blocking/unblocking messages
5642 // Return false if no request was sent
sendLocalLock(const Time & when)5643 bool SS7ISUP::sendLocalLock(const Time& when)
5644 {
5645     Lock lock(this);
5646     if (!circuits())
5647 	return false;
5648     bool needLock = false;
5649     ObjList msgs;
5650     while (true) {
5651 	bool hwReq = false;
5652 	bool lockReq = false;
5653 	unsigned int code = 0;
5654 	int locking = 0;
5655 	// Peek a starting circuit whose local state changed
5656 	ObjList* o = circuits()->circuits().skipNull();
5657 	SignallingCircuitSpan* span = 0;
5658 	for (; o; o = o->skipNext()) {
5659 	    SignallingCircuit* cic = static_cast<SignallingCircuit*>(o->get());
5660 	    if (canLock(cic,true)) {
5661 		hwReq = true;
5662 		lockReq = (0 != cic->locked(SignallingCircuit::LockLocalHWFail));
5663 		locking = SignallingCircuit::LockingHWFail;
5664 	    }
5665 	    else if (canLock(cic,false)) {
5666 		hwReq = false;
5667 		lockReq = (0 != cic->locked(SignallingCircuit::LockLocalMaint));
5668 		locking = SignallingCircuit::LockingMaint;
5669 	    }
5670 	    else {
5671 		checkNeedLock(cic,needLock);
5672 		continue;
5673 	    }
5674 	    code = cic->code();
5675 	    span = cic->span();
5676 	    cic->setLock(locking);
5677 	    o = o->skipNext();
5678 	    break;
5679 	}
5680 	if (!code)
5681 	    break;
5682 	// If remote doesn't support group block/unblock just send BLK/UBL
5683 	if (!m_lockGroup)
5684 	    o = 0;
5685 	// Check if we can pick a range of circuits within the same span
5686 	//  with the same operation to do
5687 	// Q.763 3.43: range can be 2..256. Bit: 0-no indication 1-block/unblock.
5688 	// Max bits set to 1 must be 32
5689 	char d[256];
5690 	d[0] = '1';
5691 	unsigned int cics = 1;
5692 	unsigned int lockRange = 1;
5693 	ObjList* cicPos = o;
5694 	int newRange = 0;
5695 	int flag = hwReq ? SignallingCircuit::LockLocalHWFail : SignallingCircuit::LockLocalMaint;
5696 	for (; o && cics < 32 && lockRange < 256; o = o->skipNext()) {
5697 	    SignallingCircuit* cic = static_cast<SignallingCircuit*>(o->get());
5698 	    // Presume all circuits belonging to the same span to follow each other in the list
5699 	    if (span != cic->span())
5700 		break;
5701 	    // Make sure the circuit codes are sequential
5702 	    if ((code + lockRange) != cic->code()) {
5703 		if (!newRange)
5704 		    newRange = checkValidRange(code,cic->code());
5705 		checkNeedLock(cic,needLock);
5706 		continue;
5707 	    }
5708 	    // Add circuit to map. Skip busy circuits
5709 	    // Circuit must have the same lock type and flags as the base circuit's
5710 	    if (canLock(cic,hwReq) && (lockReq == (0 != cic->locked(flag)))) {
5711 		cic->setLock(locking);
5712 		d[lockRange] = '1';
5713 		cics++;
5714 	    }
5715 	    else {
5716 		checkNeedLock(cic,needLock);
5717 		d[lockRange] = '0';
5718 	    }
5719 	    lockRange++;
5720 	}
5721 	if (cics == 1) {
5722 	    if (lockRange > 1) {
5723 		// Shorten the range: be nice to remote party, no need to check the whole map
5724 		if (hwReq)
5725 		    lockRange = 2;
5726 		else
5727 		    lockRange = 1;
5728 	    }
5729 	    else if (m_lockGroup && hwReq) {
5730 		if (!newRange) {
5731 		    // Bad luck: check for a code before the circuit
5732 		    for (o = circuits()->circuits().skipNull(); o && o != cicPos; o = o->skipNext()) {
5733 			SignallingCircuit* cic = static_cast<SignallingCircuit*>(o->get());
5734 			if (span != cic->span())
5735 			    continue;
5736 			newRange = checkValidRange(code,cic->code());
5737 			if (newRange)
5738 			    break;
5739 		    }
5740 		}
5741 		if (newRange)
5742 		    adjustRangeAndStatus(d,code,lockRange,newRange);
5743 		else
5744 		    Debug(this,DebugNote,
5745 			"Failed to pick a second circuit to group HW %sblock cic=%u [%p]",
5746 			lockReq ? "" : "un",code,this);
5747 	    }
5748 	}
5749 	else {
5750 	    // Shorten range
5751 	    unsigned int last = lockRange;
5752 	    while (d[--last] == '0')
5753 		lockRange--;
5754 	}
5755 	// Build and send the message
5756 	// Don't send individual circuit blocking for HW failure (they are supposed
5757 	//  to be sent for maintenance reason)
5758 	String map(d,lockRange);
5759 	SS7MsgISUP* msg = 0;
5760 	SignallingMessageTimer* t = 0;
5761 	if (m_lockGroup && (map.length() > 1 || hwReq)) {
5762 	    msg = new SS7MsgISUP((lockReq ? SS7MsgISUP::CGB : SS7MsgISUP::CGU),code);
5763 	    msg->params().addParam("GroupSupervisionTypeIndicator",
5764 		(hwReq ? "hw-failure" : "maintenance"));
5765 	    msg->params().addParam("RangeAndStatus",String(map.length()));
5766 	    msg->params().addParam("RangeAndStatus.map",map);
5767 	    if (lockReq)
5768 		t = new SignallingMessageTimer(m_t18Interval,m_t19Interval);
5769 	    else
5770 		t = new SignallingMessageTimer(m_t20Interval,m_t21Interval);
5771 	}
5772 	else {
5773 	    msg = new SS7MsgISUP(lockReq ? SS7MsgISUP::BLK : SS7MsgISUP::UBL,code);
5774 	    // Remember HW/maintenance flag
5775 	    if (hwReq)
5776 		msg->params().addParam("isup_pending_block_hwfail",String::boolText(true));
5777 	    if (lockReq)
5778 		t = new SignallingMessageTimer(m_t12Interval,m_t13Interval);
5779 	    else
5780 		t = new SignallingMessageTimer(m_t14Interval,m_t15Interval);
5781 	}
5782 	t->message(msg);
5783 	m_pending.add(t);
5784 	msg->ref();
5785 	msgs.append(msg)->setDelete(false);
5786     }
5787     // Restart timer if we still have cics needing lock
5788     DDebug(this,DebugAll,"%s circuit locking timer",needLock ? "Starting" : "Stopping");
5789     if (needLock)
5790 	m_lockTimer.start(when.msec());
5791     else
5792 	m_lockTimer.stop();
5793     lock.drop();
5794     return transmitMessages(msgs);
5795 }
5796 
5797 // Fill label from local/remote point codes
setLabel(SS7Label & label,unsigned int cic)5798 bool SS7ISUP::setLabel(SS7Label& label, unsigned int cic)
5799 {
5800     Lock lock(this);
5801     if (!(m_remotePoint && m_defPoint))
5802 	return false;
5803     label.assign(m_type,*m_remotePoint,*m_defPoint,
5804 	(m_defaultSls == SlsCircuit) ? cic : m_sls);
5805     return true;
5806 }
5807 
5808 // Retrieve a pending message
findPendingMessage(SS7MsgISUP::Type type,unsigned int cic,bool remove)5809 SignallingMessageTimer* SS7ISUP::findPendingMessage(SS7MsgISUP::Type type, unsigned int cic,
5810     bool remove)
5811 {
5812     Lock lock(this);
5813     for (ObjList* o = m_pending.skipNull(); o; o = o->skipNext()) {
5814 	SignallingMessageTimer* m = static_cast<SignallingMessageTimer*>(o->get());
5815 	SS7MsgISUP* msg = static_cast<SS7MsgISUP*>(m->message());
5816 	if (msg && msg->type() == type && msg->cic() == cic) {
5817 	    if (remove)
5818 		o->remove(false);
5819 	    return m;
5820 	}
5821     }
5822     return 0;
5823 }
5824 
5825 // Retrieve a pending message with given parameter
findPendingMessage(SS7MsgISUP::Type type,unsigned int cic,const String & param,const String & value,bool remove)5826 SignallingMessageTimer* SS7ISUP::findPendingMessage(SS7MsgISUP::Type type, unsigned int cic,
5827     const String& param, const String& value, bool remove)
5828 {
5829     Lock lock(this);
5830     for (ObjList* o = m_pending.skipNull(); o; o = o->skipNext()) {
5831 	SignallingMessageTimer* m = static_cast<SignallingMessageTimer*>(o->get());
5832 	SS7MsgISUP* msg = static_cast<SS7MsgISUP*>(m->message());
5833 	if (msg && msg->type() == type && msg->cic() == cic && msg->params()[param] == value) {
5834 	    if (remove)
5835 		o->remove(false);
5836 	    return m;
5837 	}
5838     }
5839     return 0;
5840 }
5841 
5842 // Transmit a list of messages. Return true if at least 1 message was sent
transmitMessages(ObjList & list)5843 bool SS7ISUP::transmitMessages(ObjList& list)
5844 {
5845     ObjList* o = list.skipNull();
5846     if (!o)
5847 	return false;
5848     for (; o; o = o->skipNext()) {
5849 	SS7MsgISUP* msg = static_cast<SS7MsgISUP*>(o->get());
5850     	SS7Label label;
5851 	setLabel(label,msg->cic());
5852 	if (m_duplicateCGB && (msg->type() == SS7MsgISUP::CGB)) {
5853 	    // ANSI needs the CGB duplicated
5854 	    msg->ref();
5855 	    transmitMessage(msg,label,false);
5856 	}
5857 	transmitMessage(msg,label,false);
5858     }
5859     return true;
5860 }
5861 
5862 // Utility: check if a circuit exists and can be start an (un)block operation
checkBlockCic(SignallingCircuit * cic,bool block,bool maint,bool force)5863 static const char* checkBlockCic(SignallingCircuit* cic, bool block, bool maint,
5864     bool force)
5865 {
5866     if (!cic)
5867 	return "not found";
5868     int flg = cic->locked(maint ? SignallingCircuit::LockLocalMaint :
5869 	SignallingCircuit::LockLocalHWFail);
5870     if ((block == (0 != flg)) && !force)
5871 	return "already in the same state";
5872     flg = maint ? SignallingCircuit::LockingMaint : SignallingCircuit::LockingHWFail;
5873     if (cic->locked(flg | SignallingCircuit::Resetting) && !force)
5874 	return "busy locking or resetting";
5875     return 0;
5876 }
5877 
5878 // Handle circuit(s) (un)block command
handleCicBlockCommand(const NamedList & p,bool block)5879 bool SS7ISUP::handleCicBlockCommand(const NamedList& p, bool block)
5880 {
5881     if (!circuits())
5882 	return false;
5883     SS7MsgISUP* msg = 0;
5884     SS7MsgISUP::Type remove = SS7MsgISUP::Unknown;
5885     bool force = p.getBoolValue(YSTRING("force"));
5886     String* param = p.getParam(YSTRING("circuit"));
5887     bool remote = p.getBoolValue(YSTRING("remote"));
5888     Lock mylock(this);
5889     if (param) {
5890 	if (remote) {
5891 	    unsigned int code = param->toInteger();
5892 	    return handleCicBlockRemoteCommand(p,&code,1,block);
5893 	}
5894 	SignallingCircuit* cic = circuits()->find(param->toInteger());
5895 	msg = buildCicBlock(cic,block,force);
5896 	if (!msg)
5897 	    return false;
5898 	if (force)
5899 	    remove = block ? SS7MsgISUP::UBL : SS7MsgISUP::BLK;
5900     }
5901     else {
5902 	// NOTE: we assume the circuits belongs to the same span for local (un)block
5903 	param = p.getParam(YSTRING("circuits"));
5904 	if (TelEngine::null(param)) {
5905 	    Debug(this,DebugNote,"Circuit '%s' missing circuit(s)",
5906 		p.getValue(YSTRING("operation")));
5907 	    return false;
5908 	}
5909 	// Parse the range
5910 	unsigned int count = 0;
5911 	unsigned int* cics = SignallingUtils::parseUIntArray(*param,1,0xffffffff,count,true);
5912 	if (!cics) {
5913 	    // Allow '*' (all circuits) for remote
5914 	    if (!(remote && *param == YSTRING("*"))) {
5915 		SignallingCircuitRange* range = circuits()->findRange(*param);
5916 		if (range)
5917 		    cics = range->copyRange(count);
5918 	    }
5919 	    else {
5920 		String tmp;
5921 		circuits()->getCicList(tmp);
5922 		SignallingCircuitRange* range = new SignallingCircuitRange(tmp);
5923 		cics = range->copyRange(count);
5924 		TelEngine::destruct(range);
5925 	    }
5926 	    if (!cics) {
5927 		Debug(this,DebugNote,"Circuit group '%s': invalid circuits=%s",
5928 		    p.getValue(YSTRING("operation")),param->c_str());
5929 		return false;
5930 	    }
5931 	}
5932 	if (remote) {
5933 	    bool ok = handleCicBlockRemoteCommand(p,cics,count,block);
5934 	    delete[] cics;
5935 	    return ok;
5936 	}
5937 	if (count > 32) {
5938 	    Debug(this,DebugNote,"Circuit group '%s': too many circuits %u (max=32)",
5939 		p.getValue(YSTRING("operation")),count);
5940 	    delete[] cics;
5941 	    return false;
5942 	}
5943 	// Check if all circuits can be (un)blocked
5944 	ObjList list;
5945 	bool maint = !p.getBoolValue(YSTRING("hwfail"));
5946 	for (unsigned int i = 0; i < count; i++) {
5947 	    SignallingCircuit* c = circuits()->find(cics[i]);
5948 	    const char* reason = checkBlockCic(c,block,maint,force);
5949 	    if (reason) {
5950 		Debug(this,DebugNote,"Circuit group '%s' range=%s failed for cic=%u: %s",
5951 		    p.getValue(YSTRING("operation")),param->c_str(),cics[i],reason);
5952 		delete[] cics;
5953 		return false;
5954 	    }
5955 	    list.append(c)->setDelete(false);
5956 	}
5957 	// Retrieve the code: the lowest circuit code
5958 	unsigned int code = cics[0];
5959 	for (unsigned int i = 1; i < count; i++)
5960 	    if (cics[i] < code)
5961 		code = cics[i];
5962 	// Build the range. Fail if falling outside maximum range
5963 	char d[256];
5964 	::memset(d,'0',256);
5965 	d[0] = '1';
5966 	unsigned int lockRange = 1;
5967 	unsigned int nCics = 0;
5968 	for (; nCics < count; nCics++) {
5969 	    if (code == cics[nCics])
5970 		continue;
5971 	    unsigned int pos = cics[nCics] - code;
5972 	    if (pos > 255)
5973 		break;
5974 	    d[pos++] = '1';
5975 	    if (pos > lockRange)
5976 		lockRange = pos;
5977 	}
5978 	delete[] cics;
5979 	if (nCics != count) {
5980 	    Debug(this,DebugNote,"Circuit group '%s': invalid circuit map=%s",
5981 		p.getValue(YSTRING("operation")),param->c_str());
5982 	    return false;
5983 	}
5984 	if (nCics == 1) {
5985 	    // Try to pick another circuit for map
5986 	    SignallingCircuit* cic = static_cast<SignallingCircuit*>(list.skipNull()->get());
5987 	    int newRange = 0;
5988 	    for (ObjList* o = circuits()->circuits().skipNull(); o ; o = o->skipNext()) {
5989 		SignallingCircuit* c = static_cast<SignallingCircuit*>(o->get());
5990 		if (c->span() != cic->span() || c == cic)
5991 		    continue;
5992 		newRange = checkValidRange(cic->code(),c->code());
5993 		if (newRange)
5994 		    break;
5995 	    }
5996 	    if (!newRange) {
5997 		Debug(this,DebugNote,
5998 		    "Circuit group '%s': failed to pick another circuit to send group command",
5999 		    p.getValue(YSTRING("operation")));
6000 		return false;
6001 	    }
6002 	    adjustRangeAndStatus(d,code,lockRange,newRange);
6003 	}
6004 	// Ok: block circuits and send the request
6005 	int flg = maint ? SignallingCircuit::LockingMaint : SignallingCircuit::LockingHWFail;
6006 	for (ObjList* o = list.skipNull(); o ; o = o->skipNext()) {
6007 	    SignallingCircuit* c = static_cast<SignallingCircuit*>(o->get());
6008 	    blockCircuit(c->code(),block,false,!maint,true,true);
6009 	    c->setLock(flg);
6010 	}
6011 	String map(d,lockRange);
6012         msg = new SS7MsgISUP(block ? SS7MsgISUP::CGB : SS7MsgISUP::CGU,code);
6013 	msg->params().addParam("GroupSupervisionTypeIndicator",
6014 	    (maint ? "maintenance" : "hw-failure"));
6015 	msg->params().addParam("RangeAndStatus",String(map.length()));
6016 	msg->params().addParam("RangeAndStatus.map",map);
6017 	SignallingMessageTimer* t = 0;
6018 	if (block)
6019 	    t = new SignallingMessageTimer(m_t18Interval,m_t19Interval);
6020 	else
6021 	    t = new SignallingMessageTimer(m_t20Interval,m_t21Interval);
6022         t->message(msg);
6023 	m_pending.add(t);
6024 	msg->ref();
6025 	if (force)
6026 	    remove = block ? SS7MsgISUP::CGU : SS7MsgISUP::CGB;
6027     }
6028     if (SS7MsgISUP::Unknown != remove) {
6029 	bool removed = false;
6030 	SignallingMessageTimer* pending = 0;
6031 	if (remove != SS7MsgISUP::CGB && remove != SS7MsgISUP::CGU) {
6032 	    while (0 != (pending = findPendingMessage(remove,msg->cic(),true))) {
6033 		TelEngine::destruct(pending);
6034 		removed = true;
6035 	    }
6036 	}
6037 	else {
6038 	    NamedString* ns = msg->params().getParam(YSTRING("GroupSupervisionTypeIndicator"));
6039 	    while (ns &&
6040 		0 != (pending = findPendingMessage(remove,msg->cic(),ns->name(),*ns,true))) {
6041 		TelEngine::destruct(pending);
6042 		removed = true;
6043 	    }
6044 	}
6045 	if (removed)
6046 	    Debug(this,DebugNote,"Removed pending operation '%s' cic=%u",
6047 		SS7MsgISUP::lookup(remove),msg->cic());
6048     }
6049     SS7Label label;
6050     setLabel(label,msg->cic());
6051     mylock.drop();
6052     if (m_duplicateCGB && (msg->type() == SS7MsgISUP::CGB)) {
6053 	// ANSI needs the CGB duplicated
6054 	msg->ref();
6055 	transmitMessage(msg,label,false);
6056     }
6057     transmitMessage(msg,label,false);
6058     return true;
6059 }
6060 
6061 // Handle remote circuit(s) (un)block command
handleCicBlockRemoteCommand(const NamedList & p,unsigned int * cics,unsigned int count,bool block)6062 bool SS7ISUP::handleCicBlockRemoteCommand(const NamedList& p, unsigned int* cics,
6063     unsigned int count, bool block)
6064 {
6065     if (!(cics && count))
6066 	return false;
6067     bool hwFail = p.getBoolValue(YSTRING("hwfail"));
6068     if (debugAt(DebugNote)) {
6069 	String s;
6070 	for (unsigned int i = 0; i < count; i++)
6071 	    s.append(String(cics[i]),",");
6072 	Debug(this,DebugNote,"Circuit remote '%s' command: hwfail=%s circuits=%s [%p]",
6073 	    p.getValue(YSTRING("operation")),String::boolText(hwFail),s.c_str(),this);
6074     }
6075     bool found = false;
6076     for (unsigned int i = 0; i < count; i++) {
6077 	if (blockCircuit(cics[i],block,true,hwFail,true,true))
6078 	    found = true;
6079 	else
6080 	    Debug(this,DebugNote,"Circuit remote '%s' command: cic %u not found [%p]",
6081 		p.getValue(YSTRING("operation")),cics[i],this);
6082     }
6083     if (found)
6084 	m_verifyEvent = true;
6085     return found;
6086 }
6087 
6088 // Handle circuit(s) event generation command
handleCicEventCommand(const NamedList & p)6089 bool SS7ISUP::handleCicEventCommand(const NamedList& p)
6090 {
6091     if (!circuits())
6092 	return false;
6093     int evType = p.getIntValue(YSTRING("type"));
6094     if (evType <= 0) {
6095 	Debug(this,DebugNote,"Control '%s': invalid type '%s'",
6096 	    p.getValue(YSTRING("operation")),p.getValue(YSTRING("type")));
6097 	return false;
6098     }
6099     ObjList cics;
6100     String* param = p.getParam(YSTRING("circuit"));
6101     if (param) {
6102 	SignallingCircuit* cic = circuits()->find(param->toInteger());
6103 	if (!cic) {
6104 	    Debug(this,DebugNote,"Control '%s' circuit %s not found",
6105 		p.getValue(YSTRING("operation")),param->c_str());
6106 	    return false;
6107 	}
6108 	cics.append(cic)->setDelete(false);
6109     }
6110     else {
6111 	param = p.getParam(YSTRING("circuits"));
6112 	if (TelEngine::null(param)) {
6113 	    Debug(this,DebugNote,"Control '%s' missing circuit(s)",
6114 		p.getValue(YSTRING("operation")));
6115 	    return false;
6116 	}
6117 	// Parse the range
6118 	unsigned int count = 0;
6119 	unsigned int* cList = SignallingUtils::parseUIntArray(*param,1,0xffffffff,count,true);
6120 	if (!cList) {
6121 	    Debug(this,DebugNote,"Control '%s' invalid circuits=%s",
6122 		p.getValue(YSTRING("operation")),param->c_str());
6123 	    return false;
6124 	}
6125 	for (unsigned int i = 0; i < count; i++) {
6126 	    SignallingCircuit* cic = circuits()->find(cList[i]);
6127 	    if (cic) {
6128 		cics.append(cic)->setDelete(false);
6129 		continue;
6130 	    }
6131 	    Debug(this,DebugNote,"Control '%s' circuit %u not found",
6132 		p.getValue(YSTRING("operation")),cList[i]);
6133 	    cics.clear();
6134 	    break;
6135 	}
6136 	delete[] cList;
6137     }
6138     ObjList* o = cics.skipNull();
6139     if (!o)
6140 	return false;
6141     for (; o; o = o->skipNext()) {
6142 	SignallingCircuit* cic = static_cast<SignallingCircuit*>(o->get());
6143 	SignallingCircuitEvent* cicEvent = new SignallingCircuitEvent(cic,
6144 	    (SignallingCircuitEvent::Type)evType);
6145 	cicEvent->copyParams(p);
6146 	SignallingEvent* ev = processCircuitEvent(cicEvent,0);
6147 	TelEngine::destruct(cicEvent);
6148 	if (ev)
6149 	    delete ev;
6150     }
6151     return true;
6152 }
6153 
6154 // Try to start single circuit (un)blocking. Set a pending operation on success
6155 // @param force True to ignore resetting/(un)blocking flags of the circuit
6156 // Return built message to be sent on success
buildCicBlock(SignallingCircuit * cic,bool block,bool force)6157 SS7MsgISUP* SS7ISUP::buildCicBlock(SignallingCircuit* cic, bool block, bool force)
6158 {
6159     const char* reason = checkBlockCic(cic,block,true,force);
6160     if (reason) {
6161 	Debug(this,DebugNote,"Failed to start circuit %sblocking for %u: %s",
6162 	    block ? "" : "un",cic ? cic->code() : 0,reason);
6163 	return 0;
6164     }
6165     blockCircuit(cic->code(),block,false,false,true,true);
6166     cic->setLock(SignallingCircuit::LockingMaint);
6167     SS7MsgISUP* m = new SS7MsgISUP(block ? SS7MsgISUP::BLK : SS7MsgISUP::UBL,cic->code());
6168     SignallingMessageTimer* t = 0;
6169     if (block)
6170 	t = new SignallingMessageTimer(m_t12Interval,m_t13Interval);
6171     else
6172         t = new SignallingMessageTimer(m_t14Interval,m_t15Interval);
6173     t->message(m);
6174     m_pending.add(t);
6175     m->ref();
6176     return m;
6177 }
6178 
6179 // Replace circuit for outgoing calls in Setup state
replaceCircuit(unsigned int cic,const String & map,bool rel)6180 void SS7ISUP::replaceCircuit(unsigned int cic, const String& map, bool rel)
6181 {
6182     ObjList calls;
6183     lock();
6184     for (unsigned int i = 0; i < map.length(); i++) {
6185 	if (map[i] != '1')
6186 	    continue;
6187         // Replace circuit for call (Q.764 2.8.2.1)
6188 	SS7ISUPCall* call = findCall(cic + i);
6189 	if (call && call->outgoing() && call->state() == SS7ISUPCall::Setup &&
6190 	    call->ref())
6191 	    calls.append(call);
6192     }
6193     unlock();
6194     for (ObjList* o = calls.skipNull(); o; o = o->skipNext()) {
6195 	SS7ISUPCall* call = static_cast<SS7ISUPCall*>(o->get());
6196 	Debug(this,DebugInfo,"Replacing remotely blocked cic=%u for existing call",call->id());
6197 	SignallingCircuit* newCircuit = 0;
6198 	if (call->canReplaceCircuit())
6199 	    reserveCircuit(newCircuit,call->cicRange(),SignallingCircuit::LockLockedBusy);
6200 	if (!newCircuit) {
6201 	    call->setTerminate(rel,"congestion",0,m_location);
6202 	    if (!rel) {
6203 		SignallingCircuit* c = call->m_circuit;
6204 		if (c && c->ref())
6205 		    startCircuitReset(c,String::empty());
6206 	    }
6207 	    continue;
6208 	}
6209 	lock();
6210 	SignallingCircuit* c = circuits()->find(call->id());
6211 	SS7MsgISUP* m = 0;
6212 	if (c && !c->locked(SignallingCircuit::Resetting)) {
6213 	    c->setLock(SignallingCircuit::Resetting);
6214 	    m = new SS7MsgISUP(rel ? SS7MsgISUP::REL : SS7MsgISUP::RSC,call->id());
6215 	    if (rel) {
6216 		m->params().addParam("CauseIndicators","normal");
6217 		m->params().addParam("CauseIndicators.location",m_location,false);
6218 	    }
6219 	    m->ref();
6220 	}
6221 	unlock();
6222 	call->replaceCircuit(newCircuit,m);
6223 	if (m) {
6224 	    SignallingMessageTimer* t = 0;
6225 	    if (rel)
6226 		t = new SignallingMessageTimer(m_t1Interval,m_t5Interval);
6227 	    else
6228 		t = new SignallingMessageTimer(m_t16Interval,m_t17Interval);
6229 	    t->message(m);
6230 	    m_pending.add(t);
6231 	}
6232     }
6233 }
6234 
6235 // Handle circuit hw-fail block
6236 // Replace cics for outgoing calls. Terminate incoming
cicHwBlocked(unsigned int cic,const String & map)6237 void SS7ISUP::cicHwBlocked(unsigned int cic, const String& map)
6238 {
6239     Debug(this,DebugNote,"Circuit(s) in HW failure cic=%u map=%s",cic,map.c_str());
6240     replaceCircuit(cic,map,true);
6241     ObjList terminate;
6242     lock();
6243     for (unsigned int i = 0; i < map.length(); i++) {
6244 	if (map[i] != '1')
6245 	    continue;
6246 	SS7ISUPCall* call = findCall(cic + i);
6247 	// We've made retransmit attempt for outgoing
6248 	bool processed = !call || (call->outgoing() && call->state() == SS7ISUPCall::Setup);
6249 	if (!processed && call->ref())
6250 	    terminate.append(call);
6251     }
6252     unlock();
6253     setCallsTerminate(terminate,true,"normal",0,m_location);
6254 }
6255 
6256 
6257 /**
6258  * SS7BICC
6259  */
SS7BICC(const NamedList & params,unsigned char sio)6260 SS7BICC::SS7BICC(const NamedList& params, unsigned char sio)
6261     : SignallingComponent(params.safe("SS7BICC"),&params,"ss7-bicc"),
6262       SS7ISUP(params,sio)
6263 {
6264     m_cicLen = 4;
6265     Debug(this,DebugInfo,"BICC Call Controller [%p]",this);
6266 }
6267 
~SS7BICC()6268 SS7BICC::~SS7BICC()
6269 {
6270     cleanup();
6271     Debug(this,DebugInfo,"BICC Call Controller destroyed [%p]",this);
6272 }
6273 
receivedMSU(const SS7MSU & msu,const SS7Label & label,SS7Layer3 * network,int sls)6274 HandledMSU SS7BICC::receivedMSU(const SS7MSU& msu, const SS7Label& label, SS7Layer3* network, int sls)
6275 {
6276     if (msu.getSIF() != sif() || !hasPointCode(label.dpc()) || !handlesRemotePC(label.opc()))
6277 	return HandledMSU::Rejected;
6278     // we should have at least 4 bytes CIC and 1 byte message type
6279     const unsigned char* s = msu.getData(label.length()+1,5);
6280     if (!s)
6281 	return false;
6282     unsigned int len = msu.length()-label.length()-1;
6283     unsigned int cic = s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24);
6284     SS7MsgISUP::Type type = (SS7MsgISUP::Type)s[4];
6285     const char* name = SS7MsgISUP::lookup(type);
6286     if (name) {
6287 	bool ok = processMSU(type,cic,s+5,len-5,label,network,sls);
6288 	String tmp;
6289 	tmp.hexify((void*)s,len,' ');
6290 	Debug(this,ok ? DebugInfo : DebugMild,"Unhandled BICC type %s, cic=%u, length %u: %s",
6291 	    name,cic,len,tmp.c_str());
6292 	return ok;
6293     }
6294     String tmp;
6295     tmp.hexify((void*)s,len,' ');
6296     Debug(this,DebugMild,"Received unknown BICC type 0x%02x, cic=%u, length %u: %s",
6297 	type,cic,len,tmp.c_str());
6298     return false;
6299 }
6300 
6301 /* vi: set ts=8 sw=4 sts=4 noet: */
6302