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,&params);
352 	if (!tr)
353 	    return false;
354 	SIGTRAN::attach(tr);
355 	if (tr->initialize(&params))
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"),&params,"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,&params);
1093 	    if (!tr)
1094 		return false;
1095 	    SIGTRAN::attach(tr);
1096 	    if (!tr->initialize(&params))
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(&params,(cmd >= 0) && control((M2PAOperations)cmd,&params));
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"),&params,"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(&params);
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"),&params,"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(&params);
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