1 /**
2  * sccp.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 
25 #include<stdlib.h>
26 #include <string.h>
27 
28 
29 using namespace TelEngine;
30 
31 #define MAX_MANDATORY_PARAMS 16
32 
33 // 227 is maximum data length that can be transported by a UDT message
34 // with 2 full gt present both numbers with 16 digits (bcd encoded)
35 #define MAX_UDT_LEN 227
36 
37 #define MAX_INFO_TIMER 1200000 // Maximum interval for sending SST 20 min
38 // Maximum length of optional parameters: 6 Segmentation, 3 Importance, 1 EOP
39 #define MAX_OPT_LEN 10
40 // Minimum data size in a SCCP message
41 #define MIN_DATA_SIZE 2
42 
43 #define MAX_DATA_ITU 3952
44 #define MAX_DATA_ANSI 3904
45 
46 static const char* s_userMutexName = "SCCPUserTransport";
47 static const char* s_sccpMutexName = "SCCPUserList";
48 static const char* s_managementMutexName = "SCCPManagement";
49 static const char* s_sccpTranslatorMutex = "SCCPTranslator";
50 static const char* s_sccpSubsystems = "SccpSubsystems";
51 static const char* s_sccpRemote = "SccpRemote";
52 
53 struct SCCPParam {
54     // numeric type of the parameter
55     SS7MsgSCCP::Parameters type;
56     // size in octets, zero for variable
57     unsigned char size;
58     // SS7 name of the parameter
59     const char* name;
60     // decoder callback function
61     bool (*decoder)(const SS7SCCP*,NamedList&,const SCCPParam*,
62 	const unsigned char*,unsigned int,const String&);
63     // encoder callback function
64     unsigned char (*encoder)(const SS7SCCP*,SS7MSU&,unsigned char*,
65 	const SCCPParam*,const NamedString*,const NamedList*,const String&);
66     // table data to be used by the callback
67     const void* data;
68 };
69 
70 struct MsgParams {
71     // type of the message described
72     SS7MsgSCCP::Type type;
73     // does the message support optional part?
74     bool optional;
75     // parameters, fixed then variable, separated/terminated by EndOfParameters
76     //  using an array is a (moderate) waste of space
77     const SS7MsgSCCP::Parameters params[MAX_MANDATORY_PARAMS];
78 };
79 
80 static const TokenDict s_return_cause[] = {
81     { "No translation for an address of such nature",                   SS7SCCP::NoTranslationAddressNature },
82     { "No translation for this specific address",                       SS7SCCP::NoTranslationSpecificAddress },
83     { "Subsystem congestion",                                           SS7SCCP::SubsystemCongestion },
84     { "Subsystem failure",                                              SS7SCCP::SubsystemFailure },
85     { "Unequipped user",                                                SS7SCCP::UnequippedUser },
86     { "MTP failure",                                                    SS7SCCP::MtpFailure },
87     { "Network Congestion",                                             SS7SCCP::NetworkCongestion },
88     { "Unqualified",                                                    SS7SCCP::Unqualified },
89     { "Error in message transport",                                     SS7SCCP::ErrorInMessageTransport },
90     { "Error in local processing",                                      SS7SCCP::ErrorInLocalProcessing },
91     { "Destination can not perform reassembly",                         SS7SCCP::DestinationCanNotPerformReassembly },
92     { "SCCP failure",                                                   SS7SCCP::SccpFailure },
93     { "Hop counter violation",                                          SS7SCCP::HopCounterViolation },
94     { "Segmentation not supported",                                     SS7SCCP::SegmentationNotSupported },
95     { "Segmentation failure",                                           SS7SCCP::SegmentationFailure },
96     // ANSI only
97     { "Message change failure",                                         SS7SCCP::MessageChangeFailure },
98     { "Invalid INS routing request",                                    SS7SCCP::InvalidINSRoutingRequest },
99     { "Invalid ISNI routing request",                                   SS7SCCP::InvalidISNIRoutingRequest },
100     { "Unauthorized message",                                           SS7SCCP::UnauthorizedMessage },
101     { "Message incompatibility",                                        SS7SCCP::MessageIncompatibility },
102     { "Can not perform ISNI constrained routing",                       SS7SCCP::NotSupportedISNIRouting },
103     { "Redundant ISNI constrained routing information",                 SS7SCCP::RedundantISNIConstrainedRouting },
104     { "Unable to perform ISNI identification",                          SS7SCCP::ISNIIdentificationFailed },
105     { 0, 0 }
106 };
107 
108 static const TokenDict s_managementMessages[] = {
109     { "SSA",    SCCPManagement::SSA },  // Subsystem-allowed
110     { "SSP",    SCCPManagement::SSP },  // Subsystem-prohibited
111     { "SST",    SCCPManagement::SST },  // Subsystem-status-test
112     { "SOR",    SCCPManagement::SOR },  // Subsystem-out-of-service-request
113     { "SOG",    SCCPManagement::SOG },  // Subsystem-out-of-service-grant
114     { "SSC",    SCCPManagement::SSC },  // SCCP/Subsystem-congested      (ITU  only)
115     { "SBR",    SCCPManagement::SBR },  // Subsystem-backup-routing      (ANSI only)
116     { "SNR",    SCCPManagement::SNR },  // Subsystem-normal-routing      (ANSI only)
117     { "SRT",    SCCPManagement::SRT },  // Subsystem-routing-status-test (ANSI only)
118     { 0, 0 }
119 };
120 
121 static const TokenDict s_dict_control[] = {
122     { "status",                      SS7SCCP::Status },
123     { "full-status",                 SS7SCCP::FullStatus },
124     { "enable-extended-monitoring",  SS7SCCP::EnableExtendedMonitoring },
125     { "disable-extended-monitoring", SS7SCCP::DisableExtendedMonitoring },
126     { "enable-print-messages",       SS7SCCP::EnablePrintMsg },
127     { "disable-print-messages",      SS7SCCP::DisablePrintMsg },
128     { 0, 0 }
129 };
130 
131 const TokenDict SCCPManagement::s_broadcastType[] = {
132     { "UserOutOfService",            SCCPManagement::UserOutOfService },
133     { "UserInService",               SCCPManagement::UserInService },
134     { "SignallingPointInaccessible", SCCPManagement::PCInaccessible },
135     { "SignallingPointAccessible",   SCCPManagement::PCAccessible },
136     { "RemoteSCCPInaccessible",      SCCPManagement::SccpRemoteInaccessible },
137     { "RemoteSCCPAccessible",        SCCPManagement::SccpRemoteAccessible },
138     { "SignallingPointCongested",    SCCPManagement::PCCongested },
139     { 0, 0 }
140 };
141 
142 static const TokenDict s_sccpNotif[] = {
143     { "Coordinate Request",            SCCP::CoordinateRequest },          // (User->SCCP)
144     { "Coordinate Confirm",            SCCP::CoordinateConfirm },          // (SCCP->User)
145     { "Coordinate Indication",         SCCP::CoordinateIndication },       // (SCCP->User)
146     { "Coordinate Response",           SCCP::CoordinateResponse },         // (User->SCCP)
147     { "Status Indication",             SCCP::StatusIndication },           // (SCCP->User)
148     { "Status Request",                SCCP::StatusRequest },              // (User->SCCP)
149     { "PointCode Status Indication",   SCCP::PointCodeStatusIndication },  // (SCCP->User)
150     { "Trafic Indication",             SCCP::TraficIndication },
151     { "Subsystem Status",              SCCP::SubsystemStatus },            // (SCCP->User)
152     { 0, 0 }
153 };
154 
155 static const TokenDict s_numberingPlan[] = {
156     { "unknown",          0x00 },
157     { "isdn",             0x01 },
158     { "e164",             0x01 },
159     { "generic",          0x02 },
160     { "data",             0x03 },
161     { "x121",             0x03 },
162     { "telex",            0x04 },
163     { "maritime-mobile",  0x05 },
164     { "e210",             0x05 },
165     { "e211",             0x05 },
166     { "land-mobile",      0x06 },
167     { "e212",             0x06 },
168     { "isdn-mobile",      0x07 },
169     { "e214",             0x07 },
170     { "network-specific", 0x0e },
171     { 0, 0 }
172 };
173 
174 static const TokenDict s_nai[] = {
175     { "unknown",                     0x00 },
176     { "subscriber",                  0x01 },
177     { "national-reserved",           0x02 },
178     { "national-significant",        0x03 },
179     { "international",               0x04 },
180     { 0, 0 }
181 };
182 
183 static const TokenDict s_encodingScheme[] = {
184     { "unknown",     0x00 },
185     { "bcd",         0x01 },
186     { "bcd",         0x02 },
187     { 0, 0 }
188 };
189 
190 static const TokenDict s_ansiSmi[] = {
191     { "unknown",       0x00 },
192     { "solitary",      0x01 },
193     { "duplicated",    0x02 },
194     { 0 , 0 }
195 };
196 
197 const TokenDict SCCPManagement::s_states[] = {
198     { "allowed",        SCCPManagement::Allowed },
199     { "prohibited",     SCCPManagement::Prohibited },
200     { "wait-for-grant", SCCPManagement::WaitForGrant },
201     { "ignore-tests",   SCCPManagement::IgnoreTests },
202     { "unknown",        SCCPManagement::Unknown },
203     { 0 , 0 }
204 };
205 
206 const TokenDict s_messageReturn[] = {
207     { "false", 0x00 },
208     { "true",  0x08 },
209     { "yes",   0x08 },
210     { "on",    0x08 },
211     { "enable",0x08 },
212     { 0, 0 }
213 };
214 
compareLabel(const SS7Label & l1,const SS7Label & l2)215 static bool compareLabel(const SS7Label& l1, const SS7Label& l2)
216 {
217     if (l1.opc() != l2.opc())
218 	return false;
219     if (l1.dpc() != l2.dpc())
220 	return false;
221     return true;
222 }
223 
224 // Helper method increments a number stored in a string
incrementNS(NamedString * ns)225 static void incrementNS(NamedString* ns)
226 {
227     if (!ns)
228 	return;
229     int counter = ns->toInteger();
230     counter++;
231     *ns = String(counter);
232 }
233 
compareNamedList(const NamedList & nl1,const NamedList & nl2)234 static bool compareNamedList(const NamedList& nl1, const NamedList& nl2)
235 {
236     if (nl1.length() != nl2.length())
237 	return false;
238     NamedIterator iter(nl1);
239     while (const NamedString* pr = iter.get()) {
240 	const NamedString* pr2 = nl2.getParam(pr->name());
241 	if (!pr2 || (*pr2 != *pr))
242 	    return false;
243     }
244     return true;
245 }
246 
getDictValue(NamedList & list,const char * paramName,int val,const TokenDict * dict)247 static void getDictValue(NamedList& list, const char* paramName, int val, const TokenDict* dict)
248 {
249     NamedString* ns = new NamedString(paramName);
250     *ns = lookup(val,dict,0);
251     if (ns->null()) {
252 	*ns = String(val).c_str();
253     }
254     list.setParam(ns);
255 }
256 
decodeRaw(const SS7SCCP * sccp,NamedList & list,const SCCPParam * param,const unsigned char * buf,unsigned int len,const String & prefix)257 static bool decodeRaw(const SS7SCCP* sccp, NamedList& list, const SCCPParam* param,
258     const unsigned char* buf, unsigned int len, const String& prefix)
259 {
260     if (len < 1)
261 	return false;
262     String raw;
263     raw.hexify((void*)buf,len,' ');
264     DDebug(sccp,DebugInfo,"decodeRaw decoded %s=%s",param->name,raw.c_str());
265     list.addParam(prefix+param->name,raw);
266     return true;
267 }
268 
269 // Raw decoder for unknown/failed parameter, dumps raw octets
decodeRawParam(const SS7SCCP * sccp,NamedList & list,unsigned char value,const unsigned char * buf,unsigned int len,const String & prefix)270 static bool decodeRawParam(const SS7SCCP* sccp, NamedList& list, unsigned char value,
271     const unsigned char* buf, unsigned int len, const String& prefix)
272 {
273     String name("Param_");
274     name << value;
275     SCCPParam p;
276     p.type = (SS7MsgSCCP::Parameters)value;
277     p.size = len;
278     p.name = name;
279     p.decoder = 0;
280     p.encoder = 0;
281     p.data = 0;
282     return decodeRaw(sccp,list,&p,buf,len,prefix);
283 };
284 
decodeInt(const SS7SCCP * sccp,NamedList & list,const SCCPParam * param,const unsigned char * buf,unsigned int len,const String & prefix)285 static bool decodeInt(const SS7SCCP* sccp, NamedList& list, const SCCPParam* param,
286     const unsigned char* buf, unsigned int len, const String& prefix)
287 {
288     unsigned int val = 0;
289     int shift = 0;
290     while (len--) {
291 	val |= ((unsigned int)*buf++) << shift;
292 	shift += 8;
293     }
294     DDebug(sccp,DebugAll,"decodeInt decoded %s=%s (%u)",param->name,lookup(val,(const TokenDict*)param->data),val);
295     SignallingUtils::addKeyword(list,prefix+param->name,(const TokenDict*)param->data,val);
296     return true;
297 }
298 
decodeProtocolClass(const SS7SCCP * sccp,NamedList & list,const SCCPParam * param,const unsigned char * buffer,unsigned int len,const String & prefix)299 static bool decodeProtocolClass(const SS7SCCP* sccp, NamedList& list, const SCCPParam* param,
300     const unsigned char* buffer, unsigned int len, const String& prefix)
301 {
302     unsigned char protocol = *buffer++;
303     unsigned int pClass = protocol & 0x0f;
304     if (pClass > 3) {
305 	Debug(sccp,DebugWarn,"Received Invalid Protocol Class %d",pClass);
306 	return false;
307     }
308     if (pClass < 2) // Protocol class 0 | 1 check return option
309 	getDictValue(list,prefix + "MessageReturn",protocol >> 4,s_messageReturn);
310     list.setParam(prefix + param->name, String(pClass));
311     return true;
312 }
313 
decodeCause(const SS7SCCP * sccp,NamedList & list,const SCCPParam * param,const unsigned char * buffer,unsigned int len,const String & prefix)314 static bool decodeCause(const SS7SCCP* sccp, NamedList& list, const SCCPParam* param,
315     const unsigned char* buffer, unsigned int len, const String& prefix)
316 {
317     if (len <  1)
318 	return false;
319     unsigned int cause = *buffer++;
320     list.setParam(prefix + param->name,String(cause));
321     return true;
322 }
323 
decodeImportance(const SS7SCCP * sccp,NamedList & list,const SCCPParam * param,const unsigned char * buffer,unsigned int len,const String & prefix)324 static bool decodeImportance(const SS7SCCP* sccp, NamedList& list, const SCCPParam* param,
325     const unsigned char* buffer, unsigned int len, const String& prefix)
326 {
327     if (len < 1)
328 	return false;
329     int importance = *buffer++ & 0x07;
330     list.setParam(prefix + "Importance",String(importance));
331     return true;
332 }
333 
getDigits(String & num,bool oddNum,const unsigned char * buf,unsigned int len,bool ignoreUnk)334 static void getDigits(String& num, bool oddNum, const unsigned char* buf, unsigned int len,
335     bool ignoreUnk)
336 {
337     static const char digits1[] = "0123456789\0BC\0\0.";
338     static const char digits2[] = "0123456789ABCDE.";
339     const char* digits = ignoreUnk ? digits1 : digits2;
340     for (unsigned int i = 0; i < len; i++) {
341 	num += digits[buf[i] & 0x0f];
342 	if (oddNum && ((i+1) == len))
343 	    break;
344 	num += digits[buf[i] >> 4];
345     }
346 }
347 
348 // Decode methods
decodeItuAddress(const SS7SCCP * sccp,NamedList & params,const SCCPParam * param,const unsigned char * buffer,unsigned int length,const String & prefix)349 static bool decodeItuAddress(const SS7SCCP* sccp, NamedList& params,const SCCPParam* param,
350 	const unsigned char* buffer, unsigned int length, const String& prefix)
351 {
352     unsigned char addressIndicator = *buffer++;
353     length--;
354     String prName = prefix + param->name;
355     while (true) {
356 	if ((addressIndicator & 0x01) == 0x01) { // Have Pointcode
357 	    if (length < 2)
358 		break;
359 	    int pointcode = *buffer++;
360 	    pointcode |= (*buffer++ & 0x3f) << 8;
361 	    params.addParam(prName + ".pointcode",String(pointcode));
362 	    length -= 2;
363 	}
364 	if ((addressIndicator & 0x02) == 0x02) { // Have SSN
365 	    if (length < 1)
366 		break;
367 	    unsigned char ssn = *buffer++;
368 	    params.addParam(prName + ".ssn",String(ssn));
369 	    length --;
370 	}
371 	params.addParam(prName + ".route", ((addressIndicator & 0x40) == 0x40)
372 		? YSTRING("ssn") : YSTRING("gt"));
373 	unsigned char gti = (addressIndicator >> 2) & 0x0f;
374 	if (!gti) // No Global Title Present
375 	    return true;
376 	bool odd = false;
377 	String tmp;
378 	String gtName = prName + ".gt";
379 	if (gti == 0x01) { // GT includes Nature Of Address Indicator
380 	    if (length < 1) {
381 		break;
382 	    }
383 	    unsigned char nai = *buffer++;
384 	    length--;
385 	    getDictValue(params,gtName + ".nature", nai & 0x7f,s_nai);
386 	    odd = (nai & 0x80) != 0;
387 	} else if (gti == 0x02) { // GT includes Translation Type
388 	    if (length < 1)
389 		break;
390 	    params.addParam(gtName + ".translation", String((int)*buffer++));
391 	    length--;
392 	    tmp.hexify((void*)buffer,length,' ');
393 	} else if (gti == 0x03) { // GT includes tt, np & es
394 	    if (length < 2)
395 		break;
396 	    params.addParam(gtName+ ".translation", String((int)*buffer++));
397 	    length--;
398 	    unsigned char npes = *buffer++;
399 	    length--;
400 	    getDictValue(params,gtName + ".plan", npes >> 4,s_numberingPlan);
401 	    unsigned int es = npes & 0x0f;
402 	    getDictValue(params,gtName + ".encoding", es,s_encodingScheme);
403 	    switch (es) {
404 		case 1:
405 		    odd = true;
406 		case 2:
407 		    break;
408 		default:
409 		    tmp.hexify((void*)buffer,length,' ');
410 	    }
411 	} else if (gti == 0x04) { // GT includes tt, np, es & nai
412 	    if (length < 3)
413 		break;
414 	    params.addParam(gtName+ ".translation", String((int)*buffer++));
415 	    length--;
416 	    unsigned char npes = *buffer++;
417 	    unsigned char es = npes & 0x0f;
418 	    length--;
419 	    getDictValue(params,gtName + ".plan", npes >> 4,s_numberingPlan);
420 	    getDictValue(params,gtName + ".encoding", es,s_encodingScheme);
421 	    getDictValue(params,gtName + ".nature", *buffer++ & 0x7f,s_nai);
422 	    length--;
423 	    switch (es) {
424 		case 1:
425 		    odd = true;
426 		case 2:
427 		    break;
428 		default:
429 		    tmp.hexify((void*)buffer,length,' ');
430 	    }
431 	} else {
432 	    Debug(sccp,DebugMild, "Unable to decode ITU GT with GTI = %d",gti);
433 	    return false;
434 	}
435 	if (tmp.null())
436 	    getDigits(tmp,odd,buffer,length,sccp && sccp->ignoreUnknownAddrSignals());
437 	params.addParam(gtName, tmp);
438 	return true;
439     }
440     Debug(sccp,DebugWarn,"Failed to decode ITU address!!! short message length");
441     return false;
442 }
443 
decodeAnsiAddress(const SS7SCCP * sccp,NamedList & params,const SCCPParam * param,const unsigned char * buffer,unsigned int length,const String & prefix)444 static bool decodeAnsiAddress(const SS7SCCP* sccp, NamedList& params,const SCCPParam* param,
445 	const unsigned char* buffer, unsigned int length, const String& prefix)
446 {
447     unsigned char addressIndicator = *buffer++;
448     length--;
449     String prName = prefix + param->name;
450     while (true) {
451 	if ((addressIndicator & 0x01) == 0x01) { // Have SSN
452 	    if (length < 1)
453 		break;
454 	    params.addParam(prName + ".ssn",String(*buffer++));
455 	    length --;
456 	}
457 	if ((addressIndicator & 0x02) == 0x02) { // Have Pointcode
458 	    if (length < 3)
459 		break;
460 	    unsigned int pointcode = *buffer++;
461 	    pointcode |= (*buffer++ << 8);
462 	    pointcode |= (*buffer++ << 16);
463 	    length -= 3;
464 	    params.addParam(prName + ".pointcode",String(pointcode));
465 	}
466 	params.addParam(prName + ".route", ((addressIndicator & 0x40) == 0x40) ?
467 		    YSTRING("ssn") : YSTRING("gt"));
468 	unsigned char gti = (addressIndicator >> 2) & 0x0f;
469 	if (!gti) // No Global Title Present
470 	    return true;
471 	bool odd = false;
472 	String tmp;
473 	String gtName = prName + ".gt";
474 	if (gti == 0x01) { // GT includes tt, np & es
475 	    if (length < 2)
476 		break;
477 	    params.addParam(gtName + ".translation", String((int)*buffer++));
478 	    length--;
479 	    unsigned char npes = *buffer++;
480 	    unsigned char es = npes & 0x0f;
481 	    length--;
482 	    getDictValue(params,gtName + ".plan", npes >> 4, s_numberingPlan);
483 	    getDictValue(params,gtName + ".encoding", es,s_encodingScheme);
484 	    switch (es) {
485 		case 1:
486 		    odd = true;
487 		case 2:
488 		    break;
489 		default:
490 		    tmp.hexify((void*)buffer,length,' ');
491 	    }
492 	} else if (gti == 0x02) { // GT includes Translation Type
493 	    if (length < 1)
494 		break;
495 	    params.addParam(gtName + ".translation", String((int)*buffer++));
496 	    length--;
497 	    tmp.hexify((void*)buffer,length,' ');
498 	} else {
499 	    Debug(sccp,DebugMild, "Unable to decode ANSI GT with GTI = %d",gti);
500 	    return false;
501 	}
502 	if (tmp.null())
503 	    getDigits(tmp,odd,buffer,length,sccp && sccp->ignoreUnknownAddrSignals());
504 	params.addParam(gtName, tmp);
505 	return true;
506     }
507     Debug(sccp,DebugWarn,"Failed to decode ANSI address!!! short message length");
508     return false;
509 }
510 
decodeAddress(const SS7SCCP * sccp,NamedList & paramsList,const SCCPParam * param,const unsigned char * buffer,unsigned int length,const String & prefix)511 static bool decodeAddress(const SS7SCCP* sccp, NamedList& paramsList,const SCCPParam* param,
512 	const unsigned char* buffer, unsigned int length, const String& prefix)
513 {
514     if (length < 1)
515 	return false;
516     if (sccp->ITU())
517 	return decodeItuAddress(sccp,paramsList,param,buffer,length,prefix);
518     else
519 	return decodeAnsiAddress(sccp,paramsList,param,buffer,length,prefix);
520 }
521 
decodeData(const SS7SCCP * sccp,SS7MsgSCCP * msg,const unsigned char * buffer,unsigned int length)522 static bool decodeData(const SS7SCCP* sccp, SS7MsgSCCP* msg, const unsigned char* buffer, unsigned int length)
523 {
524     DataBlock* data = new DataBlock((void*)buffer,length, false);
525     msg->setData(data);
526     buffer += length;
527     return true;
528 }
529 
decodeSegmentation(const SS7SCCP * sccp,NamedList & params,const SCCPParam * param,const unsigned char * buffer,unsigned int length,const String & prefix)530 static bool decodeSegmentation(const SS7SCCP* sccp, NamedList& params,const SCCPParam* param,
531 	const unsigned char* buffer, unsigned int length, const String& prefix)
532 {
533     if (length < 4) {
534 	DDebug(sccp,DebugNote,"Failed to decode %s parameter! Reason length to short.",param->name);
535 	return false;
536     }
537     unsigned char segInfo = *buffer++;
538     String prName = prefix + param->name;
539     params.addParam(prName + ".FirstSegment", String((segInfo & 0x80) == 0x80));
540     params.addParam(prName + ".ProtocolClass", String((segInfo & 0x40) >> 6));
541     params.addParam(prName + ".RemainingSegments", String(segInfo & 0x0f));
542     unsigned int segLocalReference = *buffer++;
543     segLocalReference |= *buffer++ << 8;
544     segLocalReference |= *buffer++ << 16;
545     params.addParam(prName + ".SegmentationLocalReference", String(segLocalReference));
546     params.addParam(prName ,"true");
547     return true;
548 }
549 
550 
551 // Encode methods
552 
encodeRaw(const SS7SCCP * sccp,SS7MSU & msu,unsigned char * buf,const SCCPParam * param,const NamedString * val,const NamedList *,const String &)553 static unsigned char encodeRaw(const SS7SCCP* sccp, SS7MSU& msu,
554     unsigned char* buf, const SCCPParam* param, const NamedString* val,
555     const NamedList*, const String&)
556 {
557     if (!(param && val))
558 	return 0;
559     DDebug(sccp,DebugInfo,"encodeRaw encoding %s=%s",param->name,val->c_str());
560     DataBlock raw;
561     if (!raw.unHexify(val->c_str(),val->length(),' ')) {
562 	DDebug(sccp,DebugMild,"encodeRaw failed: invalid string");
563 	return 0;
564     }
565     if (!raw.length() || raw.length() > 254 ||
566 	(param->size && param->size != raw.length())) {
567 	DDebug(sccp,DebugMild,"encodeRaw failed: param size=%u data length=%u",
568 	    param->size,raw.length());
569 	return 0;
570     }
571     if (buf) {
572 	::memcpy(buf,raw.data(),raw.length());
573 	return raw.length();
574     }
575     unsigned char size = (unsigned char)raw.length();
576     msu.append(&size,1);
577     msu += raw;
578     return size;
579 }
580 
581 // Encoder for fixed length little-endian integer values
encodeInt(const SS7SCCP * sccp,SS7MSU & msu,unsigned char * buf,const SCCPParam * param,const NamedString * val,const NamedList *,const String &)582 static unsigned char encodeInt(const SS7SCCP* sccp, SS7MSU& msu, unsigned char* buf,
583     const SCCPParam* param, const NamedString* val, const NamedList*, const String&)
584 {
585     if (!param)
586 	return 0;
587     unsigned int n = param->size;
588     if (!n)
589 	return 0;
590     unsigned int v = 0;
591     if (val)
592 	v = val->toInteger((const TokenDict*)param->data);
593     DDebug(sccp,DebugAll,"encodeInt encoding %s=%u on %u octets",param->name,v,n);
594     if (!buf) {
595 	unsigned int l = msu.length();
596 	DataBlock dummy(0,n+1);
597 	msu += dummy;
598 	buf = (unsigned char*)msu.getData(l,n+1);
599 	*buf++ = n & 0xff;
600     }
601     while (n--) {
602 	*buf++ = v & 0xff;
603 	v >>= 8;
604     }
605     return param->size;
606 }
607 
encodeProtocolClass(const SS7SCCP * sccp,SS7MSU & msu,unsigned char * buf,const SCCPParam * param,const NamedString * val,const NamedList * extra,const String & prefix)608 static unsigned char encodeProtocolClass(const SS7SCCP* sccp, SS7MSU& msu,
609     unsigned char* buf, const SCCPParam* param, const NamedString* val,
610     const NamedList* extra, const String& prefix)
611 {
612     if (!buf) {
613 	Debug(sccp,DebugWarn,"Request to encode ProtocolClass in a null buffer!!!");
614 	return 0;
615     }
616     unsigned char protocolClass = extra->getIntValue(prefix + "ProtocolClass");
617     if (protocolClass > 3) {
618 	Debug(sccp,DebugWarn,"Invalid ProtocolClass value %d, for encoding",protocolClass);
619 	return 0;
620     }
621     if (protocolClass < 2) {
622 	int errorReturn = extra->getIntValue(prefix + "MessageReturn",s_messageReturn);
623 	protocolClass |= errorReturn << 4;
624     }
625     *buf = protocolClass;
626     return 1;
627 }
628 
setDigits(const char * val)629 static DataBlock* setDigits(const char* val)
630 {
631     if (!val)
632 	return 0;
633     unsigned char buf[32];
634     unsigned int len = 0;
635     bool odd = false;
636     while (val && (len < sizeof(buf))) {
637 	char c = *val++;
638 	if (!c)
639 	    break;
640 	unsigned char n = 0;
641 	if (('0' <= c) && (c <= '9'))
642 	    n = c - '0';
643 	else switch (c) {
644 	    case 'A':
645 	    case 'a':
646 		n = 10;
647 		break;
648 	    case 'B':
649 	    case 'b':
650 		n = 11;
651 		break;
652 	    case 'C':
653 	    case 'c':
654 		n = 12;
655 		break;
656 	    case 'D':
657 	    case 'd':
658 		n = 13;
659 		break;
660 	    case 'E':
661 	    case 'e':
662 		n = 14;
663 		break;
664 	    case 'F':
665 	    case 'f':
666 		n = 15;
667 		break;
668 	    default:
669 		continue;
670 	}
671 	odd = !odd;
672 	if (odd)
673 	    buf[len] = n;
674 	else
675 	    buf[len++] |= (n << 4);
676     }
677     if (odd)
678 	len++;
679     DataBlock* tmp = new DataBlock(buf,len);
680     return tmp;
681 }
682 
encodeItuAddress(const SS7SCCP * sccp,SS7MSU & msu,unsigned char * buf,const SCCPParam * param,const NamedString * val,const NamedList * extra,const String & prefix)683 static unsigned char encodeItuAddress(const SS7SCCP* sccp, SS7MSU& msu,
684     unsigned char* buf, const SCCPParam* param, const NamedString* val,
685     const NamedList* extra, const String& prefix)
686 {
687     unsigned char length = 1;
688     unsigned char data[32];
689     unsigned char addressIndicator = 0;
690     String preName(prefix + param->name);
691     bool havePC = extra->getParam(preName + ".pointcode") != 0;
692     if (havePC) {
693 	int pointcode = extra->getIntValue(preName + ".pointcode",0);
694 	addressIndicator |= 0x01;
695 	data[++length] = pointcode & 0xff;
696 	data[++length] = (pointcode >> 8) & 0x3f;
697     }
698     bool haveSSN = extra->getParam(preName + ".ssn") != 0;
699     if (haveSSN) {
700 	int ssn = extra->getIntValue(preName + ".ssn",0);
701 	addressIndicator |= 0x02;
702 	data[++length] = ssn;
703     }
704     NamedString* route = extra->getParam(preName + ".route");
705     if (route && *route == YSTRING("ssn")) { // Marck route on SSN
706 	if (param->name == YSTRING("CalledPartyAddress") && !haveSSN)
707 	    Debug(sccp,DebugNote,"Request to route on SSN with no ssn present!");
708 	addressIndicator |= 0x40;
709     }
710     NamedString* gtNr = YOBJECT(NamedString,extra->getParam(preName + ".gt"));
711     if (!gtNr) { // No Global Title present!!!
712 	if ((addressIndicator & 0x40) == 0)
713 	    DDebug(sccp,DebugNote,"RouteIndicator set on global title. But no global title present!!!");
714 	data[1] = addressIndicator;
715 	data[0] = length;
716 	DataBlock tmp(data,length + 1,false);
717 	msu += tmp;
718 	tmp.clear(false);
719 	return data[0];
720     }
721     NamedString* nature = YOBJECT(NamedString,extra->getParam(preName + ".gt.nature"));
722     NamedString* translation = YOBJECT(NamedString,extra->getParam(preName + ".gt.translation"));
723     NamedString* plan = YOBJECT(NamedString,extra->getParam(preName + ".gt.plan"));
724     NamedString* encoding = YOBJECT(NamedString,extra->getParam(preName + ".gt.encoding"));
725     bool odd = false;
726     DataBlock* digits = 0;
727     if (nature && !translation) { // GT = 0x01
728 	addressIndicator |= 0x04;
729 	int nai = nature->toInteger(s_nai);
730 	odd = (gtNr->length() % 2) ? false : true;
731 	if (!odd)
732 	    nai |= 0x80;
733 	data[++length] = nai & 0xff;
734     } else if (translation && !(plan && encoding) && !nature) { // GT = 0x02
735 	addressIndicator |= 0x08;
736 	int tt = translation->toInteger();
737 	data[++length] = tt & 0xff;
738 	digits = new DataBlock();
739 	if (!digits->unHexify(*gtNr,gtNr->length(),' ')) {
740 	    Debug(sccp,DebugInfo,"Setting unknown odd/even number of digits!!");
741 	    TelEngine::destruct(digits);
742 	}
743     } else if (translation && plan && encoding && !nature) { // GT = 0x03
744 	addressIndicator |= 0x0c;
745 	int tt = translation->toInteger();
746 	data[++length] = tt & 0xff;
747 	int np = plan->toInteger(s_numberingPlan);
748 	int es = encoding->toInteger(s_encodingScheme);
749 	switch (es) {
750 	    case 1:
751 	    case 2:
752 		odd = (gtNr->length() % 2 == 1);
753 		es = odd ? 1 : 2;
754 		break;
755 	    default:
756 		digits = new DataBlock();
757 		if (!digits->unHexify(*gtNr,gtNr->length(),' ')) {
758 		    Debug(sccp,DebugInfo,"Setting unknown odd/even number of digits!!");
759 		    TelEngine::destruct(digits);
760 		}
761 	}
762 	data[++length] = ((np & 0x0f) << 4) | (es & 0x0f);
763     } else if (translation && plan && encoding && nature) { // GT = 0x04
764 	addressIndicator |= 0x10;
765 	int tt = translation->toInteger();
766 	data[++length] = tt & 0xff;
767 	int np = plan->toInteger(s_numberingPlan);
768 	int es = encoding->toInteger(s_encodingScheme);
769 	switch (es) {
770 	    case 1:
771 	    case 2:
772 		odd = (gtNr->length() % 2 == 1);
773 		es = odd ? 1 : 2;
774 		break;
775 	    default:
776 		digits = new DataBlock();
777 		if (!digits->unHexify(*gtNr,gtNr->length(),' ')) {
778 		    Debug(sccp,DebugInfo,"Setting unknown odd/even number of digits!!");
779 		    TelEngine::destruct(digits);
780 		}
781 	}
782 	data[++length] = ((np & 0x0f) << 4) | (es & 0x0f);
783 	int nai = nature->toInteger(s_nai);
784 	data[++length] = nai & 0x7f;
785     } else {
786 	Debug(sccp,DebugWarn,"Can not encode ITU GTI. Unknown GTI value for : nai= %s, Plan & Encoding = %s, TranslationType = %s",
787 	      nature? "present" : "missing",(plan && encoding)? "present" : "missing",translation ? "present" : "missing");
788 	return 0;
789     }
790     data[1] = addressIndicator;
791     if (!digits && !(digits = setDigits(*gtNr))) {
792 	Debug(DebugWarn,"Failed to encode digits!!");
793 	return 0;
794     }
795     data[0] = length + digits->length();
796     DataBlock tmp(data,length + 1,false);
797     msu += tmp;
798     msu += *digits;
799     tmp.clear(false);
800     TelEngine::destruct(digits);
801     return data[0];
802 
803 }
804 
encodeAnsiAddress(const SS7SCCP * sccp,SS7MSU & msu,unsigned char * buf,const SCCPParam * param,const NamedString * val,const NamedList * extra,const String & prefix)805 static unsigned char encodeAnsiAddress(const SS7SCCP* sccp, SS7MSU& msu,
806     unsigned char* buf, const SCCPParam* param, const NamedString* val,
807     const NamedList* extra, const String& prefix)
808 {
809     unsigned char length = 1;
810     unsigned char data[32];
811     unsigned char addressIndicator = 0;
812     String preName(prefix + param->name);
813     bool havePC = extra->getParam(preName + ".pointcode") != 0;
814     bool haveSSN = extra->getParam(preName + ".ssn") != 0;
815     if (haveSSN) {
816 	int ssn = extra->getIntValue(preName + ".ssn",0);
817 	addressIndicator |= 0x01;
818 	data[++length] = ssn;
819     }
820     addressIndicator |= 0x80; // Mark the 8 bit from address indicator to national use
821     if (havePC) {
822 	int pointcode = extra->getIntValue(preName + ".pointcode",0);
823 	addressIndicator |= 0x02;
824 	data[++length] = pointcode  & 0xff;
825 	data[++length] = (pointcode >> 8) & 0xff;
826 	data[++length] = (pointcode >> 16) & 0xff;
827     }
828     NamedString* route = extra->getParam(preName + ".route");
829     if (route && *route == YSTRING("ssn")) { // Marck route on SSN
830 	if (param->name == YSTRING("CalledPartyAddress") && !haveSSN)
831 	    Debug(sccp,DebugNote,"Request to route on SSN with no ssn present!");
832 	addressIndicator |= 0x40;
833     }
834     NamedString* gtNr = YOBJECT(NamedString,extra->getParam(preName + ".gt"));
835     if (!gtNr) { // No Global Title present!!!
836 	if ((addressIndicator & 0x40) == 0)
837 	    DDebug(sccp,DebugNote,"RouteIndicator set on global title. But no global title present!!!");
838 	data[1] = addressIndicator;
839 	data[0] = length & 0xff;
840 	DataBlock tmp(data,length + 1,false);
841 	msu += tmp;
842 	tmp.clear(false);
843 	return data[0];
844     }
845     NamedString* translation = YOBJECT(NamedString,extra->getParam(preName + ".gt.translation"));
846     NamedString* plan = YOBJECT(NamedString,extra->getParam(preName + ".gt.plan"));
847     NamedString* encoding = YOBJECT(NamedString,extra->getParam(preName + ".gt.encoding"));
848     DataBlock* digits = 0;
849     bool odd = false;
850     if (translation && !(plan && encoding)) { // GT = 0x02
851 	addressIndicator |= 0x08;
852 	int tt = translation->toInteger();
853 	data[++length] = tt & 0xff;
854 	digits = new DataBlock();
855 	if (!digits->unHexify(*gtNr,gtNr->length(),' ')) {
856 	    Debug(sccp,DebugInfo,"Setting unknown odd/even number of digits!!");
857 	    TelEngine::destruct(digits);
858 	}
859     } else if (translation && plan && encoding) { // GT = 0x01
860 	addressIndicator |= 0x04;
861 	int tt = translation->toInteger();
862 	data[++length] = tt & 0xff;
863 	int np = plan->toInteger(s_numberingPlan);
864 	int es = encoding->toInteger(s_encodingScheme);
865 	switch (es) {
866 	    case 1:
867 	    case 2:
868 		odd = (gtNr->length() % 2 == 1);
869 		es = odd ? 1 : 2;
870 		break;
871 	    default:
872 		digits = new DataBlock();
873 		if (!digits->unHexify(*gtNr,gtNr->length(),' ')) {
874 		    Debug(sccp,DebugInfo,"Setting unknown odd/even number of digits!!");
875 		    TelEngine::destruct(digits);
876 		}
877 	}
878 	data[++length] = ((np & 0x0f) << 4) | (es & 0x0f);
879     } else {
880 	Debug(sccp,DebugWarn,"Can not encode ANSI GTI. Unknown GTI value for : Plan & Encoding = %s, TranslationType = %s",
881 	      (plan && encoding)? "present" : "missing",translation ? "present" : "missing");
882 	return 0;
883     }
884     data[1] = addressIndicator;
885     if (!digits && !(digits = setDigits(*gtNr))) {
886 	Debug(DebugWarn,"Failed to encode digits!!");
887 	return 0;
888     }
889     data[0] = length + digits->length();
890     DataBlock tmp(data,length + 1,false);
891     msu += tmp;
892     msu += *digits;
893     tmp.clear(false);
894     TelEngine::destruct(digits);
895     return data[0];
896 
897 }
898 
encodeAddress(const SS7SCCP * sccp,SS7MSU & msu,unsigned char * buf,const SCCPParam * param,const NamedString * val,const NamedList * extra,const String & prefix)899 static unsigned char encodeAddress(const SS7SCCP* sccp, SS7MSU& msu,
900     unsigned char* buf, const SCCPParam* param, const NamedString* val,
901     const NamedList* extra, const String& prefix)
902 {
903     if (!param || buf || param->size)
904 	return 0;
905     if (sccp->ITU())
906 	return encodeItuAddress(sccp,msu,buf,param,val,extra,prefix);
907     else
908 	return encodeAnsiAddress(sccp,msu,buf,param,val,extra,prefix);
909     return 0;
910 }
911 
encodeSegmentation(const SS7SCCP * sccp,SS7MSU & msu,unsigned char * buf,const SCCPParam * param,const NamedString * val,const NamedList * extra,const String & prefix)912 static unsigned char encodeSegmentation(const SS7SCCP* sccp, SS7MSU& msu,
913     unsigned char* buf, const SCCPParam* param, const NamedString* val,
914     const NamedList* extra, const String& prefix)
915 {
916     String preName(prefix + param->name);
917     unsigned char length = 1;
918     unsigned char data[6];
919     unsigned char segInfo = 0;
920     int leftSgm = extra->getIntValue(preName + ".RemainingSegments",0);
921     segInfo |= leftSgm & 0x0f;
922     int protocolClass = extra->getIntValue(preName + ".ProtocolClass",0);
923     if (protocolClass)
924 	segInfo |= 0x40;
925     bool firstSgm = extra->getBoolValue(preName + ".FirstSegment",false);
926     if (firstSgm)
927 	segInfo |= 0x80;
928     data[1] = segInfo;
929     unsigned int sgmLocalReference = extra->getIntValue(preName + ".SegmentationLocalReference",0);
930     data[++length] = sgmLocalReference & 0xff;
931     data[++length] = sgmLocalReference >> 8 & 0xff;
932     data[++length] = sgmLocalReference >> 16 & 0xff;
933 
934     data[0] = length & 0xff;
935     DataBlock tmp(data,length + 1,false);
936     msu += tmp;
937     tmp.clear(false);
938     return data[0];
939 }
940 
encodeImportance(const SS7SCCP * sccp,SS7MSU & msu,unsigned char * buf,const SCCPParam * param,const NamedString * val,const NamedList * extra,const String & prefix)941 static unsigned char encodeImportance(const SS7SCCP* sccp, SS7MSU& msu,
942     unsigned char* buf, const SCCPParam* param, const NamedString* val,
943     const NamedList* extra, const String& prefix)
944 {
945     unsigned char data[6];
946     data[0] = 1;
947     int importance = extra->getIntValue(prefix + param->name);
948     data[1] = importance & 0x07;
949     DataBlock tmp(data,2,false);
950     msu += tmp;
951     tmp.clear(false);
952     return data[0];
953 }
954 
encodeData(const SS7SCCP * sccp,SS7MSU & msu,SS7MsgSCCP * msg)955 static unsigned int encodeData(const SS7SCCP* sccp, SS7MSU& msu, SS7MsgSCCP* msg)
956 {
957     if (!msg) {
958 	DDebug(sccp,DebugNote,"Request to encode data for a null message");
959 	return 0;
960     }
961     DataBlock* data = msg->getData();
962     if (!data) {
963 	DDebug(sccp,DebugNote,"Request to encode message %s with null data",
964 	    SS7MsgSCCP::lookup(msg->type()));
965 	return 0;
966     }
967     if (data->length() < 2) {
968 	DDebug(sccp,DebugNote,"Request to encode message %s with short data",
969 	    SS7MsgSCCP::lookup(msg->type()));
970 	return 0;
971     }
972     unsigned int length = data->length();
973     unsigned char header[2];
974     DataBlock tmp;
975     if (msg->isLongDataMessage()) {
976 	header[0] = length & 0xff;
977 	header[1] = length >> 8 & 0xff;
978 	tmp.assign(header,2,false);
979     } else {
980 	header[0] = length & 0xff;
981 	tmp.assign(header,1,false);
982     }
983     msu += tmp;
984     msu += *data;
985     tmp.clear(false);
986     return length;
987 }
988 
encodeCause(const SS7SCCP * sccp,SS7MSU & msu,unsigned char * buf,const SCCPParam * param,const NamedString * val,const NamedList *,const String &)989 static unsigned char encodeCause(const SS7SCCP* sccp, SS7MSU& msu, unsigned char* buf,
990     const SCCPParam* param, const NamedString* val, const NamedList*, const String&)
991 {
992     if (!param)
993 	return 0;
994     unsigned int n = param->size;
995     if (!n)
996 	return 0;
997     unsigned int v = 0;
998     if (val)
999 	v = val->toInteger();
1000     DDebug(sccp,DebugAll,"encodeCause encoding %s=%u on %u octets",param->name,v,n);
1001     if (!buf) {
1002 	unsigned int l = msu.length();
1003 	DataBlock dummy(0,n+1);
1004 	msu += dummy;
1005 	buf = (unsigned char*)msu.getData(l,n+1);
1006 	*buf++ = n & 0xff;
1007     }
1008     while (n--) {
1009 	*buf++ = v & 0xff;
1010 	v >>= 8;
1011     }
1012     return param->size;
1013 }
1014 
1015 #define MAKE_NAME(x) { #x, SS7MsgSCCP::x }
1016 static const TokenDict s_names[] = {
1017     // this list must be kept in synch with the header
1018     MAKE_NAME(CR),
1019     MAKE_NAME(CC),
1020     MAKE_NAME(CREF),
1021     MAKE_NAME(RLSD),
1022     MAKE_NAME(RLC),
1023     MAKE_NAME(DT1),
1024     MAKE_NAME(DT2),
1025     MAKE_NAME(AK),
1026     MAKE_NAME(UDT),
1027     MAKE_NAME(UDTS),
1028     MAKE_NAME(ED),
1029     MAKE_NAME(EA),
1030     MAKE_NAME(RSR),
1031     MAKE_NAME(RSC),
1032     MAKE_NAME(ERR),
1033     MAKE_NAME(IT),
1034     MAKE_NAME(XUDT),
1035     MAKE_NAME(XUDTS),
1036     MAKE_NAME(LUDT),
1037     MAKE_NAME(LUDTS),
1038     { 0, 0 }
1039 };
1040 #undef MAKE_NAME
1041 
1042 #define MAKE_PARAM(p,s,a,d,t) { SS7MsgSCCP::p,s,#p,a,d,t }
1043 static const SCCPParam s_paramDefs[] = {
1044 //             name                           len decoder            encoder            table                  References
1045 
1046     // Standard parameters
1047     MAKE_PARAM(DestinationLocalReference,      3,decodeInt,          encodeInt,          0),                    // ITU:Q.713 3.2  | Ansi: 1000112.3 3.2
1048     MAKE_PARAM(SourceLocalReference,           3,decodeInt,          encodeInt,          0),                    // ITU:Q.713 3.3  | Ansi: 1000112.3 3.3
1049     MAKE_PARAM(CalledPartyAddress,             0,decodeAddress,      encodeAddress,      0),                    // ITU:Q.713 3.4  | Ansi: 1000112.3 3.4
1050     MAKE_PARAM(CallingPartyAddress,            0,decodeAddress,      encodeAddress,      0),                    // ITU:Q.713 3.5  | Ansi: 1000112.3 3.5
1051     MAKE_PARAM(ProtocolClass,                  1,decodeProtocolClass,encodeProtocolClass,0),                    // ITU:Q.713 3.6  | Ansi: 1000112.3 3.6
1052     MAKE_PARAM(Segmenting,                     0,0,                  0,                  0),                    // ITU:Q.713 3.7  | Ansi: 1000112.3 3.7
1053     MAKE_PARAM(ReceiveSequenceNumber,          0,0,                  0,                  0),                    // ITU:Q.713 3.8  | Ansi: 1000112.3 3.8
1054     MAKE_PARAM(Sequencing,                     0,0,                  0,                  0),                    // ITU:Q.713 3.9  | Ansi: 1000112.3 3.9
1055     MAKE_PARAM(Credit,                         0,0,                  0,                  0),                    // ITU:Q.713 3.10 | Ansi: 1000112.3 3.10
1056     MAKE_PARAM(ReleaseCause,                   1,decodeCause,        encodeCause,        0),                    // ITU:Q.713 3.11 | Ansi: 1000112.3 3.11
1057     MAKE_PARAM(ReturnCause,                    1,decodeCause,        encodeCause,        0),                    // ITU:Q.713 3.12 | Ansi: 1000112.3 3.12
1058     MAKE_PARAM(ResetCause,                     1,decodeCause,        encodeCause,        0),                    // ITU:Q.713 3.13 | Ansi: 1000112.3 3.13
1059     MAKE_PARAM(ErrorCause,                     1,decodeCause,        encodeCause,        0),                    // ITU:Q.713 3.14 | Ansi: 1000112.3 3.14
1060     MAKE_PARAM(RefusalCause,                   1,decodeCause,        encodeCause,        0),                    // ITU:Q.713 3.15 | Ansi: 1000112.3 3.15
1061     MAKE_PARAM(Data,                           0,0,                  0,                  0),                    // ITU:Q.713 3.16 | Ansi: 1000112.3 3.16
1062     MAKE_PARAM(Segmentation,                   4,decodeSegmentation, encodeSegmentation, 0),                    // ITU:Q.713 3.17 | Ansi: 1000112.3 3.18
1063     MAKE_PARAM(HopCounter,                     1,decodeInt,          encodeInt,          0),                    // ITU:Q.713 3.18 | Ansi: 1000112.3 3.17
1064     MAKE_PARAM(Importance,                     0,decodeImportance,   encodeImportance,   0),                    // ITU:Q.713 3.19
1065     MAKE_PARAM(LongData,                       0,0,                  0,                  0),                    // ITU:Q.713 3.20 | Ansi: 1000112.3 3.20
1066     MAKE_PARAM(MessageTypeInterworking,        0,0,                  0,                  0),                    // Ansi: 1000112.3 3.22
1067     MAKE_PARAM(INS,                            0,0,                  0,                  0),                    // Ansi: 1000112.3 3.21
1068     MAKE_PARAM(ISNI,                           0,0,                  0,                  0),                    // Ansi: 1000112.3 3.19
1069     { SS7MsgSCCP::EndOfParameters, 0, 0, 0, 0, 0 }
1070 };
1071 #undef MAKE_PARAM
1072 
1073 // Descriptor of SCCP message
1074 static const MsgParams s_common_params[] = {
1075     { SS7MsgSCCP::CR, true,
1076 	{
1077 	    SS7MsgSCCP::SourceLocalReference,
1078 	    SS7MsgSCCP::ProtocolClass,
1079 	SS7MsgSCCP::EndOfParameters,
1080 	    SS7MsgSCCP::CalledPartyAddress,
1081 	SS7MsgSCCP::EndOfParameters
1082 	}
1083     },
1084     { SS7MsgSCCP::CC, true,
1085 	{
1086 	    SS7MsgSCCP::DestinationLocalReference,
1087 	    SS7MsgSCCP::SourceLocalReference,
1088 	    SS7MsgSCCP::ProtocolClass,
1089 	SS7MsgSCCP::EndOfParameters,
1090 	SS7MsgSCCP::EndOfParameters
1091 	}
1092     },
1093     { SS7MsgSCCP::CREF, true,
1094 	{
1095 	    SS7MsgSCCP::DestinationLocalReference,
1096 	    SS7MsgSCCP::RefusalCause,
1097 	SS7MsgSCCP::EndOfParameters,
1098 	SS7MsgSCCP::EndOfParameters
1099 	}
1100     },
1101     { SS7MsgSCCP::RLSD, true,
1102 	{
1103 	    SS7MsgSCCP::DestinationLocalReference,
1104 	    SS7MsgSCCP::SourceLocalReference,
1105 	    SS7MsgSCCP::ReleaseCause,
1106 	SS7MsgSCCP::EndOfParameters,
1107 	SS7MsgSCCP::EndOfParameters
1108 	}
1109     },
1110     { SS7MsgSCCP::RLC, false,
1111 	{
1112 	    SS7MsgSCCP::DestinationLocalReference,
1113 	    SS7MsgSCCP::SourceLocalReference,
1114 	SS7MsgSCCP::EndOfParameters,
1115 	SS7MsgSCCP::EndOfParameters
1116 	}
1117     },
1118     { SS7MsgSCCP::DT1, false,
1119 	{
1120 	    SS7MsgSCCP::DestinationLocalReference,
1121 	    SS7MsgSCCP::Sequencing,
1122 	SS7MsgSCCP::EndOfParameters,
1123 	    SS7MsgSCCP::Data,
1124 	SS7MsgSCCP::EndOfParameters
1125 	}
1126     },
1127     { SS7MsgSCCP::DT2, false,
1128 	{
1129 	    SS7MsgSCCP::DestinationLocalReference,
1130 	    SS7MsgSCCP::Sequencing,
1131 	SS7MsgSCCP::EndOfParameters,
1132 	    SS7MsgSCCP::Data,
1133 	SS7MsgSCCP::EndOfParameters
1134 	}
1135     },
1136     { SS7MsgSCCP::AK, false,
1137 	{
1138 	    SS7MsgSCCP::DestinationLocalReference,
1139 	    SS7MsgSCCP::ReceiveSequenceNumber,
1140 	    SS7MsgSCCP::Credit,
1141 	SS7MsgSCCP::EndOfParameters,
1142 	SS7MsgSCCP::EndOfParameters
1143 	}
1144     },
1145     { SS7MsgSCCP::UDT, false,
1146 	{
1147 	    SS7MsgSCCP::ProtocolClass,
1148 	SS7MsgSCCP::EndOfParameters,
1149 	    SS7MsgSCCP::CalledPartyAddress,
1150 	    SS7MsgSCCP::CallingPartyAddress,
1151 	    SS7MsgSCCP::Data,
1152 	SS7MsgSCCP::EndOfParameters
1153 	}
1154     },
1155     { SS7MsgSCCP::UDTS, false,
1156 	{
1157 	    SS7MsgSCCP::ReturnCause,
1158 	SS7MsgSCCP::EndOfParameters,
1159 	    SS7MsgSCCP::CalledPartyAddress,
1160 	    SS7MsgSCCP::CallingPartyAddress,
1161 	    SS7MsgSCCP::Data,
1162 	SS7MsgSCCP::EndOfParameters
1163 	}
1164     },
1165     { SS7MsgSCCP::ED, false,
1166 	{
1167 	    SS7MsgSCCP::DestinationLocalReference,
1168 	SS7MsgSCCP::EndOfParameters,
1169 	    SS7MsgSCCP::Data,
1170 	SS7MsgSCCP::EndOfParameters
1171 	}
1172     },
1173     { SS7MsgSCCP::EA, false,
1174 	{
1175 	    SS7MsgSCCP::DestinationLocalReference,
1176 	SS7MsgSCCP::EndOfParameters,
1177 	SS7MsgSCCP::EndOfParameters
1178 	}
1179     },
1180     { SS7MsgSCCP::RSR, false,
1181 	{
1182 	    SS7MsgSCCP::DestinationLocalReference,
1183 	    SS7MsgSCCP::SourceLocalReference,
1184 	    SS7MsgSCCP::ResetCause,
1185 	SS7MsgSCCP::EndOfParameters,
1186 	SS7MsgSCCP::EndOfParameters
1187 	}
1188     },
1189     { SS7MsgSCCP::RSC, false,
1190 	{
1191 	    SS7MsgSCCP::DestinationLocalReference,
1192 	    SS7MsgSCCP::SourceLocalReference,
1193 	SS7MsgSCCP::EndOfParameters,
1194 	SS7MsgSCCP::EndOfParameters
1195 	}
1196     },
1197     { SS7MsgSCCP::ERR, false,
1198 	{
1199 	    SS7MsgSCCP::DestinationLocalReference,
1200 	    SS7MsgSCCP::ErrorCause,
1201 	SS7MsgSCCP::EndOfParameters,
1202 	SS7MsgSCCP::EndOfParameters
1203 	}
1204     },
1205     { SS7MsgSCCP::IT, false,
1206 	{
1207 	    SS7MsgSCCP::DestinationLocalReference,
1208 	    SS7MsgSCCP::SourceLocalReference,
1209 	    SS7MsgSCCP::ProtocolClass,
1210 	    SS7MsgSCCP::Sequencing,
1211 	    SS7MsgSCCP::Credit,
1212 	SS7MsgSCCP::EndOfParameters,
1213 	SS7MsgSCCP::EndOfParameters
1214 	}
1215     },
1216     { SS7MsgSCCP::XUDT, true,
1217 	{
1218 	    SS7MsgSCCP::ProtocolClass,
1219 	    SS7MsgSCCP::HopCounter,
1220 	SS7MsgSCCP::EndOfParameters,
1221 	    SS7MsgSCCP::CalledPartyAddress,
1222 	    SS7MsgSCCP::CallingPartyAddress,
1223 	    SS7MsgSCCP::Data,
1224 	SS7MsgSCCP::EndOfParameters
1225 	}
1226     },
1227     { SS7MsgSCCP::LUDT, true,
1228 	{
1229 	    SS7MsgSCCP::ProtocolClass,
1230 	    SS7MsgSCCP::HopCounter,
1231 	SS7MsgSCCP::EndOfParameters,
1232 	    SS7MsgSCCP::CalledPartyAddress,
1233 	    SS7MsgSCCP::CallingPartyAddress,
1234 	    SS7MsgSCCP::LongData,
1235 	SS7MsgSCCP::EndOfParameters
1236 	}
1237     },
1238     { SS7MsgSCCP::XUDTS, true,
1239 	{
1240 	    SS7MsgSCCP::ReturnCause,
1241 	    SS7MsgSCCP::HopCounter,
1242 	SS7MsgSCCP::EndOfParameters,
1243 	    SS7MsgSCCP::CalledPartyAddress,
1244 	    SS7MsgSCCP::CallingPartyAddress,
1245 	    SS7MsgSCCP::Data,
1246 	SS7MsgSCCP::EndOfParameters
1247 	}
1248     },
1249     { SS7MsgSCCP::LUDTS, true,
1250 	{
1251 	    SS7MsgSCCP::ReturnCause,
1252 	    SS7MsgSCCP::HopCounter,
1253 	SS7MsgSCCP::EndOfParameters,
1254 	    SS7MsgSCCP::CalledPartyAddress,
1255 	    SS7MsgSCCP::CallingPartyAddress,
1256 	    SS7MsgSCCP::LongData,
1257 	SS7MsgSCCP::EndOfParameters
1258 	}
1259     },
1260     { SS7MsgSCCP::Unknown, false, { SS7MsgSCCP::EndOfParameters } }
1261 };
1262 
1263 
decodeParam(const SS7SCCP * sccp,NamedList & list,const SCCPParam * param,const unsigned char * buf,unsigned int len,const String & prefix)1264 static bool decodeParam(const SS7SCCP* sccp, NamedList& list, const SCCPParam* param,
1265     const unsigned char* buf, unsigned int len, const String& prefix)
1266 {
1267     DDebug(sccp,DebugAll,"decodeParam(%p,%p,%p,%u) type=0x%02x, size=%u, name='%s'",
1268 	&list,param,buf,len,param->type,param->size,param->name);
1269     if (param->size && (param->size != len))
1270 	return false;
1271     if (param->decoder)
1272 	return param->decoder(sccp,list,param,buf,len,prefix);
1273     return decodeRaw(sccp,list,param,buf,len,prefix);
1274 }
1275 
1276 // Generic encode helper function for a single mandatory parameter
encodeParam(const SS7SCCP * sccp,SS7MSU & msu,const SCCPParam * param,const NamedList * params,ObjList & exclude,const String & prefix,unsigned char * buf=0)1277 static unsigned char encodeParam(const SS7SCCP* sccp, SS7MSU& msu,
1278     const SCCPParam* param, const NamedList* params, ObjList& exclude,
1279     const String& prefix, unsigned char* buf = 0)
1280 {
1281     DDebug(sccp,DebugAll,"encodeParam (mand) (%p,%p,%p,%p) type=0x%02x, size=%u, name='%s'",
1282 	&msu,param,params,buf,param->type,param->size,param->name);
1283     // variable length must not receive fixed buffer
1284     if (buf && !param->size)
1285 	return 0;
1286     NamedString* val = params ? params->getParam(prefix+param->name) : 0;
1287     if (val)
1288 	exclude.append(val)->setDelete(false);
1289     if (param->encoder)
1290 	return param->encoder(sccp,msu,buf,param,val,params,prefix);
1291     return encodeRaw(sccp,msu,buf,param,val,params,prefix);
1292 }
1293 
1294 // Generic encode helper for a single optional parameter
encodeParam(const SS7SCCP * sccp,SS7MSU & msu,const SCCPParam * param,const NamedString * val,const NamedList * extra,const String & prefix)1295 static unsigned char encodeParam(const SS7SCCP* sccp, SS7MSU& msu,
1296     const SCCPParam* param, const NamedString* val,
1297     const NamedList* extra, const String& prefix)
1298 {
1299     DDebug(sccp,DebugAll,"encodeParam (opt) (%p,%p,%p,%p) type=0x%02x, size=%u, name='%s'",
1300 	&msu,param,val,extra,param->type,param->size,param->name);
1301     // add the parameter type now but remember the old length
1302     unsigned int len = msu.length();
1303     unsigned char tmp = param->type;
1304     msu.append(&tmp,1);
1305 
1306     unsigned char size = 0;
1307     if (param->encoder)
1308 	size = param->encoder(sccp,msu,0,param,val,extra,prefix);
1309     else
1310 	size = encodeRaw(sccp,msu,0,param,val,extra,prefix);
1311     if (!size) {
1312 	Debug(sccp,DebugMild,"Unwinding type storage for failed parameter %s",param->name);
1313 	msu.truncate(len);
1314     }
1315     return size;
1316 }
1317 
1318 // Locate the description for a parameter by type
getParamDesc(SS7MsgSCCP::Parameters type)1319 static const SCCPParam* getParamDesc(SS7MsgSCCP::Parameters type)
1320 {
1321     const SCCPParam* param = s_paramDefs;
1322     for (; param->type != SS7MsgSCCP::EndOfParameters; param++) {
1323 	if (param->type == type)
1324 	    return param;
1325     }
1326     return 0;
1327 }
1328 
1329 // Locate the description for a parameter by name
getParamDesc(const String & name)1330 static const SCCPParam* getParamDesc(const String& name)
1331 {
1332     const SCCPParam* param = s_paramDefs;
1333     for (; param->type != SS7MsgSCCP::EndOfParameters; param++) {
1334 	if (name == param->name)
1335 	    return param;
1336     }
1337     return 0;
1338 }
1339 
1340 // Locate the description table for a message according to protocol type
getSccpParams(SS7MsgSCCP::Type msg)1341 static const MsgParams* getSccpParams(SS7MsgSCCP::Type msg)
1342 {
1343     const MsgParams* params = 0;
1344     for (params = s_common_params; params->type != SS7MsgSCCP::Unknown; params++) {
1345 	if (params->type == msg)
1346 	    return params;
1347     }
1348     return 0;
1349 }
1350 
1351 
names()1352 const TokenDict* SS7MsgSCCP::names()
1353 {
1354     return s_names;
1355 }
1356 
~SS7MsgSCCP()1357 SS7MsgSCCP::~SS7MsgSCCP()
1358 {
1359     if (m_data) {
1360 	m_data->clear(false);
1361 	TelEngine::destruct(m_data);
1362     }
1363 }
1364 
toString(String & dest,const SS7Label & label,bool params,const void * raw,unsigned int rawLen) const1365 void SS7MsgSCCP::toString(String& dest, const SS7Label& label, bool params,
1366 	const void* raw, unsigned int rawLen) const
1367 {
1368     const char* enclose = "\r\n-----";
1369     dest = enclose;
1370     if (raw && rawLen) {
1371 	String tmp;
1372 	tmp.hexify((void*)raw,rawLen,' ');
1373 	dest << "  " << tmp;
1374     }
1375     if (params) {
1376 	unsigned int n = m_params.length();
1377 	for (unsigned int i = 0; i < n; i++) {
1378 	    NamedString* s = m_params.getParam(i);
1379 	    if (s)
1380 		dest << "\r\n  " << s->name() << "='" << *s << "'";
1381 	}
1382     }
1383     dest << enclose;
1384 }
1385 
1386 /**
1387  * SS7MsgSccpReassemble
1388  */
1389 
SS7MsgSccpReassemble(SS7MsgSCCP * msg,const SS7Label & label,unsigned int timeToLive)1390 SS7MsgSccpReassemble::SS7MsgSccpReassemble(SS7MsgSCCP* msg, const SS7Label& label,
1391 	    unsigned int timeToLive)
1392     : SS7MsgSCCP(msg->type()), m_label(label), m_callingPartyAddress(""),
1393     m_segmentationLocalReference(0), m_timeout(0), m_remainingSegments(0),
1394     m_firstSgmDataLen(0)
1395 {
1396     m_callingPartyAddress.copySubParams(msg->params(),
1397 	    YSTRING("CallingPartyAddress."));
1398     m_segmentationLocalReference = msg->params().getIntValue(
1399 	    YSTRING("Segmentation.SegmentationLocalReference"));
1400     m_timeout = Time::msecNow() + timeToLive;
1401     m_remainingSegments = msg->params().getIntValue(
1402 	    YSTRING("Segmentation.RemainingSegments"));
1403     setData(new DataBlock(*msg->getData()));
1404     params().copyParams(msg->params());
1405     m_firstSgmDataLen = getData()->length();
1406     // Update protocol class
1407     if (msg->params().getIntValue(
1408 	    YSTRING("Segmentation.ProtocolClass"), -1) > 0)
1409 	params().setParam("ProtocolClass",msg->params().getValue(
1410 		YSTRING("Segmentation.ProtocolClass")));
1411 
1412 }
1413 
~SS7MsgSccpReassemble()1414 SS7MsgSccpReassemble::~SS7MsgSccpReassemble()
1415 {
1416     TelEngine::destruct(extractData());
1417 }
1418 
canProcess(const SS7MsgSCCP * msg,const SS7Label & label)1419 bool SS7MsgSccpReassemble::canProcess(const SS7MsgSCCP* msg, const SS7Label& label)
1420 {
1421     if (!compareLabel(m_label,label))
1422 	return false;
1423     if (m_segmentationLocalReference !=
1424 	    (u_int32_t)msg->params().getIntValue(YSTRING("Segmentation.SegmentationLocalReference")))
1425 	return false;
1426     NamedList address("");
1427     address.copySubParams(msg->params(),YSTRING("CallingPartyAddress."));
1428     return compareNamedList(address,m_callingPartyAddress);
1429 }
1430 
appendSegment(SS7MsgSCCP * msg,const SS7Label & label)1431 SS7MsgSccpReassemble::Return SS7MsgSccpReassemble::appendSegment(SS7MsgSCCP* msg, const SS7Label& label)
1432 {
1433     if (!msg)
1434 	return Rejected;
1435     if (!canProcess(msg,label))
1436 	return Rejected;
1437     if ((m_remainingSegments - 1) != msg->params().getIntValue(YSTRING("Segmentation.RemainingSegments"),-1)) {
1438 	DDebug("SS7MsgSccpReassemble",DebugNote,"Received out of sequence segment %d : %d",
1439 	       msg->params().getIntValue(YSTRING("Segmentation.RemainingSegments"),-1),m_remainingSegments);
1440 	return Error;
1441     }
1442     m_remainingSegments--;
1443     if (m_firstSgmDataLen < msg->getData()->length()) {
1444 	DDebug("SS7MsgSccpReassemble",DebugNote,"Received data segment bigger than first data segment");
1445 	return Error;
1446     }
1447     getData()->append(*msg->getData());
1448     return m_remainingSegments == 0 ? Finished : Accepted;
1449 }
1450 
1451 /**
1452  * class SCCP
1453  */
1454 
SCCP()1455 SCCP::SCCP()
1456     : m_translatorLocker(true,s_sccpTranslatorMutex), m_usersLocker(true,s_sccpMutexName), m_translator(0)
1457 {
1458 }
1459 
~SCCP()1460 SCCP::~SCCP()
1461 {
1462     DDebug(this,DebugAll,"Destroying SCCP [%p]",this);
1463     // If we have undetached users scream as hard as we can
1464     if (m_users.skipNull())
1465 	Debug(this,DebugCrit,"Destroying SCCP with %d undetached users!!!",m_users.count());
1466     if (m_translator)
1467 	Debug(this,DebugCrit,"Destroying SCCP with a valid translator!!!");
1468 }
1469 
attach(SCCPUser * user)1470 void SCCP::attach(SCCPUser* user)
1471 {
1472     if (!user)
1473 	return;
1474     DDebug(this,DebugAll,"Attaching user (%p)",user);
1475     Lock lock(m_usersLocker);
1476     // Detach it if already exists
1477     detach(user);
1478     // Append the user
1479     m_users.append(user)->setDelete(false);
1480 }
1481 
detach(SCCPUser * user)1482 void SCCP::detach(SCCPUser* user)
1483 {
1484     if (!user)
1485 	return;
1486     Lock lock(m_usersLocker);
1487     m_users.remove(user,false);
1488 }
1489 
attachGTT(GTT * gtt)1490 void SCCP::attachGTT(GTT* gtt)
1491 {
1492     Lock lock(m_translatorLocker);
1493     if (gtt == m_translator)
1494 	return;
1495     m_translator = gtt;
1496 }
1497 
translateGT(const NamedList & params,const String & prefix,const String & nextPrefix)1498 NamedList* SCCP::translateGT(const NamedList& params, const String& prefix, const String& nextPrefix)
1499 {
1500     Lock lock(m_translatorLocker);
1501     if (!m_translator) {
1502 	Debug(this,isEndpoint() ? DebugInfo : DebugMild,
1503 	      "Failed to translate Global Title! Reason: No GTT attached to sccp [%p]",this);
1504 	return 0;
1505     }
1506     RefPointer<GTT> translator = m_translator;
1507     if (!translator)
1508 	return 0;
1509     lock.drop();
1510     return translator->routeGT(params,prefix,nextPrefix);
1511 }
1512 
pushMessage(DataBlock & data,NamedList & params,int ssn)1513 HandledMSU SCCP::pushMessage(DataBlock& data, NamedList& params, int ssn)
1514 {
1515     m_usersLocker.lock();
1516     ListIterator iter(m_users);
1517     SCCPUser* usr = 0;
1518     params.setParam("ssn",String(ssn));
1519     while ((usr = YOBJECT(SCCPUser,iter.get()))) {
1520 	RefPointer<SCCPUser> pointer = usr;
1521 	if (!pointer)
1522 	    continue;
1523 	m_usersLocker.unlock();
1524 	HandledMSU handled = pointer->receivedData(data,params);
1525 	switch (handled) {
1526 	    case HandledMSU::Accepted:
1527 	    case HandledMSU::Failure:
1528 		return handled;
1529 	    case HandledMSU::Rejected:
1530 	    default:
1531 		break; // break switch
1532 	}
1533 	m_usersLocker.lock();
1534     }
1535     m_usersLocker.unlock();
1536     DDebug(this,DebugInfo,"SCCP data message was not processed by any user!");
1537     return HandledMSU::Unequipped;
1538 }
1539 
notifyMessage(DataBlock & data,NamedList & params,int ssn)1540 HandledMSU SCCP::notifyMessage(DataBlock& data, NamedList& params, int ssn)
1541 {
1542     m_usersLocker.lock();
1543     ListIterator iter(m_users);
1544     SCCPUser* usr = 0;
1545     params.setParam("ssn",String(ssn));
1546     while ((usr = YOBJECT(SCCPUser,iter.get()))) {
1547 	RefPointer<SCCPUser> pointer = usr;
1548 	if (!pointer)
1549 	    continue;
1550 	m_usersLocker.unlock();
1551 	HandledMSU handled = pointer->notifyData(data,params);
1552 	switch (handled) {
1553 	    case HandledMSU::Accepted:
1554 	    case HandledMSU::Failure:
1555 		return handled;
1556 	    case HandledMSU::Rejected:
1557 	    default:
1558 		break; // break switch
1559 	}
1560 	m_usersLocker.lock();
1561     }
1562     m_usersLocker.unlock();
1563     DDebug(this,DebugAll,"SCCP notify message was not processed by any user!");
1564     return HandledMSU::Unequipped;
1565 }
1566 
managementMessage(Type type,NamedList & params)1567 bool SCCP::managementMessage(Type type, NamedList& params)
1568 {
1569     m_usersLocker.lock();
1570     ListIterator iter(m_users);
1571     bool ret = false;
1572     SCCPUser* usr = 0;
1573     while ((usr = YOBJECT(SCCPUser,iter.get()))) {
1574 	RefPointer<SCCPUser> pointer = usr;
1575 	if (!pointer)
1576 	    continue;
1577 	m_usersLocker.unlock();
1578 	if (pointer->managementNotify(type,params))
1579 	    ret = true;
1580 	m_usersLocker.lock();
1581     }
1582     m_usersLocker.unlock();
1583     return ret;
1584 }
1585 
sendMessage(DataBlock & data,const NamedList & params)1586 int SCCP::sendMessage(DataBlock& data, const NamedList& params)
1587 {
1588     Debug(this,DebugStub,"Please implement SCCP sendMessage");
1589     return false;
1590 }
1591 
managementStatus(Type type,NamedList & params)1592 bool SCCP::managementStatus(Type type, NamedList& params)
1593 {
1594     DDebug(this,DebugStub,"Please implement SCCP::managementStatus()!!");
1595     return false;
1596 }
1597 
resolveGTParams(SS7MsgSCCP * msg,const NamedList * gtParams)1598 void SCCP::resolveGTParams(SS7MsgSCCP* msg, const NamedList* gtParams)
1599 {
1600     if (!msg || !gtParams)
1601 	return;
1602     msg->params().clearParam(YSTRING("CalledPartyAddress"),'.');
1603     for (unsigned int i = 0;i < gtParams->length();i++) {
1604 	NamedString* val = gtParams->getParam(i);
1605 	if (val && (val->name().startsWith("gt") || val->name() == YSTRING("pointcode") ||
1606 		val->name() == YSTRING("ssn") || val->name() == YSTRING("route")))
1607 	    msg->params().setParam("CalledPartyAddress." + val->name(),*val);
1608     }
1609     NamedString* param = 0;
1610     if ((param = gtParams->getParam(YSTRING("sccp"))))
1611 	msg->params().setParam(param->name(),*param);
1612     if (!gtParams->hasSubParams(YSTRING("CallingPartyAddress.")))
1613 	return;
1614     msg->params().clearParam(YSTRING("CallingPartyAddress"),'.');
1615     msg->params().copySubParams(*gtParams,YSTRING("CallingPartyAddress."),false);
1616 }
1617 
1618 /**
1619  * class SCCPUser
1620  */
1621 
SCCPUser(const NamedList & config)1622 SCCPUser::SCCPUser(const NamedList& config)
1623     : SignallingComponent(config,&config),
1624       m_sccp(0), m_sccpMutex(true,s_userMutexName), m_sls(-1)
1625 {
1626     String tmp;
1627     config.dump(tmp,"\r\n  ",'\'',true);
1628     DDebug(DebugAll,"SCCPUser::SCCPUser(%s)",tmp.c_str());
1629 }
1630 
~SCCPUser()1631 SCCPUser::~SCCPUser()
1632 {
1633     DDebug(this,DebugAll,"Destroying SCCPUser [%p]",this);
1634 }
1635 
destroyed()1636 void SCCPUser::destroyed()
1637 {
1638     Lock lock(m_sccpMutex);
1639     if (m_sccp)
1640 	attach(0);
1641     lock.drop();
1642     SignallingComponent::destroyed();
1643 }
1644 
attach(SCCP * sccp)1645 void SCCPUser::attach(SCCP* sccp)
1646 {
1647     Lock lock(m_sccpMutex);
1648     if (!sccp) {
1649 	if (!m_sccp) {
1650 	    DDebug(this,DebugNote,"Request to attach null sccp!!! ");
1651 	    return;
1652 	}
1653 	m_sccp->detach(this);
1654 	TelEngine::destruct(m_sccp);
1655 	return;
1656     }
1657     if (m_sccp == sccp) {
1658 	sccp->deref();
1659 	DDebug(this,DebugInfo,"Requesting to attach the same sccp (%p)",m_sccp);
1660 	return;
1661     }
1662 
1663     SCCP* temp = m_sccp;
1664     m_sccp = sccp;
1665     // Do not ref the sccp because we already have an reference
1666     m_sccp->attach(this);
1667     // Destruct the old sccp
1668     if (temp) {
1669 	temp->detach(this);
1670 	TelEngine::destruct(temp);
1671 	temp = 0;
1672     }
1673 }
1674 
initialize(const NamedList * config)1675 bool SCCPUser::initialize(const NamedList* config)
1676 {
1677     DDebug(this,DebugInfo,"SCCPUser::initialize(%p) [%p]",config,this);
1678     if (engine()) {
1679 	NamedList params("sccp");
1680 	if (!resolveConfig(YSTRING("sccp"),params,config))
1681 	    params.addParam("local-config","true");
1682 	// NOTE SS7SCCP is created on demand!!!
1683 	// engine ->build method will search for the requested sccc and
1684 	// if it was found will return it with the ref counter incremented
1685 	// if it wasn't found the refcounter will be 1
1686 	// For this behavior SCCPUser attach method will not reference the sccp
1687 	// pointer instead will use the reference of engine build
1688 	if (params.toBoolean(true))
1689 	    attach(YOBJECT(SCCP,engine()->build("SCCP",params,true)));
1690     } else
1691 	Debug(this,DebugWarn,"SccpUser::initialize() can not attach sccp; null SigEngine!");
1692     return m_sccp != 0;
1693 }
1694 
sendData(DataBlock & data,NamedList & params)1695 bool SCCPUser::sendData(DataBlock& data, NamedList& params)
1696 {
1697     if (!m_sccp) {
1698 	Debug(this,DebugMild,"Can not send data! No Sccp attached!");
1699 	return false;
1700     }
1701     bool sequenceControl = params.getBoolValue("sequenceControl",false);
1702     params.addParam("ProtocolClass",(sequenceControl ? "1" : "0"));
1703     int sls = params.getIntValue("sls",-1);
1704     if (sls < 0) {
1705 	// Preserve the sls only if sequence control is requested
1706 	if (sequenceControl)
1707 	    sls = m_sls;
1708 	if (sls < 0)
1709 	    sls = Random::random() & 0xff;
1710     }
1711     else
1712 	sls &= 0xff;
1713     params.setParam("sls", String(sls));
1714     if (sccp()->sendMessage(data,params) < 0)
1715 	return false;
1716     m_sls = sls; // Keep the last SLS sent
1717     return true;
1718 }
1719 
sccpNotify(SCCP::Type type,NamedList & params)1720 bool SCCPUser::sccpNotify(SCCP::Type type, NamedList& params)
1721 {
1722     if (!m_sccp) {
1723 	Debug(this,DebugMild,"Can not send data! No Sccp attached!");
1724 	return false;
1725     }
1726     return sccp()->managementStatus(type,params);
1727 }
1728 
receivedData(DataBlock & data,NamedList & params)1729 HandledMSU SCCPUser::receivedData(DataBlock& data, NamedList& params)
1730 {
1731     Debug(DebugStub,"Please implement SCCPUser::receivedData(DataBlock& data, const NamedList& params)");
1732     return 0;
1733 }
1734 
notifyData(DataBlock & data,NamedList & params)1735 HandledMSU SCCPUser::notifyData(DataBlock& data, NamedList& params)
1736 {
1737     Debug(DebugStub,"Please implement SCCPUser::notifyData(DataBlock& data, const NamedList& params)");
1738     return 0;
1739 }
1740 
managementNotify(SCCP::Type type,NamedList & params)1741 bool SCCPUser::managementNotify(SCCP::Type type, NamedList& params)
1742 {
1743     Debug(this,DebugStub,"Please implement SCCPUser::managementNotify()");
1744     return false;
1745 }
1746 
1747 /**
1748  * class GTT
1749  */
1750 
GTT(const NamedList & config)1751 GTT::GTT(const NamedList& config)
1752     : SignallingComponent(config.safe("GTT"),&config,"ss7-gtt"),
1753       m_sccp(0)
1754 {
1755 }
1756 
~GTT()1757 GTT::~GTT()
1758 {
1759     if (m_sccp) {
1760 	m_sccp->attachGTT(0);
1761 	TelEngine::destruct(m_sccp);
1762 	m_sccp = 0;
1763     }
1764 }
1765 
initialize(const NamedList * config)1766 bool GTT::initialize(const NamedList* config)
1767 {
1768     DDebug(this,DebugInfo,"GTT::initialize(%p) [%p]",config,this);
1769     if (engine()) {
1770 	NamedList params("sccp");
1771 	if (!resolveConfig(YSTRING("sccp"),params,config))
1772 	    params.addParam("local-config","true");
1773 	if (params.toBoolean(true))
1774 	    attach(YOBJECT(SCCP,engine()->build("SCCP",params,true)));
1775     } else
1776 	Debug(this,DebugWarn,"GTT::initialize() can not attach sccp; null SigEngine");
1777     return m_sccp != 0;
1778 }
1779 
routeGT(const NamedList & gt,const String & prefix,const String & nextPrefix)1780 NamedList* GTT::routeGT(const NamedList& gt, const String& prefix, const String& nextPrefix)
1781 {
1782     Debug(DebugStub,"Please implement NamedList* GTT::routeGT(%s,%s,%s)",
1783 	    gt.c_str(),prefix.c_str(),nextPrefix.c_str());
1784     return 0;
1785 }
1786 
attach(SCCP * sccp)1787 void GTT::attach(SCCP* sccp)
1788 {
1789     if (!sccp)
1790 	return;
1791     if (m_sccp == sccp) {
1792 	sccp->deref();
1793 	return;
1794     }
1795     SCCP* tmp = m_sccp;
1796     m_sccp = sccp;
1797     m_sccp->attachGTT(this);
1798     if (!tmp)
1799 	return;
1800     TelEngine::destruct(tmp);
1801     tmp = 0;
1802 }
1803 
destroyed()1804 void GTT::destroyed()
1805 {
1806     if (m_sccp) {
1807 	m_sccp->attachGTT(0);
1808 	TelEngine::destruct(m_sccp);
1809 	m_sccp = 0;
1810     }
1811     SignallingComponent::destroyed();
1812 }
1813 
1814 /**
1815  * SCCPManagement
1816  */
SCCPManagement(const NamedList & params,SS7PointCode::Type type)1817 SCCPManagement::SCCPManagement(const NamedList& params, SS7PointCode::Type type)
1818     : SignallingComponent(params,&params,"ss7-sccp-mgm"),
1819       Mutex(true, s_managementMutexName), m_remoteSccp(),
1820     m_statusTest(), m_localSubsystems(), m_concerned(), m_pcType(type), m_sccp(0), m_unknownSubsystems("ssn"),
1821     m_subsystemFailure(0), m_routeFailure(0), m_autoAppend(false), m_printMessages(false)
1822 {
1823     DDebug(DebugAll,"Creating SCCP management (%p)",this);
1824     // stat.info timer
1825     m_testTimeout = params.getIntValue(YSTRING("test-timer"),5000);
1826     if (m_testTimeout < 5000)
1827 	m_testTimeout = 5000;
1828     else if (m_testTimeout > 10000)
1829 	m_testTimeout = 10000;
1830     // coord.chg timer
1831     m_coordTimeout = params.getIntValue(YSTRING("coord-timer"),1000);
1832     if (m_coordTimeout < 1000)
1833 	m_coordTimeout = 1000;
1834     if (m_coordTimeout > 2000)
1835 	m_coordTimeout = 2000;
1836     m_ignoreStatusTestsInterval = params.getIntValue(YSTRING("ignore-tests"),1000);
1837     m_printMessages = params.getBoolValue(YSTRING("print-messages"), false);
1838     m_autoAppend = params.getBoolValue(YSTRING("auto-monitor"),false);
1839     for (unsigned int i = 0;i < params.length();i++) {
1840 	NamedString* param = params.getParam(i);
1841 	if (!param)
1842 	    continue;
1843 	XDebug(this,DebugAll,"Parsing param %s : %s",param->name().c_str(),param->c_str());
1844 	if (param->name() == YSTRING("remote")) {
1845 	    SccpRemote* rem = new SccpRemote(m_pcType);
1846 	    if (rem->initialize(*param))
1847 		m_remoteSccp.append(rem);
1848 	    else {
1849 		Debug(this,DebugConf,"Failed to initialize remote sccp %s",param->c_str());
1850 		TelEngine::destruct(rem);
1851 	    }
1852 	} else if (param->name() == YSTRING("concerned")) {
1853 	    SccpRemote* rem = new SccpRemote(m_pcType);
1854 	    if (rem->initialize(*param))
1855 		m_concerned.append(rem);
1856 	    else {
1857 		Debug(this,DebugConf,"Failed to initialize concerned sccp %s",param->c_str());
1858 		TelEngine::destruct(rem);
1859 	    }
1860 	}
1861     }
1862     NamedString* lsubs = params.getParam(YSTRING("local-subsystems"));
1863     ObjList* list = lsubs ? lsubs->split(',') : 0;
1864     if (!list)
1865 	return;
1866     for (ObjList* o = list->skipNull();o;o = o->skipNext()) {
1867 	String* s = static_cast<String*>(o->get());
1868 	unsigned char ssn = s->toInteger();
1869 	if (ssn < 2)
1870 	    continue;
1871 	m_localSubsystems.append(new SccpLocalSubsystem(ssn,getCoordTimeout(),
1872 		    getIgnoreTestsInterval()));
1873     }
1874     TelEngine::destruct(list);
1875 }
1876 
~SCCPManagement()1877 SCCPManagement::~SCCPManagement()
1878 {
1879     DDebug(this,DebugAll,"Destroing SCCPManagement %p",this);
1880     m_sccp = 0;
1881 }
1882 
attach(SS7SCCP * sccp)1883 void SCCPManagement::attach(SS7SCCP* sccp)
1884 {
1885     Lock lock(this);
1886     if (!sccp || m_sccp)
1887 	return;
1888     m_sccp = sccp;
1889 }
1890 
initialize(const NamedList * config)1891 bool SCCPManagement::initialize(const NamedList* config)
1892 {
1893     if (!config) {
1894 	DDebug(this,DebugNote,"Request to initialize sccp management from null conf");
1895 	return true;
1896     }
1897     Lock lock(this);
1898 #ifdef DEBUG
1899     String dst;
1900     config->dump(dst,"\r\n");
1901     Debug(this,DebugInfo,"Initializeing SCCPManagement(%p) %s",this,dst.c_str());
1902 #endif
1903     m_printMessages = config->getBoolValue(YSTRING("print-messages"), m_printMessages);
1904     return true;
1905 }
1906 
pointcodeStatus(SS7Layer3 * link,bool operational)1907 void SCCPManagement::pointcodeStatus(SS7Layer3* link, bool operational)
1908 {
1909     if (!sccp() || !operational) {
1910 	DDebug(this,DebugNote,"Can not process pointcode status sccp(%p) , is up : %s",
1911 	       sccp(), String::boolText(operational));
1912 	return;
1913     }
1914     lock();
1915     for (ObjList* o = m_remoteSccp.skipNull();o;o = o->skipNext()) {
1916 	SccpRemote* rsccp = static_cast<SccpRemote*>(o->get());
1917 	SS7Route::State state = sccp()->network()->getRouteState(m_pcType,rsccp->getPointCode());
1918 	XDebug(this,DebugAll,"Checking route status for remote sccp %s oldState: '%s' newState: '%s'",
1919 	       rsccp->toString().c_str(),stateName(rsccp->getState()),SS7Route::stateName(state));
1920 	if ((int)state != (int)rsccp->getState()) {
1921 	    unlock();
1922 	    manageSccpRemoteStatus(rsccp,state);
1923 	    lock();
1924 	}
1925     }
1926     unlock();
1927 }
1928 
routeStatus(SS7PointCode::Type type,const SS7PointCode & node,SS7Route::State state)1929 void SCCPManagement::routeStatus(SS7PointCode::Type type, const SS7PointCode& node, SS7Route::State state)
1930 {
1931     if (!sccp() || !sccp()->isLayer3Up()) {
1932 	DDebug(this,DebugNote,"Can not process pointcode status sccp(%p) , is up : %s",
1933 	       sccp(), sccp() ? String::boolText(sccp()->isLayer3Up()) : "false");
1934 	return;
1935     }
1936     lock();
1937     for (ObjList* o = m_remoteSccp.skipNull();o;o = o->skipNext()) {
1938 	SccpRemote* rsccp = static_cast<SccpRemote*>(o->get());
1939 #ifdef XDEBUG
1940 	String dest;
1941 	dest << " Local: " << rsccp->getPointCode() << " remote : " << node;
1942 	XDebug (this,DebugNote,"Processing routeStatus %s oldState: '%s' newState: '%s'", dest.c_str(),
1943 		stateName(rsccp->getState()),SS7Route::stateName(state));
1944 #endif
1945 	if (rsccp->getPointCode() != node)
1946 	    continue;
1947 	if ((int)rsccp->getState() == (int)state)
1948 	    break;
1949 	RefPointer<SccpRemote> ref = rsccp;
1950 	if (!ref)
1951 	    continue;
1952 	unlock();
1953 	manageSccpRemoteStatus(rsccp,state);
1954 	return;
1955     }
1956     unlock();
1957 }
1958 
handleMessage(int msgType,unsigned char ssn,unsigned char smi,NamedList & params)1959 bool SCCPManagement::handleMessage(int msgType, unsigned char ssn, unsigned char smi, NamedList& params)
1960 {
1961     int pointcode = params.getIntValue(YSTRING("pointcode"));
1962     Lock lock(this);
1963     bool sendMsg = false;
1964     MsgType msg = SSA;
1965     switch (msgType) {
1966 	case SSA:
1967 	case SSP:
1968 	{
1969 	    SccpSubsystem* sccpSub = new SccpSubsystem(ssn);
1970 	    SccpRemote* rsccp = new SccpRemote(pointcode,m_pcType);
1971 	    lock.drop();
1972 	    if (ssn == 1 && msgType == SSA)
1973 		manageSccpRemoteStatus(rsccp,SS7Route::Allowed);
1974 	    else if (ssn > 1)
1975 		handleSubsystemStatus(sccpSub, msgType == SSA, rsccp, smi);
1976 	    else
1977 		Debug(this,DebugWarn,"Received Invalid sccp message %s for ssn %d",
1978 		      lookup(msgType,s_managementMessages), ssn);
1979 	    TelEngine::destruct(sccpSub);
1980 	    TelEngine::destruct(rsccp);
1981 	    return true;
1982 	}
1983 	case SST: // Received sst
1984 	{
1985 	    if (ssn == 1)  { // SST is initiated for local sccp send ssa
1986 		sendMsg = true;
1987 		break;
1988 	    }
1989 	    SccpLocalSubsystem* sccps = getLocalSubsystem(ssn);
1990 	    if (sccps) {
1991 		XDebug(this,DebugAll,"Received SST for %d state: %s ignoreTests %s",
1992 		       ssn,stateName(sccps->getState()),String::boolText(sccps->ignoreTests()));
1993 		if (sccps->ignoreTests())
1994 		    return true;
1995 		if (sccps->getState() == SCCPManagement::Allowed) {
1996 		    sendMsg = true;
1997 		    break;
1998 		}
1999 		lock.drop();
2000 		if (!managementMessage(SCCP::SubsystemStatus,params))
2001 		    return true;
2002 		String* status = params.getParam(YSTRING("subsystem-status"));
2003 		if (status && *status == YSTRING("UserInService"))
2004 		    sendMessage(msg,params);
2005 		return true;
2006 	    }
2007 	    if (!sendMsg)
2008 		Debug(this,DebugConf,"Received SST from: '%s' for missing local subsystem %d",
2009 		    params.getValue(YSTRING("RemotePC")),ssn);
2010 	    break;
2011 	}
2012 	case SOR:
2013 	{
2014 	    lock.drop();
2015 	    managementMessage(SCCP::CoordinateIndication,params);
2016 	    return true;
2017 	}
2018 	case SOG:
2019 	    handleSog(ssn,pointcode);
2020 	    return true;
2021 	default:
2022 	    Debug(sccp(),DebugNote,"Received unknown management Message '%s'",
2023 		  lookup(msgType,s_managementMessages));
2024     }
2025     lock.drop();
2026     if (sendMsg)
2027 	sendMessage(msg,params);
2028     return true;
2029 }
2030 
managementMessage(SCCP::Type type,NamedList & params)2031 bool SCCPManagement::managementMessage(SCCP::Type type, NamedList& params)
2032 {
2033     if (!m_sccp)
2034 	return false;
2035     return m_sccp->managementMessage(type,params);
2036 }
2037 
putValue(NamedList & params,int val,const char * name,bool dict)2038 void SCCPManagement::putValue(NamedList& params,int val,const char* name, bool dict)
2039 {
2040     if (val < 0)
2041 	return;
2042     if (!dict)
2043 	params.setParam(name,String(val));
2044     else
2045 	params.setParam(name,lookup(val,s_broadcastType));
2046 }
2047 
localBroadcast(SCCP::Type type,int pointcode,int sps,int rss,int rl,int ssn,int ss)2048 void SCCPManagement::localBroadcast(SCCP::Type type, int pointcode, int sps,
2049 		int rss, int rl, int ssn, int ss)
2050 {
2051     if (!m_sccp)
2052 	return;
2053     NamedList params("lb");
2054     putValue(params,pointcode,"pointcode");
2055     putValue(params,rl,"restriction-level");
2056     putValue(params,ssn,"ssn");
2057     putValue(params,sps,"signalling-point-status",true);
2058     putValue(params,ss,"subsystem-status",true);
2059     putValue(params,rss,"remote-sccp-status",true);
2060     m_sccp->managementMessage(type,params);
2061 }
2062 
getLocalSubsystem(unsigned char ssn)2063 SccpLocalSubsystem* SCCPManagement::getLocalSubsystem(unsigned char ssn)
2064 {
2065     Lock lock(this);
2066     for (ObjList* o = m_localSubsystems.skipNull();o;o = o->skipNext()) {
2067 	SccpLocalSubsystem* ss = static_cast<SccpLocalSubsystem*>(o->get());
2068 	if (ss && ss->getSSN() == ssn)
2069 	    return ss;
2070     }
2071     return 0;
2072 }
2073 
processMessage(SS7MsgSCCP * message)2074 bool SCCPManagement::processMessage(SS7MsgSCCP* message)
2075 {
2076     Debug(DebugStub,"Please implement management message decoder");
2077     return true;
2078 }
2079 
broadcastType()2080 const TokenDict* SCCPManagement::broadcastType()
2081 {
2082     return s_broadcastType;
2083 }
2084 
notify(SCCP::Type type,NamedList & params)2085 void SCCPManagement::notify(SCCP::Type type, NamedList& params)
2086 {
2087     if (!m_sccp)
2088 	return;
2089 #ifdef DEBUG
2090     String tmp;
2091     params.dump(tmp,"\r\n");
2092     Debug(this,DebugAll,"User notify %s : \r\n%s",lookup(type,s_sccpNotif),tmp.c_str());
2093 #endif
2094     unsigned char ssn = params.getIntValue(YSTRING("ssn"));
2095     if (ssn < 2) {
2096 	Debug(this,DebugNote,"Received management notify with invalid ssn %d",ssn);
2097 	return;
2098     }
2099     unsigned char smi = params.getIntValue(YSTRING("smi")); // subsystem multiplicity indicator
2100     if (smi > 3) {
2101 	Debug(this,DebugNote, "Received management notify message with unknown smi: %d , ssn: %d",
2102 		  smi,ssn);
2103 	smi = 0;
2104     }
2105     switch (type) {
2106 	case SCCP::CoordinateRequest: // Affected subsystem, subsystem multiplicity indicator
2107 	    handleCoordinateChanged(ssn,smi,params);
2108 	    break;
2109 	case SCCP::CoordinateResponse:// Affected subsystem, subsystem multiplicity indicator
2110 	    params.setParam(YSTRING("pointcode"),String(m_sccp->getPackedPointCode()));
2111 	    sendMessage(SOG,params);
2112 	    break;
2113 	case SCCP::StatusRequest: // Affected subsystem, subsystem multiplicity indicator, user status
2114 	{
2115 	    const char* subsystemStatus = params.getValue(YSTRING("subsystem-status"));
2116 	    int status = lookup(subsystemStatus,broadcastType());
2117 	    if (status != UserOutOfService && status != UserInService) {
2118 		Debug(this,DebugNote,"Reveived subsystem status indication with wrong subsystem status: %s",
2119 			subsystemStatus);
2120 		return;
2121 	    }
2122 	    SccpSubsystem* sub = new SccpSubsystem(ssn);
2123 	    handleSubsystemStatus(sub, status == UserInService, 0, smi);
2124 	    TelEngine::destruct(sub);
2125 	    break;
2126 	}
2127 	default:
2128 	    Debug(this,DebugNote,"Unhandled message '%s' received from attached users!",
2129 		  lookup(type,s_sccpNotif));
2130     }
2131 }
2132 
handleSog(unsigned char ssn,int pointcode)2133 void SCCPManagement::handleSog(unsigned char ssn, int pointcode)
2134 {
2135     for (ObjList* ol = m_localSubsystems.skipNull();ol;ol = ol->skipNext()) {
2136 	SccpLocalSubsystem* sls = static_cast<SccpLocalSubsystem*>(ol->get());
2137 	if (sls->receivedSOG(ssn,pointcode))
2138 	    break;
2139     }
2140 }
2141 
handleCoordinateChanged(unsigned char ssn,int smi,const NamedList & params)2142 void SCCPManagement::handleCoordinateChanged(unsigned char ssn, int smi, const NamedList& params)
2143 {
2144     Lock lock(this);
2145     SccpLocalSubsystem* sub = getLocalSubsystem(ssn);
2146     if (!sub) {
2147 	Debug(this,DebugInfo,"Dinamicaly appending ssn %d to local subsystems list!",ssn);
2148 	sub = new SccpLocalSubsystem(ssn,m_coordTimeout,m_ignoreStatusTestsInterval,smi);
2149 	m_localSubsystems.append(sub);
2150     }
2151     sub->ref();
2152     lock.drop();
2153     if (sub->getState() == SCCPManagement::Prohibited)
2154 	Debug(this,DebugStub,"Subsystem %d wishes to go oos but is already oos! Logic Bug?",sub->getSSN());
2155     sub->clearBackups();
2156     int count = params.getIntValue(YSTRING("backups"));
2157     for (int i = 0;i < count; i++) {
2158 	String name = "backup.";
2159 	name << i;
2160 	int subsys = params.getIntValue(name + ".ssn", -1);
2161 	int pointcode = params.getIntValue(name + ".pointcode",-1);
2162 	if (pointcode <= 0) {
2163 	    Debug(this,DebugStub,"Coordinate change request to a local subsystem!");
2164 	    continue;
2165 	}
2166 	if (subsys < 2 || pointcode < 0) {
2167 	    Debug(this,DebugMild,"Invalid backup subsystem pc:%d, ssn:%d",pointcode,subsys);
2168 	    continue;
2169 	}
2170 	RemoteBackupSubsystem* bs = new RemoteBackupSubsystem(subsys,pointcode,true);
2171 	sub->appendBackup(bs);
2172 	NamedList data("");
2173 	data.setParam("smi",String(smi));
2174 	data.setParam("ssn",String(subsys));
2175 	data.setParam("pointcode",String(pointcode));
2176 	data.setParam("RemotePC",String(pointcode));
2177 	sendMessage(SOR,data);
2178     }
2179     sub->startCoord();
2180     sub->setState(WaitForGrant);
2181     TelEngine::destruct(sub);
2182 }
2183 
getRemoteSccp(int pointcode)2184 SccpRemote* SCCPManagement::getRemoteSccp(int pointcode)
2185 {
2186     for (ObjList* o = m_remoteSccp.skipNull();o;o = o->skipNext()) {
2187 	SccpRemote* rsccp = static_cast<SccpRemote*>(o->get());
2188 	if (rsccp->getPackedPointcode() == pointcode)
2189 	    return rsccp;
2190     }
2191     return 0;
2192 }
2193 
routeFailure(SS7MsgSCCP * msg)2194 void SCCPManagement::routeFailure(SS7MsgSCCP* msg)
2195 {
2196     if (!m_sccp)
2197 	return;
2198     Lock lock(this);
2199     m_routeFailure++;
2200     if (!msg || !msg->params().getParam(YSTRING("RemotePC"))) {
2201 	DDebug(this,DebugNote,"Route failure, with no pointcode present!");
2202 	return;
2203     }
2204     int pointcode = msg->params().getIntValue(YSTRING("RemotePC"));
2205     if (pointcode < 1) {
2206 	Debug(this,DebugWarn,"Remote pointcode %d is invalid!",pointcode);
2207 	return;
2208     }
2209     if (pointcode == m_sccp->getPackedPointCode())
2210 	return;
2211     SccpRemote* rsccp = getRemoteSccp(pointcode);
2212     if (rsccp && rsccp->getState() == SCCPManagement::Prohibited) {
2213 	lock.drop();
2214 	updateTables(rsccp);
2215 	return;
2216     }
2217     if (!rsccp) {
2218 	if (m_autoAppend) {
2219 	    Debug(this,DebugNote,"Dynamic appending remote sccp %d to state monitoring list",
2220 		  pointcode);
2221 	    rsccp = new SccpRemote(pointcode,m_pcType);
2222 	    m_remoteSccp.append(rsccp);
2223 	} else
2224 	    Debug(this,DebugMild,
2225 		  "Remote sccp '%d' state is not monitored! Future message routing may not reach target!",
2226 		  pointcode);
2227     }
2228     RefPointer<SccpRemote>ref = rsccp;
2229     lock.drop();
2230     if (!ref)
2231 	return;
2232     manageSccpRemoteStatus(rsccp,SS7Route::Prohibited);
2233 }
2234 
subsystemFailure(SS7MsgSCCP * msg,const SS7Label & label)2235 void SCCPManagement::subsystemFailure(SS7MsgSCCP* msg, const SS7Label& label)
2236 {
2237     if (!m_sccp) {
2238 	DDebug(this,DebugNote,"Request to process subsystem failure with no sccp attached!");
2239 	return;
2240     }
2241     if (!msg || !msg->params().getParam(YSTRING("CalledPartyAddress.ssn"))) {
2242 	DDebug(this,DebugNote,"Subsystem failure! no ssn");
2243 	return;
2244     }
2245     int ssn = msg->params().getIntValue(YSTRING("CalledPartyAddress.ssn"),0);
2246     if (ssn <= 1) {
2247 	DDebug(this,DebugNote,"Subsystem failure, invalid ssn: '%d'",ssn);
2248 	return;
2249     }
2250     Lock lock(this);
2251     // Find local subsystem and change status
2252     SccpLocalSubsystem* ss = getLocalSubsystem(ssn);
2253     if (ss)
2254 	ss->setState(SCCPManagement::Prohibited);
2255     if (m_sccp->extendedMonitoring()) {
2256 	m_subsystemFailure++;
2257 	NamedString* sub = msg->params().getParam(YSTRING("CalledPartyAddress.ssn"));
2258 	if (sub) {
2259 	    NamedString* ssnParam = m_unknownSubsystems.getParam(*sub);
2260 	    if (ssnParam)
2261 		incrementNS(ssnParam);
2262 	    else
2263 		m_unknownSubsystems.setParam(*sub,"1");
2264 	}
2265     }
2266     lock.drop();
2267     notifyConcerned(SSP,ssn,0);
2268 }
2269 
subsystemsStatus(String & dest,bool extended)2270 void SCCPManagement::subsystemsStatus(String& dest,bool extended)
2271 {
2272     Lock lock(this);
2273     if (m_localSubsystems.skipNull()) {
2274 	dest << "Local subsystems state : count: " << m_localSubsystems.count() << "\r\n";
2275 	for (ObjList* o = m_localSubsystems.skipNull();o;o = o->skipNext()) {
2276 	    SccpLocalSubsystem* ss = static_cast<SccpLocalSubsystem*>(o->get());
2277 	    if (!ss)
2278 		continue;
2279 	    ss->dump(dest);
2280 	    dest << "\r\n";
2281 	}
2282     }
2283     if (m_subsystemFailure == 0) {
2284 	dest << "\r\nMissing Local Subsystem: " << m_subsystemFailure;
2285 	if (!extended)
2286 	    return;
2287 	for (unsigned int i = 0;i < m_unknownSubsystems.length();i++) {
2288 	    NamedString* ssn = m_unknownSubsystems.getParam(i);
2289 	    if (!ssn)
2290 		continue;
2291 	    dest << "\r\nReceived: " << *ssn << " packets for subsystem : " << ssn->name();
2292 	}
2293     }
2294     if (!m_remoteSccp.skipNull())
2295 	return;
2296     dest << "\r\nRemoteSccp: count: " << m_remoteSccp.count();
2297     for (ObjList* o = m_remoteSccp.skipNull(); o;o = o->skipNext()) {
2298 	SccpRemote* sr = static_cast<SccpRemote*>(o->get());
2299 	if (!sr)
2300 	    continue;
2301 	sr->dump(dest,true);
2302     }
2303 }
2304 
updateTables(SccpRemote * rsccp,SccpSubsystem * ssn)2305 void SCCPManagement::updateTables(SccpRemote* rsccp, SccpSubsystem* ssn)
2306 {
2307     if (!rsccp && !ssn) {
2308 	Debug(sccp(),DebugMild,"Request to update tables but no pointcode or ssn present!!");
2309 	return;
2310     }
2311     if (!sccp()) {
2312 	DDebug(this,DebugMild,"Request to update tables with no sccp attached");
2313 	return;
2314     }
2315     const SS7PointCode* local = rsccp ? &rsccp->getPointCode() : sccp()->getLocalPointCode();
2316     if (!local) {
2317 	Debug(sccp(),DebugWarn,"Can not update tables, no pointcode present!");
2318 	return;
2319     }
2320     NamedList params("sccp.update");
2321     params.setParam("pointcode",String(local->pack(m_pcType)));
2322     params.setParam("pc-type",String((int)m_pcType));
2323     if (rsccp)
2324 	params.setParam("pc-state",stateName(rsccp->getState()));
2325     params.setParam("component",sccp()->toString());
2326     if (ssn) {
2327 	params.setParam("subsystem",String(ssn->getSSN()));
2328 	params.setParam("subsystem-state",stateName(ssn->getState()));
2329     }
2330     sccp()->updateTables(params);
2331 }
2332 
routeStatus(String & dest,bool extended)2333 void SCCPManagement::routeStatus(String& dest,bool extended)
2334 {
2335     dest << "\r\nRouting Status:";
2336     dest << "\r\nMessages Failed to be routed: " << m_routeFailure;
2337     if (!extended)
2338 	return;
2339     // TODO call gtt print unknown translations
2340 }
2341 
timerTick(const Time & when)2342 void SCCPManagement::timerTick(const Time& when)
2343 {
2344     if (!lock(SignallingEngine::maxLockWait()))
2345 	return;
2346     ObjList coordt;
2347     for (ObjList* o = m_localSubsystems.skipNull();o;o = o->skipNext()) {
2348 	SccpLocalSubsystem* ss = static_cast<SccpLocalSubsystem*>(o->get());
2349 	if (!ss)
2350 	    continue;
2351 	if (ss->timeout() && ss->ref())
2352 	    coordt.append(ss);
2353     }
2354     // Use another list to append the sst's because the alternative is expensive for timer tick
2355     // (ListIterator)
2356     ObjList ssts;
2357     for (ObjList* o = m_statusTest.skipNull();o;o = o->skipNext()) {
2358 	SubsystemStatusTest* sst = static_cast<SubsystemStatusTest*>(o->get());
2359 	if (!sst->timeout())
2360 	    continue;
2361 	if (sst->ref())
2362 	    ssts.append(sst);
2363     }
2364     unlock();
2365     if (coordt.skipNull())
2366 	for (ObjList* o = coordt.skipNull();o;o = o->skipNext()) {
2367 	    SccpLocalSubsystem* ss = static_cast<SccpLocalSubsystem*>(o->get());
2368 	    ss->manageTimeout(this);
2369 	}
2370     if (!ssts.skipNull())
2371 	return;
2372     for (ObjList* o = ssts.skipNull();o;o = o->skipNext()) {
2373 	SubsystemStatusTest* sst = static_cast<SubsystemStatusTest*>(o->get());
2374 	if (!sst)
2375 	    continue;
2376 	if (sst->markAllowed() && sst->getSubsystem()->getSSN() == 1) {
2377 	    manageSccpRemoteStatus(sst->getRemote(),SS7Route::Allowed);
2378 	    continue;
2379 	}
2380 	sst->restartTimer();
2381 	if (!sendSST(sst->getRemote(),sst->getSubsystem()))
2382 	    sst->setAllowed(false);
2383     }
2384 }
2385 
stopSst(SccpRemote * remoteSccp,SccpSubsystem * rSubsystem,SccpSubsystem * less)2386 void SCCPManagement::stopSst(SccpRemote* remoteSccp, SccpSubsystem* rSubsystem, SccpSubsystem* less)
2387 {
2388     if (!remoteSccp)
2389 	return;
2390     Lock lock(this);
2391     ListIterator iter(m_statusTest);
2392     SubsystemStatusTest* sst = 0;
2393     while ((sst = YOBJECT(SubsystemStatusTest,iter.get()))) {
2394 	if (sst->getRemote()->getPointCode() != remoteSccp->getPointCode())
2395 	    continue;
2396 	if (sst->getSubsystem()) {
2397 	    if (rSubsystem && rSubsystem->getSSN() != sst->getSubsystem()->getSSN())
2398 		continue;
2399 	    if (less && less->getSSN() == sst->getSubsystem()->getSSN())
2400 		continue;
2401 	}
2402 	m_statusTest.remove(sst);
2403     }
2404 }
2405 
sendSST(SccpRemote * remote,SccpSubsystem * sub)2406 bool SCCPManagement::sendSST(SccpRemote* remote, SccpSubsystem* sub)
2407 {
2408     NamedList params("");
2409     params.setParam("pointcode",String(remote->getPackedPointcode()));
2410     params.setParam("RemotePC",String(remote->getPackedPointcode()));
2411     params.setParam("smi",String(sub->getSmi()));
2412     params.setParam("ssn",String(sub->getSSN()));
2413     return sendMessage(SST,params);
2414 }
2415 
startSst(SccpRemote * remoteSccp,SccpSubsystem * rSubsystem)2416 void SCCPManagement::startSst(SccpRemote* remoteSccp, SccpSubsystem* rSubsystem)
2417 {
2418     if (!remoteSccp || !rSubsystem)
2419 	return;
2420     DDebug(this,DebugNote,"Requested to start test for pc : %d  ssn: %d",remoteSccp->getPackedPointcode(),rSubsystem->getSSN());
2421     Lock lock(this);
2422     for (ObjList* o = m_statusTest.skipNull();o;o = o->skipNext()) {
2423 	SubsystemStatusTest* sst = static_cast<SubsystemStatusTest*>(o->get());
2424 	if (sst->getRemote()->getPointCode() != remoteSccp->getPointCode())
2425 	    continue;
2426 	if (sst->getSubsystem() && rSubsystem->getSSN() == sst->getSubsystem()->getSSN())
2427 	    return; // We already have the test
2428     }
2429     SubsystemStatusTest* sst = new SubsystemStatusTest(m_testTimeout);
2430     if (!sst->startTest(remoteSccp,rSubsystem)) {
2431 	TelEngine::destruct(sst);
2432 	return;
2433     }
2434     m_statusTest.append(sst);
2435     lock.drop();
2436     if (!sendSST(remoteSccp,rSubsystem))
2437 	sst->setAllowed(false);
2438 }
2439 
mtpEndRestart()2440 void SCCPManagement::mtpEndRestart()
2441 {
2442     if (!m_sccp)
2443 	return;
2444     lock();
2445     ListIterator iter(m_concerned);
2446     SccpRemote* sr = 0;
2447     while ((sr = YOBJECT(SccpRemote,iter.get()))) {
2448 	SS7Route::State state = sccp()->network()->getRouteState(m_pcType,sr->getPointCode());
2449 	RefPointer<SccpRemote> ptr = sr;
2450 	unlock();
2451 	if (sr->getState() !=  (SccpStates)state)
2452 	    manageSccpRemoteStatus(sr,state); // Update remote sccp state
2453 	if (state != SS7Route::Allowed) {
2454 	    lock();
2455 	    continue;
2456 	}
2457 	NamedList params("");
2458 	params.setParam("pointcode",String(m_sccp->getPackedPointCode()));
2459 	params.setParam("RemotePC",String(sr->getPackedPointcode()));
2460 	params.setParam("smi","0");
2461 	params.setParam("ssn","1");
2462 	sendMessage(SSA,params);
2463 	lock();
2464     }
2465     unlock();
2466 }
2467 
notifyConcerned(MsgType msg,unsigned char ssn,int smi)2468 void SCCPManagement::notifyConcerned(MsgType msg, unsigned char ssn, int smi)
2469 {
2470     DDebug(this,DebugAll,"Notify concerned: msg '%s' ssn: '%d', smi: %d",
2471 	   lookup(msg,s_managementMessages),ssn,smi);
2472     if (!sccp())
2473 	return;
2474     Lock lock(this);
2475     ObjList concerned;
2476     for (ObjList* o = m_concerned.skipNull();o;o = o->skipNext()) {
2477 	SccpRemote* rsccp = static_cast<SccpRemote*>(o->get());
2478 	if (!rsccp || !rsccp->getSubsystem(ssn))
2479 	    continue;
2480 	if (rsccp->ref())
2481 	    concerned.append(rsccp);
2482     }
2483     if (!concerned.skipNull()) {
2484 	DDebug(this,DebugNote,"No Concerned pointcode for ssn %d",ssn);
2485 	return;
2486     }
2487     NamedList params("");
2488     params.setParam("ssn",String((int)ssn));
2489     params.setParam("pointcode",String(sccp()->getPackedPointCode()));
2490     params.setParam("smi",String(smi));
2491     lock.drop();
2492     for (ObjList* o = concerned.skipNull();o; o = o->skipNext()) {
2493 	SccpRemote* rsccp = static_cast<SccpRemote*>(o->get());
2494 	if (!rsccp)
2495 	    continue;
2496 	params.setParam("RemotePC",String(rsccp->getPackedPointcode()));
2497 	sendMessage(msg,params);
2498     }
2499 }
2500 
sccpUnavailable(const SS7PointCode & pointcode,unsigned char cause)2501 void SCCPManagement::sccpUnavailable(const SS7PointCode& pointcode, unsigned char cause)
2502 {
2503 #ifdef DEBUG
2504     String dest;
2505     dest << pointcode;
2506     Debug(this,DebugInfo,"Received UPU %s cause : %d",dest.c_str(), cause);
2507 #endif
2508     Lock lock(this);
2509     SccpRemote* rsccp = getRemoteSccp(pointcode.pack(m_pcType));
2510     // Do not process UPU if we do not monitor the remote sccp state
2511     if (!rsccp)
2512 	return;
2513     rsccp->setState(SCCPManagement::Prohibited);
2514     // Stop all subsystem status tests
2515     ListIterator iter(m_statusTest);
2516     SubsystemStatusTest* test = 0;
2517     bool testStarted = false;
2518     while ((test = YOBJECT(SubsystemStatusTest,iter.get()))) {
2519 	if (!test || !test->getRemote() || pointcode != test->getRemote()->getPointCode())
2520 	    continue;
2521 	// Do not stop test for SSN = 1 if the cause is not Unequipped
2522 	SccpSubsystem* sub = test->getSubsystem();
2523 	if (sub->getSSN() == 1 && cause != HandledMSU::Unequipped) {
2524 	    testStarted = true;
2525 	    continue;
2526 	}
2527 	m_statusTest.remove(test);
2528     }
2529     if (!testStarted && cause != HandledMSU::Unequipped) {
2530 	SubsystemStatusTest* sst = new SubsystemStatusTest(m_testTimeout);
2531 	SccpSubsystem* sub = new SccpSubsystem(1);
2532 	if (!sst->startTest(rsccp,new SccpSubsystem(1))) {
2533 	    TelEngine::destruct(sst);
2534 	    TelEngine::destruct(sub);
2535 	    return;
2536 	}
2537 	TelEngine::destruct(sub);
2538 	m_statusTest.append(sst);
2539 	sst->setAllowed(false);
2540     }
2541     lock.drop();
2542     localBroadcast(SCCP::StatusIndication,rsccp->getPackedPointcode(),-1,SccpRemoteInaccessible);
2543 }
2544 
printMessage(String & dest,MsgType type,const NamedList & params)2545 void SCCPManagement::printMessage(String& dest, MsgType type, const NamedList& params)
2546 {
2547     const char* enclose = "\r\n-----";
2548     dest = enclose;
2549     dest << "\r\n " << lookup(type,s_managementMessages);
2550     dest << " pc: " << params.getValue(YSTRING("pointcode")) << ", ";
2551     dest << "ssn: " << params.getValue(YSTRING("ssn")) << ", ";
2552     dest << "smi: " << params.getValue(YSTRING("smi"));
2553     if (type == SSC) {
2554 	dest << ", cl: " << params.getValue(YSTRING("congestion-level"));
2555     }
2556     dest << enclose;
2557 }
2558 
2559 /**
2560  * SccpLocalSubsystem
2561  */
2562 
SccpLocalSubsystem(unsigned char ssn,u_int64_t coordInterval,u_int64_t ignoreInterval,unsigned char smi)2563 SccpLocalSubsystem::SccpLocalSubsystem(unsigned char ssn, u_int64_t coordInterval, u_int64_t ignoreInterval,unsigned char smi)
2564     : Mutex(true,s_sccpSubsystems), m_ssn(ssn), m_smi(smi), m_state(SCCPManagement::Allowed),
2565     m_coordTimer(coordInterval), m_ignoreTestsTimer(ignoreInterval), m_backups(), m_receivedAll(true)
2566 {
2567     DDebug("SccpSubsystem", DebugAll,"Creating sccp subsystem [%p] with ssn '%d', smi '%d'",this,ssn,smi);
2568 }
2569 
~SccpLocalSubsystem()2570 SccpLocalSubsystem::~SccpLocalSubsystem()
2571 {
2572     DDebug("SccpSubsystem", DebugAll,"Destroing sccp subsystem [%p] with ssn '%d'",this,m_ssn);
2573 }
2574 
timeout()2575 bool SccpLocalSubsystem::timeout()
2576 {
2577     Lock lock(this);
2578     if (m_coordTimer.timeout()) {
2579 	m_coordTimer.stop();
2580 	m_receivedAll = true;
2581 	for (ObjList* o = m_backups.skipNull();o;o = o->skipNext()) {
2582 	    RemoteBackupSubsystem* sbs = static_cast<RemoteBackupSubsystem*>(o->get());
2583 	    if (sbs->waitingForGrant())
2584 		m_receivedAll = false;
2585 	}
2586 	if (m_receivedAll)
2587 	    m_ignoreTestsTimer.start();
2588 	return true;
2589     }
2590     if (m_ignoreTestsTimer.timeout()) {
2591 	m_state = SCCPManagement::Prohibited;
2592 	m_ignoreTestsTimer.stop();
2593     }
2594     return false;
2595 }
2596 
manageTimeout(SCCPManagement * mgm)2597 void SccpLocalSubsystem::manageTimeout(SCCPManagement* mgm)
2598 {
2599     if (!mgm)
2600 	return;
2601     if (m_receivedAll) {
2602 	mgm->localBroadcast(SCCP::CoordinateConfirm,-1,-1,-1,-1,m_ssn,m_smi);
2603 	mgm->notifyConcerned(SCCPManagement::SSP,m_ssn,m_smi);
2604 	m_state = SCCPManagement::IgnoreTests;
2605 	return;
2606     }
2607     m_state = SCCPManagement::Allowed;
2608     /// TODO send local broadcast with request denied!!!
2609 }
2610 
dump(String & dest)2611 void SccpLocalSubsystem::dump(String& dest)
2612 {
2613     dest << "Subsystem: " << m_ssn << " , smi: " << m_smi;
2614     dest << ", state: " << SCCPManagement::stateName(m_state) << " ";
2615 }
2616 
receivedSOG(unsigned char ssn,int pointcode)2617 bool SccpLocalSubsystem::receivedSOG(unsigned char ssn, int pointcode)
2618 {
2619     Lock lock(this);
2620     for (ObjList* o = m_backups.skipNull();o;o = o->skipNext()) {
2621 	RemoteBackupSubsystem* sbs = static_cast<RemoteBackupSubsystem*>(o->get());
2622 	if (!sbs->equals(ssn,pointcode))
2623 	    continue;
2624 	sbs->permisionGranted();
2625 	return true;
2626     }
2627     return false;
2628 }
2629 
setIgnoreTests(bool ignore)2630 void SccpLocalSubsystem::setIgnoreTests(bool ignore)
2631 {
2632     if (ignore)
2633 	m_ignoreTestsTimer.start();
2634     else
2635 	m_ignoreTestsTimer.stop();
2636 }
2637 
2638 /**
2639  * SccpRemote
2640  */
2641 
SccpRemote(const SS7PointCode::Type type)2642 SccpRemote::SccpRemote(const SS7PointCode::Type type)
2643     : Mutex(true, s_sccpRemote), m_pointcode(type,0), m_pointcodeType(type), m_state(SCCPManagement::Allowed)
2644 {
2645     DDebug("RemoteSccp",DebugAll,"Creating remote sccp [%p]",this);
2646 }
2647 
SccpRemote(unsigned int pointcode,SS7PointCode::Type pcType)2648 SccpRemote::SccpRemote(unsigned int pointcode, SS7PointCode::Type pcType)
2649     : m_pointcode(pcType,pointcode), m_pointcodeType(pcType), m_state(SCCPManagement::Allowed)
2650 {
2651     DDebug("RemoteSccp",DebugAll,"Creating remote sccp [%p] for pointcode %d",this,pointcode);
2652 }
2653 
~SccpRemote()2654 SccpRemote::~SccpRemote()
2655 {
2656 #ifdef XDEBUG
2657     String tmp;
2658     tmp << m_pointcode;
2659     Debug("RemoteSccp",DebugAll,"Destroying remote sccp [%p], %s",this,tmp.c_str());
2660 #endif
2661 }
2662 
initialize(const String & params)2663 bool SccpRemote::initialize(const String& params)
2664 {
2665     ObjList* o = params.split(':',false);
2666     if (!o)
2667 	return false;
2668     String* pointcode = static_cast<String*>(o->get());
2669     if (!pointcode) {
2670 	TelEngine::destruct(o);
2671 	return false;
2672     }
2673     bool pointcodeAssigned = false;
2674     if (pointcode->find('-') > 0)
2675 	pointcodeAssigned = m_pointcode.assign(*pointcode,m_pointcodeType);
2676     else
2677 	pointcodeAssigned = m_pointcode.unpack(m_pointcodeType,pointcode->toInteger());
2678     if (!pointcodeAssigned) {
2679 	TelEngine::destruct(o);
2680 	return false;
2681     }
2682     ObjList* subsystems = o->skipNext();
2683     while (subsystems) {
2684 	String* sub = static_cast<String*>(subsystems->get());
2685 	if (!sub)
2686 	    break;
2687 	subsystems = sub->split(',',false);
2688 	if (!subsystems)
2689 	    break;
2690 	for (ObjList* ob = subsystems->skipNull();ob;ob = ob->skipNext()) {
2691 	    String* subsystem = static_cast<String*>(ob->get());
2692 	    unsigned int ssn = subsystem->toInteger(256);
2693 	    if (ssn > 255) {
2694 		DDebug(DebugConf,"Skipping ssn %d for pointcode %d Value too big!",
2695 		       ssn,m_pointcode.pack(m_pointcodeType));
2696 		continue;
2697 	    }
2698 	    m_subsystems.append(new SccpSubsystem(ssn));
2699 	}
2700 	TelEngine::destruct(subsystems);
2701 	break;
2702     }
2703     TelEngine::destruct(o);
2704     return true;
2705 }
2706 
getSubsystem(int ssn)2707 SccpSubsystem* SccpRemote::getSubsystem(int ssn)
2708 {
2709     Lock lock(this);
2710     for (ObjList* o = m_subsystems.skipNull();o;o = o->skipNext()) {
2711 	SccpSubsystem* sub = static_cast<SccpSubsystem*>(o->get());
2712 	if (sub && sub->getSSN() == ssn)
2713 	    return sub;
2714     }
2715     return 0;
2716 }
2717 
setState(SCCPManagement::SccpStates state)2718 void SccpRemote::setState(SCCPManagement::SccpStates state)
2719 {
2720     if (m_state == state)
2721 	return;
2722     Lock lock(this);
2723     m_state = state;
2724     for (ObjList* o = m_subsystems.skipNull();o;o = o->skipNext()) {
2725 	SccpSubsystem* sub = static_cast<SccpSubsystem*>(o->get());
2726 	sub->setState(state);
2727     }
2728 }
2729 
dump(String & dest,bool extended)2730 void SccpRemote::dump(String& dest, bool extended)
2731 {
2732     Lock lock(this);
2733     dest << "\r\n----Sccp : " << m_pointcode;
2734     dest << " (" << m_pointcode.pack(m_pointcodeType) << "," << SS7PointCode::lookup(m_pointcodeType) << ") ";
2735     dest << "State : " << SCCPManagement::stateName(m_state) << "; ";
2736     if (extended) {
2737 	dest << "Subsystems : " << m_subsystems.count() << "; ";
2738 	for (ObjList* o = m_subsystems.skipNull();o;o = o->skipNext()) {
2739 	    SccpSubsystem* ss = static_cast<SccpSubsystem*>(o->get());
2740 	    if (!ss)
2741 		continue;
2742 	    ss->dump(dest);
2743 	    dest << " | ";
2744 	}
2745     }
2746     dest << "----";
2747 }
2748 
changeSubsystemState(int ssn,SCCPManagement::SccpStates newState)2749 bool SccpRemote::changeSubsystemState(int ssn,SCCPManagement::SccpStates newState)
2750 {
2751     Lock lock(this);
2752     SccpSubsystem* ss = getSubsystem(ssn);
2753     if (!ss)
2754 	return true;
2755     if (ss->getState() == newState)
2756 	return false;
2757     ss->setState(newState);
2758     return true;
2759 }
2760 
2761 /**
2762  * SubsystemStatusTest
2763  */
2764 
~SubsystemStatusTest()2765 SubsystemStatusTest::~SubsystemStatusTest()
2766 {
2767     DDebug("SST",DebugAll,"Stoping SST for pc: '%d' ssn: '%d'", m_remoteSccp ? m_remoteSccp->getPackedPointcode() : 0,
2768 		m_remoteSubsystem ? m_remoteSubsystem->getSSN() : 0);
2769     if (m_remoteSccp)
2770 	TelEngine::destruct(m_remoteSccp);
2771     if (m_remoteSubsystem)
2772 	TelEngine::destruct(m_remoteSubsystem);
2773 }
2774 
startTest(SccpRemote * remoteSccp,SccpSubsystem * rSubsystem)2775 bool SubsystemStatusTest::startTest(SccpRemote* remoteSccp, SccpSubsystem* rSubsystem)
2776 {
2777     if (!remoteSccp || !remoteSccp->ref())
2778 	return false;
2779     m_remoteSccp = remoteSccp;
2780     if (!rSubsystem || !rSubsystem->ref()) {
2781 	TelEngine::destruct(m_remoteSccp);
2782 	return false;
2783     }
2784 #ifdef DEBUG
2785     String dump;
2786     remoteSccp->dump(dump,false);
2787     Debug("SST",DebugInfo,"Starting subsystem status test for '%s' ssn = '%d' subsystem state : %s",
2788 	  dump.c_str(),rSubsystem->getSSN(),SCCPManagement::stateName(rSubsystem->getState()));
2789 #endif
2790     m_remoteSubsystem = rSubsystem;
2791     m_statusInfo.start();
2792     if (rSubsystem->getSSN() == 1)
2793 	m_markAllowed = true;
2794     return true;
2795 }
2796 
restartTimer()2797 void SubsystemStatusTest::restartTimer()
2798 {
2799     m_interval *= 2;
2800     if (m_interval > MAX_INFO_TIMER)
2801 	m_interval = MAX_INFO_TIMER;
2802     m_statusInfo.fire(Time::msecNow() + m_interval);
2803 }
2804 
2805 /**
2806  * class SS7SCCP
2807  */
SS7SCCP(const NamedList & params)2808 SS7SCCP::SS7SCCP(const NamedList& params)
2809     : SignallingComponent(params,&params), SS7Layer4(SS7MSU::SCCP|SS7MSU::National,&params), Mutex(true,params),
2810     m_type(SS7PointCode::Other), m_localPointCode(0), m_management(0), m_hopCounter(15),
2811     m_msgReturnStatus(""), m_segTimeout(0), m_ignoreUnkDigits(false), m_layer3Up(false),
2812     m_maxUdtLength(220), m_totalSent(0), m_totalReceived(0), m_errors(0),
2813     m_totalGTTranslations(0), m_gttFailed(0), m_extendedMonitoring(false), m_mgmName("sccp-mgm"),
2814     m_printMsg(false), m_extendedDebug(false), m_endpoint(true)
2815 {
2816     DDebug(this,DebugInfo,"Creating new SS7SCCP [%p]",this);
2817 #ifdef DEBUG
2818     if (debugAt(DebugAll)) {
2819 	String tmp;
2820 	params.dump(tmp,"\r\n  ",'\'',true);
2821 	Debug(this,DebugAll,"SS7SCCP::SS7SCCP(%p) [%p]%s",
2822 	    &params,this,tmp.c_str());
2823     }
2824 #endif
2825     const char* stype = params.getValue(YSTRING("pointcodetype"));
2826     m_type = SS7PointCode::lookup(stype);
2827     if (m_type == SS7PointCode::Other) {
2828 	Debug(this,DebugConf,"Invalid point code type '%s'",c_safe(stype));
2829 	return;
2830     }
2831     String* lpc = params.getParam(YSTRING("localpointcode"));
2832     m_localPointCode = new SS7PointCode(0,0,0);
2833     bool pointcodeAssigned = false;
2834     if (lpc) {
2835 	 if (lpc->find('-') > 0)
2836 	    pointcodeAssigned = m_localPointCode->assign(*lpc,m_type);
2837 	else
2838 	    pointcodeAssigned = m_localPointCode->unpack(m_type,lpc->toInteger());
2839     }
2840     if (!pointcodeAssigned) {
2841 	Debug(this,DebugWarn,"Invalid localpointcode='%s'",lpc ? lpc->c_str() : "null");
2842 	Debug(this,DebugConf,"No local PointCode configured!! GT translations with no local PointCode may lead to undesired behavior");
2843 	TelEngine::destruct(m_localPointCode);
2844 	m_localPointCode = 0;
2845     }
2846     int hc = params.getIntValue("hopcounter",15);
2847     if (hc < 1 || hc > 15)
2848 	hc = 15;
2849     m_hopCounter = hc;
2850     m_ignoreUnkDigits = params.getBoolValue(YSTRING("ignore-unknown-digits"),true);
2851     m_printMsg = params.getBoolValue(YSTRING("print-messages"),false);
2852     m_extendedDebug = params.getBoolValue(YSTRING("extended-debug"),false);
2853     m_extendedMonitoring = params.getBoolValue(YSTRING("extended-monitoring"),false);
2854     m_maxUdtLength = params.getIntValue(YSTRING("max-udt-length"),MAX_UDT_LEN);
2855     m_segTimeout = params.getIntValue(YSTRING("segmentation-timeout"),10000);
2856     m_mgmName = params.getValue(YSTRING("management"));
2857     m_endpoint = params.getBoolValue(YSTRING("endpoint"),true);
2858     if (m_segTimeout < 5000)
2859 	m_segTimeout = 5000;
2860     if (m_segTimeout > 20000)
2861 	m_segTimeout = 20000;
2862     if ((m_type == SS7PointCode::ITU || m_type == SS7PointCode::ANSI) && m_localPointCode) {
2863 	NamedList mgmParams("sccp-mgm");
2864 	if (!resolveConfig(YSTRING("management"),mgmParams,&params))
2865 	    mgmParams.addParam("local-config","true");
2866 	mgmParams.setParam("type",m_type == SS7PointCode::ITU ? "ss7-sccp-itu-mgm" : "ss7-sccp-ansi-mgm");
2867 	if (mgmParams.toBoolean(true)) {
2868 	    if (m_type == SS7PointCode::ITU)
2869 		m_management = YOBJECT(SS7ItuSccpManagement,YSIGCREATE(SCCPManagement,&mgmParams));
2870 	    else if (m_type == SS7PointCode::ANSI)
2871 		m_management = YOBJECT(SS7AnsiSccpManagement,YSIGCREATE(SCCPManagement,&mgmParams));
2872 	}
2873 	if (!m_management)
2874 	    Debug(this,DebugWarn,"Failed to create sccp management!");
2875 	else if (m_management->initialize(&mgmParams))
2876 	    m_management->attach(this);
2877     } else
2878 	Debug(this,DebugConf,"Created SS7SCCP '%p' without management! No local pointcode pressent!",this);
2879 
2880 }
2881 
~SS7SCCP()2882 SS7SCCP::~SS7SCCP()
2883 {
2884     if (m_localPointCode)
2885 	m_localPointCode->destruct();
2886     DDebug(this,DebugAll,"Destroying SS7SCCP [%p]",this);
2887 }
2888 
initialize(const NamedList * config)2889 bool SS7SCCP::initialize(const NamedList* config)
2890 {
2891 #ifdef DEBUG
2892     String tmp;
2893     if (config && debugAt(DebugAll))
2894 	config->dump(tmp,"\r\n  ",'\'',true);
2895     Debug(this,DebugInfo,"SS7SCCP::initialize(%p) [%p]%s",config,this,tmp.c_str());
2896 #endif
2897     if (config) {
2898 	m_printMsg = config->getBoolValue(YSTRING("print-messages"),m_printMsg);
2899 	m_extendedDebug = config->getBoolValue(YSTRING("extended-debug"),m_extendedDebug);
2900 	m_ignoreUnkDigits = config->getBoolValue(YSTRING("ignore-unknown-digits"),m_ignoreUnkDigits);
2901 	m_maxUdtLength = config->getIntValue(YSTRING("max-udt-length"),m_maxUdtLength);
2902 	m_endpoint = config->getBoolValue(YSTRING("endpoint"),m_endpoint);
2903 	int hc = config->getIntValue("hopcounter",m_hopCounter);
2904 	if (hc < 1 || hc > 15)
2905 	    hc = 15;
2906 	m_hopCounter = hc;
2907 	m_extendedMonitoring = config->getBoolValue(YSTRING("extended-monitoring"),m_extendedMonitoring);
2908     }
2909     if (m_management)
2910 	SignallingComponent::insert(m_management);
2911     return SS7Layer4::initialize(config);
2912 }
2913 
destroyed()2914 void  SS7SCCP::destroyed()
2915 {
2916     if (m_management)
2917 	TelEngine::destruct(m_management);
2918     SS7Layer4::destroyed();
2919 }
2920 
attach(SS7Layer3 * network)2921 void SS7SCCP::attach(SS7Layer3* network)
2922 {
2923     SS7Layer4::attach(network);
2924     setNetworkUp(network && network->operational());
2925 }
2926 
managementStatus(Type type,NamedList & params)2927 bool SS7SCCP::managementStatus(Type type, NamedList& params)
2928 {
2929     if (m_management)
2930 	m_management->notify(type,params);
2931     return false;
2932 }
2933 
timerTick(const Time & when)2934 void SS7SCCP::timerTick(const Time& when)
2935 {
2936     if (!lock(SignallingEngine::maxLockWait()))
2937 	return;
2938     for (ObjList* o = m_reassembleList.skipNull();o;) {
2939         SS7MsgSccpReassemble* usr = YOBJECT(SS7MsgSccpReassemble,o->get());
2940         if (usr->timeout()) {
2941             o->remove();
2942             o = o->skipNull();
2943         }
2944         else
2945             o = o->skipNext();
2946    }
2947    unlock();
2948 }
2949 
ajustMessageParams(NamedList & params,SS7MsgSCCP::Type type)2950 void SS7SCCP::ajustMessageParams(NamedList& params, SS7MsgSCCP::Type type)
2951 {
2952     if (type == SS7MsgSCCP::UDT || type == SS7MsgSCCP::UDTS)
2953 	return;
2954     int hopCounter = params.getIntValue(YSTRING("HopCounter"),0);
2955     if (hopCounter < 1 || hopCounter > 15)
2956 	params.setParam("HopCounter",String(m_hopCounter));
2957     if (ITU() && params.getParam(YSTRING("Importance"))) {
2958 	int importance = params.getIntValue(YSTRING("Importance"));
2959 	int temp = checkImportanceLevel(type, importance);
2960 	if (importance != temp)
2961 	    params.setParam(YSTRING("Importance"),String(temp));
2962     }
2963 }
2964 
2965 // Called by routing method to send a msu
transmitMessage(SS7MsgSCCP * sccpMsg,bool local)2966 int SS7SCCP::transmitMessage(SS7MsgSCCP* sccpMsg, bool local)
2967 {
2968     if (!sccpMsg || !sccpMsg->getData())
2969 	return -1;
2970     if (unknownPointCodeType()) {
2971 	Debug(this,DebugConf,"SCCP unavailable!! Reason Unknown pointcode type %s",SS7PointCode::lookup(m_type));
2972 	return -1;
2973     }
2974     Lock lock(this);
2975     if (!m_layer3Up) {
2976 	DDebug(this,DebugNote,"Can not send sccp message, L3 is down");
2977 	return -1;
2978     }
2979 
2980     int dpc = getPointCode(sccpMsg,"CalledPartyAddress","RemotePC",true);
2981     if (dpc == -2) {
2982 	lock.drop();
2983 	return routeLocal(sccpMsg);
2984     }
2985     int opc = getPointCode(sccpMsg,"CallingPartyAddress","LocalPC",false);
2986     lock.drop();
2987     if (dpc < 0 || opc < 0) {
2988 	if (m_management)
2989 	    m_management->routeFailure(sccpMsg);
2990 	return -1;
2991     }
2992     return sendSCCPMessage(sccpMsg,dpc,opc,local);
2993 }
2994 
sendSCCPMessage(SS7MsgSCCP * sccpMsg,int dpc,int opc,bool local)2995 int SS7SCCP::sendSCCPMessage(SS7MsgSCCP* sccpMsg,int dpc,int opc, bool local)
2996 {
2997     Lock lock(this);
2998     int sls = sccpMsg->params().getIntValue(YSTRING("sls"),-1);
2999     SS7PointCode dest(m_type,dpc);
3000     SS7PointCode orig(m_type,opc > 0 ? opc : m_localPointCode->pack(m_type));
3001     // Build the routing label
3002     SS7Label outLabel(m_type,dest,orig,sls);
3003     if (sccpMsg->getData()->length() > m_maxUdtLength) {
3004 	lock.drop();
3005 	return segmentMessage(sccpMsg,outLabel,local);
3006     }
3007     // Check route indicator
3008     if (!sccpMsg->params().getParam("CalledPartyAddress.route")) {
3009 	// Set route indicator. If have pointcode and ssn, route on ssn
3010 	if (sccpMsg->params().getParam(YSTRING("RemotePC")) &&
3011 		sccpMsg->params().getIntValue(YSTRING("CalledPartyAddress.ssn"),0) != 0) {
3012 	    sccpMsg->params().setParam("CalledPartyAddress.route","ssn");
3013 	} else
3014 	    sccpMsg->params().setParam("CalledPartyAddress.route","gt");
3015     }
3016     // Build the msu
3017     SS7MSU* msu = buildMSU(sccpMsg,outLabel);
3018     lock.drop();
3019     if (!msu)
3020 	return segmentMessage(sccpMsg,outLabel,local);
3021     printMessage(msu,sccpMsg,outLabel);
3022     sls = transmitMSU(*msu,outLabel,sls);
3023 #ifdef DEBUG
3024     if (sls < 0)
3025 	Debug(this,DebugNote,"Failed to transmit message %s. %d",SS7MsgSCCP::lookup(sccpMsg->type()),sls);
3026 #endif
3027     // CleanUp memory
3028     TelEngine::destruct(msu);
3029     return sls;
3030 }
3031 
fillLabelAndReason(String & dest,const SS7Label & label,const SS7MsgSCCP * msg)3032 bool SS7SCCP::fillLabelAndReason(String& dest,const SS7Label& label,const SS7MsgSCCP* msg)
3033 {
3034     dest << " Routing label : " << label;
3035     if (!isSCLCSMessage(msg->type()))
3036 	return false;
3037     dest << " Reason: ";
3038     dest << lookup(msg->params().getIntValue(YSTRING("ReturnCause")),s_return_cause,
3039 	    "Unknown");
3040     return true;
3041 }
3042 
3043 // Obtain a pointcode from called/calling party address
3044 // Return: -1 On Error; -2 If the message should be routed to a local sccp; else  the pointcode
getPointCode(SS7MsgSCCP * msg,const String & prefix,const char * pCode,bool translate)3045 int SS7SCCP::getPointCode(SS7MsgSCCP* msg, const String& prefix, const char* pCode, bool translate)
3046 {
3047     if (!msg)
3048 	return -1;
3049     bool havePointCode = false;
3050     NamedString* pcNs = msg->params().getParam(pCode);
3051     if (pcNs && pcNs->toInteger(0) > 0)
3052 	havePointCode = true;
3053     if (!havePointCode) {
3054 	pcNs = msg->params().getParam(prefix + ".pointcode");
3055 	if (pcNs && pcNs->toInteger(0) > 0) {
3056 	    msg->params().setParam(new NamedString(pCode,*pcNs));
3057 	    havePointCode = true;
3058 	}
3059     }
3060     if (!havePointCode && translate) { // CalledParyAddress with no pointcode. Check for Global Title
3061 	NamedList* route = translateGT(msg->params(),prefix,
3062 		YSTRING("CallingPartyAddress"));
3063 	m_totalGTTranslations++;
3064 	if (!route) {
3065 	    m_gttFailed++;
3066 	    return -1;
3067 	}
3068 	resolveGTParams(msg,route);
3069 	NamedString* localRouting = route->getParam(YSTRING("sccp"));
3070 	if (localRouting && *localRouting != toString()) {
3071 	    msg->params().copyParam(*route,YSTRING("RemotePC"));
3072 	    TelEngine::destruct(route);
3073 	    return -2;
3074 	}
3075 	bool havePC = route->getParam(pCode) != 0;
3076 	NamedString* trpc = route->getParam(YSTRING("pointcode"));
3077 	if (!trpc && !havePC) {
3078 	    Debug(this,DebugWarn,"The GT has not been translated to a pointcode!!");
3079 	    TelEngine::destruct(route);
3080 	    return -1;
3081 	}
3082 	if (!havePC)
3083 	    msg->params().setParam(pCode,*trpc);
3084 	else
3085 	    msg->params().setParam(pCode,route->getValue(pCode));
3086 	TelEngine::destruct(route);
3087     } else if (!havePointCode && !translate) { // CallingPartyAddress with no pointcode. Assign sccp pointcode
3088 	if (!m_localPointCode) {
3089 	    Debug(this,DebugWarn,"Can not build routing label. No local pointcode present and no pointcode present in CallingPartyAddress");
3090 	    return -1;
3091 	}
3092 	return m_localPointCode->pack(m_type);
3093     }
3094     return msg->params().getIntValue(pCode);
3095 }
3096 
routeLocal(SS7MsgSCCP * msg)3097 int SS7SCCP::routeLocal(SS7MsgSCCP* msg)
3098 {
3099     if (!msg) {
3100 	Debug(this,DebugWarn,"Failed to route local! Null message!");
3101 	return -1;
3102     }
3103     NamedString* sccp = msg->params().getParam(YSTRING("sccp"));
3104     if (!sccp || *sccp == toString()) {
3105 	Debug(this,DebugStub,
3106 		"Requested to local route sccp message without sccp component!");
3107 	return -1;
3108     }
3109     int dpc = msg->params().getIntValue("RemotePC",-1);
3110     if (dpc < 0)
3111 	dpc = msg->params().getIntValue("CalledPartyAddress.pointcode",-1);
3112     if (dpc < 0) {
3113 	Debug(this,DebugNote,
3114 		"Unable to route local sccp message! No pointcode present.");
3115 	return -1;
3116     }
3117     if (!engine()) {
3118 	Debug(this,DebugMild,
3119 		"Unable to route local sccp message! No engine attached!");
3120 	return -1;
3121     }
3122     RefPointer<SS7SCCP> sccpCmp = YOBJECT(SS7SCCP,
3123 		engine()->find(*sccp,YSTRING("SS7SCCP")));
3124     if (!sccpCmp) {
3125 	Debug(this,DebugNote,
3126 		"Unable to route local sccp message! SCCP component %s not found!",
3127 		sccp->c_str());
3128 	return -1;
3129     }
3130     msg->params().clearParam(YSTRING("LocalPC"));
3131     msg->params().clearParam(YSTRING("CallingPartyAddress.pointcode"));
3132     return sccpCmp->sendSCCPMessage(msg,dpc,-1,false);
3133 }
3134 
checkImportanceLevel(int msgType,int initialImportance)3135 int SS7SCCP::checkImportanceLevel(int msgType, int initialImportance)
3136 {
3137     if ((isSCLCMessage(msgType) && isSCLCSMessage(msgType))) {
3138 	Debug(this,DebugStub,"Check Importance level for a SCOC message!");
3139 	return 0;
3140     }
3141     if (isSCLCMessage(msgType)) // Max importance level is 6 and default is 4 for UDT,XUDT and LUDT
3142 	return (initialImportance >= 0 && initialImportance <= 6) ? initialImportance : 4;
3143     if (isSCLCSMessage(msgType)) // Max importance level is 3 and default is 3 for UDTS,XUDTS and LUDTS
3144 	return (initialImportance >= 0 && initialImportance <= 3) ? initialImportance : 3;
3145     return initialImportance;
3146 }
3147 
checkSCLCOptParams(SS7MsgSCCP * msg)3148 void SS7SCCP::checkSCLCOptParams(SS7MsgSCCP* msg)
3149 {
3150     if (!msg || msg->type() == SS7MsgSCCP::UDT || !isSCLCMessage(msg->type())) // UDT does not have optional parameters
3151 	return;
3152     if (!ITU()) {
3153 	msg->params().clearParam(YSTRING("Importance"));
3154 	return;
3155     }
3156     msg->params().clearParam(YSTRING("ISNI"));
3157     msg->params().clearParam(YSTRING("INS"));
3158     msg->params().clearParam(YSTRING("MessageTypeInterworking"));
3159 }
3160 
3161 // This method is called to send connectionless data
sendMessage(DataBlock & data,const NamedList & params)3162 int SS7SCCP::sendMessage(DataBlock& data, const NamedList& params)
3163 {
3164     if (unknownPointCodeType()) {
3165 	Debug(this,DebugConf,"SCCP unavailable!! Reason Unknown pointcode type %s",SS7PointCode::lookup(m_type));
3166 	return -1;
3167     }
3168 #ifdef XDEBUG
3169     String tmp;
3170     params.dump(tmp,"\r\n  ",'\'',true);
3171     Debug(this,DebugAll,"SS7SCCP::sendMessage() [%p]%s",this,tmp.c_str());
3172 #endif
3173     Lock lock1(this);
3174     SS7MsgSCCP* sccpMsg = 0;
3175     // Do not check for data length here! If message data is too long the message
3176     // change procedure will be initiated in segmentMessage method
3177     if (params.getParam(YSTRING("Importance")) && m_type == SS7PointCode::ITU) {
3178 	// We have Importance optional parameter. Send XUDT. ITU only
3179 	sccpMsg = new SS7MsgSCCP(SS7MsgSCCP::XUDT);
3180     } else if ((params.getParam(YSTRING("ISNI")) || params.getParam(YSTRING("INS"))) &&
3181 		 m_type == SS7PointCode::ANSI) {
3182 	// XUDT message ANSI only
3183 	sccpMsg = new SS7MsgSCCP(SS7MsgSCCP::XUDT);
3184     } else if (params.getParam(YSTRING("HopCounter"))) {
3185 	sccpMsg = new SS7MsgSCCP(SS7MsgSCCP::XUDT);
3186     } else // In rest send Unit Data Messages
3187 	sccpMsg = new SS7MsgSCCP(SS7MsgSCCP::UDT);
3188 
3189     if (!sccpMsg) {
3190 	Debug(this,DebugWarn,"Failed to create SCCP message!");
3191 	m_errors++;
3192 	return -1;
3193     }
3194     sccpMsg->params().copyParams(params); // Copy the parameters to message
3195     sccpMsg->params().setParam("generated","local");
3196     if (m_localPointCode)
3197 	sccpMsg->params().setParam("LocalPC",String(getPackedPointCode()));
3198     ajustMessageParams(sccpMsg->params(),sccpMsg->type());
3199     if (params.getBoolValue(YSTRING("CallingPartyAddress.pointcode"),false) && m_localPointCode)
3200 	sccpMsg->params().setParam("CallingPartyAddress.pointcode",String(getPackedPointCode()));
3201     // Avoid sending optional parameters that aren't specified by protocol
3202     if (sccpMsg->type() == SS7MsgSCCP::XUDT || sccpMsg->type() == SS7MsgSCCP::LUDT)
3203 	checkSCLCOptParams(sccpMsg);
3204     // Append data to message
3205     sccpMsg->setData(&data);
3206     lock1.drop();
3207     int ret = transmitMessage(sccpMsg,true);
3208     sccpMsg->removeData();
3209     TelEngine::destruct(sccpMsg);
3210     lock();
3211     if (ret >= 0)
3212 	m_totalSent++;
3213     else
3214 	m_errors++;
3215     unlock();
3216     return ret;
3217 }
3218 
3219 // This method approximates the length of sccp address
getAddressLength(const NamedList & params,const String & prefix)3220 unsigned int SS7SCCP::getAddressLength(const NamedList& params, const String& prefix)
3221 {
3222     unsigned int length = 2; // Parameter length + Address information octet
3223     if (params.getParam(prefix + ".ssn"))
3224 	length++; // One octet for ssn
3225     if (params.getParam(prefix + ".pointcode"))
3226 	length += ITU() ? 2 : 3; // Pointcode has 2 octets on ITU and 3 on ANSI
3227     const NamedString* gtNr = YOBJECT(NamedString,params.getParam(prefix + ".gt"));
3228     if (!gtNr)
3229 	return length;
3230     DataBlock data;
3231     if (!data.unHexify(*gtNr,gtNr->length(),' ')) {
3232 	length += gtNr->length() / 2 + gtNr->length() % 2;
3233     } else
3234 	length += data.length();
3235     const NamedString* nature = YOBJECT(NamedString,params.getParam(prefix + ".gt.nature"));
3236     const NamedString* translation = YOBJECT(NamedString,params.getParam(prefix + ".gt.translation"));
3237     const NamedString* plan = YOBJECT(NamedString,params.getParam(prefix + ".gt.plan"));
3238     const NamedString* encoding = YOBJECT(NamedString,params.getParam(prefix + ".gt.encoding"));
3239     if (nature)
3240 	length++;
3241     if (translation)
3242 	length++;
3243     if (plan && encoding)
3244 	length++;
3245     return length;
3246 }
3247 
getMaxDataLen(const SS7MsgSCCP * msg,const SS7Label & label,unsigned int & udt,unsigned int & xudt,unsigned int & ludt)3248 void SS7SCCP::getMaxDataLen(const SS7MsgSCCP* msg, const SS7Label& label,
3249 	unsigned int& udt, unsigned int& xudt, unsigned int& ludt)
3250 {
3251     if (!network()) {
3252 	Debug(this,DebugConf,"No Network Attached!!!");
3253 	return;
3254     }
3255 
3256     unsigned int maxLen = network()->getRouteMaxLength(m_type,label.dpc().pack(m_type));
3257     if (maxLen < MAX_TDM_MSU_SIZE) {
3258 	DDebug(this,DebugInfo,"Received MSU size (%d) lower than maximum TDM!",
3259 	       maxLen);
3260 	maxLen = MAX_TDM_MSU_SIZE;
3261     }
3262     bool ludtSupport = maxLen > MAX_TDM_MSU_SIZE; // Maximum MSU size (SIO + Label + data)
3263     maxLen -= (label.length() + 1); // subtract label length and SIO octet
3264     // Now max length represents the maximum length of SCCP message
3265     // Adjust maxLen to represent maximum data in the message.
3266     unsigned int headerLength = 3; // MsgType + ProtocolClass
3267     // Memorize pointer start to adjust data size.
3268     unsigned int pointersStart = headerLength;
3269     maxLen -= headerLength;
3270     // We have 3 mandatory variable parameters CallingAddress, CalledAddress,
3271     // and Data and the pointer to optional parameters + 1 data length
3272     headerLength += 5;
3273     headerLength += getAddressLength(msg->params(), "CalledPartyAddress");
3274     headerLength += getAddressLength(msg->params(), "CallingPartyAddress");
3275     ludt = 0;
3276     unsigned int sccpParamsSize = headerLength - pointersStart;
3277     // 254 = 255 max data length - 1 hopcounter - 1 optional parameters pointer +
3278     //       1 data length indicator
3279     if (maxLen > 254 + sccpParamsSize)
3280 	udt = 255;
3281     else
3282 	udt = maxLen - sccpParamsSize;
3283     // Append optional parameters length
3284     sccpParamsSize += MAX_OPT_LEN;
3285 
3286     if (ludtSupport) {
3287 	unsigned int maxSupported  = ITU() ? MAX_DATA_ITU : MAX_DATA_ANSI;
3288 	if (maxLen < maxSupported) {
3289 	    ludt = maxLen - sccpParamsSize;
3290 	    ludt -= 5; // The pointers and data length are on 2 octets
3291 	} else
3292 	    ludt = maxSupported;
3293     }
3294     // 254 represents the maximum value that can be stored
3295     if (maxLen < 254)
3296 	xudt = maxLen - sccpParamsSize;
3297     // Adjust data length to make sure that the pointer to optional parameters
3298     // is not bigger than max unsigned char value
3299     xudt = 254 - sccpParamsSize;
3300 }
3301 
printMessage(const SS7MSU * msu,const SS7MsgSCCP * sccpMsg,const SS7Label & label)3302 void SS7SCCP::printMessage(const SS7MSU* msu, const SS7MsgSCCP* sccpMsg, const
3303 	SS7Label& label) {
3304 
3305     if (m_printMsg && debugAt(DebugInfo)) {
3306 	String tmp;
3307 	const void* data = 0;
3308 	unsigned int len = 0;
3309 	if (m_extendedDebug && msu) {
3310 	    unsigned int offs = label.length() + 4;
3311 	    data = msu->getData(offs);
3312 	    len = data ? msu->length() - offs : 0;
3313 	}
3314 	String tmp1;
3315 	fillLabelAndReason(tmp1,label,sccpMsg);
3316 	sccpMsg->toString(tmp,label,debugAt(DebugAll),data,len);
3317 	Debug(this,DebugInfo,"Sending message (%p) '%s' %s %s",sccpMsg,
3318 		SS7MsgSCCP::lookup(sccpMsg->type()),tmp1.c_str(),tmp.c_str());
3319     } else if (debugAt(DebugAll)) {
3320 	String tmp;
3321 	bool debug = fillLabelAndReason(tmp,label,sccpMsg);
3322 	Debug(this,debug ? DebugInfo : DebugAll,"Sending message '%s' %s",
3323 		sccpMsg->name(),tmp.c_str());
3324     }
3325 }
3326 
getDataSegments(unsigned int dataLength,unsigned int maxSegmentSize)3327 ObjList* SS7SCCP::getDataSegments(unsigned int dataLength,
3328 	unsigned int maxSegmentSize)
3329 {
3330     DDebug(DebugAll,"getDataSegments(%u,%u)",dataLength,maxSegmentSize);
3331     ObjList* segments = new ObjList();
3332     // The first sccp segment must be the largest
3333     int segmentSize = maxSegmentSize - 1;
3334     int dataLeft = dataLength;
3335     unsigned int totalSent = 0;
3336     int sgSize = maxSegmentSize;
3337     if (dataLength - maxSegmentSize <= MIN_DATA_SIZE)
3338 	sgSize = maxSegmentSize - MIN_DATA_SIZE;
3339     segments->append(new SS7SCCPDataSegment(0,sgSize));
3340     dataLeft -= sgSize;
3341     totalSent += sgSize;
3342     while (dataLeft > 0) {
3343 	sgSize = 0;
3344 	if ((dataLeft - segmentSize) > MIN_DATA_SIZE) { // Make sure that the left segment is longer than 2
3345 	    sgSize = segmentSize;
3346 	} else if (dataLeft > segmentSize) {
3347 	    sgSize = segmentSize - MIN_DATA_SIZE;
3348 	} else {
3349 	    sgSize = dataLeft;
3350 	}
3351 	XDebug(this,DebugAll,"Creating new data segment total send %d, segment size %d",
3352 	       totalSent,sgSize);
3353 	segments->append(new SS7SCCPDataSegment(totalSent,sgSize));
3354 	dataLeft -= sgSize;
3355 	totalSent += sgSize;
3356     }
3357     return segments;
3358 }
3359 
getAndRemoveDataSegment(ObjList * obj)3360 SS7SCCPDataSegment* getAndRemoveDataSegment(ObjList* obj)
3361 {
3362     if (!obj)
3363 	return 0;
3364     ObjList* o = obj->skipNull();
3365     if (!o)
3366 	return 0;
3367     SS7SCCPDataSegment* sgm = static_cast<SS7SCCPDataSegment*>(o->get());
3368     obj->remove(sgm,false);
3369     return sgm;
3370 }
3371 
segmentMessage(SS7MsgSCCP * origMsg,const SS7Label & label,bool local)3372 int SS7SCCP::segmentMessage(SS7MsgSCCP* origMsg, const SS7Label& label, bool local)
3373 {
3374     if (!origMsg)
3375 	return -1;
3376     unsigned int udtLength = 0;
3377     unsigned int xudtLength = 0;
3378     unsigned int ludtLength = 0;
3379     getMaxDataLen(origMsg,label,udtLength,xudtLength,ludtLength);
3380     unsigned int dataLen = 0;
3381 
3382     DDebug(this,DebugInfo, "Got max data len : udt (%d) : xudt (%d) ludt (%d)",
3383 	   udtLength,xudtLength,ludtLength);
3384     if (udtLength < 2 && xudtLength < 2 && ludtLength < 2)
3385 	return -1;
3386     int sls = origMsg->params().getIntValue(YSTRING("sls"),-1);
3387     DataBlock* data = origMsg->getData();
3388     if (!data)
3389 	return -1;
3390     // Verify if we should bother to send the message
3391     if (data->length() > (ITU() ? MAX_DATA_ITU : MAX_DATA_ANSI)) {
3392 	Debug(this,DebugNote,
3393 	      "Unable to send SCCP message! Data length (%d) is too long",
3394 	      data->length());
3395 	return -1;
3396     }
3397 
3398     SS7MsgSCCP::Type msgType = origMsg->type();
3399     if (data->length() <= udtLength && origMsg->canBeUDT()) {
3400 	msgType = isSCLCMessage(msgType) ? SS7MsgSCCP::UDT : SS7MsgSCCP::UDTS;
3401 	dataLen = udtLength;
3402     } else if (data->length() <= xudtLength) {
3403 	msgType = isSCLCMessage(msgType) ? SS7MsgSCCP::XUDT : SS7MsgSCCP::XUDTS;
3404 	dataLen = xudtLength;
3405     } else if (data->length() <= ludtLength) {
3406 	msgType = isSCLCMessage(msgType) ? SS7MsgSCCP::LUDT : SS7MsgSCCP::LUDTS;
3407 	dataLen = ludtLength;
3408     } else { // Segmentation is needed!!!
3409 	if (ludtLength > 2) { // send ludt
3410 	    msgType = isSCLCMessage(msgType) ? SS7MsgSCCP::LUDT : SS7MsgSCCP::LUDTS;
3411 	    dataLen = ludtLength;
3412 	} else if (xudtLength > 2) { // Send Ludt
3413 	    msgType = isSCLCMessage(msgType) ? SS7MsgSCCP::XUDT : SS7MsgSCCP::XUDTS;
3414 	    dataLen = xudtLength;
3415 	} else {
3416 	    Debug(this,DebugWarn,
3417 		  "Unable to segment message!! Invalid data len params! XUDT data len = %d, LUDT data len = %d",
3418 		  xudtLength,ludtLength);
3419 	}
3420     }
3421     origMsg->updateType(msgType);
3422     origMsg->params().clearParam(YSTRING("Segmentation"),'.');
3423     // Send the message if it fits in a single message
3424     if (data->length() <= dataLen) {
3425 	Lock lock(this);
3426 	ajustMessageParams(origMsg->params(),origMsg->type());
3427 	SS7MSU* msu = buildMSU(origMsg,label,false);
3428 	if (!msu) {
3429 	    Debug(this,DebugWarn,"Failed to build MSU from sccpMessage %s",
3430 		SS7MsgSCCP::lookup(origMsg->type()));
3431 	    return -1;
3432 	}
3433 	printMessage(msu,origMsg,label);
3434 	lock.drop();
3435 	sls = transmitMSU(*msu,label,sls);
3436 #ifdef DEBUG
3437 	if (sls < 0)
3438 	    Debug(this,DebugNote,"Failed to transmit message %s. %d",
3439 		  SS7MsgSCCP::lookup(origMsg->type()),sls);
3440 #endif
3441 	// CleanUp memory
3442 	TelEngine::destruct(msu);
3443 	return sls;
3444     }
3445     // Verify if we should bother to segment the message
3446     if ((data->length() > 16 * (dataLen - 1)) && !isSCLCSMessage(msgType)) {
3447 	Debug(DebugNote,
3448 	      "Unable to segment SCCP message! Data length (%d) excedes max data allowed (%d)",
3449 	      data->length(),(16 * (dataLen - 1)));
3450 	return -1;
3451     }
3452 
3453     // Start segmentation process
3454     lock();
3455     ObjList* listSegments = getDataSegments(data->length(),dataLen);
3456 
3457     // Build message params
3458     NamedList msgData("");
3459     msgData.copyParams(origMsg->params());
3460     ajustMessageParams(msgData,msgType);
3461 
3462     // Set segmentation local reference for this message
3463     msgData.setParam("Segmentation","");
3464     if (!msgData.getParam(YSTRING("Segmentation.SegmentationLocalReference")))
3465 	msgData.setParam("Segmentation.SegmentationLocalReference",String((u_int32_t)Random::random()));
3466     int segments = listSegments->count();
3467     msgData.setParam("Segmentation.ProtocolClass",msgData.getValue(YSTRING("ProtocolClass")));
3468     if (isSCLCMessage(msgType))
3469 	msgData.setParam("ProtocolClass","1"); // Segmentation is using in sequence delivery option
3470     bool msgReturn = msgData.getBoolValue(YSTRING("MessageReturn"),false);
3471     sls = msgData.getIntValue(YSTRING("sls"),-1);
3472 
3473     // Transmit first segment
3474     SS7MsgSCCP* msg = new SS7MsgSCCP(msgType);
3475     msg->params().copyParams(msgData);
3476     DataBlock temp;
3477     SS7SCCPDataSegment* sg = getAndRemoveDataSegment(listSegments);
3478     if (!sg) {
3479 	Debug(DebugStub,"Unable to extract first data segment!!!");
3480 	TelEngine::destruct(msg);
3481 	TelEngine::destruct(listSegments);
3482 	return -1;
3483     }
3484     sg->fillSegment(temp,*data);
3485     msg->params().setParam("Segmentation.RemainingSegments",
3486 	    String(isSCLCMessage(msgType) ? --segments : 0));
3487     msg->params().setParam("Segmentation.FirstSegment","true");
3488     msg->setData(&temp);
3489     SS7MSU* msu = buildMSU(msg,label,false);
3490     msg->removeData();
3491     temp.clear(false);
3492     if (!msu) {
3493 	Debug(this,DebugWarn,"Failed to build MSU from sccpMessage %s",
3494 		SS7MsgSCCP::lookup(msgType));
3495 	TelEngine::destruct(msg);
3496 	TelEngine::destruct(listSegments);
3497 	return -1;
3498     }
3499     printMessage(msu,msg,label);
3500     unlock();
3501     sls = transmitMSU(*msu,label,sls);
3502 #ifdef DEBUG
3503     if (sls < 0)
3504 	Debug(this,DebugNote,"Failed to transmit message %s. %d",
3505 		SS7MsgSCCP::lookup(msgType),sls);
3506 #endif
3507     TelEngine::destruct(msu);
3508     TelEngine::destruct(msg);
3509     TelEngine::destruct(sg);
3510     if (sls < 0) {
3511 	if (msgReturn && !local)
3512 	    returnMessage(origMsg,MtpFailure);
3513 	Debug(this,DebugNote,"Failed to transmit first segment of message");
3514 	TelEngine::destruct(listSegments);
3515 	return sls;
3516     }
3517     if (isSCLCSMessage(msgType)) {
3518 	TelEngine::destruct(listSegments);
3519 	return sls;
3520     }
3521     lock();
3522     msgData.setParam("Segmentation.FirstSegment","false");
3523     // Set message return option only for the first segment
3524     msgData.setParam("MessageReturn","false");
3525     while ((sg = getAndRemoveDataSegment(listSegments))) {
3526 	msg = new SS7MsgSCCP(msgType);
3527 	msg->params().copyParams(msgData);
3528 	sg->fillSegment(temp,*data);
3529 	TelEngine::destruct(sg);
3530 	msg->params().setParam("Segmentation.RemainingSegments",String(--segments));
3531 	msg->setData(&temp);
3532 	SS7MSU* msu = buildMSU(msg,label,false);
3533 	msg->removeData();
3534 	temp.clear(false);
3535 	if (!msu) {
3536 	    Debug(this,DebugWarn,"Failed to build MSU from sccpMessage %s",
3537 		    SS7MsgSCCP::lookup(msgType));
3538 	    TelEngine::destruct(msg);
3539 	    TelEngine::destruct(listSegments);
3540 	    return -1;
3541 	}
3542 	printMessage(msu,msg,label);
3543 	unlock();
3544 	sls = transmitMSU(*msu,label,sls);
3545 #ifdef DEBUG
3546 	if (sls < 0)
3547 	    Debug(this,DebugNote,"Failed to transmit message %s. %d",
3548 		    SS7MsgSCCP::lookup(msgType),sls);
3549 #endif
3550 	TelEngine::destruct(msg);
3551 	TelEngine::destruct(msu);
3552 	if (sls < 0) {
3553 	    if (msgReturn && !local)
3554 		returnMessage(origMsg,MtpFailure);
3555 	    Debug(this,DebugNote,"Failed to transmit segment of %s message remaining segments %d",
3556 		  SS7MsgSCCP::lookup(msgType),segments);
3557 	    return sls;
3558 	}
3559 	lock();
3560     }
3561     if (segments != 0)
3562 	Debug(this,DebugStub,"Bug in segment message!! RemainingSegments %d",segments);
3563     TelEngine::destruct(listSegments);
3564     unlock();
3565     return sls;
3566 }
3567 
reassembleSegment(SS7MsgSCCP * segment,const SS7Label & label,SS7MsgSCCP * & msg)3568 SS7MsgSccpReassemble::Return SS7SCCP::reassembleSegment(SS7MsgSCCP* segment,
3569 	    const SS7Label& label, SS7MsgSCCP*& msg)
3570 {
3571     if (segment->params().getBoolValue(YSTRING("Segmentation.FirstSegment"))) {
3572 	for (ObjList* o = m_reassembleList.skipNull(); o; o = o->skipNext()) {
3573 	    SS7MsgSccpReassemble* reass = static_cast <SS7MsgSccpReassemble*>(o->get());
3574 	    if (!reass || !reass->canProcess(segment,label))
3575 		continue;
3576 	    m_reassembleList.remove(reass);
3577 	    DDebug(this,DebugNote,"Duplicate first segment received!");
3578 	    return SS7MsgSccpReassemble::Error;
3579 	}
3580 	SS7MsgSccpReassemble* reass = new SS7MsgSccpReassemble(segment,label,m_segTimeout);
3581 	m_reassembleList.append(reass);
3582 	return SS7MsgSccpReassemble::Accepted;
3583     }
3584 
3585     SS7MsgSccpReassemble::Return ret = SS7MsgSccpReassemble::Rejected;
3586     for (ObjList* o = m_reassembleList.skipNull(); o; o = o->skipNext()) {
3587 	SS7MsgSccpReassemble* reass = static_cast <SS7MsgSccpReassemble*>(o->get());
3588 	if (!reass)
3589 	    continue;
3590 	ret = reass->appendSegment(segment,label);
3591 	if (ret == SS7MsgSccpReassemble::Rejected)
3592 	    continue;
3593 	if (ret == SS7MsgSccpReassemble::Error) {
3594 	    m_reassembleList.remove(reass,false);
3595 	    msg = reass;
3596 	    return ret;
3597 	}
3598 	if (ret == SS7MsgSccpReassemble::Finished) {
3599 	    m_reassembleList.remove(reass,false);
3600 	    msg = reass;
3601 	}
3602 	return ret;
3603     }
3604     return ret;
3605 }
3606 
buildMSU(SS7MsgSCCP * msg,const SS7Label & label,bool checkLength) const3607 SS7MSU* SS7SCCP::buildMSU(SS7MsgSCCP* msg, const SS7Label& label, bool checkLength) const
3608 {
3609     // see what mandatory parameters we should put in this message
3610     const MsgParams* msgParams = getSccpParams(msg->type());
3611     if (!msgParams) {
3612 	const char* name = SS7MsgSCCP::lookup(msg->type());
3613 	if (name)
3614 	    Debug(this,DebugWarn,"No parameter table for SCCP MSU type %s [%p]",name,this);
3615 	else
3616 	    Debug(this,DebugWarn,"Cannot create SCCP MSU type 0x%02x [%p]",msg->type(),this);
3617 	return 0;
3618     }
3619     unsigned int len = 1;
3620 
3621     const SS7MsgSCCP::Parameters* plist = msgParams->params;
3622     SS7MsgSCCP::Parameters ptype;
3623     // first add the length of mandatory fixed parameters
3624     while ((ptype = *plist++) != SS7MsgSCCP::EndOfParameters) {
3625 	const SCCPParam* param = getParamDesc(ptype);
3626 	if (!param) {
3627 	    // this is fatal as we don't know the length
3628 	    Debug(this,DebugCrit,"Missing description of fixed SCCP parameter 0x%02x [%p]",ptype,this);
3629 	    return 0;
3630 	}
3631 	if (!param->size) {
3632 	    Debug(this,DebugCrit,"Invalid (variable) description of fixed SCCP parameter 0x%02x [%p]",ptype,this);
3633 	    return 0;
3634 	}
3635 	len += param->size;
3636     }
3637     bool ludt = msg->isLongDataMessage();
3638     int pointerLen = ludt ? 2 : 1;
3639     // initialize the pointer array offset just past the mandatory fixed part
3640     unsigned int ptr = label.length() + 1 + len;
3641     // then add one pointer octet to each mandatory variable parameter
3642     while ((ptype = *plist++) != SS7MsgSCCP::EndOfParameters) {
3643 	const SCCPParam* param = getParamDesc(ptype);
3644 	if (!param) {
3645 	    // this is fatal as we won't be able to populate later
3646 	    Debug(this,DebugCrit,"Missing description of variable SCCP parameter 0x%02x [%p]",ptype,this);
3647 	    return 0;
3648 	}
3649 	if (param->size)
3650 	    Debug(this,DebugMild,"Invalid (fixed) description of variable SCCP parameter 0x%02x [%p]",ptype,this);
3651 	len += pointerLen;
3652     }
3653     // finally add a pointer to the optional part only if supported by type
3654     if (msgParams->optional)
3655 	len += pointerLen;
3656     SS7MSU* msu = new SS7MSU(sio(),label,0,len);
3657     unsigned char* d = msu->getData(label.length()+1,len);
3658     *d++ = msg->type();
3659     ObjList exclude;
3660     plist = msgParams->params;
3661     String prefix = msg->params().getValue(YSTRING("message-prefix"));
3662     // first populate with mandatory fixed parameters
3663     while ((ptype = *plist++) != SS7MsgSCCP::EndOfParameters) {
3664 	const SCCPParam* param = getParamDesc(ptype);
3665 	if (!param) {
3666 	    Debug(this,DebugFail,"Stage 2: no description of fixed SCCP parameter 0x%02x [%p]",ptype,this);
3667 	    continue;
3668 	}
3669 	if (!param->size) {
3670 	    Debug(this,DebugFail,"Stage 2: Invalid (variable) description of fixed SCCP parameter %s [%p]",param->name,this);
3671 	    continue;
3672 	}
3673 	if (!encodeParam(this,*msu,param,&msg->params(),exclude,prefix,d))
3674 	    Debug(this,DebugCrit,"Could not encode fixed SCCP parameter %s [%p]",param->name,this);
3675 	d += param->size;
3676     }
3677     // now populate with mandatory variable parameters
3678     for (; (ptype = *plist++) != SS7MsgSCCP::EndOfParameters; ptr += pointerLen) {
3679 	const SCCPParam* param = getParamDesc(ptype);
3680 	if (!param) {
3681 	    Debug(this,DebugFail,"Stage 2: no description of variable SCCP parameter 0x%02x [%p]",ptype,this);
3682 	    continue;
3683 	}
3684 	if (param->size) {
3685 	    Debug(this,DebugFail,"Stage 2: Invalid (fixed) description of variable SCCP parameter %s [%p]",param->name,this);
3686 	    continue;
3687 	}
3688 	// remember the offset this parameter will actually get stored
3689 	len = msu->length();
3690 	unsigned int size = 0;
3691 	if (ptype == SS7MsgSCCP::Data || ptype == SS7MsgSCCP::LongData) {
3692 	    size = encodeData(this,*msu,msg);
3693 	    if (ptype == SS7MsgSCCP::Data) {
3694 		// Data parameter is the last of variable mandatory parameters
3695 		// Check if the pointer to variable part may be bigger than 255
3696 		// (max unsigned char value)
3697 		if (checkLength && ((len + size + MAX_OPT_LEN) > 254)) {
3698 		    TelEngine::destruct(msu);
3699 		    return 0;
3700 		}
3701 	    }
3702 	} else
3703 	    size = encodeParam(this,*msu,param,&msg->params(),exclude,prefix);
3704 	d = msu->getData(0,len+1);
3705 	if (!(size && d)) {
3706 	    Debug(this,DebugCrit,"Could not encode variable SCCP parameter %s [%p]",param->name,this);
3707 	    continue;
3708 	}
3709 	if (ptype != SS7MsgSCCP::LongData && ((d[len] != size) || (msu->length() != (len + size + 1)))) {
3710 	    Debug(this,DebugCrit,"Invalid encoding variable SCCP parameter %s (len=%u size=%u stor=%u msuLength = %u) [%p]",
3711 		param->name,len,size,d[len],msu->length(),this);
3712 	    continue;
3713 	}
3714 	// store pointer to parameter
3715 	unsigned int storedLength = len - ptr;
3716 	if (!ludt) {
3717 	    d[ptr] = storedLength;
3718 	    continue;
3719 	}
3720 	storedLength --;
3721 	d[ptr] = storedLength & 0xff;
3722 	d[ptr+1] = storedLength >> 8;
3723     }
3724     if (msgParams->optional) {
3725 	// remember the offset past last mandatory == first optional parameter
3726 	len = msu->length();
3727 	// optional parameters are possible - try to set anything left in the message
3728 	unsigned int n = msg->params().length();
3729 	for (unsigned int i = 0; i < n; i++) {
3730 	    NamedString* ns = msg->params().getParam(i);
3731 	    if (!ns || exclude.find(ns))
3732 		continue;
3733 	    if (prefix && !ns->name().startsWith(prefix))
3734 		continue;
3735 	    String tmp(ns->name());
3736 	    tmp >> prefix.c_str();
3737 	    const SCCPParam* param = getParamDesc(tmp);
3738 	    unsigned char size = 0;
3739 	    if (param)
3740 		size = encodeParam(this,*msu,param,ns,&msg->params(),prefix);
3741 	    else if (tmp.startSkip("Param_",false)) {
3742 		int val = tmp.toInteger(-1);
3743 		if (val >= 0 && val <= 255) {
3744 		    SCCPParam p;
3745 		    p.name = tmp;
3746 		    p.type = (SS7MsgSCCP::Parameters)val;
3747 		    p.size = 0;
3748 		    p.encoder = 0;
3749 		    size = encodeParam(this,*msu,&p,ns,&msg->params(),prefix);
3750 		}
3751 	    }
3752 	    if (!size)
3753 		continue;
3754 	    if (len) {
3755 		d = msu->getData(0,len+1);
3756 		unsigned int storedLength = len - ptr;
3757 		if (ludt) {
3758 		    storedLength --;
3759 		    d[ptr] = storedLength & 0xff;
3760 		    d[ptr+1] = storedLength >> 8;
3761 		} else {
3762 		    // Do not try to set the pointer to optional parameters
3763 		    // if is bigger than max unsigned char value because will
3764 		    // result in a malformed packet!
3765 		    if (storedLength > 255) {
3766 			Debug(this,checkLength ? DebugAll : DebugStub,
3767 			      "Build MSU the pointer to optional parameters is bigger than 255!!!! %d",
3768 			      storedLength);
3769 			TelEngine::destruct(msu);
3770 			return 0;
3771 		    }
3772 		    d[ptr] = storedLength;
3773 		}
3774 		len = 0;
3775 	    }
3776 	}
3777 	if (!len) {
3778 	    // we stored some optional parameters so we need to put the terminator
3779 	    DataBlock tmp(0,1);
3780 	    *msu += tmp;
3781 	}
3782     }
3783     return msu;
3784 }
3785 
receivedMSU(const SS7MSU & msu,const SS7Label & label,SS7Layer3 * network,int sls)3786 HandledMSU SS7SCCP::receivedMSU(const SS7MSU& msu, const SS7Label& label, SS7Layer3* network, int sls)
3787 {
3788     if (msu.getSIF() != sif()) // SCCP message?
3789 	return HandledMSU::Rejected;
3790     Lock lock(this);
3791     if (unknownPointCodeType()) {
3792 	DDebug(this,DebugNote,"Rejecting MSU! Reason Unknown pointcode type");
3793 	lock.drop();
3794 	return HandledMSU::Rejected;
3795     }
3796     if (m_localPointCode && *m_localPointCode != label.dpc()) { // Is the msu for us?
3797 	lock.drop();
3798 	return HandledMSU::Rejected;
3799     }
3800     lock.drop();
3801     const unsigned char* s = msu.getData(label.length() + 1,1);
3802     if (!s) {
3803 	Debug(this,DebugNote,"Got short MSU");
3804 	return false;
3805     }
3806     unsigned int len = msu.length()-label.length()-1;
3807     SS7MsgSCCP::Type type = (SS7MsgSCCP::Type)s[0];
3808     String name = SS7MsgSCCP::lookup(type);
3809     if (!name) {
3810         String tmp;
3811 	tmp.hexify((void*)s,len,' ');
3812 	DDebug(this,DebugMild,"Received unknown SCCP type 0x%02x, length %u: %s",
3813 	    type,len,tmp.c_str());
3814 	return false;
3815     }
3816     bool ok = processMSU(type,s+1,len-1,label,network,sls);
3817     if (!ok && debugAt(DebugMild)) {
3818 	String tmp;
3819 	tmp.hexify((void*)s,len,' ');
3820 	Debug(this,DebugMild,"Unhandled SCCP message %s,  length %u: %s",
3821 	    name.c_str(),len,tmp.c_str());
3822     }
3823     return ok;
3824 }
3825 
processMSU(SS7MsgSCCP::Type type,const unsigned char * paramPtr,unsigned int paramLen,const SS7Label & label,SS7Layer3 * network,int sls)3826 bool SS7SCCP::processMSU(SS7MsgSCCP::Type type, const unsigned char* paramPtr,
3827 	unsigned int paramLen, const SS7Label& label, SS7Layer3* network, int sls)
3828 {
3829     XDebug(this,DebugAll,"SS7SCCP::processMSU(%u,%p,%u,%p,%p,%d) [%p]",
3830 	type,paramPtr,paramLen,&label,network,sls,this);
3831 
3832     Lock lock(this);
3833     SS7MsgSCCP* msg = new SS7MsgSCCP(type);
3834     if (!decodeMessage(msg,label.type(),paramPtr,paramLen)) {
3835 	DDebug(this,DebugNote,"Failed to decode SCCP message!");
3836 	m_errors++;
3837 	TelEngine::destruct(msg);
3838 	return false;
3839     }
3840     msg->params().setParam("LocalPC",String(label.dpc().pack(m_type)));
3841     msg->params().setParam("RemotePC",String(label.opc().pack(m_type)));
3842     msg->params().setParam("generated","remote");
3843     // Set the sls in case of STP routing for sequence control
3844     msg->params().setParam("sls",String(label.sls()));
3845     if (m_printMsg && debugAt(DebugInfo)) {
3846 	String tmp;
3847 	msg->toString(tmp,label,debugAt(DebugAll),
3848 	    m_extendedDebug ? paramPtr : 0,paramLen);
3849 	String tmp1;
3850 	fillLabelAndReason(tmp1,label,msg);
3851 	Debug(this,DebugInfo,"Received message (%p) '%s' %s %s",
3852 	      msg,SS7MsgSCCP::lookup(msg->type()),tmp1.c_str(),tmp.c_str());
3853     } else if (debugAt(DebugAll)) {
3854 	String tmp;
3855 	bool debug = fillLabelAndReason(tmp,label,msg);
3856 	Debug(this,debug ? DebugInfo : DebugAll,"Received message '%s' %s",
3857 	    msg->name(),tmp.c_str());
3858     }
3859     // Form here something will happened with the message!
3860     // return true
3861     m_totalReceived++;
3862     int protocolClass = msg->params().getIntValue(YSTRING("ProtocolClass"), -1);
3863     if (isSCOCMsg(msg->type())) {
3864 	Debug(DebugWarn,"Received Connection oriented message!!");
3865 	if (msg->type() != SS7MsgSCCP::CR) { // Received Connection Oriented message other than Connect Request
3866 	    // Drop the message
3867 	    DDebug(this,DebugNote,"Received message %s without a connection!",SS7MsgSCCP::lookup(msg->type()));
3868 	    TelEngine::destruct(msg);
3869 	    return true;
3870 	}
3871 	// Send Connection Refused
3872 	SS7MsgSCCP* ref = new SS7MsgSCCP(SS7MsgSCCP::CREF);
3873 	ref->params().setParam("DestinationLocalReference",msg->params().getValue(YSTRING("SourceLocalReference")));
3874 	ref->params().setParam("RefusalCause",String(0x13)); // Unequipped user
3875 	SS7Label outLabel(label.type(),label.opc(),label.dpc(),label.sls());
3876 	SS7MSU* msu = buildMSU(ref,outLabel);
3877 	if (!msu)
3878 	    Debug(this,DebugWarn,"Failed to build msu from sccpMessage %s",
3879 		SS7MsgSCCP::lookup(ref->type()));
3880 	lock.drop();
3881 	if (msu) {
3882 	    transmitMSU(*msu,outLabel,outLabel.sls());
3883 	    TelEngine::destruct(msu);
3884 	}
3885 	TelEngine::destruct(ref);
3886 	TelEngine::destruct(msg);
3887 	return true;
3888     }
3889     // If the Calling party address does not contain route information
3890     // Set OPC as Calling Party Address pointcode
3891     if (((protocolClass == 0 || protocolClass == 1) &&
3892 	    isSCLCMessage(msg->type())) || isSCLCSMessage(msg->type())) { // ConnectionLess message
3893 	lock.drop();
3894 	routeSCLCMessage(msg,label);
3895     } else {
3896 	Debug(this,DebugMild,"Received bad message! Inconsistence between msg type %s and protocol class %d",
3897 		SS7MsgSCCP::lookup(msg->type()),protocolClass);
3898     }
3899     TelEngine::destruct(msg);
3900     return true;
3901 }
3902 
3903 // Process a SCCP message! return false if an error was detected
routeSCLCMessage(SS7MsgSCCP * & msg,const SS7Label & label)3904 bool SS7SCCP::routeSCLCMessage(SS7MsgSCCP*& msg, const SS7Label& label)
3905 {
3906     Lock lock(this);
3907     if (!msg) {
3908 	Debug(this,DebugWarn,"Request to route null sccp message");
3909 	m_errors++;
3910 	return false;
3911     }
3912     if (msg->params().getParam(YSTRING("Segmentation"))) {
3913 	// Verify if we had received Segmentation parameter with only one segment
3914 	// and let it pass trough
3915 	// The reassamblation of XUTDS and LUDTS is optional but, for code flow
3916 	// purpose, we are manageing it.
3917 	if (msg->params().getIntValue(YSTRING("Segmentation.RemainingSegments"),0) != 0 ||
3918 		!msg->params().getBoolValue(YSTRING("Segmentation.FirstSegment"),true)) {
3919 	    // We have segmentation parameter with multiple segments
3920 	    SS7MsgSCCP* finishead = 0;
3921 	    int ret = reassembleSegment(msg,label,finishead);
3922 	    if (ret == SS7MsgSccpReassemble::Accepted ||
3923 		    ret == SS7MsgSccpReassemble::Rejected)
3924 		return true;
3925 	    if (ret == SS7MsgSccpReassemble::Error) {
3926 		// For XUDTS and LUDTS messages the message return should allways
3927 		// be false
3928 		if (finishead && finishead->params().getBoolValue(YSTRING("MessageReturn"),false))
3929 		    returnMessage(finishead,SegmentationFailure);
3930 		if (finishead)
3931 		    TelEngine::destruct(finishead);
3932 		m_errors++;
3933 		return true;
3934 	    }
3935 	    if (!finishead) {
3936 		Debug(this,DebugStub,"Sccp Message finishead to reassemble but the message was not returned");
3937 		return true;
3938 	    }
3939 	    TelEngine::destruct(msg);
3940 	    msg = finishead;
3941 	}
3942     }
3943     int errorCode = -1;
3944     NamedString* route = msg->params().getParam(YSTRING("CalledPartyAddress.route"));
3945     bool msgReturn = msg->params().getBoolValue(YSTRING("MessageReturn"),false);
3946     bool informManagement = false;
3947     while (route && *route != YSTRING("ssn")) {
3948 	if (!msg->params().getParam(YSTRING("CalledPartyAddress.gt"))) {
3949 	    if (m_endpoint && msg->params().getParam(YSTRING("CalledPartyAddress.ssn")))
3950 		break; // If we are endpoint and we have a ssn try to process the message
3951 	    Debug(this,DebugInfo,"Message requested to be routed on gt but no gt present!");
3952 	    break;
3953 	}
3954 	NamedList* gtRoute = translateGT(msg->params(),"CalledPartyAddress",
3955 		"CallingPartyAddress");
3956 	m_totalGTTranslations++;
3957 	if (!gtRoute) {
3958 	    if (m_endpoint && msg->params().getParam(YSTRING("CalledPartyAddress.ssn")))
3959 		break; // If we are endpoint and we have a ssn try to process the message
3960 	    m_gttFailed++;
3961 	    errorCode = NoTranslationSpecificAddress;
3962 	    Debug(this,DebugInfo,"No Gt Found for : %s, or all routes are down!",
3963 		  msg->params().getValue(YSTRING("CalledPartyAddress.gt")));
3964 	    break;
3965 	}
3966 	resolveGTParams(msg,gtRoute);
3967 	NamedString* localRouting = gtRoute->getParam(YSTRING("sccp"));
3968 	if (localRouting && *localRouting != toString()) {
3969 	    msg->params().copyParam(*gtRoute,YSTRING("RemotePC"));
3970 	    TelEngine::destruct(gtRoute);
3971 	    lock.drop();
3972 	    return routeLocal(msg) >= 0;
3973 	}
3974 	bool haveRemotePC = gtRoute->getParam(YSTRING("RemotePC")) != 0;
3975 	if (!gtRoute->getParam(YSTRING("pointcode")) && !haveRemotePC) {
3976 	    if (m_endpoint) {
3977 		// If we have an ssn try to process the message
3978 		if (msg->params().getParam(YSTRING("CalledPartyAddress.ssn")))
3979 		    break;
3980 		if (gtRoute->getParam(YSTRING("ssn"))) {
3981 		    msg->params().setParam("CalledPartyAddress.ssn",gtRoute->getValue(YSTRING("ssn")));
3982 		    break;
3983 		}
3984 	    }
3985 	    Debug(this,DebugWarn,"The GT has not been translated to a pointcode!!");
3986 	    TelEngine::destruct(gtRoute);
3987 	    errorCode = NoTranslationAddressNature;
3988 	    break;
3989 	}
3990 	msg->params().clearParam(YSTRING("CalledPartyAddress"),'.');
3991 	for (unsigned int i = 0;i < gtRoute->length();i++) {
3992 	    NamedString* val = gtRoute->getParam(i);
3993     	    if (val && (val->name().startsWith("gt") || val->name() == YSTRING("pointcode") ||
3994 		    val->name() == YSTRING("ssn") || val->name() == YSTRING("route")))
3995 		msg->params().setParam("CalledPartyAddress." + val->name(),*val);
3996 	}
3997 	int pointcode = haveRemotePC ? gtRoute->getIntValue(YSTRING("RemotePC")) :
3998 	    msg->params().getIntValue(YSTRING("CalledPartyAddress.pointcode"));
3999 
4000 	TelEngine::destruct(gtRoute);
4001 	if (msg->params().getIntValue(YSTRING("CalledPartyAddress.ssn"),-1) == 1) {
4002 	    Debug(this,DebugNote,"GT Routing Warn!! Message %s global title translated for management!",
4003 		  SS7MsgSCCP::lookup(msg->type()));
4004 	    m_errors++;
4005 	    return false; // Management message with global title translation
4006 	}
4007 	if (!m_localPointCode)
4008 	    Debug(this,DebugConf,
4009 		  "No local PointCode configured!! GT translations with no local PointCode may lead to undesired behavior");
4010 	if (msg->params().getParam(YSTRING("HopCounter"))) {
4011 	    int hopcounter = msg->params().getIntValue(YSTRING("HopCounter"));
4012 	    hopcounter --;
4013 	    if (hopcounter <= 0) {
4014 		errorCode = HopCounterViolation;
4015 		break;
4016 	    }
4017 	    msg->params().setParam("HopCounter",String(hopcounter));
4018 	}
4019 	// If from the translated gt resulted a pointcode other then ours forward the message
4020 	if (pointcode > 0 && m_localPointCode && (unsigned int)pointcode != m_localPointCode->pack(m_type)) {
4021 	    msg->params().setParam("RemotePC",String(pointcode));
4022 	    lock.drop();
4023 	    if (transmitMessage(msg) >= 0)
4024 		return true;
4025 	    informManagement = true;
4026 	    errorCode = MtpFailure;
4027 	}
4028 	break;
4029     }
4030     if (errorCode >= 0) {
4031 	m_errors++;
4032 	lock.drop();
4033 	if (informManagement && m_management)
4034 	    m_management->routeFailure(msg);
4035 	if (msgReturn)
4036 	    returnMessage(msg,errorCode);
4037 	else
4038 	    Debug(this,DebugInfo,"Dropping message %s. Reason: %s",
4039 		    SS7MsgSCCP::lookup(msg->type()),lookup(errorCode,s_return_cause));
4040 	return false;
4041     }
4042     int ssn = msg->params().getIntValue(YSTRING("CalledPartyAddress.ssn"),-1);
4043     errorCode = SccpFailure;
4044     while (ssn > 0) {
4045 	if (ssn == 0) {
4046 	    Debug(this,DebugNote,"Requested user with ssn 0!");
4047 	    errorCode = UnequippedUser;
4048 	    break;
4049 	}
4050 	if (ssn == 1) { // Local Management message ?
4051 	    while (true) {
4052 		int protocolClass = msg->params().getIntValue(YSTRING("ProtocolClass"));
4053 		// SCCP management messages need to have protocol class 0 with no special options
4054 		if (protocolClass != 0 || msgReturn)
4055 		    break;
4056 		// Remote SSN must be management SSN (1)
4057 		if (msg->params().getIntValue(YSTRING("CallingPartyAddress.ssn"),-1) != 1)
4058 		    break;
4059 		if (m_management) {
4060 		    lock.drop();
4061 		    return m_management->processMessage(msg);
4062 		}
4063 		break;
4064 	    }
4065 #ifdef DEBUG
4066 	    String tmp;
4067 	    msg->params().dump(tmp,"\r\n  ",'\'',true);
4068 	    Debug(this,DebugNote,"Received invalid SCCPManagement message! %s",tmp.c_str());
4069 #endif
4070 	    m_errors++;
4071 	    return false;
4072 	}
4073 	// If we are here that means that the message is for local processing!
4074 	switch (msg->type()) {
4075 	    case SS7MsgSCCP::XUDT:
4076 	    case SS7MsgSCCP::LUDT:
4077 	    case SS7MsgSCCP::UDT:
4078 		lock.drop();
4079 		{
4080 		    int ret = pushMessage(*msg->getData(),msg->params(),ssn);
4081 		    if (ret == HandledMSU::Accepted)
4082 			return true;
4083 		    if (m_management)
4084 			m_management->subsystemFailure(msg,label);
4085 		    errorCode = (ret == HandledMSU::Unequipped) ? UnequippedUser : SubsystemFailure;
4086 		}
4087 		break;
4088 	    case SS7MsgSCCP::XUDTS:
4089 	    case SS7MsgSCCP::LUDTS:
4090 	    case SS7MsgSCCP::UDTS:
4091 		if (m_extendedMonitoring)
4092 		    archiveMessage(msg);
4093 		DDebug(this,DebugAll,"Received service message %s. Reason: %s",
4094 			SS7MsgSCCP::lookup(msg->type()),lookup(msg->params().getIntValue(YSTRING("ReturnCause")),s_return_cause));
4095 		msg->params().setParam("location","remote");
4096 		lock.drop();
4097 		notifyMessage(*msg->getData(),msg->params(),ssn);
4098 		// Do not bother to verify the return code, because there is nothing that we can do for service messages
4099 		return true;
4100 	    default:
4101 		Debug(this,DebugWarn,"Received unknown SCLC msg type %d",msg->type());
4102 		errorCode = ErrorInLocalProcessing;
4103 		break;
4104 	}
4105 	break;
4106     }
4107     m_errors++;
4108     lock.drop();
4109     if (msgReturn)
4110 	returnMessage(msg,errorCode);
4111     else
4112 	Debug(this,DebugInfo,"Dropping message %s. Reason: %s",
4113 	      SS7MsgSCCP::lookup(msg->type()),lookup(errorCode,s_return_cause));
4114     return false;
4115 }
4116 
returnMessage(SS7MsgSCCP * message,int error)4117 void SS7SCCP::returnMessage(SS7MsgSCCP* message, int error)
4118 {
4119     DDebug(this,DebugInfo,"Returning message %s! reason : %s",SS7MsgSCCP::lookup(message->type()),lookup(error,s_return_cause));
4120     if (!message) {
4121 	DDebug(this,DebugNote,"Message return method called for a null message!!");
4122 	return;
4123     }
4124     if (!message->getData()) {
4125 	DDebug(this,DebugWarn,"Message Return initiated with no data parameter");
4126 	return;
4127     }
4128     SS7MsgSCCP* msg = 0;
4129     switch (message->type()) {
4130 	case SS7MsgSCCP::UDT:
4131 	    msg = new SS7MsgSCCP(SS7MsgSCCP::UDTS);
4132 	    break;
4133 	case SS7MsgSCCP::XUDT:
4134 	    msg = new SS7MsgSCCP(SS7MsgSCCP::XUDTS);
4135 	    break;
4136 	case SS7MsgSCCP::LUDT:
4137 	    msg = new SS7MsgSCCP(SS7MsgSCCP::LUDTS);
4138 	    break;
4139 	default:
4140 	    DDebug(this,DebugInfo,"Message return procedure initiated for wrong message type %s",
4141 			SS7MsgSCCP::lookup(msg->type()));
4142 	    return;
4143     }
4144     if (!msg) {
4145 	Debug(this,DebugStub,"Implementation bug!! null SCCP message");
4146 	return;
4147     }
4148     msg->params().copyParams(message->params());
4149     switchAddresses(message->params(),msg->params());
4150     msg->params().setParam("ReturnCause",String(error));
4151     msg->setData(message->getData());
4152     msg->params().clearParam(YSTRING("ProtocolClass"),'.');
4153     msg->params().clearParam(YSTRING("Segmentation"),'.');
4154     msg->params().clearParam(YSTRING("MessageReturn"),'.');
4155     if (msg->params().getParam(YSTRING("Importance")))
4156 	msg->params().setParam("Importance","3"); // Default value for service messages
4157     if (msg->params().getParam(YSTRING("HopCounter")))
4158 	msg->params().setParam("HopCounter",String(m_hopCounter));
4159     transmitMessage(msg,true);
4160     msg->removeData();
4161     TelEngine::destruct(msg);
4162 }
4163 
switchAddresses(const NamedList & source,NamedList & dest)4164 void SS7SCCP::switchAddresses(const NamedList& source, NamedList& dest)
4165 {
4166     // First remove the called and calling party address from dest
4167     dest.clearParam(YSTRING("CalledPartyAddress"),'.');
4168     dest.clearParam(YSTRING("CallingPartyAddress"),'.');
4169     dest.clearParam(YSTRING("LocalPC"));
4170     dest.clearParam(YSTRING("RemotePC"));
4171     if (source.getParam(YSTRING("LocalPC")))
4172 	dest.setParam("LocalPC",source.getValue(YSTRING("LocalPC")));
4173     // Do not set RemotePC because the message can fail after a gt was performed
4174     // and than RemotePC represents message destination pc rather then
4175     // originating pc. Obtain return address from CallingPartyAddress
4176     // Copy the params
4177     for (unsigned int i = 0;i < source.length();i++) {
4178 	NamedString* param = source.getParam(i);
4179 	if (!param || !param->name().startsWith("Call"))
4180 	    continue;
4181 	String name = param->name();
4182 	if (name.startSkip(YSTRING("CalledPartyAddress"),false))
4183 	    dest.setParam(new NamedString("CallingPartyAddress" + name,*param));
4184 	if (name.startSkip(YSTRING("CallingPartyAddress"),false))
4185 	    dest.setParam(new NamedString("CalledPartyAddress" + name,*param));
4186     }
4187 }
4188 
decodeMessage(SS7MsgSCCP * msg,SS7PointCode::Type pcType,const unsigned char * paramPtr,unsigned int paramLen)4189 bool SS7SCCP::decodeMessage(SS7MsgSCCP* msg, SS7PointCode::Type pcType,
4190     const unsigned char* paramPtr, unsigned int paramLen)
4191 {
4192     if (!msg)
4193 	return false;
4194     String msgTypeName((int)msg->type());
4195     const char* msgName = SS7MsgSCCP::lookup(msg->type(),msgTypeName);
4196 #ifdef XDEBUG
4197     String tmp;
4198     tmp.hexify((void*)paramPtr,paramLen,' ');
4199     Debug(this,DebugAll,"Decoding msg=%s len=%u: %s [%p]",
4200 	msgName,paramLen,tmp.c_str(),this);
4201 #else
4202     DDebug(this,DebugAll,"Decoding msg=%s len=%u [%p]",
4203 	msgName,paramLen,this);
4204 #endif
4205 
4206     // see what parameters we expect for this message
4207     const MsgParams* params = getSccpParams(msg->type());
4208     if (!params) {
4209 	Debug(this,DebugWarn,"Parameters list could not be found for message %s [%p]",msgName,this);
4210 	return false;
4211     }
4212 
4213     // Get parameter prefix
4214     String prefix = msg->params().getValue(YSTRING("message-prefix"));
4215 
4216     // Add protocol and message type
4217     switch (pcType) {
4218 	case SS7PointCode::ITU:
4219 	    msg->params().addParam(prefix+"protocol-type","itu-t");
4220 	    break;
4221 	case SS7PointCode::ANSI:
4222 	case SS7PointCode::ANSI8:
4223 	    msg->params().addParam(prefix+"protocol-type","ansi");
4224 	    break;
4225 	default: ;
4226     }
4227     msg->params().addParam(prefix+"message-type",msgName);
4228 
4229     String unsupported;
4230     const SS7MsgSCCP::Parameters* plist = params->params;
4231     SS7MsgSCCP::Parameters ptype;
4232     // first decode any mandatory fixed parameters the message should have
4233     while ((ptype = *plist++) != SS7MsgSCCP::EndOfParameters) {
4234 	const SCCPParam* param = getParamDesc(ptype);
4235 	if (!param) {
4236 	    // this is fatal as we don't know the length
4237 	    Debug(this,DebugCrit,"Missing description of fixed SCCP parameter 0x%02x [%p]",ptype,this);
4238 	    return false;
4239 	}
4240 	if (!param->size) {
4241 	    Debug(this,DebugCrit,"Invalid (variable) description of fixed SCCP parameter %s [%p]",param->name,this);
4242 	    return false;
4243 	}
4244 	if (paramLen < param->size) {
4245 	    Debug(this,DebugWarn,"Truncated SCCP message! [%p]",this);
4246 	    return false;
4247 	}
4248 	DDebug(this,DebugAll,"Decoding fixed SCCP Param %s",param->name);
4249 	if (!decodeParam(this,msg->params(),param,paramPtr,param->size,prefix)) {
4250 	    Debug(this,DebugWarn,"Could not decode fixed SCCP parameter %s [%p]",param->name,this);
4251 	    decodeRaw(this,msg->params(),param,paramPtr,param->size,prefix);
4252 	    unsupported.append(param->name,",");
4253 	}
4254 	paramPtr += param->size;
4255 	paramLen -= param->size;
4256     } // while ((ptype = *plist++)...
4257     bool mustWarn = true;
4258     bool ludt = msg->isLongDataMessage();
4259     // next decode any mandatory variable parameters the message should have
4260     while ((ptype = *plist++) != SS7MsgSCCP::EndOfParameters) {
4261 	mustWarn = false;
4262 	const SCCPParam* param = getParamDesc(ptype);
4263 	if (!param) {
4264 	    // we could skip over unknown mandatory variable length but it's still bad
4265 	    Debug(this,DebugCrit,"Missing description of variable SCCP parameter 0x%02x [%p]",ptype,this);
4266 	    return false;
4267 	}
4268 	if (param->size)
4269 	    Debug(this,DebugMild,"Invalid (fixed) description of variable SCCP parameter %s [%p]",param->name,this);
4270 	if (!paramPtr || paramLen <= 0) {
4271 	    Debug(this,DebugWarn,
4272 		  "Unexpected end of stream!! Expecting to decode variabile parameter %s but there is no data left!!!",
4273 		   param->name);
4274 	    return false;
4275 	}
4276 	unsigned int offs = paramPtr[0];
4277 	if (ludt) {
4278 	    offs |= (paramPtr[1] << 8);
4279 	    paramPtr++;
4280 	    paramLen--;
4281 	}
4282 	if ((offs < 1) || (offs >= paramLen)) {
4283 	    Debug(this,DebugWarn,"Invalid offset %u (len=%u) SCCP parameter %s [%p]",
4284 		offs,paramLen,param->name,this);
4285 	    return false;
4286 	}
4287 	unsigned int size = paramPtr[offs];
4288 	if (ptype == SS7MsgSCCP::LongData) {
4289 	    size |= (paramPtr[++offs] << 8);
4290 	    size --;
4291 	}
4292 	if ((size < 1) || (offs+size >= paramLen)) {
4293 	    Debug(this,DebugWarn,"Invalid size %u (ofs=%u, len=%u) SCCP parameter %s [%p]",
4294 		size,offs,paramLen,param->name,this);
4295 	    return false;
4296 	}
4297 	bool decoded = false;
4298 	if (ptype == SS7MsgSCCP::Data || ptype == SS7MsgSCCP::LongData) {
4299 	    if (!decodeData(this,msg,paramPtr+offs+1,size)) {
4300 		Debug(this,DebugWarn,"Could not decode data SCCP parameter %s (size=%u) [%p]",
4301 			param->name,size,this);
4302 		decodeRaw(this,msg->params(),param,paramPtr+offs+1,size,prefix);
4303 	    }
4304 	    decoded = true;
4305 	}
4306 	if (!decoded && !decodeParam(this,msg->params(),param,paramPtr+offs+1,size,prefix)) {
4307 	    Debug(this,DebugWarn,"Could not decode variable SCCP parameter %s (size=%u) [%p]",
4308 		param->name,size,this);
4309 	    decodeRaw(this,msg->params(),param,paramPtr+offs+1,size,prefix);
4310 	    unsupported.append(param->name,",");
4311 	}
4312 	paramPtr++;
4313 	paramLen--;
4314     } // while ((ptype = *plist++)...
4315     // now decode the optional parameters if the message supports them
4316     if (params->optional) {
4317 	unsigned int offs = 0;
4318 	if (paramLen) {
4319 	    if (ludt && paramLen > 1) {
4320 		offs = paramPtr[0] | (paramPtr[1] << 8);
4321 		paramPtr++;
4322 		paramLen--;
4323 	    } else if (!ludt)
4324 		offs = paramPtr[0];
4325 	}
4326 	if (offs >= paramLen) {
4327 	    if (paramLen) {
4328 		Debug(this,DebugWarn,"Invalid SCCP optional offset %u (len=%u) [%p]",
4329 		    offs,paramLen,this);
4330 		return false;
4331 	    }
4332 	    Debug(this,DebugMild,"SCCP message %s lacking optional parameters [%p]",
4333 		msgName,this);
4334 	}
4335 	else if (offs) {
4336 	    mustWarn = true;
4337 	    // advance pointer past mandatory parameters
4338 	    paramPtr += offs;
4339 	    paramLen -= offs;
4340 	    while (paramLen) {
4341 		ptype = (SS7MsgSCCP::Parameters)(*paramPtr++);
4342 		paramLen--;
4343 		if (ptype == SS7MsgSCCP::EndOfParameters)
4344 		    break;
4345 		if (paramLen < 2) {
4346 		    Debug(this,DebugWarn,"Only %u octets while decoding optional SCCP parameter 0x%02x [%p]",
4347 			paramLen,ptype,this);
4348 		    return false;
4349 		}
4350 		unsigned int size = *paramPtr++;
4351 		paramLen--;
4352 		if ((size < 1) || (size >= paramLen)) {
4353 		    Debug(this,DebugWarn,"Invalid size %u (len=%u) SCCP optional parameter 0x%02x [%p]",
4354 			size,paramLen,ptype,this);
4355 		    return false;
4356 		}
4357 		const SCCPParam* param = getParamDesc(ptype);
4358 		if (!param) {
4359 		    Debug(this,DebugMild,"Unknown optional SCCP parameter 0x%02x (size=%u) [%p]",ptype,size,this);
4360 		    decodeRawParam(this,msg->params(),ptype,paramPtr,size,prefix);
4361 		    unsupported.append(String((unsigned int)ptype),",");
4362 		}
4363 		else if (!decodeParam(this,msg->params(),param,paramPtr,size,prefix)) {
4364 		    Debug(this,DebugWarn,"Could not decode optional SCCP parameter %s (size=%u) [%p]",param->name,size,this);
4365 		    decodeRaw(this,msg->params(),param,paramPtr,size,prefix);
4366 		    unsupported.append(param->name,",");
4367 		}
4368 		paramPtr += size;
4369 		paramLen -= size;
4370 	    } // while (paramLen)
4371 	} // else if (offs)
4372 	else
4373 	    paramLen = 0;
4374     }
4375     if (unsupported)
4376 	msg->params().addParam(prefix + "parameters-unsupported",unsupported);
4377     if (paramLen && mustWarn)
4378 	Debug(this,DebugWarn,"Got %u garbage octets after message type 0x%02x [%p]",
4379 	    paramLen,msg->type(),this);
4380     return true;
4381 }
4382 
4383 
receivedUPU(SS7PointCode::Type type,const SS7PointCode node,SS7MSU::Services part,unsigned char cause,const SS7Label & label,int sls)4384 void SS7SCCP::receivedUPU(SS7PointCode::Type type, const SS7PointCode node,
4385 	SS7MSU::Services part, unsigned char cause, const SS7Label& label, int sls)
4386 {
4387     if (part != sif() || !m_management) // not SCCP
4388 	return;
4389     m_management->sccpUnavailable(node,cause);
4390 }
4391 
control(NamedList & params)4392 bool SS7SCCP::control(NamedList& params)
4393 {
4394     String* ret = params.getParam(YSTRING("completion"));
4395     const String* oper = params.getParam(YSTRING("operation"));
4396     const char* cmp = params.getValue(YSTRING("component"));
4397     int cmd = oper ? oper->toInteger(s_dict_control,-1) : -1;
4398 
4399     if (ret) {
4400 	if (oper && (cmd < 0))
4401 	    return false;
4402 	String part = params.getValue(YSTRING("partword"));
4403 	if (cmp) {
4404 	    if (toString() != cmp)
4405 		return false;
4406 	    for (const TokenDict* d = s_dict_control; d->token; d++)
4407 		Module::itemComplete(*ret,d->token,part);
4408 	    return true;
4409 	}
4410 	return Module::itemComplete(*ret,toString(),part);
4411     }
4412     if (toString() != cmp)
4413 	return false;
4414     Lock lock(this);
4415     switch (cmd) {
4416 	case Status:
4417 	    printStatus(false);
4418 	    return TelEngine::controlReturn(&params,true);
4419 	case FullStatus:
4420 	    if (m_extendedMonitoring)
4421 		printStatus(true);
4422 	    else
4423 		Output("Extended monitoring disabled!! Full Status unavailable!");
4424 	    return TelEngine::controlReturn(&params,true);
4425 	case EnableExtendedMonitoring:
4426 	    m_extendedMonitoring = true;
4427 	    return TelEngine::controlReturn(&params,true);
4428 	case DisableExtendedMonitoring:
4429 	    m_extendedMonitoring = false;
4430 	    return TelEngine::controlReturn(&params,true);
4431 	case EnablePrintMsg:
4432 	    m_printMsg = true;
4433 	    return TelEngine::controlReturn(&params,true);
4434 	case DisablePrintMsg:
4435 	    m_printMsg = false;
4436 	    return TelEngine::controlReturn(&params,true);
4437     }
4438     return TelEngine::controlReturn(&params,false);
4439 }
4440 
printStatus(bool extended)4441 void SS7SCCP::printStatus(bool extended)
4442 {
4443     String dest = "";
4444     dumpArchive(dest,extended);
4445     if (!m_management)
4446 	return;
4447     m_management->subsystemsStatus(dest);
4448     m_management->routeStatus(dest);
4449     Output("SCCP '%s' [%p] Time: " FMT64 " Status:%s",debugName(),this,Time::msecNow(),dest.c_str());
4450 }
4451 
notify(SS7Layer3 * link,int sls)4452 void SS7SCCP::notify(SS7Layer3* link, int sls)
4453 {
4454     if (!(link && network()))
4455 	return;
4456     setNetworkUp(network()->operational());
4457     if (m_management)
4458 	m_management->pointcodeStatus(link,network()->operational());
4459 }
4460 
setNetworkUp(bool operational)4461 void SS7SCCP::setNetworkUp(bool operational)
4462 {
4463     if (m_layer3Up == operational)
4464 	return;
4465     m_layer3Up = operational;
4466     if (!m_management)
4467 	return;
4468     DDebug(this,DebugInfo,"L3 is %s %p",operational ? "operational" : "down", m_management);
4469     if (m_layer3Up)
4470 	m_management->mtpEndRestart();
4471     else
4472 	m_management->stopSSTs();
4473 
4474 }
4475 
routeStatusChanged(SS7PointCode::Type type,const SS7PointCode & node,SS7Route::State state)4476 void SS7SCCP::routeStatusChanged(SS7PointCode::Type type, const SS7PointCode& node, SS7Route::State state)
4477 {
4478 #ifdef DEBUG
4479     String dump;
4480     dump << node;
4481     DDebug(this,DebugAll,"Route status changed %s %s %p",dump.c_str(),SS7Route::stateName(state),m_management);
4482 #endif
4483     state = network()->getRouteState(type,node);
4484     if (m_management)
4485 	m_management->routeStatus(type,node,state);
4486 }
4487 
archiveMessage(SS7MsgSCCP * msg)4488 void SS7SCCP::archiveMessage(SS7MsgSCCP* msg)
4489 {
4490     if (!msg)
4491 	return;
4492     const char* type = SS7MsgSCCP::lookup(msg->type());
4493     NamedString* msgType = m_msgReturnStatus.getParam(type);
4494     if (msgType)
4495 	incrementNS(msgType);
4496     else
4497 	m_msgReturnStatus.addParam(type,"1");
4498     const char* code = msg->params().getValue(YSTRING("ReturnCode"));
4499     NamedString* retCode = m_msgReturnStatus.getParam(code);
4500     if (retCode)
4501 	incrementNS(retCode);
4502     else
4503 	m_msgReturnStatus.addParam(code,"1");
4504 }
4505 
dumpArchive(String & msg,bool extended)4506 void SS7SCCP::dumpArchive(String& msg, bool extended)
4507 {
4508     msg << "\r\nMessages Sent :          " << m_totalSent;
4509     msg << "\r\nMessages Received :      " << m_totalReceived;
4510     msg << "\r\nGT Translations :        " << m_totalGTTranslations;
4511     msg << "\r\nErrors :                 " << m_errors;
4512     msg << "\r\nGT Translations failed : " << m_gttFailed;
4513     NamedString* udts = m_msgReturnStatus.getParam(SS7MsgSCCP::lookup(SS7MsgSCCP::UDTS));
4514     if (udts)
4515 	msg << "\r\n" << udts->name() << " : " << *udts;
4516     NamedString* xudts = m_msgReturnStatus.getParam(SS7MsgSCCP::lookup(SS7MsgSCCP::XUDTS));
4517     if (xudts)
4518 	msg << "\r\n" << xudts->name() << " : " << *xudts;
4519     NamedString* ludts = m_msgReturnStatus.getParam(SS7MsgSCCP::lookup(SS7MsgSCCP::LUDTS));
4520     if (ludts)
4521 	msg << "\r\n" << ludts->name() << " : " << *ludts;
4522     if (!extended)
4523 	return;
4524     msg << "\r\n Error Causes:";
4525     for (unsigned int i = 0;i < m_msgReturnStatus.length();i++) {
4526 	NamedString* param = m_msgReturnStatus.getParam(i);
4527 	if (!param || param == udts || param == xudts || param == ludts)
4528 	    continue;
4529 	const char* error = lookup(param->name().toInteger(),s_return_cause);
4530 	if (!error)
4531 	    continue;
4532 	msg << "\r\nCount: " << *param << " Error: " << error;
4533     }
4534 }
4535 
isSCOCMsg(int msgType)4536 bool SS7SCCP::isSCOCMsg(int msgType)
4537 {
4538     switch (msgType) {
4539 	case SS7MsgSCCP::CR:
4540 	case SS7MsgSCCP::CC:
4541 	case SS7MsgSCCP::CREF:
4542 	case SS7MsgSCCP::RLSD:
4543 	case SS7MsgSCCP::RLC:
4544 	case SS7MsgSCCP::DT1:
4545 	case SS7MsgSCCP::DT2:
4546 	case SS7MsgSCCP::AK:
4547 	case SS7MsgSCCP::ED:
4548 	case SS7MsgSCCP::EA:
4549 	case SS7MsgSCCP::RSR:
4550 	case SS7MsgSCCP::RSC:
4551 	case SS7MsgSCCP::ERR:
4552 	case SS7MsgSCCP::IT:
4553 	    return true;
4554 	default:
4555 	    return false;
4556     }
4557     return false;
4558 }
4559 
4560 /**
4561  * SS7ItuSCCPManagement
4562  */
4563 
SS7ItuSccpManagement(const NamedList & params)4564 SS7ItuSccpManagement::SS7ItuSccpManagement(const NamedList& params)
4565     : SCCPManagement(params,SS7PointCode::ITU)
4566 {
4567     DDebug(this,DebugAll,"Creating SS7ItuSccpManagement(%s) %p",params.c_str(),this);
4568 }
4569 
processMessage(SS7MsgSCCP * message)4570 bool SS7ItuSccpManagement::processMessage(SS7MsgSCCP* message)
4571 {
4572     if (!sccp())
4573 	return false;
4574     DataBlock* data = message->getData();
4575     if (!data) {
4576 	Debug(sccp(),DebugNote,"Request to process Itu management message with no data!");
4577 	return false;
4578     }
4579     if (data->length() < 5) {
4580 	Debug(sccp(),DebugNote,"Received short management message!");
4581 	return false;
4582     }
4583     const unsigned char* paramsPtr = (const unsigned char*)data->data();
4584     unsigned char msg = *paramsPtr++;
4585     const char* msgType = lookup(msg,s_managementMessages);
4586     if (!msgType) {
4587 	Debug(sccp(),DebugNote,"Received unknown management message! 0x%x",msg);
4588 	return false;
4589     }
4590     if (msg > SSC) {
4591 	Debug(sccp(),DebugNote,"Received unknown ITU management message! 0x%x",msg);
4592 	return false;
4593     }
4594     // After msg type is SSN
4595     message->params().setParam("ssn",String((int)*paramsPtr++));
4596     // Pointcode 2 o
4597     int pointcode = *paramsPtr++;
4598     pointcode |= (*paramsPtr++ & 0x3f) << 8;
4599     message->params().setParam("pointcode",String(pointcode));
4600     // Subsystem Multiplicity Indicator
4601     message->params().setParam("smi",String(*paramsPtr++ & 0x03));
4602     // If message type is SSC decode congestion level
4603     if (msg == SSC) {
4604 	if (!paramsPtr) {
4605 	    Debug(sccp(),DebugNote,"Failed to decode SSC congestion level parameter! Reason short message.");
4606 	    return false;
4607 	}
4608 	message->params().setParam("congestion-level",String(*paramsPtr & 0x0f));
4609     }
4610     if (printMessagess()) {
4611 	String dest;
4612 	printMessage(dest, (MsgType)msg,message->params());
4613 	Debug(this,DebugInfo,"Received message %s",dest.c_str());
4614     }
4615     return handleMessage(msg,message->params());
4616 }
4617 
sendMessage(SCCPManagement::MsgType msgType,const NamedList & params)4618 bool SS7ItuSccpManagement::sendMessage(SCCPManagement::MsgType msgType, const NamedList& params)
4619 {
4620     if (!sccp())
4621 	return false;
4622     if (printMessagess()) {
4623 	String dest;
4624 	printMessage(dest, msgType,params);
4625 	Debug(this,DebugInfo,"Sending message %s",dest.c_str());
4626     }
4627     unsigned char ssn = params.getIntValue(YSTRING("ssn"));
4628     int pointcode = params.getIntValue(YSTRING("pointcode"));
4629     int smi = params.getIntValue(YSTRING("smi"));
4630     int dataLen = msgType == SSC ? 6 : 5;
4631     DataBlock data(0,dataLen);
4632     unsigned char * d = (unsigned char*)data.data();
4633     d[0] = msgType;
4634     d[1] = ssn;
4635     d[2] = pointcode & 0xff;
4636     d[3] = (pointcode >> 8) & 0x3f;
4637     d[4] = smi & 0x03;
4638     if (msgType == SSC)
4639 	d[5] = params.getIntValue(YSTRING("congestion-level"),0) & 0x0f;
4640     int localPC = sccp()->getPackedPointCode();
4641     SS7MsgSCCP* msg = new SS7MsgSCCP(SS7MsgSCCP::UDT);
4642     const char* remotePC = params.getValue(YSTRING("RemotePC"));
4643     msg->params().setParam("ProtocolClass","0");
4644     msg->params().setParam("CalledPartyAddress.ssn","1");
4645     msg->params().setParam("CalledPartyAddress.pointcode",remotePC);
4646     msg->params().setParam("CalledPartyAddress.route","ssn");
4647     msg->params().setParam("CallingPartyAddress.ssn","1");
4648     msg->params().setParam("CallingPartyAddress.route","ssn");
4649     msg->params().setParam("CallingPartyAddress.pointcode",String(localPC));
4650     msg->params().setParam("LocalPC",String(localPC));
4651     msg->params().setParam("RemotePC",remotePC);
4652     msg->setData(&data);
4653     bool ret = sccp()->transmitMessage(msg) >= 0;
4654     if (!ret)
4655 	Debug(this,DebugNote,"Failed to send management message %s to remote %s",
4656 	      lookup(msgType,s_managementMessages),params.getValue(YSTRING("RemotePC")));
4657     msg->extractData();
4658     TelEngine::destruct(msg);
4659     return ret;
4660 }
4661 
manageSccpRemoteStatus(SccpRemote * rsccp,SS7Route::State newState)4662 void SS7ItuSccpManagement::manageSccpRemoteStatus(SccpRemote* rsccp, SS7Route::State newState)
4663 {
4664     if (!rsccp)
4665 	return;
4666 #ifdef XDEBUG
4667     String pc;
4668     rsccp->dump(pc,false);
4669     XDebug(this,DebugInfo,"Remote sccp '%s' status changed, new state: %s",pc.c_str(),SS7Route::stateName(newState));
4670 #endif
4671     switch (newState) {
4672 	case SS7Route::Congestion:
4673 	    Debug(sccp(),DebugStub,"Please implement SCCPManagement Congestion");
4674 	    break;
4675 	case SS7Route::Allowed:
4676 	{
4677 	    // Set state should set the state to all subsystems
4678 	    rsccp->setState(SCCPManagement::Allowed);
4679 	    updateTables(rsccp);
4680 	    rsccp->resetCongestion();
4681 	    // Discontinue the Subsystem Status Test for SSN = 1
4682 	    SccpSubsystem* ss = new SccpSubsystem(1);
4683 	    stopSst(rsccp,ss);
4684 	    TelEngine::destruct(ss);
4685 	    localBroadcast(SCCP::PointCodeStatusIndication,rsccp->getPackedPointcode(),PCAccessible,-1,0);
4686 	    localBroadcast(SCCP::PointCodeStatusIndication,rsccp->getPackedPointcode(),-1,SccpRemoteAccessible,0);
4687 	    break;
4688 	}
4689 	case SS7Route::Prohibited:
4690 	{
4691 	    rsccp->setState(SCCPManagement::Prohibited);
4692 	    updateTables(rsccp);
4693 	    // Discontinue all tests for the remote sccp
4694 	    SccpSubsystem* ss = new SccpSubsystem(1);
4695 	    stopSst(rsccp,0,ss); // Stop all sst except management
4696 	    // Do not start SST if the route is down the message will fail to be
4697 	    // sent. The status will be changed to allowed when the route is up
4698 	    TelEngine::destruct(ss);
4699 	    localBroadcast(SCCP::PointCodeStatusIndication,rsccp->getPackedPointcode(),PCInaccessible,-1,0);
4700 	    localBroadcast(SCCP::PointCodeStatusIndication,rsccp->getPackedPointcode(),-1,SccpRemoteInaccessible,0);
4701 	    break;
4702 	}
4703 	case SS7Route::Unknown:
4704 	    rsccp->setState(SCCPManagement::Unknown);
4705 	    break;
4706 	default:
4707 	    DDebug(this,DebugNote,"Unhandled remote sccp status '%s'",SS7Route::stateName(newState));
4708     }
4709 }
4710 
handleMessage(int msgType,NamedList & params)4711 bool SS7ItuSccpManagement::handleMessage(int msgType, NamedList& params)
4712 {
4713     unsigned char ssn = params.getIntValue(YSTRING("ssn"));
4714     if (ssn == 0) {
4715 	Debug(this,DebugNote,"Received management message '%s' with invalid ssn '%d'",
4716 	      lookup(msgType,s_managementMessages),ssn);
4717 	return false;
4718     }
4719     unsigned char smi = params.getIntValue(YSTRING("smi")); // subsystem multiplicity indicator
4720     if (smi != 0) {
4721 	if (smi > 3) {
4722 	    Debug(this,DebugWarn, "Received management message '%s' with unknown smi: '%d' , ssn: '%d'",
4723 		  lookup(msgType,s_managementMessages),smi,ssn);
4724 	    smi = 0;
4725 	} else
4726 	    DDebug(this,DebugNote,"Received management message '%s' with national smi: %d",
4727 		   lookup(msgType,s_managementMessages),smi);
4728     }
4729     switch (msgType) {
4730 	case SSC:
4731 	    Debug(this,DebugStub,"Please implement subsystem congested!");
4732 	    break;
4733 	default:
4734 	    return SCCPManagement::handleMessage(msgType,ssn,smi,params);
4735     }
4736     return true;
4737 }
4738 
handleSubsystemStatus(SccpSubsystem * subsystem,bool allowed,SccpRemote * remote,int smi)4739 void SS7ItuSccpManagement::handleSubsystemStatus(SccpSubsystem* subsystem, bool allowed, SccpRemote* remote, int smi)
4740 {
4741     if (!subsystem) {
4742 	Debug(sccp(),DebugWarn,"Request to handle subsystem status with no subsystem!");
4743 	return;
4744     }
4745     SCCPManagement::SccpStates ssnState = allowed ? SCCPManagement::Allowed : SCCPManagement::Prohibited;
4746     subsystem->setState(ssnState);
4747     DDebug(this,DebugInfo,"Handle subsystem status for pc: '%d' ssn: '%d' status %s", remote ? remote->getPackedPointcode() : 0,
4748 		subsystem ? subsystem->getSSN() : 0, stateName(ssnState));
4749     Lock lock(this);
4750     bool localSubsystem = false;
4751     // Change the status of the subsystem
4752     if (!remote || remote->getPointCode() == *sccp()->getLocalPointCode()) { // LocalSubsystem
4753 	SccpLocalSubsystem* subs = getLocalSubsystem(subsystem->getSSN());
4754 	if (subs) {
4755 	    if (subs->getState() == ssnState) // Same state? do nothing
4756 		return;
4757 	    subs->resetTimers();
4758 	    subs->setState(ssnState);
4759 	} else // Append dynamically
4760 	    m_localSubsystems.append(new SccpLocalSubsystem(subsystem->getSSN(),getCoordTimeout(),
4761 		    getIgnoreTestsInterval()));
4762 	localSubsystem = true;
4763     } else {
4764 	SccpRemote* rsccp = getRemoteSccp(remote->getPackedPointcode());
4765 	if (rsccp && !rsccp->changeSubsystemState(subsystem->getSSN(),ssnState))
4766 	    return;
4767     }
4768     // Stop all subsystem status tests
4769     if (!localSubsystem && allowed)
4770 	stopSst(remote,subsystem);
4771     else if (!localSubsystem) // Initiate subsystem status test
4772 	startSst(remote,subsystem);
4773     lock.drop();
4774     // update translation tables
4775     if (!localSubsystem)
4776 	updateTables(remote,subsystem);
4777     // Local Broadcast user in/out of service
4778     NamedList params("");
4779     if (!localSubsystem)
4780 	params.setParam("pointcode",String(remote->getPackedPointcode()));
4781     params.setParam("ssn",String(subsystem->getSSN()));
4782     params.setParam("subsystem-status",lookup(allowed ? UserInService : UserOutOfService,broadcastType()));
4783     managementMessage(SCCP::StatusIndication,params);
4784     // Send broadcast for all concerned signalling points
4785     ///TODO for now we send only for local interested subsystems
4786     if (!localSubsystem)
4787 	return;
4788     notifyConcerned(allowed ? SSA : SSP, subsystem->getSSN(),smi);
4789 }
4790 
4791 /**
4792  * SS7AnsiSCCPManagement
4793  */
~SS7AnsiSccpManagement()4794 SS7AnsiSccpManagement::~SS7AnsiSccpManagement()
4795 {
4796     DDebug(this,DebugAll,"Destroing Ansi Sccp Management(%p)",this);
4797 }
4798 
processMessage(SS7MsgSCCP * message)4799 bool SS7AnsiSccpManagement::processMessage(SS7MsgSCCP* message)
4800 {
4801     if (!sccp()) {
4802 	return false;
4803     }
4804     DataBlock* data = message->getData();
4805     if (!data) {
4806 	DDebug(sccp(),DebugNote,"Request to process Ansi management message with no data!");
4807 	return false;
4808     }
4809     if (data->length() < 6) {
4810 	DDebug(sccp(),DebugNote,"Received short Ansi management message! %d",data->length());
4811 	return false;
4812     }
4813     const unsigned char* paramsPtr = (const unsigned char*)data->data();
4814     unsigned char msg = *paramsPtr++;
4815     const char* msgType = lookup(msg,s_managementMessages);
4816     if (!msgType) {
4817 	DDebug(sccp(),DebugNote,"Received unknown management message! 0x%x",msg);
4818 	return false;
4819     }
4820     if (msg > 0x05 && msg < 0xfd) {
4821 	DDebug(sccp(),DebugNote,"Received unknown Ansi management message! 0x%x",msg);
4822 	return false;
4823     }
4824     // After msg type is SSN
4825     message->params().setParam("ssn",String((int)*paramsPtr++));
4826     // Pointcode 2 o
4827     unsigned int pointcode = *paramsPtr++;
4828     pointcode |= (*paramsPtr++ << 8);
4829     pointcode |= (*paramsPtr++ << 16);
4830     message->params().setParam("pointcode",String(pointcode));
4831     // Subsystem Multiplicity Indicator
4832     message->params().setParam("SMI",String(*paramsPtr++ & 0x03));
4833 
4834     if (printMessagess()) {
4835 	String dest;
4836 	printMessage(dest, (MsgType)msg,message->params());
4837 	Debug(this,DebugInfo,"Received message %s",dest.c_str());
4838     }
4839     return handleMessage(msg,message->params());
4840 }
4841 
sendMessage(SCCPManagement::MsgType msgType,const NamedList & params)4842 bool SS7AnsiSccpManagement::sendMessage(SCCPManagement::MsgType msgType, const NamedList& params)
4843 {
4844     if (!sccp())
4845 	return false;
4846     if (printMessagess()) {
4847 	String dest;
4848 	printMessage(dest, msgType,params);
4849 	Debug(this,DebugInfo,"Sending message %s",dest.c_str());
4850     }
4851     unsigned char ssn = params.getIntValue(YSTRING("ssn"));
4852     int pointcode = params.getIntValue(YSTRING("pointcode"));
4853     int smi = params.getIntValue(YSTRING("smi"));
4854     DataBlock data(0,6);
4855     unsigned char * d = (unsigned char*)data.data();
4856     d[0] = msgType;
4857     d[1] = ssn;
4858     d[2] = pointcode & 0xff;
4859     d[3] = (pointcode >> 8) & 0xff;
4860     d[4] = (pointcode >> 16) & 0xff;
4861     d[5] = smi & 0x03;
4862     int localPC = sccp()->getPackedPointCode();
4863     SS7MsgSCCP* msg = new SS7MsgSCCP(SS7MsgSCCP::UDT);
4864     const char* remotePC = params.getValue(YSTRING("RemotePC"));
4865     msg->params().setParam("ProtocolClass","0");
4866     msg->params().setParam("CalledPartyAddress.ssn","1");
4867     msg->params().setParam("CalledPartyAddress.pointcode",remotePC);
4868     msg->params().setParam("CalledPartyAddress.route","ssn");
4869     msg->params().setParam("CallingPartyAddress.ssn","1");
4870     msg->params().setParam("CallingPartyAddress.route","ssn");
4871     msg->params().setParam("CallingPartyAddress.pointcode",String(localPC));
4872     msg->params().setParam("LocalPC",String(localPC));
4873     msg->params().setParam("RemotePC",remotePC);
4874     msg->setData(&data);
4875     bool ret = sccp()->transmitMessage(msg) >= 0;
4876     if (!ret)
4877 	Debug(this,DebugNote,"Failed to send management message %s to remote %s",
4878 	      lookup(msgType,s_managementMessages),params.getValue(YSTRING("RemotePC")));
4879     msg->extractData();
4880     TelEngine::destruct(msg);
4881     return ret;
4882 }
4883 
handleMessage(int msgType,NamedList & params)4884 bool SS7AnsiSccpManagement::handleMessage(int msgType, NamedList& params)
4885 {
4886     unsigned char ssn = params.getIntValue(YSTRING("ssn"));
4887     if (ssn == 0) {
4888 	Debug(this,DebugNote,"Received management message '%s' with invalid ssn '%d'",
4889 	      lookup(msgType,s_managementMessages),ssn);
4890 	return false;
4891     }
4892     unsigned char smi = params.getIntValue(YSTRING("smi")); // subsystem multiplicity indicator
4893     if (!lookup(smi,s_ansiSmi)) {
4894 	Debug(this,DebugWarn, "Received management message '%s' with invalid smi: '%d' , ssn: '%d'",
4895 		  lookup(msgType,s_managementMessages),smi,ssn);
4896 	smi = 0;
4897     }
4898     switch (msgType) {
4899 	case SBR:
4900 	case SNR:
4901 	case SRT:
4902 	    Debug(this,DebugStub,"Please implement %s message handling!",lookup(msgType,s_managementMessages));
4903 	    break;
4904 	default:
4905 	    return SCCPManagement::handleMessage(msgType,ssn,smi,params);
4906     }
4907     return true;
4908 }
4909 
manageSccpRemoteStatus(SccpRemote * rsccp,SS7Route::State newState)4910 void SS7AnsiSccpManagement::manageSccpRemoteStatus(SccpRemote* rsccp, SS7Route::State newState)
4911 {
4912     if (!rsccp)
4913 	return;
4914 #ifdef XDEBUG
4915     String pc;
4916     rsccp->dump(pc,false);
4917     XDebug(this,DebugInfo,"Remote sccp '%s' status changed, new state: %s",pc.c_str(),SS7Route::stateName(newState));
4918 #endif
4919     switch (newState) {
4920 	case SS7Route::Congestion:
4921 	    Debug(sccp(),DebugStub,"Please implement SCCPManagement Congestion");
4922 	    break;
4923 	case SS7Route::Allowed:
4924 	{
4925 	    // Set state should set the state to all subsystems
4926 	    rsccp->setState(SCCPManagement::Allowed);
4927 	    rsccp->resetCongestion();
4928 	    localBroadcast(SCCP::PointCodeStatusIndication,rsccp->getPackedPointcode(),
4929 		    PCAccessible,-1,0);
4930 	    // Discontinue all subsystem status tests
4931 	    stopSst(rsccp);
4932 	    localBroadcast(SCCP::PointCodeStatusIndication,rsccp->getPackedPointcode(),
4933 		    -1,SccpRemoteAccessible,0);
4934 	    updateTables(rsccp);
4935 	    rsccp->lock();
4936 	    ListIterator ssns(rsccp->getSubsystems());
4937 	    rsccp->unlock();
4938 	    SccpSubsystem* ss = 0;
4939 	    while ((ss = YOBJECT(SccpSubsystem,ssns.get())))
4940 		localBroadcast(SCCP::StatusIndication,-1,-1,-1,-1,ss->getSSN(),UserInService);
4941 	    break;
4942 	}
4943 	case SS7Route::Prohibited:
4944 	{
4945 	    rsccp->setState(SCCPManagement::Prohibited);
4946 	    localBroadcast(SCCP::PointCodeStatusIndication,rsccp->getPackedPointcode(),
4947 		    PCInaccessible,-1,0);
4948 	    SccpSubsystem* ss = new SccpSubsystem(1);
4949 	    stopSst(rsccp,ss);
4950 	    TelEngine::destruct(ss);
4951 	    updateTables(rsccp);
4952 	    localBroadcast(SCCP::PointCodeStatusIndication,rsccp->getPackedPointcode(),
4953 		    -1,SccpRemoteInaccessible,0);
4954 	    rsccp->lock();
4955 	    ListIterator ssns(rsccp->getSubsystems());
4956 	    rsccp->unlock();
4957 	    SccpSubsystem* ss1 = 0;
4958 	    while ((ss1 = YOBJECT(SccpSubsystem,ssns.get())))
4959 		localBroadcast(SCCP::StatusIndication,-1,-1,-1,-1,ss1->getSSN(),UserOutOfService);
4960 	    break;
4961 	}
4962 	case SS7Route::Unknown:
4963 	    rsccp->setState(SCCPManagement::Unknown);
4964 	    break;
4965 	default:
4966 	    DDebug(this,DebugNote,"Unhandled remote sccp status '%s'",SS7Route::stateName(newState));
4967     }
4968 }
4969 
handleSubsystemStatus(SccpSubsystem * subsystem,bool allowed,SccpRemote * remote,int smi)4970 void SS7AnsiSccpManagement::handleSubsystemStatus(SccpSubsystem* subsystem, bool allowed, SccpRemote* remote, int smi)
4971 {
4972     if (!subsystem || subsystem->getSSN() <= 0) {
4973 	Debug(sccp(),DebugWarn,"Request to handle subsystem status with no subsystem!");
4974 	return;
4975     }
4976     SCCPManagement::SccpStates ssnState = allowed ? SCCPManagement::Allowed : SCCPManagement::Prohibited;
4977     subsystem->setState(ssnState);
4978     DDebug(this,DebugInfo,"Handle subsystem status for pc: '%d' ssn: '%d' status %s", remote ? remote->getPackedPointcode() : 0,
4979 		subsystem ? subsystem->getSSN() : 0, stateName(ssnState));
4980     Lock lock(this);
4981     bool localSubsystem = false;
4982     // Change the status of the subsystem
4983     if (!remote || remote->getPointCode() == *sccp()->getLocalPointCode()) { // LocalSubsystem
4984 	SccpLocalSubsystem* subs = getLocalSubsystem(subsystem->getSSN());
4985 	if (subs) {
4986 	    if (subs->getState() == ssnState) // Same state? do nothing
4987 		return;
4988 	    subs->resetTimers();
4989 	    subs->setState(ssnState);
4990 	} else // Append dynamically
4991 	    m_localSubsystems.append(new SccpLocalSubsystem(subsystem->getSSN(),getCoordTimeout(),
4992 		    getIgnoreTestsInterval()));
4993 	localSubsystem = true;
4994     } else {
4995 	SccpRemote* rsccp = getRemoteSccp(remote->getPackedPointcode());
4996 	if (rsccp && !rsccp->changeSubsystemState(subsystem->getSSN(),ssnState))
4997 	    return;
4998     }
4999     // Stop all subsystem status tests
5000     if (!localSubsystem && allowed)
5001 	stopSst(remote,subsystem);
5002     else if (!localSubsystem) // Initiate subsystem status test
5003 	startSst(remote,subsystem);
5004     lock.drop();
5005     // update translation tables
5006     if (!localSubsystem)
5007 	updateTables(remote,subsystem);
5008     // Local Broadcast user in/out of service
5009     localBroadcast(SCCP::StatusIndication,localSubsystem ? -1 :remote->getPackedPointcode(),
5010 	    -1,-1,-1,subsystem->getSSN(), allowed ? UserInService : UserOutOfService);
5011     // Send broadcast for all concerned signalling points
5012     ///TODO for now we send only for local interested subsystems
5013     if (!localSubsystem)
5014 	return;
5015     notifyConcerned(allowed ? SSA : SSP, subsystem->getSSN(),smi);
5016 }
5017 
5018 /* vi: set ts=8 sw=4 sts=4 noet: */
5019