PageRenderTime 58ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/libs/ysig/management.cpp

https://bitbucket.org/daybologic/yate
C++ | 1213 lines | 1113 code | 47 blank | 53 comment | 357 complexity | 2e3c425469ffb214296edd950a4934dc MD5 | raw file
Possible License(s): GPL-2.0
  1. /**
  2. * management.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-2006 Null Team
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
  23. */
  24. #include "yatesig.h"
  25. #include <yatephone.h>
  26. #include <string.h>
  27. using namespace TelEngine;
  28. #define MAKE_NAME(x) { #x, SS7MsgSNM::x }
  29. static const TokenDict s_snm_names[] = {
  30. // this list must be kept in synch with the header
  31. MAKE_NAME(COO),
  32. MAKE_NAME(ECO),
  33. MAKE_NAME(RCT),
  34. MAKE_NAME(TFP),
  35. MAKE_NAME(RST),
  36. MAKE_NAME(RSP), // alias
  37. MAKE_NAME(LIN),
  38. MAKE_NAME(TRA),
  39. MAKE_NAME(DLC),
  40. MAKE_NAME(UPU),
  41. MAKE_NAME(COA),
  42. MAKE_NAME(ECA),
  43. MAKE_NAME(TFC),
  44. MAKE_NAME(TCP),
  45. MAKE_NAME(TFPA), // alias
  46. MAKE_NAME(RSR),
  47. MAKE_NAME(LUN),
  48. MAKE_NAME(TRW),
  49. MAKE_NAME(CSS),
  50. MAKE_NAME(XCO),
  51. MAKE_NAME(TFR),
  52. MAKE_NAME(RCP),
  53. MAKE_NAME(LIA),
  54. MAKE_NAME(CNS),
  55. MAKE_NAME(XCA),
  56. MAKE_NAME(TCR),
  57. MAKE_NAME(RCR),
  58. MAKE_NAME(LUA),
  59. MAKE_NAME(CNP),
  60. MAKE_NAME(CBD),
  61. MAKE_NAME(TFA),
  62. MAKE_NAME(LID),
  63. MAKE_NAME(CBA),
  64. MAKE_NAME(TCA),
  65. MAKE_NAME(TFAA), // alias
  66. MAKE_NAME(LFU),
  67. MAKE_NAME(LLT),
  68. MAKE_NAME(LLI), // alias
  69. MAKE_NAME(LRT),
  70. MAKE_NAME(LRI), // alias
  71. { 0, 0 }
  72. };
  73. static const TokenDict s_snm_group[] = {
  74. // this list must be kept in synch with the header
  75. MAKE_NAME(CHM),
  76. MAKE_NAME(ECM),
  77. MAKE_NAME(FCM),
  78. MAKE_NAME(TFM),
  79. MAKE_NAME(RSM),
  80. MAKE_NAME(MIM),
  81. MAKE_NAME(TRM),
  82. MAKE_NAME(DLM),
  83. MAKE_NAME(UFC),
  84. { 0, 0 }
  85. };
  86. #undef MAKE_NAME
  87. #define TIMER5M 300000
  88. namespace { //anonymous
  89. class SnmPending : public SignallingMessageTimer, public SS7Label
  90. {
  91. public:
  92. inline SnmPending(SS7MSU* msg, const SS7Label& label, int txSls, u_int64_t interval, u_int64_t global = 0)
  93. : SignallingMessageTimer(interval,global), SS7Label(label),
  94. m_msu(msg), m_txSls(txSls)
  95. { }
  96. inline ~SnmPending()
  97. { TelEngine::destruct(m_msu); }
  98. inline SS7MSU& msu() const
  99. { return *m_msu; }
  100. inline int txSls() const
  101. { return m_txSls; }
  102. inline SS7MsgSNM::Type snmType() const
  103. { return (SS7MsgSNM::Type)m_msu->at(length()+1,0); }
  104. inline const char* snmName() const
  105. { return SS7MsgSNM::lookup(snmType(),"Unknown"); }
  106. inline bool matches(const SS7Label& lbl) const
  107. { return opc() == lbl.dpc() && dpc() == lbl.opc() && sls() == lbl.sls(); }
  108. private:
  109. SS7MSU* m_msu;
  110. int m_txSls;
  111. };
  112. }; // anonymous namespace
  113. // Constructor
  114. SS7MsgSNM::SS7MsgSNM(unsigned char type)
  115. : SignallingMessage(lookup((Type)type,"Unknown")),
  116. m_type(type)
  117. {
  118. }
  119. void SS7MsgSNM::toString(String& dest, const SS7Label& label, bool params) const
  120. {
  121. const char* enclose = "\r\n-----";
  122. dest = enclose;
  123. dest << "\r\n" << name() << " [label=" << label << ']';
  124. if (params) {
  125. unsigned int n = m_params.length();
  126. for (unsigned int i = 0; i < n; i++) {
  127. NamedString* s = m_params.getParam(i);
  128. if (s)
  129. dest << "\r\n " << s->name() << "='" << *s << "'";
  130. }
  131. }
  132. dest << enclose;
  133. }
  134. // Parse a received buffer and build a message from it
  135. SS7MsgSNM* SS7MsgSNM::parse(SS7Management* receiver, unsigned char type,
  136. SS7PointCode::Type pcType, const unsigned char* buf, unsigned int len)
  137. {
  138. const char* pct = SS7PointCode::lookup(pcType);
  139. if (!pct)
  140. return 0;
  141. SS7MsgSNM* msg = new SS7MsgSNM(type);
  142. msg->params().addParam("pointcodetype",pct);
  143. #ifdef XDEBUG
  144. String tmp;
  145. tmp.hexify((void*)buf,len,' ');
  146. Debug(receiver,DebugAll,"Decoding msg=%s pctype=%s buf: %s [%p]",
  147. msg->name(),pct,tmp.c_str(),receiver);
  148. #endif
  149. // TODO: parse the rest of the message. Check extra bytes (message specific)
  150. if (!(buf && len))
  151. return msg;
  152. do {
  153. // TFP,TFR,TFA: Q.704 15.7, RST,RSR: Q.704 15.10
  154. // There must be at least 2 bytes in buffer
  155. if (type == TFP || type == TFR || type == TFA || type == TFC ||
  156. type == RST || type == RSR) {
  157. // 2 bytes destination
  158. SS7PointCode pc;
  159. unsigned char spare;
  160. if (pc.assign(pcType,buf,len,&spare)) {
  161. String tmp;
  162. tmp << pc;
  163. msg->params().addParam("destination",tmp);
  164. if (spare) {
  165. tmp.hexify(&spare,1);
  166. msg->params().addParam("spare",tmp);
  167. }
  168. }
  169. else
  170. Debug(receiver,DebugNote,
  171. "Failed to decode destination for msg=%s len=%u [%p]",
  172. msg->name(),len,receiver);
  173. break;
  174. }
  175. // COO,COA,XCO,XCA: changeover sequence, slc
  176. else if (type == COO || type == COA || type == XCO || type == XCA) {
  177. int seq = -1;
  178. int slc = -1;
  179. switch (pcType) {
  180. case SS7PointCode::ITU:
  181. if (len >= 1)
  182. seq = buf[0];
  183. if ((type == XCO || type == XCA) && (len >= 3))
  184. seq |= (((unsigned int)buf[1]) << 8) | (((unsigned int)buf[2]) << 16);
  185. break;
  186. case SS7PointCode::ANSI:
  187. if (len >= 2) {
  188. slc = buf[0] & 0x0f;
  189. seq = (buf[0] >> 4) | (((unsigned int)buf[1]) << 4);
  190. if ((type == XCO || type == XCA) && (len >= 4))
  191. seq |= (((unsigned int)buf[2]) << 12) | (((unsigned int)buf[3]) << 20);
  192. }
  193. break;
  194. default:
  195. Debug(DebugStub,"Please implement COO decoding for type %u",pcType);
  196. }
  197. if (seq >= 0)
  198. msg->params().addParam("sequence",String(seq));
  199. if (slc >= 0)
  200. msg->params().addParam("slc",String(slc));
  201. }
  202. // CBD,CBA: changeback code, slc
  203. else if (type == CBD || type == CBA) {
  204. int code = -1;
  205. int slc = -1;
  206. switch (pcType) {
  207. case SS7PointCode::ITU:
  208. if (len >= 1)
  209. code = buf[0];
  210. break;
  211. case SS7PointCode::ANSI:
  212. if (len >= 2) {
  213. slc = buf[0] & 0x0f;
  214. code = (buf[0] >> 4) | (((unsigned int)buf[1]) << 4);
  215. }
  216. break;
  217. default:
  218. Debug(DebugStub,"Please implement CBD decoding for type %u",pcType);
  219. }
  220. if (code >= 0)
  221. msg->params().addParam("code",String(code));
  222. if (slc >= 0)
  223. msg->params().addParam("slc",String(slc));
  224. }
  225. // UPU: user part ID, unavailability cause
  226. else if (type == UPU) {
  227. SS7PointCode pc;
  228. unsigned char spare;
  229. if (pc.assign(pcType,buf,len,&spare)) {
  230. String tmp;
  231. tmp << pc;
  232. msg->params().addParam("destination",tmp);
  233. if (spare) {
  234. tmp.hexify(&spare,1);
  235. msg->params().addParam("spare",tmp);
  236. }
  237. unsigned int dlen = SS7PointCode::length(pcType);
  238. if (dlen < len) {
  239. msg->params().addParam("part",String((unsigned int)buf[dlen] & 0x0f));
  240. msg->params().addParam("cause",String((unsigned int)buf[dlen] >> 4));
  241. }
  242. }
  243. else
  244. Debug(receiver,DebugNote,
  245. "Failed to decode destination for msg=%s len=%u [%p]",
  246. msg->name(),len,receiver);
  247. }
  248. } while (false);
  249. return msg;
  250. }
  251. const TokenDict* SS7MsgSNM::names()
  252. {
  253. return s_snm_names;
  254. }
  255. #define MAKE_NAME(x) { #x, SS7MsgMTN::x }
  256. static const TokenDict s_mtn_names[] = {
  257. // this list must be kept in synch with the header
  258. MAKE_NAME(SLTM),
  259. MAKE_NAME(SLTA),
  260. { 0, 0 }
  261. };
  262. #undef MAKE_NAME
  263. const TokenDict* SS7MsgMTN::names()
  264. {
  265. return s_mtn_names;
  266. }
  267. // Control operations
  268. static const TokenDict s_dict_control[] = {
  269. { "prohibit", SS7MsgSNM::TFP },
  270. { "restrict", SS7MsgSNM::TFR },
  271. { "congest", SS7MsgSNM::TFC },
  272. { "allow", SS7MsgSNM::TFA },
  273. { "restart", SS7MsgSNM::TRA },
  274. { "changeover", SS7MsgSNM::COO },
  275. { "changeback", SS7MsgSNM::CBD },
  276. { "link-inhibit", SS7MsgSNM::LIN },
  277. { "link-uninhibit", SS7MsgSNM::LUN },
  278. { "link-force-uninhibit", SS7MsgSNM::LFU },
  279. { "test-congestion", SS7MsgSNM::RCT },
  280. { "test-prohibited", SS7MsgSNM::RST },
  281. { "test-restricted", SS7MsgSNM::RSR },
  282. { 0, 0 }
  283. };
  284. SS7Management::SS7Management(const NamedList& params, unsigned char sio)
  285. : SignallingComponent(params.safe("SS7Management"),&params,"ss7-snm"),
  286. SS7Layer4(sio,&params),
  287. m_changeMsgs(true), m_changeSets(false), m_neighbours(true)
  288. {
  289. m_changeMsgs = params.getBoolValue(YSTRING("changemsgs"),m_changeMsgs);
  290. m_changeSets = params.getBoolValue(YSTRING("changesets"),m_changeSets);
  291. m_neighbours = params.getBoolValue(YSTRING("neighbours"),m_neighbours);
  292. }
  293. HandledMSU SS7Management::receivedMSU(const SS7MSU& msu, const SS7Label& label, SS7Layer3* network, int sls)
  294. {
  295. if (msu.getSIF() != sif())
  296. return HandledMSU::Rejected;
  297. if (network) {
  298. unsigned int local = network->getLocal(label.type());
  299. if (local && label.dpc().pack(label.type()) != local)
  300. return HandledMSU::Rejected;
  301. }
  302. SS7Router* router = YOBJECT(SS7Router,SS7Layer4::network());
  303. if (router && (router != network)) {
  304. unsigned int local = router->getLocal(label.type());
  305. if (local && label.dpc().pack(label.type()) != local)
  306. return HandledMSU::Rejected;
  307. }
  308. unsigned int len = msu.length() - label.length() - 1;
  309. // according to Q.704 there should be at least the heading codes (8 bit)
  310. const unsigned char* buf = msu.getData(label.length()+1,1);
  311. if (!buf)
  312. return false;
  313. SS7MsgSNM* msg = SS7MsgSNM::parse(this,buf[0],label.type(),buf+1,len-1);
  314. if (!msg)
  315. return false;
  316. if (debugAt(DebugInfo)) {
  317. String tmp;
  318. msg->toString(tmp,label,debugAt(DebugAll));
  319. const char* name = network ? network->toString().c_str() : 0;
  320. Debug(this,DebugInfo,"Received %u bytes message (%p) on %s:%d%s",
  321. len,msg,name,sls,tmp.c_str());
  322. }
  323. String addr;
  324. addr << label;
  325. if (m_neighbours && (msg->type() != SS7MsgSNM::UPU)) {
  326. int prio = -1;
  327. if (router)
  328. prio = (int)router->getRoutePriority(label.type(),label.opc());
  329. else if (network)
  330. prio = (int)network->getRoutePriority(label.type(),label.opc());
  331. if (prio) {
  332. Debug(this,DebugMild,"Refusing %s message from %s node %s",
  333. msg->name(),(prio > 0 ? "non-neighboor" : "unknown"),addr.c_str());
  334. return false;
  335. }
  336. }
  337. SS7Label lbl(label,label.sls(),0);
  338. {
  339. String tmp;
  340. tmp << SS7PointCode::lookup(label.type()) << "," << addr;
  341. // put the addresses with commas as we need them
  342. char* fix = const_cast<char*>(tmp.c_str());
  343. for (; *fix; fix++)
  344. if (':' == *fix)
  345. *fix = ',';
  346. msg->params().addParam("address",tmp);
  347. tmp.clear();
  348. tmp << SS7PointCode::lookup(label.type()) << "," << lbl;
  349. fix = const_cast<char*>(tmp.c_str());
  350. for (; *fix; fix++)
  351. if (':' == *fix)
  352. *fix = ',';
  353. msg->params().addParam("back-address",tmp);
  354. }
  355. switch (msg->group()) {
  356. case SS7MsgSNM::CHM:
  357. case SS7MsgSNM::ECM:
  358. case SS7MsgSNM::MIM:
  359. {
  360. // for ANSI the SLC is not stored in SLS but in a separate field
  361. int slc = msg->params().getIntValue(YSTRING("slc"),-1);
  362. if (slc >= 0 && slc <= 255)
  363. lbl.setSls((unsigned char)slc);
  364. }
  365. // check if the addressed link exists
  366. if (router && !router->inhibit(lbl,0,0)) {
  367. Debug(this,DebugMild,"Received %s for inexistent %s on SLS %d [%p]",
  368. msg->name(),addr.c_str(),sls,this);
  369. return false;
  370. }
  371. }
  372. if (msg->type() == SS7MsgSNM::TFP ||
  373. msg->type() == SS7MsgSNM::TFR ||
  374. msg->type() == SS7MsgSNM::TFA ||
  375. msg->type() == SS7MsgSNM::TFC ||
  376. msg->type() == SS7MsgSNM::RST ||
  377. msg->type() == SS7MsgSNM::RSR) {
  378. String dest = msg->params().getValue(YSTRING("destination"));
  379. if (!dest.null()) {
  380. const char* oper = lookup(msg->type(),s_dict_control);
  381. Debug(this,DebugInfo,"%s (label=%s): Traffic %s to dest=%s [%p]",
  382. msg->name(),addr.c_str(),oper,dest.c_str(),this);
  383. if (router && oper) {
  384. NamedList* ctrl = router->controlCreate(oper);
  385. if (ctrl) {
  386. ctrl->copyParams(msg->params());
  387. ctrl->setParam("automatic",String::boolText(true));
  388. router->controlExecute(ctrl);
  389. }
  390. }
  391. }
  392. else
  393. Debug(this,DebugNote,"Received %s (label=%s) without destination [%p]",
  394. msg->name(),addr.c_str(),this);
  395. }
  396. else if (msg->type() == SS7MsgSNM::TRA) {
  397. String dest;
  398. dest << label.opc();
  399. Debug(this,DebugInfo,"%s (label=%s): Traffic can restart to dest=%s [%p]",
  400. msg->name(),addr.c_str(),dest.c_str(),this);
  401. if (router) {
  402. NamedList* ctrl = router->controlCreate("allowed");
  403. if (ctrl) {
  404. ctrl->copyParams(msg->params());
  405. ctrl->setParam("destination",dest);
  406. ctrl->setParam("automatic",String::boolText(true));
  407. router->controlExecute(ctrl);
  408. }
  409. }
  410. }
  411. else if (msg->type() == SS7MsgSNM::COO ||
  412. msg->type() == SS7MsgSNM::XCO ||
  413. msg->type() == SS7MsgSNM::ECO) {
  414. if (!len--)
  415. return false;
  416. const unsigned char* s = msu.getData(label.length()+2,len);
  417. if (!s)
  418. return false;
  419. Debug(this,DebugAll,"%s (code len=%u) [%p]",msg->name(),len,this);
  420. if (!m_changeMsgs)
  421. return true;
  422. if (inhibit(lbl,SS7Layer2::Inactive)) {
  423. String link;
  424. link << msg->params().getValue(YSTRING("pointcodetype")) << "," << lbl;
  425. Debug(this,DebugNote,"Changeover order on %s",link.c_str());
  426. int seq = msg->params().getIntValue(YSTRING("sequence"),-1);
  427. if (seq >= 0)
  428. recover(lbl,seq);
  429. seq = router ? router->getSequence(lbl) : -1;
  430. if (seq >= 0) {
  431. int len = 2;
  432. unsigned char data[5];
  433. data[0] = SS7MsgSNM::COA;
  434. if (seq & 0xff000000) {
  435. seq &= 0x00ffffff;
  436. if (msg->type() != SS7MsgSNM::COO || (seq & 0x00ffff80)) {
  437. data[0] = SS7MsgSNM::XCA;
  438. len += 2;
  439. }
  440. }
  441. switch (label.type()) {
  442. case SS7PointCode::ITU:
  443. data[1] = (unsigned char)seq;
  444. if (len >= 4) {
  445. data[2] = (unsigned char)(seq >> 8);
  446. data[3] = (unsigned char)(seq >> 16);
  447. }
  448. break;
  449. case SS7PointCode::ANSI:
  450. data[1] = (unsigned char)((msg->params().getIntValue(YSTRING("slc"),sls) & 0x0f) | (seq << 4));
  451. data[2] = (unsigned char)(seq >> 4);
  452. len++;
  453. if (len >= 5) {
  454. data[3] = (unsigned char)(seq >> 12);
  455. data[4] = (unsigned char)(seq >> 20);
  456. }
  457. break;
  458. default:
  459. Debug(DebugStub,"Please implement COO for type %u",label.type());
  460. return false;
  461. }
  462. return transmitMSU(SS7MSU(msu.getSIO(),lbl,&data,len),lbl,sls) >= 0;
  463. }
  464. else {
  465. // postpone an ECA in case we are unable to send a COA/XCA
  466. static unsigned char data = SS7MsgSNM::ECA;
  467. return postpone(new SS7MSU(msu.getSIO(),lbl,&data,1),lbl,sls,0,200);
  468. }
  469. }
  470. else
  471. Debug(this,DebugMild,"Unexpected %s %s [%p]",msg->name(),addr.c_str(),this);
  472. }
  473. else if (msg->type() == SS7MsgSNM::COA ||
  474. msg->type() == SS7MsgSNM::XCA ||
  475. msg->type() == SS7MsgSNM::ECA) {
  476. if (!len--)
  477. return false;
  478. Debug(this,DebugAll,"%s (code len=%u) [%p]",msg->name(),len,this);
  479. if (!m_changeMsgs)
  480. return true;
  481. lock();
  482. SnmPending* pend = 0;
  483. for (ObjList* l = m_pending.skipNull(); l; l = l->skipNext()) {
  484. SnmPending* p = static_cast<SnmPending*>(l->get());
  485. const unsigned char* ptr = p->msu().getData(p->length()+1,1);
  486. if (!(ptr && p->matches(label)))
  487. continue;
  488. switch (ptr[0]) {
  489. case SS7MsgSNM::COO:
  490. case SS7MsgSNM::XCO:
  491. case SS7MsgSNM::ECO:
  492. break;
  493. default:
  494. continue;
  495. }
  496. pend = static_cast<SnmPending*>(m_pending.remove(p,false));
  497. break;
  498. }
  499. unlock();
  500. if (pend) {
  501. String link;
  502. link << msg->params().getValue(YSTRING("pointcodetype")) << "," << *pend;
  503. Debug(this,DebugNote,"Changeover acknowledged on %s",link.c_str());
  504. inhibit(*pend,SS7Layer2::Inactive);
  505. int seq = msg->params().getIntValue(YSTRING("sequence"),-1);
  506. if (seq >= 0)
  507. recover(*pend,seq);
  508. }
  509. else
  510. Debug(this,DebugMild,"Unexpected %s %s [%p]",msg->name(),addr.c_str(),this);
  511. TelEngine::destruct(pend);
  512. }
  513. else if (msg->type() == SS7MsgSNM::CBD) {
  514. if (!len--)
  515. return false;
  516. const unsigned char* s = msu.getData(label.length()+2,len);
  517. if (!s)
  518. return false;
  519. Debug(this,DebugAll,"%s (code len=%u) [%p]",msg->name(),len,this);
  520. if (!m_changeMsgs)
  521. return true;
  522. if (inhibit(lbl,0,SS7Layer2::Inactive)) {
  523. String link;
  524. link << msg->params().getValue(YSTRING("pointcodetype")) << "," << lbl;
  525. Debug(this,DebugNote,"Changeback declaration on %s",link.c_str());
  526. SS7MSU answer(msu.getSIO(),lbl,0,len+1);
  527. unsigned char* d = answer.getData(lbl.length()+1,len+1);
  528. if (!d)
  529. return false;
  530. *d++ = SS7MsgSNM::CBA;
  531. while (len--)
  532. *d++ = *s++;
  533. return transmitMSU(answer,lbl,sls) >= 0;
  534. }
  535. else
  536. Debug(this,DebugMild,"Unexpected %s %s [%p]",msg->name(),addr.c_str(),this);
  537. }
  538. else if (msg->type() == SS7MsgSNM::CBA) {
  539. if (!len--)
  540. return false;
  541. Debug(this,DebugAll,"%s (code len=%u) [%p]",msg->name(),len,this);
  542. if (!m_changeMsgs)
  543. return true;
  544. lock();
  545. SnmPending* pend = 0;
  546. for (ObjList* l = m_pending.skipNull(); l; l = l->skipNext()) {
  547. SnmPending* p = static_cast<SnmPending*>(l->get());
  548. if (p->msu().length() != msu.length())
  549. continue;
  550. const unsigned char* ptr = p->msu().getData(p->length()+1,len+1);
  551. if (!ptr || (ptr[0] != SS7MsgSNM::CBD))
  552. continue;
  553. if (::memcmp(ptr+1,buf+1,len) || !p->matches(label))
  554. continue;
  555. pend = static_cast<SnmPending*>(m_pending.remove(p,false));
  556. break;
  557. }
  558. unlock();
  559. if (pend) {
  560. String link;
  561. link << msg->params().getValue(YSTRING("pointcodetype")) << "," << *pend;
  562. Debug(this,DebugNote,"Changeback acknowledged on %s",link.c_str());
  563. inhibit(*pend,0,SS7Layer2::Inactive);
  564. }
  565. else
  566. Debug(this,DebugMild,"Unexpected %s %s [%p]",msg->name(),addr.c_str(),this);
  567. TelEngine::destruct(pend);
  568. }
  569. else if (msg->type() == SS7MsgSNM::LIN) {
  570. Debug(this,DebugAll,"%s (code len=%u) [%p]",msg->name(),len,this);
  571. if (router) {
  572. bool ok = router->inhibit(lbl,SS7Layer2::Remote,0,true);
  573. unsigned char data = ok ? SS7MsgSNM::LIA : SS7MsgSNM::LID;
  574. if (ok) {
  575. static unsigned char lrt = SS7MsgSNM::LRT;
  576. postpone(new SS7MSU(msu.getSIO(),lbl,&lrt,1),lbl,sls,0,TIMER5M);
  577. }
  578. return transmitMSU(SS7MSU(msu.getSIO(),lbl,&data,1),lbl,sls) >= 0;
  579. }
  580. }
  581. else if (msg->type() == SS7MsgSNM::LIA || msg->type() == SS7MsgSNM::LUA) {
  582. Debug(this,DebugAll,"%s (code len=%u) [%p]",msg->name(),len,this);
  583. unsigned char test = (msg->type() == SS7MsgSNM::LIA) ? SS7MsgSNM::LIN : SS7MsgSNM::LUN;
  584. lock();
  585. SnmPending* pend = 0;
  586. for (ObjList* l = m_pending.skipNull(); l; l = l->skipNext()) {
  587. SnmPending* p = static_cast<SnmPending*>(l->get());
  588. const unsigned char* ptr = p->msu().getData(p->length()+1,1);
  589. if (!(ptr && p->matches(label)))
  590. continue;
  591. if (ptr[0] != test)
  592. continue;
  593. pend = static_cast<SnmPending*>(m_pending.remove(p,false));
  594. break;
  595. }
  596. unlock();
  597. if (pend) {
  598. if (test == SS7MsgSNM::LIN) {
  599. inhibit(*pend,SS7Layer2::Local);
  600. static unsigned char llt = SS7MsgSNM::LLT;
  601. postpone(new SS7MSU(msu.getSIO(),*pend,&llt,1),*pend,sls,0,TIMER5M);
  602. }
  603. else {
  604. inhibit(*pend,0,SS7Layer2::Local);
  605. lock();
  606. for (ObjList* l = m_pending.skipNull(); l; l = l->skipNext()) {
  607. SnmPending* p = static_cast<SnmPending*>(l->get());
  608. const unsigned char* ptr = p->msu().getData(p->length()+1,1);
  609. if (!ptr || (ptr[0] != SS7MsgSNM::LLT))
  610. continue;
  611. if (!p->matches(label))
  612. continue;
  613. m_pending.remove(p);
  614. break;
  615. }
  616. unlock();
  617. }
  618. }
  619. else
  620. Debug(this,DebugMild,"Unexpected %s %s [%p]",msg->name(),addr.c_str(),this);
  621. }
  622. else if (msg->type() == SS7MsgSNM::LUN) {
  623. Debug(this,DebugAll,"%s (code len=%u) [%p]",msg->name(),len,this);
  624. if (router && router->inhibit(lbl,0,SS7Layer2::Remote)) {
  625. lock();
  626. for (ObjList* l = m_pending.skipNull(); l; ) {
  627. SnmPending* p = static_cast<SnmPending*>(l->get());
  628. const unsigned char* ptr = p->msu().getData(p->length()+1,1);
  629. if (ptr && ((ptr[0] == SS7MsgSNM::LRT) || (ptr[0] == SS7MsgSNM::LFU)) && p->matches(label)) {
  630. m_pending.remove(p);
  631. l = m_pending.skipNull();
  632. }
  633. else
  634. l = l->skipNext();
  635. }
  636. unlock();
  637. static unsigned char lua = SS7MsgSNM::LUA;
  638. return transmitMSU(SS7MSU(msu.getSIO(),lbl,&lua,1),lbl,sls) >= 0;
  639. }
  640. }
  641. else if (msg->type() == SS7MsgSNM::LID) {
  642. Debug(this,DebugAll,"%s (code len=%u) [%p]",msg->name(),len,this);
  643. bool found = false;
  644. lock();
  645. for (ObjList* l = m_pending.skipNull(); l; l = l->skipNext()) {
  646. SnmPending* p = static_cast<SnmPending*>(l->get());
  647. const unsigned char* ptr = p->msu().getData(p->length()+1,1);
  648. if (!ptr || (ptr[0] != SS7MsgSNM::LIN))
  649. continue;
  650. if (!p->matches(label))
  651. continue;
  652. m_pending.remove(p);
  653. found = true;
  654. break;
  655. }
  656. unlock();
  657. if (found)
  658. Debug(this,DebugWarn,"Remote refused to inhibit link %d",label.sls());
  659. else
  660. Debug(this,DebugMild,"Unexpected %s %s [%p]",msg->name(),addr.c_str(),this);
  661. }
  662. else if (msg->type() == SS7MsgSNM::LFU) {
  663. Debug(this,DebugAll,"%s (code len=%u) [%p]",msg->name(),len,this);
  664. static unsigned char data = SS7MsgSNM::LUN;
  665. int global = 0;
  666. // if link is locally inhibited execute the complete procedure
  667. if (router && router->inhibited(lbl,SS7Layer2::Local))
  668. global = 2400;
  669. return postpone(new SS7MSU(msu.getSIO(),lbl,&data,1),lbl,sls,1200,global);
  670. }
  671. else if (msg->type() == SS7MsgSNM::LRT) {
  672. Debug(this,DebugAll,"%s (code len=%u) [%p]",msg->name(),len,this);
  673. if (router && router->inhibited(lbl,SS7Layer2::Local))
  674. return true;
  675. static unsigned char data = SS7MsgSNM::LUN;
  676. return postpone(new SS7MSU(msu.getSIO(),lbl,&data,1),lbl,sls,1200,2400);
  677. }
  678. else if (msg->type() == SS7MsgSNM::LLT) {
  679. Debug(this,DebugAll,"%s (code len=%u) [%p]",msg->name(),len,this);
  680. if (router && router->inhibited(lbl,SS7Layer2::Remote))
  681. return true;
  682. static unsigned char data = SS7MsgSNM::LFU;
  683. return postpone(new SS7MSU(msu.getSIO(),lbl,&data,1),lbl,sls,1200,2400);
  684. }
  685. else if (msg->type() == SS7MsgSNM::UPU) {
  686. Debug(this,DebugNote,"Unavailable part %s at %s, cause %s",
  687. msg->params().getValue(YSTRING("part"),"?"),
  688. msg->params().getValue(YSTRING("destination"),"?"),
  689. msg->params().getValue(YSTRING("cause"),"?"));
  690. if (router) {
  691. unsigned char part = msg->params().getIntValue(YSTRING("part"),-1);
  692. unsigned char cause = msg->params().getIntValue(YSTRING("cause"),-1);
  693. SS7PointCode pc;
  694. if (part > SS7MSU::MTNS && part <= 0x0f && cause <= 0x0f &&
  695. pc.assign(msg->params().getValue(YSTRING("destination")),label.type()))
  696. router->receivedUPU(label.type(),pc,(SS7MSU::Services)part,
  697. cause,label,sls);
  698. }
  699. }
  700. else {
  701. String tmp;
  702. tmp.hexify((void*)buf,len,' ');
  703. String params;
  704. unsigned int n = msg->params().count();
  705. if (n)
  706. for (unsigned int i = 0; i < n; i++) {
  707. NamedString* ns = static_cast<NamedString*>(msg->params().getParam(i));
  708. if (ns)
  709. params.append(String(ns->name()) + "=" + *ns,",");
  710. }
  711. Debug(this,DebugMild,
  712. "Unhandled SNM type=%s group=%s label=%s params:%s len=%u: %s ",
  713. msg->name(),lookup(msg->group(),s_snm_group,"Spare"),
  714. addr.c_str(),params.c_str(),len,tmp.c_str());
  715. }
  716. TelEngine::destruct(msg);
  717. return true;
  718. }
  719. bool SS7Management::control(NamedList& params)
  720. {
  721. String* ret = params.getParam(YSTRING("completion"));
  722. const String* oper = params.getParam(YSTRING("operation"));
  723. const char* cmp = params.getValue(YSTRING("component"));
  724. int cmd = -1;
  725. if (!TelEngine::null(oper)) {
  726. cmd = oper->toInteger(s_dict_control,cmd);
  727. if (cmd < 0)
  728. cmd = oper->toInteger(s_snm_names,cmd);
  729. }
  730. if (ret) {
  731. if (oper && (cmd < 0))
  732. return false;
  733. String part = params.getValue(YSTRING("partword"));
  734. if (cmp) {
  735. if (toString() != cmp)
  736. return false;
  737. for (const TokenDict* d = s_dict_control; d->token; d++)
  738. Module::itemComplete(*ret,d->token,part);
  739. return true;
  740. }
  741. return Module::itemComplete(*ret,toString(),part);
  742. }
  743. if (!(cmp && toString() == cmp))
  744. return false;
  745. m_changeMsgs = params.getBoolValue(YSTRING("changemsgs"),m_changeMsgs);
  746. m_changeSets = params.getBoolValue(YSTRING("changesets"),m_changeSets);
  747. m_neighbours = params.getBoolValue(YSTRING("neighbours"),m_neighbours);
  748. const String* addr = params.getParam(YSTRING("address"));
  749. if (cmd < 0 || TelEngine::null(addr))
  750. return SignallingComponent::control(params);
  751. // TYPE,opc,dpc,sls,spare
  752. SS7PointCode::Type t = SS7PointCode::Other;
  753. ObjList* l = addr->split(',');
  754. if (l->at(0) && (t = SS7PointCode::lookup(l->at(0)->toString())) != SS7PointCode::Other) {
  755. unsigned char netInd = ni();
  756. if (network())
  757. netInd = network()->getNI(t,netInd);
  758. unsigned char txSio = getSIO(params,ssf(),prio(),netInd);
  759. SS7PointCode opc,dpc;
  760. int sls = -1;
  761. int spare = 0;
  762. if (l->at(1) && opc.assign(l->at(1)->toString(),t) &&
  763. l->at(2) && dpc.assign(l->at(2)->toString(),t)) {
  764. if (l->at(3))
  765. sls = l->at(3)->toString().toInteger(sls);
  766. if (l->at(4))
  767. spare = l->at(4)->toString().toInteger(spare);
  768. TelEngine::destruct(l);
  769. SS7Label lbl(t,dpc,opc,sls,spare);
  770. int txSls = sls;
  771. switch (cmd) {
  772. case SS7MsgSNM::COO:
  773. case SS7MsgSNM::COA:
  774. case SS7MsgSNM::XCO:
  775. case SS7MsgSNM::XCA:
  776. case SS7MsgSNM::CBD:
  777. case SS7MsgSNM::CBA:
  778. case SS7MsgSNM::LIN:
  779. case SS7MsgSNM::LIA:
  780. case SS7MsgSNM::LID:
  781. case SS7MsgSNM::LUN:
  782. case SS7MsgSNM::LUA:
  783. case SS7MsgSNM::LFU:
  784. txSls = (txSls + 1) & 0xff;
  785. }
  786. txSls = params.getIntValue(YSTRING("linksel"),txSls) & 0xff;
  787. String tmp;
  788. tmp << SS7PointCode::lookup(lbl.type()) << "," << lbl;
  789. Debug(this,DebugAll,"Sending %s to %s on %d [%p]",
  790. SS7MsgSNM::lookup((SS7MsgSNM::Type)cmd),tmp.c_str(),txSls,this);
  791. switch (cmd) {
  792. // Messages containing a destination point code
  793. case SS7MsgSNM::TFP:
  794. case SS7MsgSNM::TFA:
  795. case SS7MsgSNM::TFR:
  796. case SS7MsgSNM::TFC:
  797. case SS7MsgSNM::RST:
  798. case SS7MsgSNM::RSR:
  799. {
  800. addr = params.getParam(YSTRING("destination"));
  801. SS7PointCode dest(opc);
  802. if (TelEngine::null(addr) || dest.assign(*addr,t)) {
  803. unsigned char data[5];
  804. int len = SS7PointCode::length(t)+1;
  805. data[0] = cmd;
  806. return dest.store(t,data+1,spare) &&
  807. ((cmd == SS7MsgSNM::TFP) ?
  808. postpone(new SS7MSU(txSio,lbl,data,len),lbl,txSls,1000) :
  809. (transmitMSU(SS7MSU(txSio,lbl,data,len),lbl,txSls) >= 0));
  810. }
  811. }
  812. return false;
  813. // Messages sent with just the code
  814. case SS7MsgSNM::ECO:
  815. case SS7MsgSNM::TRA:
  816. case SS7MsgSNM::LIA:
  817. case SS7MsgSNM::LUA:
  818. case SS7MsgSNM::LID:
  819. case SS7MsgSNM::LLT:
  820. case SS7MsgSNM::LRT:
  821. case SS7MsgSNM::RCT:
  822. case SS7MsgSNM::CSS:
  823. case SS7MsgSNM::CNS:
  824. case SS7MsgSNM::CNP:
  825. {
  826. unsigned char data = cmd;
  827. return transmitMSU(SS7MSU(txSio,lbl,&data,1),lbl,txSls) >= 0;
  828. }
  829. // Messages postponed with just the code
  830. case SS7MsgSNM::LIN:
  831. {
  832. unsigned char data = cmd;
  833. return postpone(new SS7MSU(txSio,lbl,&data,1),lbl,txSls,2500,5000);
  834. }
  835. case SS7MsgSNM::LUN:
  836. case SS7MsgSNM::LFU:
  837. {
  838. unsigned char data = cmd;
  839. return postpone(new SS7MSU(txSio,lbl,&data,1),lbl,txSls,1200,2400);
  840. }
  841. // Changeover messages
  842. case SS7MsgSNM::COO:
  843. case SS7MsgSNM::COA:
  844. case SS7MsgSNM::XCO:
  845. case SS7MsgSNM::XCA:
  846. if (params.getBoolValue(YSTRING("emergency"),false)) {
  847. unsigned char data = (SS7MsgSNM::COO == cmd) ? SS7MsgSNM::ECO : SS7MsgSNM::ECA;
  848. return transmitMSU(SS7MSU(txSio,lbl,&data,1),lbl,txSls) >= 0;
  849. }
  850. else {
  851. int seq = params.getIntValue(YSTRING("sequence"),0) & 0x00ffffff;
  852. if (SS7MsgSNM::COO == cmd || SS7MsgSNM::COA == cmd)
  853. seq &= 0x7f;
  854. int len = 2;
  855. unsigned char data[5];
  856. data[0] = cmd;
  857. switch (t) {
  858. case SS7PointCode::ITU:
  859. data[1] = (unsigned char)seq;
  860. if (SS7MsgSNM::XCO == cmd || SS7MsgSNM::XCA == cmd) {
  861. data[2] = (unsigned char)(seq >> 8);
  862. data[3] = (unsigned char)(seq >> 16);
  863. len += 2;
  864. }
  865. break;
  866. case SS7PointCode::ANSI:
  867. data[1] = (unsigned char)((params.getIntValue(YSTRING("slc"),sls) & 0x0f) | (seq << 4));
  868. data[2] = (unsigned char)(seq >> 4);
  869. len = 3;
  870. if (SS7MsgSNM::XCO == cmd || SS7MsgSNM::XCA == cmd) {
  871. data[3] = (unsigned char)(seq >> 12);
  872. data[4] = (unsigned char)(seq >> 20);
  873. len += 2;
  874. }
  875. break;
  876. default:
  877. Debug(DebugStub,"Please implement COO for type %u",t);
  878. return false;
  879. }
  880. return (cmd == SS7MsgSNM::COA)
  881. ? transmitMSU(SS7MSU(txSio,lbl,&data,len),lbl,txSls) >= 0
  882. : postpone(new SS7MSU(txSio,lbl,&data,len),lbl,txSls,1800,0,true);
  883. }
  884. // Changeback messages
  885. case SS7MsgSNM::CBD:
  886. case SS7MsgSNM::CBA:
  887. {
  888. int code = params.getIntValue(YSTRING("code"),0);
  889. int len = 2;
  890. unsigned char data[3];
  891. data[0] = cmd;
  892. switch (t) {
  893. case SS7PointCode::ITU:
  894. data[1] = (unsigned char)code;
  895. break;
  896. case SS7PointCode::ANSI:
  897. data[1] = (unsigned char)((params.getIntValue(YSTRING("slc"),sls) & 0x0f) | (code << 4));
  898. data[2] = (unsigned char)(code >> 4);
  899. len = 3;
  900. break;
  901. default:
  902. Debug(DebugStub,"Please implement CBD for type %u",t);
  903. return false;
  904. }
  905. return (cmd == SS7MsgSNM::CBA)
  906. ? transmitMSU(SS7MSU(txSio,lbl,&data,len),lbl,txSls) >= 0
  907. : postpone(new SS7MSU(txSio,lbl,&data,len),lbl,txSls,1000,2000,true);
  908. }
  909. default:
  910. if (cmd >= 0)
  911. Debug(this,DebugStub,"Unimplemented control %s (%d) [%p]",
  912. lookup(cmd,s_snm_names,"???"),cmd,this);
  913. }
  914. }
  915. }
  916. TelEngine::destruct(l);
  917. return false;
  918. }
  919. void SS7Management::notify(SS7Layer3* network, int sls)
  920. {
  921. Debug(this,DebugAll,"SS7Management::notify(%p,%d) [%p]",network,sls,this);
  922. if (network && (sls >= 0)) {
  923. DDebug(this,DebugInfo,"Link %d inhibitions: 0x%02X [%p]",
  924. sls,network->inhibited(sls),this);
  925. bool linkUp = network->operational(sls);
  926. if (linkUp && !network->inhibited(sls,SS7Layer2::Inactive))
  927. return;
  928. bool linkAvail[257];
  929. bool force = true;
  930. int txSls;
  931. bool localLink = false;
  932. for (txSls = 0; m_changeMsgs && (txSls < 256); txSls++)
  933. localLink = (linkAvail[txSls] = (txSls != sls) && network->inService(txSls)) || localLink;
  934. // if no link is available in linkset rely on another linkset
  935. linkAvail[256] = m_changeSets && !localLink;
  936. for (unsigned int i = 0; m_changeMsgs && (i < YSS7_PCTYPE_COUNT); i++) {
  937. SS7PointCode::Type type = static_cast<SS7PointCode::Type>(i+1);
  938. unsigned int local = network->getLocal(type);
  939. if (!local && SS7Layer4::network())
  940. local = SS7Layer4::network()->getLocal(type);
  941. if (!local)
  942. continue;
  943. String addr;
  944. addr << SS7PointCode::lookup(type) << "," << SS7PointCode(type,local);
  945. Debug(this,DebugNote,"Link %s:%d is %s [%p]",addr.c_str(),sls,
  946. (linkUp ? "up" : "down"),this);
  947. const char* oper = linkUp ? "changeback" : "changeover";
  948. ObjList* routes = getNetRoutes(network,type);
  949. if (routes)
  950. routes = routes->skipNull();
  951. for (; routes; routes = routes->skipNext()) {
  952. const SS7Route* r = static_cast<const SS7Route*>(routes->get());
  953. if (r && !r->priority()) {
  954. // found adjacent node, emit change orders to it
  955. int seq = -1;
  956. txSls = 0;
  957. if (!linkUp && network->inhibited(sls,SS7Layer2::Inactive)) {
  958. // already inactive, fix sequences if possible
  959. seq = network->getSequence(sls);
  960. DDebug(this,DebugAll,"Got sequence %d for link %s:%d [%p]",
  961. seq,addr.c_str(),sls,this);
  962. if (seq < 0)
  963. return;
  964. txSls = 256;
  965. }
  966. String tmp = addr;
  967. tmp << "," << SS7PointCode(type,r->packed()) << "," << sls;
  968. String slc(sls);
  969. for (; txSls <= 256; txSls++) {
  970. if (!linkAvail[txSls])
  971. continue;
  972. NamedList* ctl = controlCreate(oper);
  973. if (!ctl)
  974. continue;
  975. Debug(this,DebugAll,"Sending Link %d %s %s on %d [%p]",
  976. sls,oper,tmp.c_str(),txSls,this);
  977. ctl->setParam("address",tmp);
  978. ctl->setParam("slc",slc);
  979. ctl->setParam("linksel",String(txSls & 0xff));
  980. if (linkUp)
  981. ctl->setParam("code",String((txSls + sls) & 0xff));
  982. else {
  983. if (seq < 0)
  984. seq = network->getSequence(sls);
  985. DDebug(this,DebugAll,"Got sequence number %d [%p]",seq,this);
  986. if (seq >= 0)
  987. ctl->setParam("sequence",String(seq));
  988. else
  989. ctl->setParam("emergency",String::boolText(true));
  990. }
  991. ctl->setParam("automatic",String::boolText(true));
  992. controlExecute(ctl);
  993. force = false;
  994. }
  995. while (seq >= 0) {
  996. // scan pending list for matching ECA, turn them into COA/XCA
  997. SS7Label label(type,local,r->packed(),sls);
  998. lock();
  999. SnmPending* pend = 0;
  1000. for (ObjList* l = m_pending.skipNull(); l; l = l->skipNext()) {
  1001. SnmPending* p = static_cast<SnmPending*>(l->get());
  1002. const unsigned char* ptr = p->msu().getData(p->length()+1,1);
  1003. if (!(ptr && p->matches(label)))
  1004. continue;
  1005. if (ptr[0] != SS7MsgSNM::ECA)
  1006. continue;
  1007. pend = static_cast<SnmPending*>(m_pending.remove(p,false));
  1008. break;
  1009. }
  1010. unlock();
  1011. if (pend) {
  1012. const char* cmd = "COA";
  1013. if (seq & 0xff000000) {
  1014. seq &= 0x00ffffff;
  1015. cmd = "XCA";
  1016. }
  1017. Debug(this,DebugInfo,"Turning pending ECA into %s with sequence %d [%p]",
  1018. cmd,seq,this);
  1019. NamedList* ctl = controlCreate(cmd);
  1020. if (ctl) {
  1021. ctl->setParam("address",tmp);
  1022. ctl->setParam("slc",slc);
  1023. ctl->setParam("linksel",String(pend->txSls()));
  1024. ctl->setParam("sequence",String(seq));
  1025. ctl->setParam("automatic",String::boolText(true));
  1026. controlExecute(ctl);
  1027. force = false;
  1028. }
  1029. TelEngine::destruct(pend);
  1030. }
  1031. else
  1032. break;
  1033. }
  1034. }
  1035. }
  1036. }
  1037. if (force) {
  1038. if (linkUp) {
  1039. Debug(this,DebugMild,"Could not changeback link %d, activating anyway [%p]",sls,this);
  1040. network->inhibit(sls,0,SS7Layer2::Inactive);
  1041. }
  1042. else {
  1043. Debug(this,DebugMild,"Could not changeover link %d, deactivating anyway [%p]",sls,this);
  1044. network->inhibit(sls,SS7Layer2::Inactive,0);
  1045. }
  1046. }
  1047. }
  1048. }
  1049. bool SS7Management::postpone(SS7MSU* msu, const SS7Label& label, int txSls,
  1050. u_int64_t interval, u_int64_t global, bool force, const Time& when)
  1051. {
  1052. lock();
  1053. unsigned int len = msu->length();
  1054. for (ObjList* l = m_pending.skipNull(); l; l = l->skipNext()) {
  1055. SnmPending* p = static_cast<SnmPending*>(l->get());
  1056. if (p->txSls() != txSls || p->msu().length() != len)
  1057. continue;
  1058. if (::memcmp(msu->data(),p->msu().data(),len))
  1059. continue;
  1060. const unsigned char* buf = msu->getData(label.length()+1,1);
  1061. Debug(this,DebugAll,"Refusing to postpone duplicate %s on %d",
  1062. SS7MsgSNM::lookup((SS7MsgSNM::Type)buf[0],"???"),txSls);
  1063. TelEngine::destruct(msu);
  1064. break;
  1065. }
  1066. unlock();
  1067. if (msu && ((interval == 0) || (transmitMSU(*msu,label,txSls) >= 0) || force)) {
  1068. lock();
  1069. m_pending.add(new SnmPending(msu,label,txSls,interval,global),when);
  1070. unlock();
  1071. return true;
  1072. }
  1073. TelEngine::destruct(msu);
  1074. return false;
  1075. }
  1076. bool SS7Management::timeout(const SS7MSU& msu, const SS7Label& label, int txSls, bool final)
  1077. {
  1078. DDebug(this,DebugAll,"Timeout %u%s [%p]",txSls,(final ? " final" : ""),this);
  1079. if (!final)
  1080. return true;
  1081. const unsigned char* buf = msu.getData(label.length()+1,1);
  1082. if (!buf)
  1083. return false;
  1084. String link;
  1085. link << SS7PointCode::lookup(label.type()) << "," << label;
  1086. switch (buf[0]) {
  1087. case SS7MsgSNM::COO:
  1088. case SS7MsgSNM::XCO:
  1089. case SS7MsgSNM::ECO:
  1090. Debug(this,DebugNote,"Changeover timed out on %s",link.c_str());
  1091. inhibit(label,SS7Layer2::Inactive);
  1092. break;
  1093. case SS7MsgSNM::ECA:
  1094. Debug(this,DebugNote,"Emergency changeover acknowledge on %s",link.c_str());
  1095. transmitMSU(msu,label,txSls);
  1096. break;
  1097. case SS7MsgSNM::CBD:
  1098. Debug(this,DebugNote,"Changeback timed out on %s",link.c_str());
  1099. inhibit(label,0,SS7Layer2::Inactive);
  1100. break;
  1101. case SS7MsgSNM::LIN:
  1102. Debug(this,DebugWarn,"Link inhibit timed out on %s",link.c_str());
  1103. break;
  1104. case SS7MsgSNM::LUN:
  1105. Debug(this,DebugWarn,"Link uninhibit timed out on %s",link.c_str());
  1106. break;
  1107. case SS7MsgSNM::LRT:
  1108. if (inhibited(label,SS7Layer2::Remote))
  1109. postpone(new SS7MSU(msu),label,txSls,TIMER5M);
  1110. break;
  1111. case SS7MsgSNM::LLT:
  1112. if (inhibited(label,SS7Layer2::Local))
  1113. postpone(new SS7MSU(msu),label,txSls,TIMER5M);
  1114. break;
  1115. case SS7MsgSNM::TFP:
  1116. return false;
  1117. }
  1118. return true;
  1119. }
  1120. bool SS7Management::timeout(SignallingMessageTimer& timer, bool final)
  1121. {
  1122. SnmPending& msg = static_cast<SnmPending&>(timer);
  1123. if (final) {
  1124. String addr;
  1125. addr << msg;
  1126. Debug(this,DebugInfo,"Expired %s control sequence to %s [%p]",
  1127. msg.snmName(),addr.c_str(),this);
  1128. }
  1129. return timeout(msg.msu(),msg,msg.txSls(),final);
  1130. }
  1131. void SS7Management::timerTick(const Time& when)
  1132. {
  1133. for (;;) {
  1134. if (!lock(SignallingEngine::maxLockWait()))
  1135. break;
  1136. SnmPending* msg = static_cast<SnmPending*>(m_pending.timeout(when));
  1137. unlock();
  1138. if (!msg)
  1139. break;
  1140. if (!msg->global().started() || msg->global().timeout(when.msec()))
  1141. timeout(*msg,true);
  1142. else if (timeout(*msg,false)) {
  1143. transmitMSU(msg->msu(),*msg,msg->txSls());
  1144. m_pending.add(msg,when);
  1145. msg = 0;
  1146. }
  1147. TelEngine::destruct(msg);
  1148. }
  1149. }
  1150. bool SS7Management::inhibit(const SS7Label& link, int setFlags, int clrFlags)
  1151. {
  1152. SS7Router* router = YOBJECT(SS7Router,SS7Layer4::network());
  1153. return router && router->inhibit(link,setFlags,clrFlags);
  1154. }
  1155. bool SS7Management::inhibited(const SS7Label& link, int flags)
  1156. {
  1157. SS7Router* router = YOBJECT(SS7Router,SS7Layer4::network());
  1158. return router && router->inhibited(link,flags);
  1159. }
  1160. void SS7Management::recover(const SS7Label& link, int sequence)
  1161. {
  1162. SS7Router* router = YOBJECT(SS7Router,SS7Layer4::network());
  1163. if (router)
  1164. router->recoverMSU(link,sequence);
  1165. }
  1166. /* vi: set ts=8 sw=4 sts=4 noet: */