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"),¶ms,"ss7-isup"),
3317 SignallingCallControl(params,"isup."),
3318 SS7Layer4(sio,¶ms),
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 ¶ms,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(¶ms,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(¶ms,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(¶ms,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(¶ms,true);
4157 case SS7MsgISUP::RSC:
4158 if (0 == (m_rscSpeedup = circuits() ? circuits()->count() : 0))
4159 return TelEngine::controlReturn(¶ms,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(¶ms,true);
4167 case SS7MsgISUP::BLK:
4168 case SS7MsgISUP::UBL:
4169 return TelEngine::controlReturn(¶ms,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(¶ms,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(¶ms,false);
4188 mylock.drop();
4189 call->setTerminate(true,params.getValue(YSTRING("reason"),"normal"));
4190 }
4191 }
4192 return TelEngine::controlReturn(¶ms,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(¶ms,true);
4210 case SS7MsgISUP::CtrlSave:
4211 setVerify(true,true);
4212 return TelEngine::controlReturn(¶ms,true);
4213 #ifdef ISUP_HANDLE_CIC_EVENT_CONTROL
4214 case SS7MsgISUP::CtrlCicEvent:
4215 return TelEngine::controlReturn(¶ms,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,¶ms);
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"),¶ms,"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