1 /**
2 * sigtran.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 #define MAX_UNACK 256
26 #define AVG_DELAY 100
27
28 using namespace TelEngine;
29
30 #define MAKE_NAME(x) { #x, SIGTRAN::x }
31 static const TokenDict s_classes[] = {
32 // this list must be kept in synch with the header
33 MAKE_NAME(MGMT),
34 MAKE_NAME(TRAN),
35 MAKE_NAME(SSNM),
36 MAKE_NAME(ASPSM),
37 MAKE_NAME(ASPTM),
38 MAKE_NAME(QPTM),
39 MAKE_NAME(MAUP),
40 MAKE_NAME(CLMSG),
41 MAKE_NAME(COMSG),
42 MAKE_NAME(RKM),
43 MAKE_NAME(IIM),
44 MAKE_NAME(M2PA),
45 { 0, 0 }
46 };
47 #undef MAKE_NAME
48
49 #define MAKE_NAME(x) { #x, SIGTRAN::Mgmt##x }
50 static const TokenDict s_mgmt_types[] = {
51 MAKE_NAME(ERR),
52 MAKE_NAME(NTFY),
53 { 0, 0 }
54 };
55 #undef MAKE_NAME
56
57 #define MAKE_NAME(x) { #x, SIGTRAN::Ssnm##x }
58 static const TokenDict s_ssnm_types[] = {
59 MAKE_NAME(DUNA),
60 MAKE_NAME(DAVA),
61 MAKE_NAME(DAUD),
62 MAKE_NAME(SCON),
63 MAKE_NAME(DUPU),
64 MAKE_NAME(DRST),
65 { 0, 0 }
66 };
67 #undef MAKE_NAME
68
69 #define MAKE_NAME(x) { #x, SIGTRAN::Aspsm##x }
70 static const TokenDict s_aspsm_types[] = {
71 MAKE_NAME(UP),
72 MAKE_NAME(DOWN),
73 MAKE_NAME(BEAT),
74 MAKE_NAME(UP_ACK),
75 MAKE_NAME(DOWN_ACK),
76 MAKE_NAME(BEAT_ACK),
77 { 0, 0 }
78 };
79 #undef MAKE_NAME
80
81 #define MAKE_NAME(x) { #x, SIGTRAN::Asptm##x }
82 static const TokenDict s_asptm_types[] = {
83 MAKE_NAME(ACTIVE),
84 MAKE_NAME(INACTIVE),
85 MAKE_NAME(ACTIVE_ACK),
86 MAKE_NAME(INACTIVE_ACK),
87 { 0, 0 }
88 };
89 #undef MAKE_NAME
90
91 #define MAKE_NAME(x) { #x, SIGTRAN::Rkm##x }
92 static const TokenDict s_rkm_types[] = {
93 MAKE_NAME(REG_REQ),
94 MAKE_NAME(REG_RSP),
95 MAKE_NAME(DEREG_REQ),
96 MAKE_NAME(DEREG_RSP),
97 { 0, 0 }
98 };
99 #undef MAKE_NAME
100
101 #define MAKE_NAME(x) { #x, SIGTRAN::Iim##x }
102 static const TokenDict s_iim_types[] = {
103 MAKE_NAME(REG_REQ),
104 MAKE_NAME(REG_RSP),
105 MAKE_NAME(DEREG_REQ),
106 MAKE_NAME(DEREG_RSP),
107 { 0, 0 }
108 };
109 #undef MAKE_NAME
110
111 #define MAKE_NAME(x) { #x, SS7M2PA::x }
112 static TokenDict s_m2pa_types[] = {
113 MAKE_NAME(UserData),
114 MAKE_NAME(LinkStatus),
115 { 0, 0 }
116 };
117 #undef MAKE_NAME
118
classNames()119 const TokenDict* SIGTRAN::classNames()
120 {
121 return s_classes;
122 }
123
typeName(unsigned char msgClass,unsigned char msgType,const char * defValue)124 const char* SIGTRAN::typeName(unsigned char msgClass, unsigned char msgType, const char* defValue)
125 {
126 switch (msgClass) {
127 case MGMT:
128 return lookup(msgType,s_mgmt_types,defValue);
129 case SSNM:
130 return lookup(msgType,s_ssnm_types,defValue);
131 case ASPSM:
132 return lookup(msgType,s_aspsm_types,defValue);
133 case ASPTM:
134 return lookup(msgType,s_asptm_types,defValue);
135 case RKM:
136 return lookup(msgType,s_rkm_types,defValue);
137 case IIM:
138 return lookup(msgType,s_iim_types,defValue);
139 case M2PA:
140 return lookup(msgType,s_m2pa_types,defValue);
141 default:
142 return defValue;
143 }
144 }
145
SIGTRAN(u_int32_t payload,u_int16_t port)146 SIGTRAN::SIGTRAN(u_int32_t payload, u_int16_t port)
147 : m_trans(0), m_payload(payload), m_defPort(port),
148 m_transMutex(false,"SIGTRAN::transport")
149 {
150 }
151
~SIGTRAN()152 SIGTRAN::~SIGTRAN()
153 {
154 attach(0);
155 }
156
157 // Check if a stream in the transport is connected
connected(int streamId) const158 bool SIGTRAN::connected(int streamId) const
159 {
160 m_transMutex.lock();
161 RefPointer<SIGTransport> trans = m_trans;
162 m_transMutex.unlock();
163 return trans && trans->connected(streamId);
164 }
165
166 // Attach a transport to the SIGTRAN instance
attach(SIGTransport * trans)167 void SIGTRAN::attach(SIGTransport* trans)
168 {
169 Lock lock(m_transMutex);
170 if (trans == m_trans)
171 return;
172 if (!(trans && trans->ref()))
173 trans = 0;
174 SIGTransport* tmp = m_trans;
175 m_trans = trans;
176 lock.drop();
177 if (tmp) {
178 tmp->attach(0);
179 tmp->destruct();
180 }
181 if (trans) {
182 trans->attach(this);
183 SignallingEngine* engine = SignallingEngine::self();
184 if (engine)
185 engine->insert(trans);
186 trans->deref();
187 }
188 }
189
190 // Transmit a SIGTRAN message over the attached transport
transmitMSG(unsigned char msgVersion,unsigned char msgClass,unsigned char msgType,const DataBlock & msg,int streamId) const191 bool SIGTRAN::transmitMSG(unsigned char msgVersion, unsigned char msgClass,
192 unsigned char msgType, const DataBlock& msg, int streamId) const
193 {
194 m_transMutex.lock();
195 RefPointer<SIGTransport> trans = m_trans;
196 m_transMutex.unlock();
197 return trans && trans->transmitMSG(msgVersion,msgClass,msgType,msg,streamId);
198 }
199
restart(bool force)200 bool SIGTRAN::restart(bool force)
201 {
202 m_transMutex.lock();
203 RefPointer<SIGTransport> trans = m_trans;
204 m_transMutex.unlock();
205 if (!trans)
206 return false;
207 trans->reconnect(force);
208 return true;
209 }
210
getSocketParams(const String & params,NamedList & result)211 bool SIGTRAN::getSocketParams(const String& params, NamedList& result)
212 {
213 m_transMutex.lock();
214 RefPointer<SIGTransport> trans = m_trans;
215 m_transMutex.unlock();
216 if (!trans)
217 return false;
218 trans->getSocketParams(params,result);
219 return true;
220 }
221
hasTransportThread()222 bool SIGTRAN::hasTransportThread()
223 {
224 m_transMutex.lock();
225 RefPointer<SIGTransport> trans = m_trans;
226 m_transMutex.unlock();
227 if (!trans)
228 return false;
229 return trans->hasThread();
230 }
231
stopTransportThread()232 void SIGTRAN::stopTransportThread()
233 {
234 m_transMutex.lock();
235 RefPointer<SIGTransport> trans = m_trans;
236 m_transMutex.unlock();
237 if (trans)
238 trans->stopThread();
239 }
240
241 // Attach or detach an user adaptation layer
attach(SIGTRAN * sigtran)242 void SIGTransport::attach(SIGTRAN* sigtran)
243 {
244 if (m_sigtran != sigtran) {
245 m_sigtran = sigtran;
246 attached(sigtran != 0);
247 }
248 }
249
250 // Retrieve the default port to use
defPort() const251 u_int32_t SIGTransport::defPort() const
252 {
253 return m_sigtran ? m_sigtran->defPort() : 0;
254 }
255
256 // Request processing from the adaptation layer
processMSG(unsigned char msgVersion,unsigned char msgClass,unsigned char msgType,const DataBlock & msg,int streamId) const257 bool SIGTransport::processMSG(unsigned char msgVersion, unsigned char msgClass,
258 unsigned char msgType, const DataBlock& msg, int streamId) const
259 {
260 XDebug(this,DebugAll,"Received message class %s type %s (0x%02X) on stream %d",
261 lookup(msgClass,s_classes,"Unknown"),
262 SIGTRAN::typeName(msgClass,msgType,"Unknown"),msgType,streamId);
263 return alive() && m_sigtran && m_sigtran->processMSG(msgVersion,msgClass,msgType,msg,streamId);
264 }
265
notifyLayer(SignallingInterface::Notification event)266 void SIGTransport::notifyLayer(SignallingInterface::Notification event)
267 {
268 if (alive() && m_sigtran)
269 m_sigtran->notifyLayer(event);
270 }
271
272 // Build the common header and transmit a message to the network
transmitMSG(unsigned char msgVersion,unsigned char msgClass,unsigned char msgType,const DataBlock & msg,int streamId)273 bool SIGTransport::transmitMSG(unsigned char msgVersion, unsigned char msgClass,
274 unsigned char msgType, const DataBlock& msg, int streamId)
275 {
276 if (!alive())
277 return false;
278 XDebug(this,DebugAll,"Sending message class %s type %s (0x%02X) on stream %d",
279 lookup(msgClass,s_classes,"Unknown"),
280 SIGTRAN::typeName(msgClass,msgType,"Unknown"),msgType,streamId);
281
282 if (!connected(streamId)) {
283 Debug(this,DebugMild,"Cannot send message, stream %d not connected [%p]",
284 streamId,this);
285 return false;
286 }
287
288 unsigned char hdr[8];
289 unsigned int len = 8 + msg.length();
290 hdr[0] = msgVersion;
291 hdr[1] = 0;
292 hdr[2] = msgClass;
293 hdr[3] = msgType;
294 hdr[4] = 0xff & (len >> 24);
295 hdr[5] = 0xff & (len >> 16);
296 hdr[6] = 0xff & (len >> 8);
297 hdr[7] = 0xff & len;
298
299 DataBlock header(hdr,8,false);
300 bool ok = transmitMSG(header,msg,streamId);
301 header.clear(false);
302 return ok;
303 }
304
transportNotify(SIGTransport * newTransport,const SocketAddr & addr)305 bool SIGTransport::transportNotify(SIGTransport* newTransport, const SocketAddr& addr)
306 {
307 if (alive() && m_sigtran) {
308 return m_sigtran->transportNotify(newTransport,addr);
309 }
310 TelEngine::destruct(newTransport);
311 return false;
312 }
313
314
315 /**
316 * Class SIGAdaptation
317 */
318
SIGAdaptation(const char * name,const NamedList * params,u_int32_t payload,u_int16_t port)319 SIGAdaptation::SIGAdaptation(const char* name, const NamedList* params,
320 u_int32_t payload, u_int16_t port)
321 : SignallingComponent(name,params), SIGTRAN(payload,port),
322 Mutex(true,"SIGAdaptation"), m_maxRetransmit(1000), m_sendHeartbeat(0),
323 m_waitHeartbeatAck(0)
324 {
325 DDebug(this,DebugAll,"Creating SIGTRAN UA [%p]",this);
326 for (int i = 0; i < 32;i++)
327 m_streamsHB[i] = HeartbeatDisabled;
328 if (params) {
329 m_waitHeartbeatAck.interval(*params,"wait_hb_ack",500,2000,false);
330 m_sendHeartbeat.interval(*params,"send_hb",15000,30000,true);
331 // The maximum interval in miliseconds allowed for SCTP to retransmit
332 // a lost package
333 m_maxRetransmit = params->getIntValue("max_interval_retrans",1000);
334 }
335 }
336
~SIGAdaptation()337 SIGAdaptation::~SIGAdaptation()
338 {
339 DDebug(this,DebugAll,"Destroying SIGTRAN UA [%p]",this);
340 }
341
initialize(const NamedList * config)342 bool SIGAdaptation::initialize(const NamedList* config)
343 {
344 if (transport())
345 return true;
346 NamedList params("");
347 if (resolveConfig(YSTRING("sig"),params,config) ||
348 resolveConfig(YSTRING("basename"),params,config)) {
349 DDebug(this,DebugInfo,"Creating transport for SIGTRAN UA [%p]",this);
350 params.addParam("basename",params);
351 SIGTransport* tr = YSIGCREATE(SIGTransport,¶ms);
352 if (!tr)
353 return false;
354 SIGTRAN::attach(tr);
355 if (tr->initialize(¶ms))
356 return true;
357 SIGTRAN::attach(0);
358 }
359 return false;
360 }
361
notifyLayer(SignallingInterface::Notification status)362 void SIGAdaptation::notifyLayer(SignallingInterface::Notification status)
363 {
364 Lock myLock(this);
365 if (status != SignallingInterface::LinkUp) {
366 m_waitHeartbeatAck.stop();
367 m_sendHeartbeat.stop();
368 for (int i = 0;i < 32;i++) {
369 if (m_streamsHB[i] == HeartbeatDisabled)
370 continue;
371 m_streamsHB[i] = HeartbeatEnabled;
372 }
373 return;
374 }
375 m_sendHeartbeat.start();
376 String params = "rto_max";
377 NamedList result("sctp_params");
378 if (getSocketParams(params,result)) {
379 int rtoMax = result.getIntValue(YSTRING("rto_max"));
380 unsigned int maxRetrans = rtoMax + AVG_DELAY;
381 if (maxRetrans > m_maxRetransmit) {
382 Debug(this,DebugConf,
383 "%s! Maximum SCTP interval to retransmit a packet is: %d, maximum allowed is: %d ",
384 "The SCTP configuration timers are unreliable",
385 maxRetrans,m_maxRetransmit);
386 }
387 } else
388 Debug(this,DebugNote,"Failed to obtain socket params");
389 }
390
391 // Process common (MGMT, ASPSM, ASPTM) messages
processCommonMSG(unsigned char msgClass,unsigned char msgType,const DataBlock & msg,int streamId)392 bool SIGAdaptation::processCommonMSG(unsigned char msgClass,
393 unsigned char msgType, const DataBlock& msg, int streamId)
394 {
395 switch (msgClass) {
396 case MGMT:
397 return processMgmtMSG(msgType,msg,streamId);
398 case ASPSM:
399 if (msgType == AspsmBEAT || msgType == AspsmBEAT_ACK)
400 return processHeartbeat(msgType,msg,streamId);
401 return processAspsmMSG(msgType,msg,streamId);
402 case ASPTM:
403 return processAsptmMSG(msgType,msg,streamId);
404 default:
405 Debug(this,DebugWarn,"Unsupported message class 0x%02X",msgClass);
406 return false;
407 }
408 }
409
processHeartbeat(unsigned char msgType,const DataBlock & msg,int streamId)410 bool SIGAdaptation::processHeartbeat(unsigned char msgType, const DataBlock& msg,
411 int streamId)
412 {
413 XDebug(this,DebugAll,"Received %s in stream %d",lookup(msgType,s_aspsm_types),streamId);
414 if (msgType == AspsmBEAT)
415 return transmitMSG(ASPSM,AspsmBEAT_ACK,msg,streamId);
416 if (msgType != AspsmBEAT_ACK || streamId > 32)
417 return false;
418 Lock myLock(this);
419 // Mark the first stream witch waits to receive heartbeat
420 // Do not mark the received stream because some implementations may send
421 // heartbeat responses only on stream 0.
422 for (int i = 0;i < 32;i++) {
423 if (m_streamsHB[i] == HeartbeatWaitResponse) {
424 m_streamsHB[i] = HeartbeatEnabled;
425 return true;
426 }
427 }
428 return false;
429 }
430
431 // Advance to next tag in a message
nextTag(const DataBlock & data,int & offset,uint16_t & tag,uint16_t & length)432 bool SIGAdaptation::nextTag(const DataBlock& data, int& offset, uint16_t& tag, uint16_t& length)
433 {
434 unsigned int offs = (offset < 0) ? 0 : offset;
435 unsigned char* ptr = data.data(offs,4);
436 if (!ptr)
437 return false;
438 unsigned int len = ((uint16_t)ptr[2] << 8) | ptr[3];
439 if (len < 4)
440 return false;
441 if (offset >= 0) {
442 // Skip over current parameter
443 offs += (len + 3) & ~3;
444 ptr = data.data(offs,4);
445 if (!ptr)
446 return false;
447 len = ((uint16_t)ptr[2] << 8) | ptr[3];
448 if (len < 4)
449 return false;
450 }
451 if ((offs + len) > data.length())
452 return false;
453
454 offset = offs;
455 tag = ((uint16_t)ptr[0] << 8) | ptr[1];
456 length = len - 4;
457 return true;
458 }
459
460 // Find a specific tag in a message
findTag(const DataBlock & data,int & offset,uint16_t tag,uint16_t & length)461 bool SIGAdaptation::findTag(const DataBlock& data, int& offset, uint16_t tag, uint16_t& length)
462 {
463 int offs = -1;
464 uint16_t type = 0;
465 uint16_t len = 0;
466 while (nextTag(data,offs,type,len)) {
467 if (type == tag) {
468 offset = offs;
469 length = len;
470 return true;
471 }
472 }
473 return false;
474 }
475
476 // Get a 32 bit integer parameter
getTag(const DataBlock & data,uint16_t tag,uint32_t & value)477 bool SIGAdaptation::getTag(const DataBlock& data, uint16_t tag, uint32_t& value)
478 {
479 int offs = -1;
480 uint16_t len = 0;
481 if (findTag(data,offs,tag,len) && (4 == len)) {
482 value = data.at(offs + 4) << 24 | data.at(offs + 5) << 16 |
483 data.at(offs + 6) << 8 | data.at(offs + 7);
484 return true;
485 }
486 return false;
487 }
488
489 // Get a string parameter
getTag(const DataBlock & data,uint16_t tag,String & value)490 bool SIGAdaptation::getTag(const DataBlock& data, uint16_t tag, String& value)
491 {
492 int offs = -1;
493 uint16_t len = 0;
494 if (findTag(data,offs,tag,len)) {
495 value.assign((char*)data.data(offs + 4),len);
496 return true;
497 }
498 return false;
499 }
500
501 // Get a raw binary parameter
getTag(const DataBlock & data,uint16_t tag,DataBlock & value)502 bool SIGAdaptation::getTag(const DataBlock& data, uint16_t tag, DataBlock& value)
503 {
504 int offs = -1;
505 uint16_t len = 0;
506 if (findTag(data,offs,tag,len)) {
507 value.assign(data.data(offs + 4),len);
508 return true;
509 }
510 return false;
511 }
512
513 // Add a 32 bit integer parameter
addTag(DataBlock & data,uint16_t tag,uint32_t value)514 void SIGAdaptation::addTag(DataBlock& data, uint16_t tag, uint32_t value)
515 {
516 unsigned char buf[8];
517 buf[0] = tag >> 8;
518 buf[1] = tag & 0xff;
519 buf[2] = 0;
520 buf[3] = 8;
521 buf[4] = (value >> 24) & 0xff;
522 buf[5] = (value >> 16) & 0xff;
523 buf[6] = (value >> 8) & 0xff;
524 buf[7] = value & 0xff;
525 DataBlock tmp(buf,8,false);
526 data += tmp;
527 tmp.clear(false);
528 }
529
530 // Add a string parameter
addTag(DataBlock & data,uint16_t tag,const String & value)531 void SIGAdaptation::addTag(DataBlock& data, uint16_t tag, const String& value)
532 {
533 unsigned int len = value.length() + 4;
534 if (len > 32768)
535 return;
536 unsigned char buf[4];
537 buf[0] = tag >> 8;
538 buf[1] = tag & 0xff;
539 buf[2] = (len >> 8) & 0xff;
540 buf[3] = len & 0xff;
541 DataBlock tmp(buf,4,false);
542 data += tmp;
543 data += value;
544 tmp.clear(false);
545 len = (len & 3);
546 if (len) {
547 buf[0] = buf[1] = buf[2] = 0;
548 tmp.assign(buf,4 - len,false);
549 data += tmp;
550 tmp.clear(false);
551 }
552 }
553
554 // Add a raw binary parameter
addTag(DataBlock & data,uint16_t tag,const DataBlock & value)555 void SIGAdaptation::addTag(DataBlock& data, uint16_t tag, const DataBlock& value)
556 {
557 unsigned int len = value.length() + 4;
558 if (len > 32768)
559 return;
560 unsigned char buf[4];
561 buf[0] = tag >> 8;
562 buf[1] = tag & 0xff;
563 buf[2] = (len >> 8) & 0xff;
564 buf[3] = len & 0xff;
565 DataBlock tmp(buf,4,false);
566 data += tmp;
567 data += value;
568 tmp.clear(false);
569 len = (len & 3);
570 if (len) {
571 buf[0] = buf[1] = buf[2] = 0;
572 tmp.assign(buf,4 - len,false);
573 data += tmp;
574 tmp.clear(false);
575 }
576 }
577
timerTick(const Time & when)578 void SIGAdaptation::timerTick(const Time& when)
579 {
580 if (m_sendHeartbeat.timeout()) {
581 m_sendHeartbeat.stop();
582 Lock myLock(this);
583 DataBlock data;
584 for (int i = 0; i < 32; i++) {
585 if (m_streamsHB[i] == HeartbeatDisabled)
586 continue;
587 transmitMSG(ASPSM,AspsmBEAT,data,i);
588 m_streamsHB[i] = HeartbeatWaitResponse;
589 }
590 m_waitHeartbeatAck.start();
591 }
592 if (m_waitHeartbeatAck.timeout()) {
593 m_waitHeartbeatAck.stop();
594 Lock myLock(this);
595 for (int i = 0;i < 32;i++) {
596 if (m_streamsHB[i] == HeartbeatWaitResponse) {
597 // The stream is freezed
598 Debug(this,DebugWarn,
599 "Stream %d is freezed! Restarting transport",i);
600 restart(true);
601 return;
602 }
603 }
604 m_sendHeartbeat.start();
605 }
606 }
607
608 /**
609 * Class SIGAdaptClient
610 */
611
612 #define MAKE_NAME(x) { #x, SIGAdaptClient::x }
613 static const TokenDict s_clientStates[] = {
614 MAKE_NAME(AspDown),
615 MAKE_NAME(AspUpRq),
616 MAKE_NAME(AspUp),
617 MAKE_NAME(AspActRq),
618 MAKE_NAME(AspActive),
619 { 0, 0 }
620 };
621 #undef MAKE_NAME
622
623 static const TokenDict s_uaErrors[] = {
624 { "Invalid Version", SIGAdaptation::InvalidVersion },
625 { "Invalid Interface Identifier", SIGAdaptation::InvalidIID },
626 { "Unsupported Message Class", SIGAdaptation::UnsupportedMessageClass },
627 { "Unsupported Message Type", SIGAdaptation::UnsupportedMessageType },
628 { "Unsupported Traffic Handling Mode", SIGAdaptation::UnsupportedTrafficMode },
629 { "Unexpected Message", SIGAdaptation::UnexpectedMessage },
630 { "Protocol Error", SIGAdaptation::ProtocolError },
631 { "Unsupported Interface Identifier Type", SIGAdaptation::UnsupportedIIDType },
632 { "Invalid Stream Identifier", SIGAdaptation::InvalidStreamIdentifier },
633 { "Unassigned TEI", SIGAdaptation::UnassignedTEI },
634 { "Unrecognized SAPI", SIGAdaptation::UnrecognizedSAPI },
635 { "Invalid TEI, SAPI combination", SIGAdaptation::InvalidTEISAPI },
636 { "Refused - Management Blocking", SIGAdaptation::ManagementBlocking },
637 { "ASP Identifier Required", SIGAdaptation::ASPIDRequired },
638 { "Invalid ASP Identifier", SIGAdaptation::InvalidASPID },
639 { "ASP Active for Interface Identifier(s)", SIGAdaptation::ASPActiveIID },
640 { "Invalid Parameter Value ", SIGAdaptation::InvalidParameterValue },
641 { "Parameter Field Error", SIGAdaptation::ParameterFieldError },
642 { "Unexpected Parameter", SIGAdaptation::UnexpectedParameter },
643 { "Destination Status Unknown", SIGAdaptation::DestinationStatusUnknown },
644 { "Invalid Network Appearance", SIGAdaptation::InvalidNetworkAppearance },
645 { "Missing Parameter", SIGAdaptation::MissingParameter },
646 { "Invalid Routing Context", SIGAdaptation::InvalidRoutingContext },
647 { "No Configured AS for ASP", SIGAdaptation::NotConfiguredAS },
648 { "Subsystem Status Unknown", SIGAdaptation::SubsystemStatusUnknown },
649 { "Invalid loadsharing label", SIGAdaptation::InvalidLoadsharingLabel },
650 { 0, 0 }
651 };
652
653 static const TokenDict s_trafficModes[] = {
654 { "unused", SIGAdaptation::TrafficUnused },
655 { "override", SIGAdaptation::TrafficOverride },
656 { "loadshare", SIGAdaptation::TrafficLoadShare },
657 { "broadcast", SIGAdaptation::TrafficBroadcast },
658 { 0, 0 }
659 };
660
661 // Helper storage object
662 typedef GenPointer<SIGAdaptUser> AdaptUserPtr;
663
664 // Constructor
SIGAdaptClient(const char * name,const NamedList * params,u_int32_t payload,u_int16_t port)665 SIGAdaptClient::SIGAdaptClient(const char* name, const NamedList* params,
666 u_int32_t payload, u_int16_t port)
667 : SIGAdaptation(name,params,payload,port),
668 m_aspId(-1), m_traffic(TrafficOverride), m_state(AspDown)
669 {
670 if (params) {
671 #ifdef DEBUG
672 String tmp;
673 if (debugAt(DebugAll))
674 params->dump(tmp,"\r\n ",'\'',true);
675 Debug(this,DebugInfo,"SIGAdaptClient(%u,%u) created [%p]%s",
676 payload,port,this,tmp.c_str());
677 #endif
678 m_aspId = params->getIntValue(YSTRING("aspid"),m_aspId);
679 m_traffic = (TrafficMode)params->getIntValue(YSTRING("traffic"),s_trafficModes,m_traffic);
680 }
681 // Enable heartbeat on stream 0; because is unlikely to have a adapt user
682 // who uses stream 0
683 enableHeartbeat(0);
684 }
685
686 // Attach one user entity to the ASP
attach(SIGAdaptUser * user)687 void SIGAdaptClient::attach(SIGAdaptUser* user)
688 {
689 if (!user)
690 return;
691 Lock mylock(this);
692 m_users.append(new AdaptUserPtr(user));
693 // Enable heartbeat on users stream id
694 enableHeartbeat(user->getStreamId());
695 }
696
697 // Detach one user entity from the ASP
detach(SIGAdaptUser * user)698 void SIGAdaptClient::detach(SIGAdaptUser* user)
699 {
700 if (!user)
701 return;
702 Lock mylock(this);
703 for (ObjList* o = m_users.skipNull(); o; o = o->skipNext()) {
704 AdaptUserPtr* p = static_cast<AdaptUserPtr*>(o->get());
705 if (*p != user)
706 continue;
707 m_users.remove(p,false);
708 if (!m_users.count()) {
709 setState(AspDown,false);
710 transmitMSG(ASPSM,AspsmDOWN,DataBlock::empty());
711 }
712 return;
713 }
714 // Reset all heartbeat streams
715 resetHeartbeat();
716 enableHeartbeat(0);
717 for (ObjList* o = m_users.skipNull(); o; o = o->skipNext()) {
718 AdaptUserPtr* p = static_cast<AdaptUserPtr*>(o->get());
719 enableHeartbeat((*p)->getStreamId());
720 }
721 }
722
723 // Status notification from transport layer
notifyLayer(SignallingInterface::Notification status)724 void SIGAdaptClient::notifyLayer(SignallingInterface::Notification status)
725 {
726 SIGAdaptation::notifyLayer(status);
727 switch (status) {
728 case SignallingInterface::LinkDown:
729 case SignallingInterface::HardwareError:
730 switch (m_state) {
731 case AspDown:
732 case AspUpRq:
733 break;
734 default:
735 setState(AspUpRq);
736 }
737 break;
738 case SignallingInterface::LinkUp:
739 if (m_state >= AspUpRq) {
740 setState(AspUpRq,false);
741 DataBlock data;
742 if (m_aspId != -1)
743 addTag(data,0x0011,m_aspId);
744 transmitMSG(ASPSM,AspsmUP,data);
745 }
746 break;
747 default:
748 return;
749 }
750 }
751 // Request activation of the ASP
activate()752 bool SIGAdaptClient::activate()
753 {
754 Lock mylock(this);
755 if (m_state >= AspActRq)
756 return true;
757 if (!transport())
758 return false;
759 switch (m_state) {
760 case AspUpRq:
761 return true;
762 case AspDown:
763 setState(AspUpRq,false);
764 {
765 DataBlock data;
766 if (m_aspId != -1)
767 addTag(data,0x0011,m_aspId);
768 mylock.drop();
769 transmitMSG(ASPSM,AspsmUP,data);
770 return true;
771 }
772 case AspUp:
773 setState(AspActRq,false);
774 {
775 DataBlock data;
776 if (m_traffic != TrafficUnused)
777 addTag(data,0x000b,m_traffic);
778 mylock.drop();
779 return transmitMSG(ASPTM,AsptmACTIVE,data,1);
780 }
781 default:
782 return false;
783 }
784 }
785
786 // Change the state of the ASP
setState(AspState state,bool notify)787 void SIGAdaptClient::setState(AspState state, bool notify)
788 {
789 Lock mylock(this);
790 if (state == m_state)
791 return;
792 Debug(this,DebugAll,"ASP state change: %s -> %s [%p]",
793 lookup(m_state,s_clientStates,"?"),lookup(state,s_clientStates,"?"),this);
794 bool up = aspUp();
795 bool act = aspActive();
796 m_state = state;
797 if (!notify)
798 return;
799 if (act != aspActive())
800 activeChange(aspActive());
801 else if (aspUp() && !up) {
802 setState(AspActRq,false);
803 DataBlock data;
804 if (m_traffic != TrafficUnused)
805 addTag(data,0x000b,m_traffic);
806 transmitMSG(ASPTM,AsptmACTIVE,data,1);
807 }
808 }
809
810 // Notification of activity state change
activeChange(bool active)811 void SIGAdaptClient::activeChange(bool active)
812 {
813 Debug(this,DebugNote,"ASP traffic is now %s [%p]",
814 (active ? "active" : "inactive"),this);
815 Lock mylock(this);
816 for (ObjList* o = m_users.skipNull(); o; o = o->skipNext()) {
817 AdaptUserPtr* p = static_cast<AdaptUserPtr*>(o->get());
818 (*p)->activeChange(active);
819 }
820 }
821
822 // Process common MGMT messages
processMgmtMSG(unsigned char msgType,const DataBlock & msg,int streamId)823 bool SIGAdaptClient::processMgmtMSG(unsigned char msgType, const DataBlock& msg, int streamId)
824 {
825 switch (msgType) {
826 case SIGTRAN::MgmtERR:
827 {
828 u_int32_t errCode = 0;
829 if (SIGAdaptation::getTag(msg,0x000c,errCode)) {
830 switch (errCode) {
831 case 1:
832 Debug(this,DebugWarn,"SG Reported invalid version");
833 setState(AspDown);
834 return true;
835 case 5:
836 Debug(this,DebugWarn,"SG Reported invalid traffic mode %s",
837 lookup(m_traffic,s_trafficModes,"Unknown"));
838 setState(AspDown);
839 return true;
840 case 14:
841 Debug(this,DebugWarn,"SG Reported ASP ID required");
842 setState(AspDown);
843 return true;
844 case 15:
845 Debug(this,DebugWarn,"SG Reported invalid ASP id=%d",m_aspId);
846 setState(AspDown);
847 return true;
848 default:
849 Debug(this,DebugWarn,"SG reported error %u: %s",errCode,lookup(errCode,s_uaErrors,"Unknown"));
850 return true;
851 }
852 }
853 }
854 break;
855 case SIGTRAN::MgmtNTFY:
856 {
857 u_int32_t status = 0;
858 if (SIGAdaptation::getTag(msg,0x000d,status)) {
859 const char* our = "";
860 if (m_aspId != -1) {
861 our = "Some ";
862 u_int32_t aspid = 0;
863 if (SIGAdaptation::getTag(msg,0x0011,aspid))
864 our = ((int32_t)aspid == m_aspId) ? "Our " : "Other ";
865 }
866 switch (status >> 16) {
867 case 1:
868 Debug(this,DebugInfo,"%sASP State Change: %u",our,status & 0xffff);
869 return true;
870 case 2:
871 Debug(this,DebugInfo,"%sASP State Info: %u",our,status & 0xffff);
872 return true;
873 }
874 }
875 }
876 break;
877 }
878 Debug(this,DebugStub,"Please handle ASP message %u class MGMT",msgType);
879 return false;
880 }
881
882 // Process common ASPSM messages
processAspsmMSG(unsigned char msgType,const DataBlock & msg,int streamId)883 bool SIGAdaptClient::processAspsmMSG(unsigned char msgType, const DataBlock& msg, int streamId)
884 {
885 switch (msgType) {
886 case AspsmUP_ACK:
887 setState(AspUp);
888 return true;
889 case AspsmDOWN_ACK:
890 setState(AspDown);
891 return true;
892 case AspsmUP:
893 case AspsmDOWN:
894 Debug(this,DebugWarn,"Wrong direction for ASPSM %s ASP message!",
895 SIGTRAN::typeName(ASPSM,msgType));
896 return false;
897 }
898 Debug(this,DebugStub,"Please handle ASP message %u class ASPSM",msgType);
899 return false;
900 }
901
902 // Process common ASPTM messages
processAsptmMSG(unsigned char msgType,const DataBlock & msg,int streamId)903 bool SIGAdaptClient::processAsptmMSG(unsigned char msgType, const DataBlock& msg, int streamId)
904 {
905 switch (msgType) {
906 case AsptmACTIVE_ACK:
907 setState(AspActive);
908 return true;
909 case AsptmINACTIVE_ACK:
910 if (aspUp())
911 setState(AspUp);
912 return true;
913 case AsptmACTIVE:
914 case AsptmINACTIVE:
915 Debug(this,DebugWarn,"Wrong direction for ASPTM %s ASP message!",
916 SIGTRAN::typeName(ASPTM,msgType));
917 return false;
918 }
919 Debug(this,DebugStub,"Please handle ASP message %u class ASPTM",msgType);
920 return false;
921 }
922
923
924 /**
925 * Class SIGAdaptServer
926 */
927
928 // Process common MGMT messages
processMgmtMSG(unsigned char msgType,const DataBlock & msg,int streamId)929 bool SIGAdaptServer::processMgmtMSG(unsigned char msgType, const DataBlock& msg, int streamId)
930 {
931 Debug(this,DebugStub,"Please handle SG message %u class MGMT",msgType);
932 return false;
933 }
934
935 // Process common ASPSM messages
processAspsmMSG(unsigned char msgType,const DataBlock & msg,int streamId)936 bool SIGAdaptServer::processAspsmMSG(unsigned char msgType, const DataBlock& msg, int streamId)
937 {
938 switch (msgType) {
939 case AspsmUP:
940 case AspsmDOWN:
941 break;
942 case AspsmUP_ACK:
943 case AspsmDOWN_ACK:
944 Debug(this,DebugWarn,"Wrong direction for ASPSM %s SG message!",
945 SIGTRAN::typeName(ASPSM,msgType));
946 return false;
947 }
948 Debug(this,DebugStub,"Please handle SG message %u class ASPSM",msgType);
949 return false;
950 }
951
952 // Process common ASPTM messages
processAsptmMSG(unsigned char msgType,const DataBlock & msg,int streamId)953 bool SIGAdaptServer::processAsptmMSG(unsigned char msgType, const DataBlock& msg, int streamId)
954 {
955 switch (msgType) {
956 case AsptmACTIVE:
957 case AsptmINACTIVE:
958 break;
959 case AsptmACTIVE_ACK:
960 case AsptmINACTIVE_ACK:
961 Debug(this,DebugWarn,"Wrong direction for ASPTM %s SG message!",
962 SIGTRAN::typeName(ASPTM,msgType));
963 return false;
964 }
965 Debug(this,DebugStub,"Please handle SG message %u class ASPTM",msgType);
966 return false;
967 }
968
969
970 /**
971 * Class SIGAdaptUser
972 */
973
~SIGAdaptUser()974 SIGAdaptUser::~SIGAdaptUser()
975 {
976 adaptation(0);
977 }
978
979 // Attach an ASP CLient to this user, detach old client
adaptation(SIGAdaptClient * adapt)980 void SIGAdaptUser::adaptation(SIGAdaptClient* adapt)
981 {
982 if (adapt == m_adaptation)
983 return;
984 if (m_adaptation) {
985 m_adaptation->detach(this);
986 TelEngine::destruct(m_adaptation);
987 }
988 m_adaptation = adapt;
989 if (adapt && adapt->ref())
990 adapt->attach(this);
991 }
992
993
994 /**
995 * Class SS7M2PA
996 */
997
998 static TokenDict s_state[] = {
999 {"Alignment", SS7M2PA::Alignment},
1000 {"ProvingNormal", SS7M2PA::ProvingNormal},
1001 {"ProvingEmergency", SS7M2PA::ProvingEmergency},
1002 {"Ready", SS7M2PA::Ready},
1003 {"ProcessorOutage", SS7M2PA::ProcessorOutage},
1004 {"ProcessorRecovered", SS7M2PA::ProcessorRecovered},
1005 {"Busy", SS7M2PA::Busy},
1006 {"BusyEnded", SS7M2PA::BusyEnded},
1007 {"OutOfService", SS7M2PA::OutOfService},
1008 {0,0}
1009 };
1010
1011 static const TokenDict s_m2pa_dict_control[] = {
1012 { "pause", SS7M2PA::Pause },
1013 { "resume", SS7M2PA::Resume },
1014 { "align", SS7M2PA::Align },
1015 { "transport_restart", SS7M2PA::TransRestart },
1016 { 0, 0 }
1017 };
1018
SS7M2PA(const NamedList & params)1019 SS7M2PA::SS7M2PA(const NamedList& params)
1020 : SignallingComponent(params.safe("SS7M2PA"),¶ms,"ss7-m2pa"),
1021 SIGTRAN(5,3565),
1022 m_seqNr(0xffffff), m_needToAck(0xffffff), m_lastAck(0xffffff), m_maxQueueSize(MAX_UNACK),
1023 m_localStatus(OutOfService), m_state(OutOfService),
1024 m_remoteStatus(OutOfService), m_transportState(Idle), m_connFailCounter(0),
1025 m_connFailThreshold(0), m_mutex(true,"SS7M2PA"), m_t1(0), m_t2(0), m_t3(0),
1026 m_t4(0), m_ackTimer(0), m_confTimer(0), m_oosTimer(0),m_waitOosTimer(0),
1027 m_connFailTimer(0), m_autostart(false), m_sequenced(false), m_dumpMsg(false)
1028
1029 {
1030 // Alignment ready timer ~45s
1031 m_t1.interval(params,"t1",45000,50000,false);
1032 // Not Aligned timer ~5s
1033 m_t2.interval(params,"t2",5000,5500,false);
1034 // Aligned timer ~1s
1035 m_t3.interval(params,"t3",1000,1500,false);
1036 // Proving timer Normal ~8s, Emergency ~0.5s
1037 m_t4.interval(params,"t4",500,8000,false);
1038 // Acknowledge timer ~1s
1039 m_ackTimer.interval(params,"ack_timer",1000,1100,false);
1040 // Confirmation timer 1/2 t4
1041 m_confTimer.interval(params,"conf_timer",50,150,false);
1042 // Out of service timer
1043 m_oosTimer.interval(params,"oos_timer",3000,5000,false);
1044 m_waitOosTimer.interval(params,"wait_oos",500,1000,false);
1045 m_connFailTimer.interval(params,"conn_test",50000,300000,false);
1046 m_connFailThreshold = params.getIntValue(YSTRING("conn_threshold"),3);
1047 m_sequenced = params.getBoolValue(YSTRING("sequenced"),false);
1048 // Maximum unacknowledged messages, max_unack+1 will force an ACK
1049 m_maxUnack = params.getIntValue(YSTRING("max_unack"),4);
1050 if (m_maxUnack > 10)
1051 m_maxUnack = 10;
1052 m_maxQueueSize = params.getIntValue(YSTRING("max_queue_size"),MAX_UNACK);
1053 if (m_maxQueueSize < 16)
1054 m_maxQueueSize = 16;
1055 if (m_maxQueueSize > 65356)
1056 m_maxQueueSize = 65356;
1057 DDebug(this,DebugAll,"Creating SS7M2PA [%p]",this);
1058 }
1059
~SS7M2PA()1060 SS7M2PA::~SS7M2PA()
1061 {
1062 Lock lock(m_mutex);
1063 m_ackList.clear();
1064 DDebug(this,DebugAll,"Destroying SS7M2PA [%p]",this);
1065 }
1066
destroyed()1067 void SS7M2PA::destroyed()
1068 {
1069 stopTransportThread();
1070 SIGTRAN::attach(0);
1071 SS7Layer2::destroyed();
1072 }
1073
initialize(const NamedList * config)1074 bool SS7M2PA::initialize(const NamedList* config)
1075 {
1076 #ifdef DEBUG
1077 String tmp;
1078 if (config && debugAt(DebugAll))
1079 config->dump(tmp,"\r\n ",'\'',true);
1080 Debug(this,DebugInfo,"SS7M2PA::initialize(%p) [%p]%s",config,this,tmp.c_str());
1081 #endif
1082 m_dumpMsg = config && config->getBoolValue(YSTRING("dumpMsg"),false);
1083 m_autostart = !config || config->getBoolValue(YSTRING("autostart"),true);
1084 m_autoEmergency = !config || config->getBoolValue(YSTRING("autoemergency"),true);
1085 if (config && !transport()) {
1086 NamedList params("");
1087 if (resolveConfig(YSTRING("sig"),params,config) ||
1088 resolveConfig(YSTRING("basename"),params,config)) {
1089 params.addParam("basename",params);
1090 params.addParam("protocol","ss7");
1091 params.addParam("listen-notify","false");
1092 SIGTransport* tr = YSIGCREATE(SIGTransport,¶ms);
1093 if (!tr)
1094 return false;
1095 SIGTRAN::attach(tr);
1096 if (!tr->initialize(¶ms))
1097 SIGTRAN::attach(0);
1098 m_sequenced = config->getBoolValue(YSTRING("sequenced"),transport() ?
1099 transport()->reliable() : false);
1100 }
1101 }
1102 return transport() && control(Resume,const_cast<NamedList*>(config));
1103 }
1104
dumpMsg(u_int8_t version,u_int8_t mClass,u_int8_t type,const DataBlock & data,int stream,bool send)1105 void SS7M2PA::dumpMsg(u_int8_t version, u_int8_t mClass, u_int8_t type,
1106 const DataBlock& data, int stream, bool send)
1107 {
1108 String dump = "SS7M2PA ";
1109 dump << (send ? "Sending:" : "Received:");
1110 dump << "\r\n-----";
1111 String indent = "\r\n ";
1112 dump << indent << "Version: " << version;
1113 dump << " " << "Message class: " << mClass;
1114 dump << " " << "Message type: " << lookup(type,s_m2pa_types,"Unknown");
1115 dump << indent << "Stream: " << stream;
1116 if (data.length() >= 8) {
1117 u_int32_t bsn = (data[1] << 16) | (data[2] << 8) | data[3];
1118 u_int32_t fsn = (data[5] << 16) | (data[6] << 8) | data[7];
1119 dump << indent << "FSN : " << fsn << " BSN: " << bsn;
1120 if (type == LinkStatus) {
1121 u_int32_t status = (data[8] << 24) | (data[9] << 16) | (data[10] << 8) | data[11];
1122 dump << indent << "Status: " << lookup(status,s_state);
1123 }
1124 else {
1125 String hex;
1126 hex.hexify((u_int8_t*)data.data() + 8,data.length() - 8,' ');
1127 dump << indent << "Data: " << hex;
1128 }
1129 }
1130 dump << "\r\n-----";
1131 Debug(this,DebugInfo,"%s",dump.c_str());
1132 }
1133
processMSG(unsigned char msgVersion,unsigned char msgClass,unsigned char msgType,const DataBlock & msg,int streamId)1134 bool SS7M2PA::processMSG(unsigned char msgVersion, unsigned char msgClass,
1135 unsigned char msgType, const DataBlock& msg, int streamId)
1136 {
1137 if (msgClass != M2PA) {
1138 Debug(this,(msg.null() ? DebugInfo : DebugWarn),
1139 "Received non M2PA message class %d",msgClass);
1140 dumpMsg(msgVersion,msgClass,msgType,msg,streamId,false);
1141 return false;
1142 }
1143 if (m_dumpMsg)
1144 dumpMsg(msgVersion,msgClass,msgType,msg,streamId,false);
1145 Lock lock(m_mutex);
1146 if (!operational() && msgType == UserData)
1147 return false;
1148 if (!decodeSeq(msg,(u_int8_t)msgType))
1149 return false;
1150 DataBlock data(msg);
1151 data.cut(-8);
1152 if (!data.length())
1153 return true;
1154 if (msgType == LinkStatus)
1155 return m_sequenced ? processSLinkStatus(data,streamId) : processLinkStatus(data,streamId);
1156 #ifdef DEBUG
1157 if (streamId != 1)
1158 Debug(this,DebugNote,"Received data message on Link status stream");
1159 #endif
1160 lock.drop();
1161 data.cut(-1); // priority octet
1162 SS7MSU msu(data);
1163 return receivedMSU(msu);
1164 }
1165
nextBsn(u_int32_t bsn) const1166 bool SS7M2PA::nextBsn(u_int32_t bsn) const
1167 {
1168 u_int32_t n = (0x1000000 + m_seqNr - bsn) & 0xffffff;
1169 if (n > m_maxQueueSize) {
1170 Debug(this,DebugWarn,"Maximum number of unacknowledged messages reached!!!");
1171 return false;
1172 }
1173 n = (0x1000000 + bsn - m_lastAck) & 0xffffff;
1174 return (n != 0) && (n <= m_maxQueueSize);
1175 }
1176
decodeSeq(const DataBlock & data,u_int8_t msgType)1177 bool SS7M2PA::decodeSeq(const DataBlock& data,u_int8_t msgType)
1178 {
1179 if (data.length() < 8)
1180 return false;
1181 u_int32_t bsn = (data[1] << 16) | (data[2] << 8) | data[3];
1182 u_int32_t fsn = (data[5] << 16) | (data[6] << 8) | data[7];
1183 if (msgType == LinkStatus) {
1184 // Do not check sequence numbers if either end is OutOfService
1185 if (OutOfService == m_state)
1186 return true;
1187 if (data.length() >= 12) {
1188 u_int32_t status = (data[8] << 24) | (data[9] << 16) | (data[10] << 8) | data[11];
1189 if (OutOfService == status)
1190 return true;
1191 }
1192 if (fsn != m_needToAck) {
1193 Debug(this,DebugWarn,"Received LinkStatus with wrong sequence %d, expected %d in state %s",
1194 fsn,m_needToAck,lookup(m_localStatus,s_state));
1195 abortAlignment("Wrong Sequence number");
1196 transmitLS();
1197 return false;
1198 }
1199 if (bsn == m_lastAck)
1200 return true;
1201 // If we are here means that something went wrong
1202 abortAlignment("msgType == LinkStatus");
1203 transmitLS();
1204 return false;
1205 }
1206 // UserData
1207 bool ok = false;
1208 if (fsn == getNext(m_needToAck)) {
1209 m_needToAck = fsn;
1210 ok = true;
1211 if (m_confTimer.started()) {
1212 if (++m_confCounter >= m_maxUnack) {
1213 m_confTimer.stop();
1214 sendAck();
1215 }
1216 }
1217 else if (m_maxUnack) {
1218 m_confCounter = 0;
1219 m_confTimer.start();
1220 }
1221 else
1222 sendAck();
1223 }
1224 else if (fsn != m_needToAck) {
1225 abortAlignment("Received Out of sequence frame");
1226 transmitLS();
1227 return false;
1228 }
1229 while (nextBsn(bsn) && removeFrame(getNext(m_lastAck)))
1230 ;
1231 if (bsn != m_lastAck) {
1232 abortAlignment(String("Received unexpected bsn: ") << bsn);
1233 transmitLS();
1234 return false;
1235 }
1236 m_lastSeqRx = (m_needToAck & 0x00ffffff) | 0x01000000;
1237 return ok;
1238 }
1239
timerTick(const Time & when)1240 void SS7M2PA::timerTick(const Time& when)
1241 {
1242 SS7Layer2::timerTick(when);
1243 Lock lock(m_mutex,SignallingEngine::maxLockWait());
1244 if (!lock.locked())
1245 return;
1246 if (m_confTimer.timeout(when.msec())) {
1247 sendAck(); // Acknowledge last received message before endpoint drops down the link
1248 m_confTimer.stop();
1249 }
1250 if (m_ackTimer.timeout(when.msec())) {
1251 m_ackTimer.stop();
1252 if (!transport() || transport()->reliable()) {
1253 lock.drop();
1254 abortAlignment("Ack timer timeout");
1255 } else
1256 retransData();
1257 }
1258 if (m_waitOosTimer.timeout(when.msec())) {
1259 m_waitOosTimer.stop();
1260 setLocalStatus(OutOfService);
1261 transmitLS();
1262 }
1263 if (m_connFailTimer.timeout(when.msec())) {
1264 m_connFailTimer.stop();
1265 if (m_connFailCounter >= m_connFailThreshold) {
1266 Debug(this,DebugMild,
1267 "Connection proving failed but transport was not restarted!");
1268 restart(true);
1269 }
1270 m_connFailCounter = 0;
1271 }
1272 if (m_oosTimer.timeout(when.msec())) {
1273 m_oosTimer.stop();
1274 if (m_transportState == Established)
1275 abortAlignment("Out of service timeout");
1276 else
1277 m_oosTimer.start();
1278 return;
1279 }
1280 if (m_t2.timeout(when.msec())) {
1281 abortAlignment("T2 timeout");
1282 setLocalStatus(Alignment);
1283 transmitLS();
1284 m_t2.start();
1285 return;
1286 }
1287 if (m_t3.timeout(when.msec())) {
1288 m_t3.stop();
1289 abortAlignment("T3 timeout");
1290 return;
1291 }
1292 if (m_t4.started()) {
1293 if (m_t4.timeout(when.msec())) {
1294 m_t4.stop();
1295 setLocalStatus(Ready);
1296 transmitLS();
1297 m_t1.start();
1298 return;
1299 }
1300 // Retransmit proving state
1301 if ((when & 0x3f) == 0)
1302 transmitLS();
1303 }
1304 if (m_t1.timeout(when.msec())) {
1305 m_t1.stop();
1306 abortAlignment("T1 timeout");
1307 }
1308 }
1309
removeFrame(u_int32_t bsn)1310 bool SS7M2PA::removeFrame(u_int32_t bsn)
1311 {
1312 Lock lock(m_mutex);
1313 for (ObjList* o = m_ackList.skipNull();o;o = o->skipNext()) {
1314 DataBlock* d = static_cast<DataBlock*>(o->get());
1315 u_int32_t seq = (d->at(5) << 16) | (d->at(6) << 8) | d->at(7);
1316 if (bsn != seq)
1317 continue;
1318 m_lastAck = bsn;
1319 m_ackList.remove(d);
1320 m_ackTimer.stop();
1321 return true;
1322 }
1323 Debug(this,DebugWarn,"Failed to remove frame %d! Frame is missing!",bsn);
1324 return false;
1325 }
1326
setLocalStatus(unsigned int status)1327 void SS7M2PA::setLocalStatus(unsigned int status)
1328 {
1329 if (status == m_localStatus)
1330 return;
1331 DDebug(this,DebugInfo,"Local status change %s -> %s [%p]",
1332 lookup(m_localStatus,s_state),lookup(status,s_state),this);
1333 if (status == Ready)
1334 m_ackList.clear();
1335 m_localStatus = status;
1336 }
1337
setRemoteStatus(unsigned int status)1338 void SS7M2PA::setRemoteStatus(unsigned int status)
1339 {
1340 if (status == m_remoteStatus)
1341 return;
1342 DDebug(this,DebugInfo,"Remote status change %s -> %s [%p]",
1343 lookup(m_remoteStatus,s_state),lookup(status,s_state),this);
1344 m_remoteStatus = status;
1345 }
1346
aligned() const1347 bool SS7M2PA::aligned() const
1348 {
1349 switch (m_localStatus) {
1350 case ProvingNormal:
1351 case ProvingEmergency:
1352 case Ready:
1353 switch (m_remoteStatus) {
1354 case ProvingNormal:
1355 case ProvingEmergency:
1356 case Ready:
1357 return true;
1358 }
1359 }
1360 return false;
1361 }
1362
operational() const1363 bool SS7M2PA::operational() const
1364 {
1365 return m_localStatus == Ready && m_remoteStatus == Ready;
1366 }
1367
sendAck()1368 void SS7M2PA::sendAck()
1369 {
1370 DataBlock data;
1371 setHeader(data);
1372 if (m_dumpMsg)
1373 dumpMsg(1,M2PA,UserData,data,1,true);
1374 transmitMSG(1,M2PA,UserData,data,1);
1375 }
1376
status() const1377 unsigned int SS7M2PA::status() const
1378 {
1379 switch (m_localStatus) {
1380 case ProvingNormal:
1381 case ProvingEmergency:
1382 return SS7Layer2::OutOfAlignment;
1383 case Ready:
1384 switch (m_remoteStatus) {
1385 case Ready:
1386 return SS7Layer2::NormalAlignment;
1387 case ProcessorOutage:
1388 return SS7Layer2::ProcessorOutage;
1389 case Busy:
1390 return SS7Layer2::Busy;
1391 case OutOfService:
1392 return SS7Layer2::OutOfService;
1393 default:
1394 return SS7Layer2::OutOfAlignment;
1395 }
1396 }
1397 return SS7Layer2::OutOfService;
1398 }
1399
control(NamedList & params)1400 bool SS7M2PA::control(NamedList& params)
1401 {
1402 String* ret = params.getParam(YSTRING("completion"));
1403 const String* oper = params.getParam(YSTRING("operation"));
1404 const char* cmp = params.getValue(YSTRING("component"));
1405 int cmd = oper ? oper->toInteger(s_m2pa_dict_control,-1) : -1;
1406 if (ret) {
1407 if (oper && (cmd < 0))
1408 return false;
1409 String part = params.getValue(YSTRING("partword"));
1410 if (cmp) {
1411 if (toString() != cmp)
1412 return false;
1413 for (const TokenDict* d = s_m2pa_dict_control; d->token; d++)
1414 Module::itemComplete(*ret,d->token,part);
1415 return true;
1416 }
1417 return Module::itemComplete(*ret,toString(),part);
1418 }
1419 if (!(cmp && toString() == cmp))
1420 return false;
1421 return TelEngine::controlReturn(¶ms,(cmd >= 0) && control((M2PAOperations)cmd,¶ms));
1422 }
1423
control(M2PAOperations oper,NamedList * params)1424 bool SS7M2PA::control(M2PAOperations oper, NamedList* params)
1425 {
1426 if (params) {
1427 m_autostart = params->getBoolValue(YSTRING("autostart"),m_autostart);
1428 m_autoEmergency = params->getBoolValue(YSTRING("autoemergency"),m_autoEmergency);
1429 m_maxUnack = params->getIntValue(YSTRING("max_unack"),m_maxUnack);
1430 if (m_maxUnack > 10)
1431 m_maxUnack = 10;
1432 }
1433 switch (oper) {
1434 case Pause:
1435 m_state = OutOfService;
1436 abortAlignment("Control request pause.");
1437 transmitLS();
1438 return TelEngine::controlReturn(params,true);
1439 case Resume:
1440 if (aligned() || !m_autostart)
1441 return TelEngine::controlReturn(params,true);
1442 case Align:
1443 {
1444 m_state = getEmergency(params) ? ProvingEmergency : ProvingNormal;
1445 abortAlignment("Control request align.");
1446 return TelEngine::controlReturn(params,true);
1447 }
1448 case Status:
1449 return TelEngine::controlReturn(params,operational());
1450 case TransRestart:
1451 return TelEngine::controlReturn(params,restart(true));
1452 default:
1453 return TelEngine::controlReturn(params,false);
1454 }
1455 }
1456
startAlignment(bool emergency)1457 void SS7M2PA::startAlignment(bool emergency)
1458 {
1459 setLocalStatus(OutOfService);
1460 transmitLS();
1461 if (!m_sequenced)
1462 setLocalStatus(Alignment);
1463 m_oosTimer.start();
1464 SS7Layer2::notify();
1465 }
1466
transmitLS(int streamId)1467 void SS7M2PA::transmitLS(int streamId)
1468 {
1469 if (m_transportState != Established)
1470 return;
1471 if (m_state == OutOfService)
1472 m_localStatus = OutOfService;
1473 DataBlock data;
1474 setHeader(data);
1475 u_int8_t ms[4];
1476 ms[2] = ms[1] = ms[0] = 0;
1477 ms[3] = m_localStatus;
1478 data.append(ms,4);
1479 if (m_dumpMsg)
1480 dumpMsg(1,M2PA, 2,data,streamId,true);
1481 transmitMSG(1,M2PA, 2, data,streamId);
1482 XDebug(this,DebugInfo,"Sending LinkStatus %s",lookup(m_localStatus,s_state));
1483 }
1484
setHeader(DataBlock & data)1485 void SS7M2PA::setHeader(DataBlock& data)
1486 {
1487 u_int8_t head[8];
1488 head[0] = head[4] = 0;
1489 head[1] = (m_needToAck >> 16) & 0xff;
1490 head[2] = (m_needToAck >> 8) & 0xff;
1491 head[3] = m_needToAck & 0xff ;
1492 head[5] = (m_seqNr >> 16) & 0xff;
1493 head[6] = (m_seqNr >> 8) & 0xff;
1494 head[7] = m_seqNr & 0xff ;
1495 data.append(head,8);
1496 }
1497
abortAlignment(const char * info)1498 void SS7M2PA::abortAlignment(const char* info)
1499 {
1500 m_connFailCounter++;
1501 if (!m_connFailTimer.started())
1502 m_connFailTimer.start();
1503 else if (m_connFailCounter >= m_connFailThreshold) {
1504 restart(true);
1505 m_connFailTimer.stop();
1506 }
1507 if (info)
1508 Debug(this,DebugNote,"Aborting alignment: %s",info);
1509 setLocalStatus(OutOfService);
1510 setRemoteStatus(OutOfService);
1511 m_needToAck = m_lastAck = m_seqNr = 0xffffff;
1512 m_confTimer.stop();
1513 m_ackTimer.stop();
1514 m_oosTimer.stop();
1515 m_t2.stop();
1516 m_t3.stop();
1517 m_t4.stop();
1518 m_t1.stop();
1519 if (m_state == ProvingNormal || m_state == ProvingEmergency) {
1520 startAlignment();
1521 if (m_sequenced)
1522 m_waitOosTimer.start();
1523 } else
1524 SS7Layer2::notify();
1525 }
1526
processLinkStatus(DataBlock & data,int streamId)1527 bool SS7M2PA::processLinkStatus(DataBlock& data,int streamId)
1528 {
1529 if (data.length() < 4)
1530 return false;
1531 u_int32_t status = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
1532 if (m_remoteStatus == status && status != OutOfService)
1533 return true;
1534
1535 XDebug(this,DebugAll,"Received link status: %s, local status : %s, requested status %s",
1536 lookup(status,s_state),lookup(m_localStatus,s_state),lookup(m_state,s_state));
1537 switch (status) {
1538 case Alignment:
1539 m_oosTimer.stop();
1540 if (m_t2.started()) {
1541 m_t2.stop();
1542 setLocalStatus(m_state);
1543 m_t3.start();
1544 transmitLS();
1545 }
1546 else if (m_state == ProvingNormal || m_state == ProvingEmergency)
1547 transmitLS();
1548 else
1549 return false;
1550 setRemoteStatus(status);
1551 break;
1552 case ProvingNormal:
1553 case ProvingEmergency:
1554 m_t2.stop();
1555 if (m_localStatus != ProvingNormal && m_localStatus != ProvingEmergency &&
1556 (m_localStatus == Alignment && m_t3.started()))
1557 return false;
1558 if (m_t3.started()) {
1559 m_t3.stop();
1560 if (status == ProvingEmergency || m_state == ProvingEmergency)
1561 m_t4.fire(Time::msecNow() + (m_t4.interval() / 16));
1562 else
1563 m_t4.start();
1564 }
1565 else if (m_state == ProvingNormal || m_state == ProvingEmergency) {
1566 setLocalStatus(status);
1567 transmitLS();
1568 if (status == ProvingEmergency || m_state == ProvingEmergency)
1569 m_t4.fire(Time::msecNow() + (m_t4.interval() / 16));
1570 else
1571 m_t4.start();
1572 }
1573 setRemoteStatus(status);
1574 break;
1575 case Ready:
1576 if (m_localStatus != Ready) {
1577 setLocalStatus(Ready);
1578 transmitLS();
1579 }
1580 setRemoteStatus(status);
1581 m_lastSeqRx = -1;
1582 SS7Layer2::notify();
1583 m_oosTimer.stop();
1584 m_t2.stop();
1585 m_t3.stop();
1586 m_t4.stop();
1587 m_t1.stop();
1588 break;
1589 case ProcessorRecovered:
1590 transmitLS();
1591 setRemoteStatus(status);
1592 break;
1593 case BusyEnded:
1594 setRemoteStatus(Ready);
1595 SS7Layer2::notify();
1596 break;
1597 case ProcessorOutage:
1598 case Busy:
1599 setRemoteStatus(status);
1600 SS7Layer2::notify();
1601 break;
1602 case OutOfService:
1603 m_oosTimer.stop();
1604 if (m_localStatus == Ready) {
1605 abortAlignment("Received : LinkStatus Out of service, local status Ready");
1606 SS7Layer2::notify();
1607 }
1608 if ((m_state == ProvingNormal || m_state == ProvingEmergency)) {
1609 if (m_localStatus == Alignment) {
1610 transmitLS();
1611 if (!m_t2.started())
1612 m_t2.start();
1613 } else if (m_localStatus == OutOfService)
1614 startAlignment();
1615 else
1616 abortAlignment("Recv remote OOS");
1617 }
1618 setRemoteStatus(status);
1619 break;
1620 default:
1621 Debug(this,DebugNote,"Received unknown link status message %d",status);
1622 return false;
1623 }
1624 return true;
1625 }
1626
processSLinkStatus(DataBlock & data,int streamId)1627 bool SS7M2PA::processSLinkStatus(DataBlock& data,int streamId)
1628 {
1629 if (data.length() < 4)
1630 return false;
1631 u_int32_t status = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
1632 if (m_remoteStatus == status && status != OutOfService)
1633 return true;
1634 if (m_waitOosTimer.started())
1635 return true;
1636 Debug(this,DebugAll,"Received link status: %s, local status : %s, requested status %s",
1637 lookup(status,s_state),lookup(m_localStatus,s_state),lookup(m_state,s_state));
1638 switch (status) {
1639 case Alignment:
1640 m_oosTimer.stop();
1641 if (m_localStatus == Alignment && m_t2.started()) {
1642 m_t2.stop();
1643 if (m_state == ProvingNormal || m_state == ProvingEmergency) {
1644 setLocalStatus(m_state);
1645 transmitLS();
1646 m_t3.start();
1647 }
1648 } else if (m_localStatus == OutOfService) {
1649 setLocalStatus(Alignment);
1650 transmitLS();
1651 m_t3.start();
1652 } else
1653 abortAlignment("Out of order alignment message");
1654 setRemoteStatus(status);
1655 break;
1656 case ProvingNormal:
1657 case ProvingEmergency:
1658 m_t2.stop();
1659 if (m_localStatus == Alignment && m_t3.started()) {
1660 m_t3.stop();
1661 setLocalStatus(status);
1662 transmitLS();
1663 if (status == ProvingEmergency || m_state == ProvingEmergency)
1664 m_t4.fire(Time::msecNow() + (m_t4.interval() / 16));
1665 else
1666 m_t4.start();
1667 } else if (m_localStatus == ProvingNormal || m_localStatus == ProvingEmergency) {
1668 m_t3.stop();
1669 if (status == ProvingEmergency || m_state == ProvingEmergency)
1670 m_t4.fire(Time::msecNow() + (m_t4.interval() / 16));
1671 else
1672 m_t4.start();
1673 } else
1674 abortAlignment("Out of order proving message");
1675 setRemoteStatus(status);
1676 break;
1677 case Ready:
1678 if (m_localStatus == ProvingNormal || m_localStatus == ProvingEmergency) {
1679 setLocalStatus(Ready);
1680 transmitLS();
1681 } else if (m_localStatus != Ready) {
1682 abortAlignment("Out of order Ready message");
1683 return true;
1684 }
1685 setRemoteStatus(status);
1686 m_lastSeqRx = -1;
1687 SS7Layer2::notify();
1688 m_oosTimer.stop();
1689 m_t2.stop();
1690 m_t3.stop();
1691 m_t4.stop();
1692 m_t1.stop();
1693 break;
1694 case ProcessorRecovered:
1695 transmitLS();
1696 setRemoteStatus(status);
1697 break;
1698 case BusyEnded:
1699 setRemoteStatus(Ready);
1700 SS7Layer2::notify();
1701 break;
1702 case ProcessorOutage:
1703 case Busy:
1704 setRemoteStatus(status);
1705 SS7Layer2::notify();
1706 break;
1707 case OutOfService:
1708 if (!(m_state == ProvingNormal || m_state == ProvingEmergency)) {
1709 abortAlignment("Requested Pause");
1710 setRemoteStatus(status);
1711 return true;
1712 }
1713 if (m_localStatus == OutOfService) {
1714 m_oosTimer.stop();
1715 setLocalStatus(Alignment);
1716 transmitLS();
1717 if (!m_t2.started())
1718 m_t2.start();
1719 } else if (m_localStatus == Alignment)
1720 transmitLS();
1721 else {
1722 abortAlignment("Remote OOS");
1723 m_waitOosTimer.fire(Time::msecNow() + (m_waitOosTimer.interval() / 2));
1724 }
1725 setRemoteStatus(status);
1726 break;
1727 default:
1728 Debug(this,DebugNote,"Received unknown link status message %d",status);
1729 return false;
1730 }
1731 return true;
1732 }
1733
recoverMSU(int sequence)1734 void SS7M2PA::recoverMSU(int sequence)
1735 {
1736 if (operational()) {
1737 Debug(this,DebugMild,"Recover MSU from sequence %d while link is operational",sequence);
1738 return;
1739 }
1740 Debug(this,DebugInfo,"Recovering MSUs from sequence %d",sequence);
1741 for (;;) {
1742 m_mutex.lock();
1743 DataBlock* pkt = static_cast<DataBlock*>(m_ackList.remove(false));
1744 m_mutex.unlock();
1745 if (!pkt)
1746 break;
1747 unsigned char* head = pkt->data(0,8);
1748 if (head) {
1749 int seq = head[7] | ((int)head[6] << 8) | ((int)head[5] << 16);
1750 if (sequence < 0 || ((seq - sequence) & 0x00ffffff) < 0x007fffff) {
1751 sequence = -1;
1752 SS7MSU msu(head + 8,pkt->length() - 8);
1753 recoveredMSU(msu);
1754 }
1755 else
1756 Debug(this,DebugAll,"Not recovering MSU with seq=%d, requested %d",
1757 seq,sequence);
1758 }
1759 TelEngine::destruct(pkt);
1760 }
1761 }
1762
retransData()1763 void SS7M2PA::retransData()
1764 {
1765 for (ObjList* o = m_ackList.skipNull();o;o = o->skipNext()) {
1766 DataBlock* msg = static_cast<DataBlock*>(o->get());
1767 u_int8_t* head = (u_int8_t*)msg->data();
1768 head[1] = (m_needToAck >> 16) & 0xff;
1769 head[2] = (m_needToAck >> 8) & 0xff;
1770 head[3] = m_needToAck & 0xff ;
1771 if (m_confTimer.started())
1772 m_confTimer.stop();
1773 if (!m_ackTimer.started())
1774 m_ackTimer.start();
1775 transmitMSG(1,M2PA, 1, *msg,1);
1776 }
1777 }
1778
transmitMSU(const SS7MSU & msu)1779 bool SS7M2PA::transmitMSU(const SS7MSU& msu)
1780 {
1781 if (msu.length() < 3) {
1782 Debug(this,DebugWarn,"Asked to send too short MSU of length %u [%p]",
1783 msu.length(),this);
1784 return false;
1785 }
1786 // If we don't have an attached interface don't bother
1787 if (!transport())
1788 return false;
1789 Lock lock(m_mutex);
1790 if (!operational())
1791 return false;
1792 DataBlock packet;
1793 increment(m_seqNr);
1794 setHeader(packet);
1795 if (m_confTimer.started())
1796 m_confTimer.stop();
1797 static const DataBlock priority(0,1);
1798 packet += priority;
1799 packet += msu;
1800 m_ackList.append(new DataBlock(packet));
1801 if (m_dumpMsg)
1802 dumpMsg(1,M2PA,1,packet,1,true);
1803 if (!m_ackTimer.started())
1804 m_ackTimer.start();
1805 return transmitMSG(1,M2PA,1,packet,1);
1806 }
1807
notifyLayer(SignallingInterface::Notification event)1808 void SS7M2PA::notifyLayer(SignallingInterface::Notification event)
1809 {
1810 switch (event) {
1811 case SignallingInterface::LinkDown:
1812 m_transportState = Idle;
1813 m_connFailCounter = 0;
1814 abortAlignment("LinkDown");
1815 m_connFailTimer.stop();
1816 m_connFailCounter = 0;
1817 SS7Layer2::notify();
1818 break;
1819 case SignallingInterface::LinkUp:
1820 {
1821 m_transportState = Established;
1822 Debug(this,DebugInfo,"Interface is up [%p]",this);
1823 String params = "rto_max";
1824 NamedList result("sctp_params");
1825 if (getSocketParams(params,result)) {
1826 int rtoMax = result.getIntValue(YSTRING("rto_max"));
1827 unsigned int maxRetrans = rtoMax + (int)m_confTimer.interval() + AVG_DELAY;
1828 if (maxRetrans > m_ackTimer.interval()) {
1829 Debug(this,DebugConf,
1830 "%s (%d) is greater than ack timer (%d)! Max RTO: %d, conf timer %d, avg delay: %d",
1831 "The maximum time interval to retransmit a packet",
1832 maxRetrans,(int)m_ackTimer.interval(),
1833 rtoMax,(int)m_confTimer.interval(),AVG_DELAY);
1834 }
1835 } else
1836 Debug(this,DebugNote,"Failed to obtain socket params");
1837 if (m_autostart)
1838 startAlignment();
1839 SS7Layer2::notify();
1840 break;
1841 }
1842 case SignallingInterface::HardwareError:
1843 abortAlignment("HardwareError");
1844 if (m_autostart && (m_transportState == Established))
1845 startAlignment();
1846 SS7Layer2::notify();
1847 break;
1848 default:
1849 return;
1850 }
1851 }
1852
1853
processMSG(unsigned char msgVersion,unsigned char msgClass,unsigned char msgType,const DataBlock & msg,int streamId)1854 bool SS7M2UAClient::processMSG(unsigned char msgVersion, unsigned char msgClass,
1855 unsigned char msgType, const DataBlock& msg, int streamId)
1856 {
1857 u_int32_t iid = (u_int32_t)-1;
1858 if (MGMT == msgClass && getTag(msg,0x0001,iid)) {
1859 Lock mylock(this);
1860 for (ObjList* o = users().skipNull(); o; o = o->skipNext()) {
1861 AdaptUserPtr* p = static_cast<AdaptUserPtr*>(o->get());
1862 RefPointer<SS7M2UA> m2ua = static_cast<SS7M2UA*>(static_cast<SIGAdaptUser*>(*p));
1863 if (!m2ua || (m2ua->iid() != (int32_t)iid))
1864 continue;
1865 mylock.drop();
1866 return m2ua->processMGMT(msgType,msg,streamId);
1867 }
1868 Debug(this,DebugStub,"Unhandled M2UA MGMT message type %u for IID=%u",msgType,iid);
1869 return false;
1870 }
1871 else if (MAUP != msgClass)
1872 return processCommonMSG(msgClass,msgType,msg,streamId);
1873 switch (msgType) {
1874 case 2: // Establish Request
1875 case 4: // Release Request
1876 case 7: // State Request
1877 case 10: // Data Retrieval Request
1878 Debug(this,DebugWarn,"Received M2UA SG request %u on ASP side!",msgType);
1879 return false;
1880 }
1881 getTag(msg,0x0001,iid);
1882 Lock mylock(this);
1883 for (ObjList* o = users().skipNull(); o; o = o->skipNext()) {
1884 AdaptUserPtr* p = static_cast<AdaptUserPtr*>(o->get());
1885 RefPointer<SS7M2UA> m2ua = static_cast<SS7M2UA*>(static_cast<SIGAdaptUser*>(*p));
1886 if (!m2ua || (m2ua->iid() != (int32_t)iid))
1887 continue;
1888 mylock.drop();
1889 return m2ua->processMAUP(msgType,msg,streamId);
1890 }
1891 Debug(this,DebugStub,"Unhandled M2UA message type %u for IID=%d",msgType,(int32_t)iid);
1892 return false;
1893 }
1894
1895
SS7M2UA(const NamedList & params)1896 SS7M2UA::SS7M2UA(const NamedList& params)
1897 : SignallingComponent(params.safe("SS7M2UA"),¶ms,"ss7-m2ua"),
1898 m_retrieve(50),
1899 m_iid(params.getIntValue(YSTRING("iid"),-1)),
1900 m_linkState(LinkDown), m_rpo(false),
1901 m_longSeq(false)
1902 {
1903 DDebug(DebugInfo,"Creating SS7M2UA [%p]",this);
1904 m_retrieve.interval(params,"retrieve",5,200,true);
1905 m_longSeq = params.getBoolValue(YSTRING("longsequence"));
1906 m_lastSeqRx = -2;
1907 }
1908
initialize(const NamedList * config)1909 bool SS7M2UA::initialize(const NamedList* config)
1910 {
1911 #ifdef DEBUG
1912 String tmp;
1913 if (config && debugAt(DebugAll))
1914 config->dump(tmp,"\r\n ",'\'',true);
1915 Debug(this,DebugInfo,"SS7M2UA::initialize(%p) [%p]%s",config,this,tmp.c_str());
1916 #endif
1917 m_autostart = !config || config->getBoolValue(YSTRING("autostart"),true);
1918 m_autoEmergency = !config || config->getBoolValue(YSTRING("autoemergency"),true);
1919 if (config && !adaptation()) {
1920 m_iid = config->getIntValue(YSTRING("iid"),m_iid);
1921 NamedList params("");
1922 if (resolveConfig(YSTRING("client"),params,config) ||
1923 resolveConfig(YSTRING("basename"),params,config)) {
1924 DDebug(this,DebugInfo,"Creating adaptation '%s' for SS7 M2UA [%p]",
1925 params.c_str(),this);
1926 params.addParam("basename",params);
1927 SS7M2UAClient* client =
1928 YOBJECT(SS7M2UAClient,engine()->build("SS7M2UAClient",params,false));
1929 if (!client)
1930 return false;
1931 adaptation(client);
1932 client->initialize(¶ms);
1933 TelEngine::destruct(client);
1934 }
1935 }
1936 return transport() && control(Resume,const_cast<NamedList*>(config));
1937 }
1938
control(Operation oper,NamedList * params)1939 bool SS7M2UA::control(Operation oper, NamedList* params)
1940 {
1941 if (params) {
1942 m_autostart = params->getBoolValue(YSTRING("autostart"),m_autostart);
1943 m_autoEmergency = params->getBoolValue(YSTRING("autoemergency"),m_autoEmergency);
1944 m_longSeq = params->getBoolValue(YSTRING("longsequence"),m_longSeq);
1945 }
1946 switch (oper) {
1947 case Pause:
1948 if (aspActive()) {
1949 DataBlock buf;
1950 if (m_iid >= 0)
1951 SIGAdaptation::addTag(buf,0x0001,(u_int32_t)m_iid);
1952 // Release Request
1953 if (!adaptation()->transmitMSG(SIGTRAN::MAUP,4,buf,getStreamId()))
1954 return TelEngine::controlReturn(params,false);
1955 getSequence();
1956 }
1957 m_linkState = LinkDown;
1958 if (!m_retrieve.started())
1959 SS7Layer2::notify();
1960 return TelEngine::controlReturn(params,true);
1961 case Resume:
1962 if (operational())
1963 return TelEngine::controlReturn(params,true);
1964 if (!m_autostart)
1965 return TelEngine::controlReturn(params,activate());
1966 if (m_retrieve.started()) {
1967 if (LinkDown == m_linkState)
1968 m_linkState = getEmergency(params,false) ? LinkReqEmg : LinkReq;
1969 return TelEngine::controlReturn(params,activate());
1970 }
1971 // fall through
1972 case Align:
1973 if (aspActive()) {
1974 if (operational()) {
1975 m_linkState = LinkDown;
1976 SS7Layer2::notify();
1977 }
1978 bool emg = (LinkUpEmg == m_linkState) || (LinkReqEmg == m_linkState);
1979 emg = getEmergency(params,emg);
1980 m_linkState = emg ? LinkReqEmg : LinkReq;
1981 DataBlock buf;
1982 if (m_iid >= 0)
1983 SIGAdaptation::addTag(buf,0x0001,(u_int32_t)m_iid);
1984 SIGAdaptation::addTag(buf,0x0302,(emg ? 2 : 3));
1985 // State Request
1986 if (!adaptation()->transmitMSG(SIGTRAN::MAUP,7,buf,getStreamId()))
1987 return TelEngine::controlReturn(params,false);
1988 buf.clear();
1989 if (m_iid >= 0)
1990 SIGAdaptation::addTag(buf,0x0001,(u_int32_t)m_iid);
1991 // Establish Request
1992 return TelEngine::controlReturn(params,
1993 adaptation()->transmitMSG(SIGTRAN::MAUP,2,buf,getStreamId()));
1994 }
1995 return TelEngine::controlReturn(params,activate());
1996 case Status:
1997 return TelEngine::controlReturn(params,operational());
1998 default:
1999 return TelEngine::controlReturn(params,false);
2000 }
2001 }
2002
status() const2003 unsigned int SS7M2UA::status() const
2004 {
2005 switch (m_linkState) {
2006 case LinkDown:
2007 return SS7Layer2::OutOfService;
2008 case LinkUp:
2009 return m_rpo ? SS7Layer2::ProcessorOutage : SS7Layer2::NormalAlignment;
2010 case LinkUpEmg:
2011 return m_rpo ? SS7Layer2::ProcessorOutage : SS7Layer2::EmergencyAlignment;
2012 }
2013 return SS7Layer2::OutOfAlignment;
2014 }
2015
transmitMSU(const SS7MSU & msu)2016 bool SS7M2UA::transmitMSU(const SS7MSU& msu)
2017 {
2018 if (msu.length() < 3) {
2019 Debug(this,DebugWarn,"Asked to send too short MSU of length %u [%p]",
2020 msu.length(),this);
2021 return false;
2022 }
2023 Lock mylock(adaptation());
2024 // If we don't have an attached interface don't bother
2025 if (!transport())
2026 return false;
2027 DataBlock buf;
2028 if (m_iid >= 0)
2029 SIGAdaptation::addTag(buf,0x0001,(u_int32_t)m_iid);
2030 SIGAdaptation::addTag(buf,0x0300,msu);
2031 // Data
2032 return adaptation()->transmitMSG(SIGTRAN::MAUP,1,buf,getStreamId());
2033 }
2034
recoverMSU(int sequence)2035 void SS7M2UA::recoverMSU(int sequence)
2036 {
2037 Lock mylock(adaptation());
2038 if (sequence >= 0 && aspUp() && transport()) {
2039 Debug(this,DebugInfo,"Retrieving MSUs from sequence %d from M2UA SG",sequence);
2040 DataBlock buf;
2041 if (m_iid >= 0)
2042 SIGAdaptation::addTag(buf,0x0001,(u_int32_t)m_iid);
2043 // Retrieve MSGS action
2044 SIGAdaptation::addTag(buf,0x0306,(u_int32_t)0);
2045 SIGAdaptation::addTag(buf,0x0307,(u_int32_t)sequence);
2046 // Data Retrieval Request
2047 adaptation()->transmitMSG(SIGTRAN::MAUP,10,buf,getStreamId());
2048 }
2049 }
2050
getSequence()2051 int SS7M2UA::getSequence()
2052 {
2053 if (m_lastSeqRx == -1) {
2054 m_lastSeqRx = -2;
2055 Lock mylock(adaptation());
2056 if (aspUp() && transport()) {
2057 Debug(this,DebugInfo,"Requesting sequence number from M2UA SG");
2058 DataBlock buf;
2059 if (m_iid >= 0)
2060 SIGAdaptation::addTag(buf,0x0001,(u_int32_t)m_iid);
2061 // Retrieve BSN action
2062 SIGAdaptation::addTag(buf,0x0306,(u_int32_t)1);
2063 // Data Retrieval Request
2064 if (adaptation()->transmitMSG(SIGTRAN::MAUP,10,buf,getStreamId()))
2065 m_retrieve.start();
2066 }
2067 }
2068 return m_lastSeqRx;
2069 }
2070
timerTick(const Time & when)2071 void SS7M2UA::timerTick(const Time& when)
2072 {
2073 SS7Layer2::timerTick(when);
2074 if (m_retrieve.timeout(when.msec())) {
2075 m_retrieve.stop();
2076 if (m_lastSeqRx == -2) {
2077 Debug(this,DebugWarn,"Sequence retrieval from M2UA SG timed out");
2078 SS7Layer2::notify();
2079 }
2080 if (m_linkState != LinkDown)
2081 control(Resume);
2082 }
2083 }
2084
processMGMT(unsigned char msgType,const DataBlock & msg,int streamId)2085 bool SS7M2UA::processMGMT(unsigned char msgType, const DataBlock& msg, int streamId)
2086 {
2087 const char* err = "Unhandled";
2088 switch (msgType) {
2089 case SIGTRAN::MgmtERR:
2090 {
2091 u_int32_t errCode = 0;
2092 if (SIGAdaptation::getTag(msg,0x000c,errCode)) {
2093 switch (errCode) {
2094 case 2:
2095 Debug(this,DebugWarn,"M2UA SG reported invalid IID=%d",m_iid);
2096 m_linkState = LinkDown;
2097 return true;
2098 default:
2099 Debug(this,DebugWarn,"M2UA SG reported error %u: %s",errCode,lookup(errCode,s_uaErrors,"Unknown"));
2100 return true;
2101 }
2102 }
2103 }
2104 err = "Error";
2105 break;
2106 }
2107 Debug(this,DebugStub,"%s M2UA MGMT message type %u",err,msgType);
2108 return false;
2109 }
2110
processMAUP(unsigned char msgType,const DataBlock & msg,int streamId)2111 bool SS7M2UA::processMAUP(unsigned char msgType, const DataBlock& msg, int streamId)
2112 {
2113 const char* err = "Unhandled";
2114 switch (msgType) {
2115 case 1: // Data
2116 {
2117 SS7MSU data;
2118 if (!SIGAdaptation::getTag(msg,0x0300,data)) {
2119 err = "Missing data in";
2120 break;
2121 }
2122 u_int32_t corrId;
2123 if (SIGAdaptation::getTag(msg,0x0013,corrId)) {
2124 // Correlation ID present, send Data Ack
2125 DataBlock buf;
2126 SIGAdaptation::addTag(buf,0x0013,corrId);
2127 adaptation()->transmitMSG(SIGTRAN::MAUP,15,buf,streamId);
2128 }
2129 return receivedMSU(data);
2130 }
2131 break;
2132 case 3: // Establish Confirm
2133 m_lastSeqRx = -1;
2134 m_linkState = LinkUp;
2135 m_congestion = 0;
2136 m_rpo = false;
2137 SS7Layer2::notify();
2138 return true;
2139 case 5: // Release Confirm
2140 case 6: // Release Indication
2141 activeChange(false);
2142 return true;
2143 case 8: // State Confirm
2144 err = "Ignoring";
2145 break;
2146 case 9: // State Indication
2147 {
2148 u_int32_t evt = 0;
2149 if (!SIGAdaptation::getTag(msg,0x0303,evt)) {
2150 err = "Missing state event";
2151 break;
2152 }
2153 bool oper = operational();
2154 switch (evt) {
2155 case 1:
2156 Debug(this,DebugInfo,"Remote entered Processor Outage");
2157 m_rpo = true;
2158 break;
2159 case 2:
2160 Debug(this,DebugInfo,"Remote exited Processor Outage");
2161 m_rpo = false;
2162 break;
2163 }
2164 if (operational() != oper)
2165 SS7Layer2::notify();
2166 }
2167 return true;
2168 case 11: // Data Retrieval Confirm
2169 {
2170 u_int32_t res = 0;
2171 if (!SIGAdaptation::getTag(msg,0x0308,res)) {
2172 err = "Missing retrieval result";
2173 break;
2174 }
2175 if (res) {
2176 err = "Retrieval failed";
2177 break;
2178 }
2179 if (SIGAdaptation::getTag(msg,0x0306,res) && (res == 1)) {
2180 // Action was BSN retrieval
2181 res = (u_int32_t)-1;
2182 if (!SIGAdaptation::getTag(msg,0x0307,res)) {
2183 err = "Missing BSN field in retrieval";
2184 m_lastSeqRx = -3;
2185 postRetrieve();
2186 break;
2187 }
2188 Debug(this,DebugInfo,"Recovered sequence number %u",res);
2189 if (m_longSeq || res & 0xffffff80)
2190 res = (res & 0x00ffffff) | 0x01000000;
2191 m_lastSeqRx = res;
2192 postRetrieve();
2193 return true;
2194 }
2195 }
2196 break;
2197 case 12: // Data Retrieval Indication
2198 case 13: // Data Retrieval Complete Indication
2199 {
2200 SS7MSU data;
2201 if (!SIGAdaptation::getTag(msg,0x0300,data)) {
2202 if (msgType == 13)
2203 return true;
2204 err = "Missing data in";
2205 break;
2206 }
2207 return recoveredMSU(data);
2208 }
2209 break;
2210 case 14: // Congestion Indication
2211 {
2212 u_int32_t cong = 0;
2213 if (!SIGAdaptation::getTag(msg,0x0304,cong)) {
2214 err = "Missing congestion state";
2215 break;
2216 }
2217 u_int32_t disc = 0;
2218 SIGAdaptation::getTag(msg,0x0305,disc);
2219 int level = disc ? DebugWarn : (cong ? DebugMild : DebugNote);
2220 Debug(this,level,"Congestion level %u, discard level %u",cong,disc);
2221 m_congestion = cong;
2222 }
2223 return true;
2224 }
2225 Debug(this,DebugStub,"%s M2UA MAUP message type %u",err,msgType);
2226 return false;
2227 }
2228
postRetrieve()2229 void SS7M2UA::postRetrieve()
2230 {
2231 if (!m_retrieve.started())
2232 return;
2233 m_retrieve.stop();
2234 SS7Layer2::notify();
2235 m_retrieve.fire(Time::msecNow()+100);
2236 }
2237
activeChange(bool active)2238 void SS7M2UA::activeChange(bool active)
2239 {
2240 if (!active) {
2241 getSequence();
2242 m_congestion = 0;
2243 m_rpo = false;
2244 switch (m_linkState) {
2245 case LinkUpEmg:
2246 m_linkState = LinkReqEmg;
2247 if (!m_retrieve.started())
2248 SS7Layer2::notify();
2249 break;
2250 case LinkUp:
2251 m_linkState = LinkReq;
2252 if (!m_retrieve.started())
2253 SS7Layer2::notify();
2254 break;
2255 case LinkReqEmg:
2256 case LinkReq:
2257 break;
2258 default:
2259 return;
2260 }
2261 }
2262 control(Resume);
2263 }
2264
operational() const2265 bool SS7M2UA::operational() const
2266 {
2267 return (m_linkState >= LinkUp) && !m_rpo;
2268 }
2269
2270 /**
2271 * ISDNIUAClient
2272 */
2273
processMSG(unsigned char msgVersion,unsigned char msgClass,unsigned char msgType,const DataBlock & msg,int streamId)2274 bool ISDNIUAClient::processMSG(unsigned char msgVersion, unsigned char msgClass,
2275 unsigned char msgType, const DataBlock& msg, int streamId)
2276 {
2277 u_int32_t iid = (u_int32_t)-1;
2278 if (MGMT == msgClass && getTag(msg,0x0001,iid)) {
2279 Lock mylock(this);
2280 for (ObjList* o = users().skipNull(); o; o = o->skipNext()) {
2281 AdaptUserPtr* p = static_cast<AdaptUserPtr*>(o->get());
2282 RefPointer<ISDNIUA> iua = static_cast<ISDNIUA*>(static_cast<SIGAdaptUser*>(*p));
2283 if (!iua || (iua->iid() != (int32_t)iid))
2284 continue;
2285 mylock.drop();
2286 return iua->processMGMT(msgType,msg,streamId);
2287 }
2288 Debug(this,DebugStub,"Unhandled IUA MGMT message type %u for IID=%u",msgType,iid);
2289 return false;
2290 }
2291 else if (QPTM != msgClass)
2292 return processCommonMSG(msgClass,msgType,msg,streamId);
2293 switch (msgType) {
2294 case 1: // Data Request Message
2295 case 3: // Unit Data Request Message
2296 case 5: // Establish Request
2297 case 8: // Release Request
2298 Debug(this,DebugWarn,"Received IUA SG request %u on ASP side!",msgType);
2299 return false;
2300 }
2301 getTag(msg,0x0001,iid);
2302 Lock mylock(this);
2303 for (ObjList* o = users().skipNull(); o; o = o->skipNext()) {
2304 AdaptUserPtr* p = static_cast<AdaptUserPtr*>(o->get());
2305 RefPointer<ISDNIUA> iua = static_cast<ISDNIUA*>(static_cast<SIGAdaptUser*>(*p));
2306 if (!iua || (iua->iid() != (int32_t)iid))
2307 continue;
2308 mylock.drop();
2309 return iua->processQPTM(msgType,msg,streamId);
2310 }
2311 Debug(this,DebugStub,"Unhandled IUA message type %u for IID=%d",msgType,(int32_t)iid);
2312 return false;
2313 }
2314
2315
ISDNIUA(const NamedList & params,const char * name,u_int8_t tei)2316 ISDNIUA::ISDNIUA(const NamedList& params, const char *name, u_int8_t tei)
2317 : SignallingComponent(params.safe(name ? name : "ISDNIUA"),¶ms,"isdn-iua"),
2318 ISDNLayer2(params,name,tei),
2319 m_iid(params.getIntValue(YSTRING("iid"),-1))
2320 {
2321 DDebug(DebugInfo,"Creating ISDNIUA [%p]",this);
2322 }
2323
~ISDNIUA()2324 ISDNIUA::~ISDNIUA()
2325 {
2326 Lock lock(l2Mutex());
2327 cleanup();
2328 ISDNLayer2::attach((ISDNLayer3*)0);
2329 }
2330
multipleFrame(u_int8_t tei,bool establish,bool force)2331 bool ISDNIUA::multipleFrame(u_int8_t tei, bool establish, bool force)
2332 {
2333 Lock lock(l2Mutex());
2334 if (!transport())
2335 return false;
2336 if ((localTei() != tei) || (state() == WaitEstablish) || (state() == WaitRelease))
2337 return false;
2338 if (!force &&
2339 ((establish && (state() == Established)) ||
2340 (!establish && (state() == Released))))
2341 return false;
2342 XDebug(this,DebugAll,"Process '%s' request, TEI=%u",
2343 establish ? "ESTABLISH" : "RELEASE",tei);
2344
2345 DataBlock buf;
2346 if (m_iid >= 0)
2347 SIGAdaptation::addTag(buf,0x0001,(u_int32_t)m_iid);
2348 u_int32_t dlci = 0x10000 | ((unsigned int)tei << 17);
2349 SIGAdaptation::addTag(buf,0x0005,dlci);
2350 if (establish)
2351 changeState(WaitEstablish,"multiple frame");
2352 else {
2353 SIGAdaptation::addTag(buf,0x000f,(u_int32_t)(force ? 2 : 0));
2354 changeState(WaitRelease,"multiple frame");
2355 multipleFrameReleased(tei,true,false);
2356 }
2357 // Establish Request or Release Request
2358 return adaptation()->transmitMSG(SIGTRAN::QPTM,(establish ? 5 : 8),buf,getStreamId());
2359 }
2360
sendData(const DataBlock & data,u_int8_t tei,bool ack)2361 bool ISDNIUA::sendData(const DataBlock& data, u_int8_t tei, bool ack)
2362 {
2363 if (data.null())
2364 return false;
2365 Lock lock(l2Mutex());
2366 if (!transport())
2367 return false;
2368 DataBlock buf;
2369 if (m_iid >= 0)
2370 SIGAdaptation::addTag(buf,0x0001,(u_int32_t)m_iid);
2371 u_int32_t dlci = 0x10000 | ((unsigned int)tei << 17);
2372 SIGAdaptation::addTag(buf,0x0005,dlci);
2373 SIGAdaptation::addTag(buf,0x000e,data);
2374 // Data Request Message or Unit Data Request Message
2375 return adaptation()->transmitMSG(SIGTRAN::QPTM,(ack ? 1 : 3),buf,getStreamId());
2376 }
2377
cleanup()2378 void ISDNIUA::cleanup()
2379 {
2380 Lock lock(l2Mutex());
2381 DDebug(this,DebugAll,"Cleanup in state '%s'",stateName(state()));
2382 if (state() == Established)
2383 multipleFrame(localTei(),false,true);
2384 changeState(Released,"cleanup");
2385 }
2386
processMGMT(unsigned char msgType,const DataBlock & msg,int streamId)2387 bool ISDNIUA::processMGMT(unsigned char msgType, const DataBlock& msg, int streamId)
2388 {
2389 const char* err = "Unhandled";
2390 switch (msgType) {
2391 case SIGTRAN::MgmtERR:
2392 {
2393 u_int32_t errCode = 0;
2394 if (SIGAdaptation::getTag(msg,0x000c,errCode)) {
2395 switch (errCode) {
2396 case 2:
2397 Debug(this,DebugWarn,"IUA SG reported invalid IID=%d",m_iid);
2398 changeState(Released,"invalid IID");
2399 multipleFrameReleased(localTei(),false,true);
2400 return true;
2401 case 10:
2402 Debug(this,DebugWarn,"IUA SG reported unassigned TEI");
2403 changeState(Released,"unassigned TEI");
2404 multipleFrameReleased(localTei(),false,true);
2405 return true;
2406 case 12:
2407 Debug(this,DebugWarn,"IUA SG reported unrecognized SAPI");
2408 changeState(Released,"unrecognized SAPI");
2409 multipleFrameReleased(localTei(),false,true);
2410 return true;
2411 default:
2412 Debug(this,DebugWarn,"IUA SG reported error %u: %s",errCode,lookup(errCode,s_uaErrors,"Unknown"));
2413 return true;
2414 }
2415 }
2416 }
2417 err = "Error";
2418 break;
2419 case 2: // TEI Status Request
2420 err = "Wrong direction TEI Status Request";
2421 break;
2422 case 3: // TEI Status Confirm
2423 case 4: // TEI Status Indication
2424 {
2425 u_int32_t status = 0;
2426 if (!SIGAdaptation::getTag(msg,0x0010,status)) {
2427 err = "Missing TEI status in";
2428 break;
2429 }
2430 u_int32_t dlci = 0;
2431 if (!SIGAdaptation::getTag(msg,0x0005,dlci)) {
2432 err = "Missing DLCI in";
2433 break;
2434 }
2435 u_int8_t tei = (dlci >> 17) & 0x7e;
2436 Debug(this,DebugNote,"%sTEI %u Status is %s",
2437 (localTei() == tei ? "Our " : ""),tei,
2438 (status ? "unassigned" : "assigned"));
2439 if (status && (localTei() == tei)) {
2440 changeState(Released,"unassigned TEI");
2441 multipleFrameReleased(localTei(),false,true);
2442 }
2443 return true;
2444 }
2445 case 5: // TEI Query Request
2446 err = "Wrong direction TEI Status Query";
2447 break;
2448 }
2449 Debug(this,DebugStub,"%s IUA MGMT message type %u",err,msgType);
2450 return false;
2451 }
2452
processQPTM(unsigned char msgType,const DataBlock & msg,int streamId)2453 bool ISDNIUA::processQPTM(unsigned char msgType, const DataBlock& msg, int streamId)
2454 {
2455 const char* err = "Unhandled";
2456 switch (msgType) {
2457 case 2: // Data Request Message
2458 case 4: // Unit Data Request Message
2459 {
2460 u_int32_t dlci = 0;
2461 if (!SIGAdaptation::getTag(msg,0x0005,dlci)) {
2462 err = "Missing DLCI in";
2463 break;
2464 }
2465 DataBlock data;
2466 if (!SIGAdaptation::getTag(msg,0x000e,data)) {
2467 err = "Missing data in";
2468 break;
2469 }
2470 receiveData(data,(dlci >> 17) & 0x7e);
2471 return true;
2472 }
2473 break;
2474 case 6: // Establish Confirm
2475 case 7: // Establish Indication
2476 changeState(Established);
2477 multipleFrameEstablished(localTei(),(6 == msgType),false);
2478 return true;
2479 case 9: // Release Confirm
2480 changeState(Released,"remote confirm");
2481 multipleFrameReleased(localTei(),true,false);
2482 return true;
2483 case 10: // Release Indication
2484 {
2485 u_int32_t reason = 0;
2486 if (SIGAdaptation::getTag(msg,0x000f,reason))
2487 Debug(this,DebugMild,"IUA SG released interface, reason %d",reason);
2488 else
2489 Debug(this,DebugMild,"IUA SG released interface, no reason");
2490 }
2491 changeState(Released,"remote indication");
2492 multipleFrameReleased(localTei(),false,true);
2493 return true;
2494 }
2495 Debug(this,DebugStub,"%s IUA QPTM message type %u",err,msgType);
2496 return false;
2497 }
2498
activeChange(bool active)2499 void ISDNIUA::activeChange(bool active)
2500 {
2501 if (active) {
2502 if (m_autostart)
2503 multipleFrame(localTei(),true,false);
2504 }
2505 else {
2506 changeState(Released,"remote inactive");
2507 multipleFrameReleased(localTei(),false,true);
2508 }
2509 }
2510
initialize(const NamedList * config)2511 bool ISDNIUA::initialize(const NamedList* config)
2512 {
2513 #ifdef DEBUG
2514 String tmp;
2515 if (config && debugAt(DebugAll))
2516 config->dump(tmp,"\r\n ",'\'',true);
2517 Debug(this,DebugInfo,"ISDNIUA::initialize(%p) [%p]%s",config,this,tmp.c_str());
2518 #endif
2519 m_autostart = !config || config->getBoolValue(YSTRING("autostart"),true);
2520 if (config && !adaptation()) {
2521 m_iid = config->getIntValue(YSTRING("iid"),m_iid);
2522 NamedList params("");
2523 if (resolveConfig(YSTRING("client"),params,config) ||
2524 resolveConfig(YSTRING("basename"),params,config)) {
2525 DDebug(this,DebugInfo,"Creating adaptation '%s' for ISDN UA [%p]",
2526 params.c_str(),this);
2527 params.addParam("basename",params);
2528 ISDNIUAClient* client =
2529 YOBJECT(ISDNIUAClient,engine()->build("ISDNIUAClient",params,false));
2530 if (!client)
2531 return false;
2532 adaptation(client);
2533 client->initialize(¶ms);
2534 TelEngine::destruct(client);
2535 }
2536 }
2537 if (!transport())
2538 return false;
2539 return (m_autostart && aspActive()) ? multipleFrame(localTei(),true,false) : activate();
2540 }
2541
2542 /* vi: set ts=8 sw=4 sts=4 noet: */
2543