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,¶ms,"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,¶ms), SS7Layer4(SS7MSU::SCCP|SS7MSU::National,¶ms), 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 ¶ms,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,¶ms))
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(¶ms,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(¶ms,true);
4425 case EnableExtendedMonitoring:
4426 m_extendedMonitoring = true;
4427 return TelEngine::controlReturn(¶ms,true);
4428 case DisableExtendedMonitoring:
4429 m_extendedMonitoring = false;
4430 return TelEngine::controlReturn(¶ms,true);
4431 case EnablePrintMsg:
4432 m_printMsg = true;
4433 return TelEngine::controlReturn(¶ms,true);
4434 case DisablePrintMsg:
4435 m_printMsg = false;
4436 return TelEngine::controlReturn(¶ms,true);
4437 }
4438 return TelEngine::controlReturn(¶ms,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